- verifica email se non è stata verificata (componente)
- altri aggiornamenti grafica PAGERIS. - OLLAMA AI
This commit is contained in:
1778
_LIMBO/Casi d'Uso Ollama - Esempi Pratici.html
Normal file
1778
_LIMBO/Casi d'Uso Ollama - Esempi Pratici.html
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -13,15 +13,15 @@
|
||||
<div class="card-icon-wrapper">
|
||||
<q-icon name="fas fa-sign-in-alt" size="48px" class="card-icon" />
|
||||
</div>
|
||||
|
||||
|
||||
<div class="card-content">
|
||||
<h3 class="card-title">Benvenuto su RISO</h3>
|
||||
<h3 class="card-title">Benvenuto su {{ tools.sitename() }}</h3>
|
||||
<p class="card-description">
|
||||
Accedi con le tue credenziali per utilizzare la APP e per unirti
|
||||
al Circuito di scambio RIS del tuo territorio
|
||||
ai membri della Community
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="card-actions">
|
||||
<q-btn
|
||||
unelevated
|
||||
@@ -47,7 +47,7 @@
|
||||
<span class="telegram-subtitle">Unisciti al gruppo Provinciale</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<q-btn
|
||||
rounded
|
||||
unelevated
|
||||
@@ -71,7 +71,7 @@
|
||||
<span class="help-subtitle">Consulta la guida completa</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<q-btn
|
||||
rounded
|
||||
unelevated
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
<div class="key-label">
|
||||
{{ mykey }}
|
||||
</div>
|
||||
<div class="value-content" :style="color ? `background-color: ${color}; color: white;` : ''">
|
||||
<div
|
||||
class="value-content"
|
||||
:style="color ? `background-color: ${color}; color: white;` : ''"
|
||||
>
|
||||
<span v-if="mydate">
|
||||
<CDateTime
|
||||
v-model:value="mydate"
|
||||
@@ -11,10 +14,17 @@
|
||||
:canEdit="false"
|
||||
/>
|
||||
</span>
|
||||
<span v-else class="value-text">
|
||||
<span
|
||||
v-else
|
||||
class="value-text"
|
||||
>
|
||||
{{ myvalue || '-' }}
|
||||
</span>
|
||||
|
||||
</div>
|
||||
<div
|
||||
class="value-content"
|
||||
:style="color ? `background-color: ${color}; color: white;` : ''"
|
||||
>
|
||||
<q-btn
|
||||
v-if="showSetButton && onSetValue"
|
||||
rounded
|
||||
@@ -30,8 +40,7 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" src="./CKeyAndValue.ts">
|
||||
</script>
|
||||
<script lang="ts" src="./CKeyAndValue.ts"></script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import './CKeyAndValue.scss';
|
||||
|
||||
@@ -32,6 +32,7 @@ import { shared_consts } from '@/common/shared_vuejs';
|
||||
import { LandingFooter } from '@/components/LandingFooter';
|
||||
import { CMyActivities } from '@/components/CMyActivities';
|
||||
import { CECommerce } from '@/components/CECommerce';
|
||||
import { CheckEmail } from '@/components/CheckEmail';
|
||||
import { HomeRiso } from '@/components/HomeRiso';
|
||||
import mycircuits from '@/views/user/mycircuits/mycircuits.vue';
|
||||
import PageRis from '@/components/pageris/pageris.vue';
|
||||
@@ -118,6 +119,7 @@ export default defineComponent({
|
||||
CCheckIfIsLogged,
|
||||
CStatusReg,
|
||||
CDashboard,
|
||||
CheckEmail,
|
||||
CMainView,
|
||||
CNotifAtTop,
|
||||
CPresentazione,
|
||||
|
||||
@@ -904,14 +904,7 @@
|
||||
>
|
||||
Msg di Controllo Verifica Email
|
||||
</div>
|
||||
<div class="q-pa-xs q-gutter-md">
|
||||
<div
|
||||
v-if="tools.isLogged() && !tools.isVerified()"
|
||||
class="text-verified"
|
||||
>
|
||||
{{ t('components.authentication.email_verification.link_sent') }}
|
||||
</div>
|
||||
</div>
|
||||
<CheckEmail />
|
||||
</div>
|
||||
<div v-else-if="myel.type === shared_consts.ELEMTYPE.PRESENTAZIONE">
|
||||
<div
|
||||
@@ -1090,10 +1083,10 @@
|
||||
Check Sito di Test
|
||||
</div>
|
||||
<q-banner
|
||||
v-if="tools.isTest() && false"
|
||||
v-if="tools.isTest()"
|
||||
rounded
|
||||
dense
|
||||
class="bg-negative text-white"
|
||||
class="bg-negative text-white q-ma-sm"
|
||||
color="primary q-title"
|
||||
style="text-align: center"
|
||||
>
|
||||
@@ -1104,7 +1097,7 @@
|
||||
size="xs"
|
||||
/>
|
||||
</template>
|
||||
<span class="mybanner"> TEST !</span>
|
||||
<span class="mybanner"> AMBIENTE DI TEST !</span>
|
||||
</q-banner>
|
||||
</div>
|
||||
<div v-else-if="myel.type === shared_consts.ELEMTYPE.CHECKNEWVERSION">
|
||||
|
||||
@@ -588,4 +588,48 @@
|
||||
padding: 8px 12px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.annuncio-location {
|
||||
font-size: 1rem;
|
||||
color: #718096;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
|
||||
&::before {
|
||||
content: '📍';
|
||||
}
|
||||
}
|
||||
|
||||
// Il contenitore padre (q-item o card) deve avere position relative
|
||||
.q-item,
|
||||
.event-card {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
// Bottone overlay fisso a destra
|
||||
.action-menu-btn-overlay {
|
||||
position: absolute !important;
|
||||
top: 8px;
|
||||
right: 0px;
|
||||
transform: translateY(-50%);
|
||||
z-index: 10;
|
||||
|
||||
// Sfondo semi-trasparente per visibilità
|
||||
background: rgba(255, 255, 255, 0.8) !important;
|
||||
|
||||
// Ombra leggera
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 1) !important;
|
||||
}
|
||||
}
|
||||
|
||||
// Alternativa: in alto a destra
|
||||
.action-menu-btn-overlay--top {
|
||||
position: absolute !important;
|
||||
top: 4px;
|
||||
right: 4px;
|
||||
z-index: 10;
|
||||
}
|
||||
@@ -340,8 +340,9 @@
|
||||
<span
|
||||
v-for="(rec, ind) of myrec.mycities"
|
||||
:key="ind"
|
||||
class="annuncio-location"
|
||||
>
|
||||
<span v-if="ind > 0">, </span>
|
||||
<span v-if="ind > 0"></span>
|
||||
<span v-if="table === shared_consts.TABLES_MYHOSPS" class="cities-text-bold">{{ rec.comune }} ({{ rec.prov }})</span>
|
||||
<span v-else>{{ rec.comune }} ({{ rec.prov }})</span>
|
||||
</span>
|
||||
@@ -353,12 +354,11 @@
|
||||
<q-item-section
|
||||
v-if="tools.canModifyThisRec(myrec, table) || editOn"
|
||||
side
|
||||
top
|
||||
class="actions-section"
|
||||
>
|
||||
<q-btn
|
||||
round
|
||||
flat
|
||||
dense
|
||||
icon="more_vert"
|
||||
size="sm"
|
||||
class="action-menu-btn"
|
||||
|
||||
@@ -459,7 +459,7 @@
|
||||
<q-item-label>
|
||||
<q-btn rounded icon="fas fa-ellipsis-h">
|
||||
<q-menu>
|
||||
<q-list
|
||||
<!--<q-list
|
||||
v-if="!userStore.IsMyFriendByUsername(contact.username)"
|
||||
style="min-width: 200px"
|
||||
>
|
||||
@@ -481,7 +481,7 @@
|
||||
t('friends.ask_friend')
|
||||
}}</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-list>-->
|
||||
<q-list style="min-width: 200px">
|
||||
<q-item
|
||||
clickable
|
||||
@@ -515,7 +515,7 @@
|
||||
>
|
||||
<q-menu>
|
||||
<q-list style="min-width: 200px">
|
||||
<q-item
|
||||
<!--<q-item
|
||||
v-if="
|
||||
!userStore.IsMyFriendByUsername(contact.username) &&
|
||||
!userStore.IsAskedFriendByUsername(contact.username)
|
||||
@@ -538,9 +538,9 @@
|
||||
<q-item-section>{{
|
||||
t('friends.ask_friend')
|
||||
}}</q-item-section>
|
||||
</q-item>
|
||||
</q-item>-->
|
||||
<q-item
|
||||
v-else-if="
|
||||
v-if="
|
||||
!userStore.IsMyFriendByUsername(contact.username) &&
|
||||
userStore.IsAskedFriendByUsername(contact.username)
|
||||
"
|
||||
|
||||
@@ -35,6 +35,7 @@ export default defineComponent({
|
||||
});
|
||||
|
||||
const handleInput = (value: string | number) => {
|
||||
// console.log('value', value)
|
||||
if (value === '⌫') {
|
||||
inputValue.value = inputValue.value.slice(0, -1);
|
||||
} else if (value === '.' && !inputValue.value.includes('.')) {
|
||||
@@ -43,12 +44,14 @@ export default defineComponent({
|
||||
inputValue.value += value.toString();
|
||||
}
|
||||
|
||||
// console.log('inputValue.value', inputValue.value)
|
||||
|
||||
// Verifica se inputValue contiene più di due cifre decimali
|
||||
const decimalPattern = /^\d+(\.\d{0,2})?$/; // Regex per validare il numero
|
||||
const newValue = inputValue.value;
|
||||
|
||||
// Se non rispetta il formato, tronca il numero a 2 cifre decimali
|
||||
if (!decimalPattern.test(newValue)) {
|
||||
/*if (!decimalPattern.test(newValue)) {
|
||||
// Se troviamo un punto decimale, manteniamo solo le prime 2 cifre
|
||||
const parts = newValue.split('.'); // Dividi il numero in parte intera e decimale
|
||||
if (parts.length > 1) {
|
||||
@@ -58,7 +61,7 @@ export default defineComponent({
|
||||
// Nessuna parte decimale, quindi usa solo la parte intera
|
||||
inputValue.value = parts[0];
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
emit('update:modelValue', inputValue.value);
|
||||
};
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
class="balance-text-saldo"
|
||||
>Saldo:
|
||||
</span>
|
||||
{{ currentBalance > 0 ? '+' : '' }}{{ currentBalance }} RIS
|
||||
{{ currentBalance > 0 ? '+' : '' }}{{ currentBalance.toFixed(2) }} RIS
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -47,14 +47,14 @@
|
||||
:style="{ '--zero-position': zeroPosition + '%' }"
|
||||
>
|
||||
<div class="marker min-marker">
|
||||
<span class="marker-value">{{ minLimit }}</span>
|
||||
<span class="marker-value">{{ minLimit.toFixed(2) }}</span>
|
||||
<span class="marker-label">Fido</span>
|
||||
</div>
|
||||
<div class="marker zero-marker-label">
|
||||
<span class="marker-value">0</span>
|
||||
</div>
|
||||
<div class="marker max-marker">
|
||||
<span class="marker-value">+{{ maxLimit }}</span>
|
||||
<span class="marker-value">+{{ maxLimit.toFixed(2) }}</span>
|
||||
<span class="marker-label">Max</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -69,7 +69,7 @@
|
||||
color="negative"
|
||||
/>
|
||||
<span class="availability-text">
|
||||
Puoi dare ancora: <strong>{{ canGive }} RIS</strong>
|
||||
Puoi dare ancora: <strong>{{ canGive.toFixed(2) }} RIS</strong>
|
||||
</span>
|
||||
</div>
|
||||
<div class="availability-item">
|
||||
@@ -79,7 +79,7 @@
|
||||
color="positive"
|
||||
/>
|
||||
<span class="availability-text">
|
||||
Puoi ricevere: <strong>{{ canReceive }} RIS</strong>
|
||||
Puoi ricevere: <strong>{{ canReceive.toFixed(2) }} RIS</strong>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,341 +1,575 @@
|
||||
.c-send-coins {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
padding-bottom: 80px;
|
||||
// Variables
|
||||
$primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
$orange-gradient: linear-gradient(135deg, #f97316 0%, #ea580c 100%);
|
||||
$ris-color: #ff5500;
|
||||
$border-radius-lg: 16px;
|
||||
$border-radius-md: 12px;
|
||||
$border-radius-sm: 8px;
|
||||
$shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||
$shadow-md: 0 4px 16px rgba(0, 0, 0, 0.12);
|
||||
|
||||
// Main Dialog
|
||||
.send-coins-dialog {
|
||||
border-radius: $border-radius-lg $border-radius-lg 0 0;
|
||||
overflow: hidden;
|
||||
max-width: 420px;
|
||||
width: 100%;
|
||||
|
||||
@media (min-width: 600px) {
|
||||
border-radius: $border-radius-lg;
|
||||
max-height: 90vh;
|
||||
}
|
||||
}
|
||||
|
||||
.page-header {
|
||||
.mobile-fullheight {
|
||||
height: 100vh;
|
||||
max-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
// Header
|
||||
.dialog-header {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.header-gradient {
|
||||
background: $primary-gradient;
|
||||
padding: 12px 16px 14px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.header-top-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 12px 16px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
backdrop-filter: blur(10px);
|
||||
|
||||
.back-btn {
|
||||
color: white;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.header-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: white;
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
}
|
||||
}
|
||||
|
||||
.content-section {
|
||||
padding: 20px 16px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: white;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.section-subtitle {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
margin-bottom: 16px;
|
||||
|
||||
:deep(.q-field__control) {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border-radius: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.circuit-selector {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.circuit-select {
|
||||
:deep(.q-field__control) {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border-radius: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.user-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.user-item {
|
||||
.header-title-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 12px;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border-radius: 12px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
background: rgba(255, 255, 255, 0.85);
|
||||
}
|
||||
|
||||
.user-info {
|
||||
flex: 1;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.user-name {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
.user-username {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.selected-user-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 16px;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border-radius: 16px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.user-info {
|
||||
margin-left: 12px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.circuit-badge {
|
||||
display: inline-block;
|
||||
padding: 4px 12px;
|
||||
background: rgba(103, 126, 234, 0.1);
|
||||
color: #667eea;
|
||||
border-radius: 12px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
margin-top: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.circuit-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.circuit-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 16px;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border-radius: 12px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
|
||||
&.selected {
|
||||
background: rgba(103, 126, 234, 0.15);
|
||||
border: 2px solid #667eea;
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.circuit-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.circuit-name {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #1a1a1a;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.circuit-balance {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.amount-section {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border-radius: 16px;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.amount-display {
|
||||
.ris-coin-icon {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 50%;
|
||||
background: $orange-gradient;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 24px;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
border-radius: 16px;
|
||||
margin-bottom: 16px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
|
||||
.currency {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
margin-right: 8px;
|
||||
box-shadow: 0 2px 8px rgba(255, 107, 53, 0.4);
|
||||
|
||||
.ris-logo {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.amount-value {
|
||||
font-size: 42px;
|
||||
|
||||
.coin-symbol {
|
||||
color: white;
|
||||
font-weight: 700;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.keyboard-btn {
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: white;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.limits-info {
|
||||
.header-title {
|
||||
color: white;
|
||||
font-size: 17px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
// Balance Card - Compatto
|
||||
.balance-card {
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
backdrop-filter: blur(20px);
|
||||
border-radius: $border-radius-sm;
|
||||
padding: 10px 14px;
|
||||
}
|
||||
|
||||
.balance-info {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding: 12px 0;
|
||||
margin-bottom: 16px;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.1);
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.limit-item {
|
||||
.balance-main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.limit-label {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.limit-value {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #1a1a1a;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.balance-label {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.balance-value {
|
||||
color: white;
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
line-height: 1.2;
|
||||
|
||||
.balance-symbol {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
opacity: 0.9;
|
||||
}
|
||||
}
|
||||
|
||||
.description-input {
|
||||
:deep(.q-field__control) {
|
||||
border-radius: 12px;
|
||||
}
|
||||
.balance-fido {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
border-radius: 12px;
|
||||
padding: 12px;
|
||||
font-size: 16px;
|
||||
.fido-label {
|
||||
display: block;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.fido-value {
|
||||
color: #4ade80;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
.confirmation-card {
|
||||
border-radius: 24px;
|
||||
max-width: 400px;
|
||||
width: 90vw;
|
||||
// Content
|
||||
.dialog-content {
|
||||
padding: 14px 16px;
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.confirmation-header {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
padding: 20px;
|
||||
|
||||
.header-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: white;
|
||||
// Section Block - Più compatto
|
||||
.section-block {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.section-label {
|
||||
display: block;
|
||||
color: #6b7280;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
// Modern Select
|
||||
.modern-select {
|
||||
:deep(.q-field__control) {
|
||||
border-radius: $border-radius-sm;
|
||||
background: #f9fafb;
|
||||
border: 1.5px solid #e5e7eb;
|
||||
min-height: 40px;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
border-color: #d1d5db;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.q-field__control-container) {
|
||||
|
||||
}
|
||||
|
||||
:deep(.q-field--focused .q-field__control) {
|
||||
border-color: #667eea;
|
||||
box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.15);
|
||||
}
|
||||
|
||||
:deep(.q-field__native) {
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
color: #374151;
|
||||
}
|
||||
|
||||
:deep(.q-field__label) {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.modern-input {
|
||||
:deep(.q-field__control) {
|
||||
border-radius: $border-radius-sm;
|
||||
background: #f9fafb;
|
||||
border: 1.5px solid #e5e7eb;
|
||||
min-height: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
// Recipient Card - Compatto
|
||||
.recipient-card {
|
||||
background: linear-gradient(135deg, #f5f3ff 0%, #ede9fe 100%);
|
||||
border: 1.5px solid #ddd6fe;
|
||||
border-radius: $border-radius-md;
|
||||
padding: 10px 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.recipient-content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.recipient-view {
|
||||
:deep(.q-item) {
|
||||
padding: 0;
|
||||
min-height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.circuit-badge {
|
||||
color: white;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
padding: 4px 10px;
|
||||
border-radius: 16px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
// Amount Input Row - Compatto
|
||||
.amount-input-row {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.amount-input {
|
||||
:deep(.q-field__control) {
|
||||
border-radius: $border-radius-sm;
|
||||
background: linear-gradient(135deg, #1e1b4b 0%, #312e81 100%);
|
||||
border: none;
|
||||
min-height: 48px;
|
||||
padding: 4px 12px;
|
||||
}
|
||||
|
||||
:deep(.q-field__native) {
|
||||
color: white !important;
|
||||
font-size: 22px !important;
|
||||
font-weight: 700 !important;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.confirmation-content {
|
||||
padding: 24px;
|
||||
text-align: center;
|
||||
}
|
||||
:deep(.q-field__prepend) {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.amount-label {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.amount-display-large {
|
||||
font-size: 36px;
|
||||
font-weight: 700;
|
||||
color: #1a1a1a;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.users-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 24px;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.user-col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.user-name-small {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.verify-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #1a1a1a;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.verify-text {
|
||||
font-size: 15px;
|
||||
color: #666;
|
||||
line-height: 1.5;
|
||||
|
||||
.amount-highlight {
|
||||
color: #667eea;
|
||||
font-weight: 700;
|
||||
:deep(.q-field__append) {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.confirmation-actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
padding: 16px 24px;
|
||||
.currency-symbol {
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
font-size: 18px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.cancel-btn,
|
||||
.confirm-btn {
|
||||
flex: 1;
|
||||
border-radius: 12px;
|
||||
padding: 12px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
text-transform: none;
|
||||
.coin-badge {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 20%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
font-weight: 700;
|
||||
font-size: 12px;
|
||||
box-shadow: 0 2px 8px rgba(255, 107, 53, 0.3);
|
||||
}
|
||||
|
||||
.keyboard-btn {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
|
||||
&:hover {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
// Banners
|
||||
.warning-banner {
|
||||
background: $orange-gradient;
|
||||
color: white;
|
||||
font-weight: 500;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.error-banner {
|
||||
background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
|
||||
color: white;
|
||||
font-weight: 500;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
// Note Input - Compatto
|
||||
.modern-textarea {
|
||||
:deep(.q-field__control) {
|
||||
border-radius: $border-radius-sm;
|
||||
background: #f9fafb;
|
||||
border: 1.5px solid #e5e7eb;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
:deep(.q-field--focused .q-field__control) {
|
||||
border-color: #667eea;
|
||||
box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.15);
|
||||
}
|
||||
|
||||
:deep(.q-field__native) {
|
||||
resize: none;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
:deep(.q-field__counter) {
|
||||
color: #9ca3af;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
:deep(.q-field__label) {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
// Actions
|
||||
.dialog-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
padding: 12px 16px;
|
||||
background: white;
|
||||
border-top: 1px solid #f3f4f6;
|
||||
}
|
||||
|
||||
.fixed-bottom-actions {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 100;
|
||||
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.08);
|
||||
padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px));
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
flex: 1;
|
||||
background: #f3f4f6;
|
||||
color: #6b7280;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
padding: 10px 16px;
|
||||
border-radius: $border-radius-sm;
|
||||
text-transform: none;
|
||||
|
||||
&:hover {
|
||||
background: #e5e7eb;
|
||||
}
|
||||
}
|
||||
|
||||
.send-btn {
|
||||
flex: 2;
|
||||
background: $orange-gradient;
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
padding: 10px 20px;
|
||||
border-radius: $border-radius-sm;
|
||||
text-transform: none;
|
||||
box-shadow: 0 2px 8px rgba(249, 115, 22, 0.3);
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:hover:not(.btn-disabled) {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(249, 115, 22, 0.4);
|
||||
}
|
||||
|
||||
&.btn-disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.send-btn-text {
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.send-btn-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
// Keyboard Dialog
|
||||
.keyboard-dialog {
|
||||
width: 100%;
|
||||
max-width: 420px;
|
||||
border-radius: $border-radius-lg $border-radius-lg 0 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.keyboard-header {
|
||||
background: #f9fafb;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
.keyboard-header-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.keyboard-title {
|
||||
color: #6b7280;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.done-btn {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.keyboard-display {
|
||||
background: linear-gradient(135deg, #1e1b4b 0%, #312e81 100%);
|
||||
border-radius: $border-radius-sm;
|
||||
padding: 14px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.keyboard-amount {
|
||||
color: white;
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.keyboard-coin-badge {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 20%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
font-weight: 700;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.keyboard-section {
|
||||
padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px)) !important;
|
||||
}
|
||||
|
||||
// Dark mode support
|
||||
.body--dark {
|
||||
.send-coins-dialog {
|
||||
background: #1f2937;
|
||||
}
|
||||
|
||||
.dialog-content {
|
||||
background: #1f2937;
|
||||
}
|
||||
|
||||
.section-label {
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
.modern-select,
|
||||
.modern-input {
|
||||
:deep(.q-field__control) {
|
||||
background: #374151;
|
||||
border-color: #4b5563;
|
||||
}
|
||||
|
||||
:deep(.q-field__native) {
|
||||
color: #f3f4f6;
|
||||
}
|
||||
}
|
||||
|
||||
.recipient-card {
|
||||
background: linear-gradient(135deg, #374151 0%, #4b5563 100%);
|
||||
border-color: #6b7280;
|
||||
}
|
||||
|
||||
.modern-textarea {
|
||||
:deep(.q-field__control) {
|
||||
background: #374151;
|
||||
border-color: #4b5563;
|
||||
}
|
||||
|
||||
:deep(.q-field__native) {
|
||||
color: #f3f4f6;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-actions {
|
||||
background: #1f2937;
|
||||
border-top-color: #374151;
|
||||
}
|
||||
|
||||
.fixed-bottom-actions {
|
||||
background: #1f2937;
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
background: #374151;
|
||||
color: #d1d5db;
|
||||
}
|
||||
|
||||
.keyboard-dialog {
|
||||
background: #1f2937;
|
||||
}
|
||||
|
||||
.keyboard-header {
|
||||
background: #374151;
|
||||
border-color: #4b5563;
|
||||
}
|
||||
|
||||
.keyboard-title {
|
||||
color: #d1d5db;
|
||||
}
|
||||
}
|
||||
|
||||
// Responsive - Ultra compatto per mobile piccoli
|
||||
@media (max-width: 360px) {
|
||||
.header-gradient {
|
||||
padding: 10px 12px 12px;
|
||||
}
|
||||
|
||||
.balance-value {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.dialog-content {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.section-block {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.amount-input {
|
||||
:deep(.q-field__native) {
|
||||
font-size: 20px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,43 +1,47 @@
|
||||
import type { PropType } from 'vue';
|
||||
import { computed, defineComponent, onMounted, ref, watch } from 'vue'
|
||||
import { computed, defineComponent, onMounted, ref, watch } from 'vue';
|
||||
|
||||
import type { IAccount, ICircuit, IMyGroup, ISendCoin, IUserFields } from '../../model';
|
||||
import { IOperators, ISpecialField } from '../../model'
|
||||
import { tools } from '@tools'
|
||||
import { CSaldo } from '@/components/CSaldo'
|
||||
import { useUserStore } from '@store/UserStore'
|
||||
import { useCircuitStore } from '@store/CircuitStore'
|
||||
import { useQuasar } from 'quasar'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { CNumericKeyboard } from '@/components/CNumericKeyboard'
|
||||
import { CMyUserOnlyView } from '@/components/CMyUserOnlyView'
|
||||
import { CMyGroupOnlyView } from '@/components/CMyGroupOnlyView'
|
||||
import { CCheckCircuitsEnabled } from '@/components/CCheckCircuitsEnabled'
|
||||
import { costanti } from '@costanti'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { shared_consts } from '@/common/shared_vuejs'
|
||||
import { IOperators, ISpecialField } from '../../model';
|
||||
import { tools } from '@tools';
|
||||
import { CSaldo } from '@/components/CSaldo';
|
||||
import { useUserStore } from '@store/UserStore';
|
||||
import { useCircuitStore } from '@store/CircuitStore';
|
||||
import { useQuasar } from 'quasar';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { CNumericKeyboard } from '@/components/CNumericKeyboard';
|
||||
import { CMyUserOnlyView } from '@/components/CMyUserOnlyView';
|
||||
import { CMyGroupOnlyView } from '@/components/CMyGroupOnlyView';
|
||||
import { CCheckCircuitsEnabled } from '@/components/CCheckCircuitsEnabled';
|
||||
import { costanti } from '@costanti';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { shared_consts } from '@/common/shared_vuejs';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'CSendCoins',
|
||||
emits: ['close', 'showed'],
|
||||
props: {
|
||||
loadprofile: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
showprop: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
circuitname: {
|
||||
type: String,
|
||||
default: ''
|
||||
default: '',
|
||||
},
|
||||
qtydefault: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: ''
|
||||
default: '',
|
||||
},
|
||||
to_user: {
|
||||
type: Object as PropType<IUserFields>,
|
||||
required: false,
|
||||
default: null
|
||||
default: null,
|
||||
},
|
||||
to_group: {
|
||||
type: Object as PropType<IMyGroup>,
|
||||
@@ -65,99 +69,133 @@ export default defineComponent({
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
components: { CSaldo, CMyUserOnlyView, CMyGroupOnlyView, CCheckCircuitsEnabled, CNumericKeyboard },
|
||||
components: {
|
||||
CSaldo,
|
||||
CMyUserOnlyView,
|
||||
CMyGroupOnlyView,
|
||||
CCheckCircuitsEnabled,
|
||||
CNumericKeyboard,
|
||||
},
|
||||
|
||||
setup(props, { emit }) {
|
||||
const $q = useQuasar()
|
||||
const { t } = useI18n()
|
||||
const showpage = ref(false)
|
||||
const userStore = useUserStore()
|
||||
const circuitStore = useCircuitStore()
|
||||
const $router = useRouter()
|
||||
const $q = useQuasar();
|
||||
const { t } = useI18n();
|
||||
const showpage = ref(false);
|
||||
const userStore = useUserStore();
|
||||
const circuitStore = useCircuitStore();
|
||||
const $router = useRouter();
|
||||
|
||||
const from_username = ref(userStore.my.username)
|
||||
const from_groupname = ref('')
|
||||
const from_contocom = ref('')
|
||||
const circuitsel = ref('')
|
||||
const qty = ref(<string | number>'')
|
||||
const causal = ref('')
|
||||
const loading = ref(false)
|
||||
const visubanner = ref(true)
|
||||
const bothcircuits = ref(<any>[])
|
||||
const to_user_real = ref(<IUserFields>{});
|
||||
|
||||
const showProvinceToSelect = ref(false)
|
||||
const from_username = ref(userStore.my.username);
|
||||
const from_groupname = ref('');
|
||||
const from_contocom = ref('');
|
||||
const circuitsel = ref('');
|
||||
const qty = ref(<string | number>'');
|
||||
const causal = ref('');
|
||||
const loading = ref(false);
|
||||
const visubanner = ref(true);
|
||||
const bothcircuits = ref(<any>[]);
|
||||
|
||||
const groupSel = ref(<IMyGroup | null | undefined>null)
|
||||
const showProvinceToSelect = ref(false);
|
||||
const showKeyboard = ref(false);
|
||||
|
||||
const datasaved = ref(<any>null)
|
||||
const step = ref(0)
|
||||
const sendCoinDialog = ref(null)
|
||||
const groupSel = ref(<IMyGroup | null | undefined>null);
|
||||
|
||||
const circuittoload = ref(<ICircuit | undefined>undefined)
|
||||
const circuitloaded = ref(<ICircuit>{})
|
||||
const circuitdest = ref(<ICircuit | undefined>undefined)
|
||||
const accountloaded = ref(<IAccount | undefined | null>undefined)
|
||||
const accountdest = ref(<IAccount | undefined>undefined)
|
||||
const remainingCoins = ref(0)
|
||||
const maxsendable = ref(0)
|
||||
const numstep = ref(0)
|
||||
const arrTypesAccounts = ref(<any>[])
|
||||
const tipoConto = ref(shared_consts.AccountType.USER)
|
||||
const datasaved = ref(<any>null);
|
||||
const step = ref(0);
|
||||
const sendCoinDialog = ref(null);
|
||||
|
||||
const priceLabel = computed(() => circuitloaded.value ? `${qty.value} ` + circuitloaded.value.symbol : '')
|
||||
const arrayMarkerLabel = ref(<any>[])
|
||||
const circuittoload = ref(<ICircuit | undefined>undefined);
|
||||
const circuitloaded = ref(<ICircuit>{});
|
||||
const circuitdest = ref(<ICircuit | undefined>undefined);
|
||||
const accountloaded = ref(<IAccount | undefined | null>undefined);
|
||||
const accountdest = ref(<IAccount | undefined>undefined);
|
||||
const remainingCoins = ref(0);
|
||||
const maxsendable = ref(0);
|
||||
const numstep = ref(0);
|
||||
const arrTypesAccounts = ref(<any>[]);
|
||||
const tipoConto = ref(shared_consts.AccountType.USER);
|
||||
|
||||
const qtyRef = ref(<any>null)
|
||||
const causalRef = ref(<any>null)
|
||||
const priceLabel = computed(() =>
|
||||
circuitloaded.value ? `${qty.value} ` + circuitloaded.value.symbol : ''
|
||||
);
|
||||
const arrayMarkerLabel = ref(<any>[]);
|
||||
|
||||
const groupsListAdmin = ref(<IMyGroup[]>[])
|
||||
const qtyRef = ref(<any>null);
|
||||
const causalRef = ref(<any>null);
|
||||
|
||||
const arrGroupsList = ref(<any[]>[])
|
||||
const groupsListAdmin = ref(<IMyGroup[]>[]);
|
||||
|
||||
watch(() => circuitsel.value, (newval, oldval) => {
|
||||
tools.setCookie(tools.CIRCUIT_USE, newval)
|
||||
aggiorna()
|
||||
})
|
||||
const arrGroupsList = ref(<any[]>[]);
|
||||
|
||||
watch(() => tipoConto.value, (newval, oldval) => {
|
||||
watch(
|
||||
() => circuitsel.value,
|
||||
(newval, oldval) => {
|
||||
tools.setCookie(tools.CIRCUIT_USE, newval);
|
||||
aggiorna(true);
|
||||
}
|
||||
);
|
||||
|
||||
if (tipoConto.value === shared_consts.AccountType.CONTO_DI_GRUPPO) {
|
||||
if (arrGroupsList.value.length >= 1)
|
||||
from_groupname.value = arrGroupsList.value[0].value
|
||||
watch(
|
||||
() => tipoConto.value,
|
||||
(newval, oldval) => {
|
||||
if (tipoConto.value === shared_consts.AccountType.CONTO_DI_GRUPPO) {
|
||||
if (arrGroupsList.value.length >= 1)
|
||||
from_groupname.value = arrGroupsList.value[0].value;
|
||||
}
|
||||
|
||||
tools.setCookie(tools.COOK_TIPOCONTO, tipoConto.value.toString());
|
||||
|
||||
aggiorna(true);
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => from_groupname.value,
|
||||
(newval, oldval) => {
|
||||
aggiorna(true);
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => from_username.value,
|
||||
(newval, oldval) => {
|
||||
aggiorna(true);
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.showprop,
|
||||
(newval, oldval) => {
|
||||
showpage.value = newval;
|
||||
}
|
||||
);
|
||||
|
||||
async function aggiorna(load: boolean = false) {
|
||||
if (load) {
|
||||
inizio_caricamento();
|
||||
}
|
||||
|
||||
tools.setCookie(tools.COOK_TIPOCONTO, tipoConto.value.toString())
|
||||
groupSel.value = null;
|
||||
from_contocom.value = '';
|
||||
accountloaded.value = null;
|
||||
|
||||
aggiorna()
|
||||
})
|
||||
|
||||
watch(() => from_groupname.value, (newval, oldval) => {
|
||||
aggiorna()
|
||||
})
|
||||
|
||||
watch(() => from_username.value, (newval, oldval) => {
|
||||
aggiorna()
|
||||
})
|
||||
|
||||
watch(() => props.showprop, (newval, oldval) => {
|
||||
console.log('props.showprop', props.showprop, newval)
|
||||
showpage.value = newval
|
||||
})
|
||||
|
||||
async function aggiorna() {
|
||||
|
||||
groupSel.value = null
|
||||
from_contocom.value = ''
|
||||
accountloaded.value = null
|
||||
|
||||
if (!circuittoload.value || (circuittoload.value && circuittoload.value.name !== circuitsel.value)) {
|
||||
circuittoload.value = circuitStore.listcircuits.find((rec: ICircuit) => rec.name === circuitsel.value)
|
||||
if (
|
||||
!circuittoload.value ||
|
||||
(circuittoload.value && circuittoload.value.name !== circuitsel.value)
|
||||
) {
|
||||
circuittoload.value = circuitStore.listcircuits.find(
|
||||
(rec: ICircuit) => rec.name === circuitsel.value
|
||||
);
|
||||
|
||||
if (circuittoload.value) {
|
||||
loading.value = true
|
||||
await userStore.loadCircuit(circuittoload.value.path, '').then(({ data, status }: { data: any, status: number }) => {
|
||||
datasaved.value = data
|
||||
})
|
||||
loading.value = true;
|
||||
await userStore
|
||||
.loadCircuit(circuittoload.value.path, '')
|
||||
.then(({ data, status }: { data: any; status: number }) => {
|
||||
datasaved.value = data;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,201 +203,232 @@ export default defineComponent({
|
||||
try {
|
||||
arrTypesAccounts.value = [
|
||||
{
|
||||
label: t('circuit.personale') + ' ' + from_username.value,
|
||||
label: '👤 ' + t('circuit.personale') + ' - ' + from_username.value,
|
||||
value: shared_consts.AccountType.USER,
|
||||
},
|
||||
]
|
||||
|
||||
];
|
||||
|
||||
if (datasaved.value.circuit) {
|
||||
circuitloaded.value = datasaved.value.circuit
|
||||
circuitloaded.value = datasaved.value.circuit;
|
||||
|
||||
if (tipoConto.value === shared_consts.AccountType.USER) {
|
||||
accountloaded.value = userStore.getAccountByCircuitId(circuitloaded.value._id)
|
||||
accountloaded.value = userStore.getAccountByCircuitId(
|
||||
circuitloaded.value._id
|
||||
);
|
||||
} else if (tipoConto.value === shared_consts.AccountType.CONTO_DI_GRUPPO) {
|
||||
groupSel.value = userStore.my.profile.manage_mygroups.find((group: IMyGroup) => from_groupname.value === group.groupname)
|
||||
groupSel.value = userStore.my.profile.manage_mygroups.find(
|
||||
(group: IMyGroup) => from_groupname.value === group.groupname
|
||||
);
|
||||
|
||||
accountloaded.value = groupSel.value ? groupSel.value.account : null
|
||||
accountloaded.value = groupSel.value ? groupSel.value.account : null;
|
||||
} else if (tipoConto.value === shared_consts.AccountType.COMMUNITY_ACCOUNT) {
|
||||
from_contocom.value = circuitloaded.value.path
|
||||
accountloaded.value = circuitloaded.value ? circuitloaded.value.account : null
|
||||
from_contocom.value = circuitloaded.value.path;
|
||||
accountloaded.value = circuitloaded.value
|
||||
? circuitloaded.value.account
|
||||
: null;
|
||||
}
|
||||
|
||||
groupsListAdmin.value = userStore.GroupsListWhereIAmAdminInTheCircuit(circuitloaded.value.name)
|
||||
// console.log('groupsListAdmin.value', groupsListAdmin.value)
|
||||
groupsListAdmin.value = userStore.GroupsListWhereIAmAdminInTheCircuit(
|
||||
circuitloaded.value.name
|
||||
);
|
||||
|
||||
arrGroupsList.value = []
|
||||
arrGroupsList.value = [];
|
||||
|
||||
if (groupsListAdmin.value) {
|
||||
for (const group of groupsListAdmin.value) {
|
||||
let aggiungi = true
|
||||
let aggiungi = true;
|
||||
|
||||
if (props.to_group && props.to_group.groupname === group.groupname)
|
||||
aggiungi = false
|
||||
aggiungi = false;
|
||||
|
||||
if (aggiungi)
|
||||
arrGroupsList.value.push({ label: group.groupname, value: group.groupname });
|
||||
arrGroupsList.value.push({
|
||||
label: group.groupname,
|
||||
value: group.groupname,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (arrGroupsList.value.length > 0) {
|
||||
arrTypesAccounts.value.push(
|
||||
{
|
||||
label: t('circuit.conticollettivi'),
|
||||
value: shared_consts.AccountType.CONTO_DI_GRUPPO,
|
||||
})
|
||||
}
|
||||
|
||||
if (tools.iCanSendCoinsSuperUserCircuit(circuitsel.value) && (!props.to_contocom)) {
|
||||
arrTypesAccounts.value.push({
|
||||
label: t('circuit.contocom'),
|
||||
value: shared_consts.AccountType.COMMUNITY_ACCOUNT,
|
||||
})
|
||||
label: '👥 ' + t('circuit.conticollettivi'),
|
||||
value: shared_consts.AccountType.CONTO_DI_GRUPPO,
|
||||
});
|
||||
}
|
||||
|
||||
// if (tools.iAmAdminCircuit(circuitloaded.value.name))
|
||||
// arrGroupsList.value.push({ label: circuitloaded.value.name, value: circuitloaded.value.path });
|
||||
if (
|
||||
tools.iCanSendCoinsSuperUserCircuit(circuitsel.value) &&
|
||||
!props.to_contocom
|
||||
) {
|
||||
arrTypesAccounts.value.push({
|
||||
label: '🏛️ ' + t('circuit.contocom'),
|
||||
value: shared_consts.AccountType.COMMUNITY_ACCOUNT,
|
||||
});
|
||||
}
|
||||
|
||||
// accountdest.value = userStore.getAccountByCircuitId(circuitloaded.value._id)
|
||||
if (accountloaded.value) {
|
||||
remainingCoins.value = circuitStore.getRemainingCoinsToSend(accountloaded.value)
|
||||
remainingCoins.value = circuitStore.getRemainingCoinsToSend(
|
||||
accountloaded.value
|
||||
);
|
||||
if (accountloaded.value.saldo > 0) {
|
||||
maxsendable.value = accountloaded.value.saldo + accountloaded.value.fidoConcesso
|
||||
maxsendable.value =
|
||||
accountloaded.value.saldo + accountloaded.value.fidoConcesso;
|
||||
} else {
|
||||
maxsendable.value = accountloaded.value.fidoConcesso
|
||||
maxsendable.value = accountloaded.value.fidoConcesso;
|
||||
}
|
||||
|
||||
if (remainingCoins.value < 10) {
|
||||
remainingCoins.value = 10
|
||||
remainingCoins.value = 10;
|
||||
}
|
||||
|
||||
numstep.value = Math.round(maxsendable.value / 10)
|
||||
numstep.value = Math.round(maxsendable.value / 10);
|
||||
if (numstep.value < 1) {
|
||||
numstep.value = 1
|
||||
numstep.value = 1;
|
||||
}
|
||||
|
||||
const quanti = [...Array(20).keys()].map(i => i + 1)
|
||||
const quanti = [...Array(20).keys()].map((i) => i + 1);
|
||||
for (const ind of quanti) {
|
||||
const valuenorm = ind * numstep.value
|
||||
const value = ind * numstep.value
|
||||
const valuenorm = ind * numstep.value;
|
||||
const value = ind * numstep.value;
|
||||
if (value > remainingCoins.value) {
|
||||
break
|
||||
break;
|
||||
} else {
|
||||
const label = valuenorm.toString()
|
||||
arrayMarkerLabel.value.push({ value, label })
|
||||
const label = valuenorm.toString();
|
||||
arrayMarkerLabel.value.push({ value, label });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
loading.value = false
|
||||
loading.value = false;
|
||||
if (load) {
|
||||
fine_caricamento();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function inizio_caricamento() {
|
||||
$q.loading.show({
|
||||
message: 'Caricamento in corso...',
|
||||
spinnerColor: 'white',
|
||||
backgroundColor: 'primary',
|
||||
messageColor: 'white',
|
||||
});
|
||||
}
|
||||
|
||||
function fine_caricamento() {
|
||||
$q.loading.hide();
|
||||
}
|
||||
|
||||
async function mounted() {
|
||||
inizio_caricamento();
|
||||
|
||||
loading.value = true
|
||||
to_user_real.value = props.to_user;
|
||||
loading.value = true;
|
||||
|
||||
arrTypesAccounts.value = [
|
||||
{
|
||||
label: t('circuit.personale') + ' ' + from_username.value,
|
||||
label: '👤 ' + t('circuit.personale') + ' - ' + from_username.value,
|
||||
value: shared_consts.AccountType.USER,
|
||||
},
|
||||
]
|
||||
];
|
||||
|
||||
let salvatoprec = tools.getCookie(tools.COOK_TIPOCONTO, -2, true)
|
||||
let salvatoprec = tools.getCookie(tools.COOK_TIPOCONTO, -2, true);
|
||||
|
||||
// ....
|
||||
if (props.to_user) {
|
||||
console.log('user', props.to_user)
|
||||
bothcircuits.value = userStore.getMyCircuitsInCommonByUser(props.to_user)
|
||||
if (to_user_real.value) {
|
||||
if (props.loadprofile) {
|
||||
await userStore
|
||||
.loadUserProfile({ username: to_user_real.value.username })
|
||||
.then((ris) => {
|
||||
to_user_real.value = ris;
|
||||
});
|
||||
}
|
||||
|
||||
bothcircuits.value = userStore.getMyCircuitsInCommonByUser(to_user_real.value);
|
||||
|
||||
if (props.circuitname) {
|
||||
circuitsel.value = props.circuitname
|
||||
circuitsel.value = props.circuitname;
|
||||
} else {
|
||||
const circcookie = tools.getCookie(tools.CIRCUIT_USE, bothcircuits.value[0])
|
||||
if (circcookie && bothcircuits.value.findIndex((circ: ICircuit) => circ.name === circcookie) >= 0)
|
||||
circuitsel.value = circcookie
|
||||
const circcookie = tools.getCookie(tools.CIRCUIT_USE, bothcircuits.value[0]);
|
||||
if (
|
||||
circcookie &&
|
||||
bothcircuits.value.findIndex((circ: ICircuit) => circ.name === circcookie) >=
|
||||
0
|
||||
)
|
||||
circuitsel.value = circcookie;
|
||||
}
|
||||
if (bothcircuits.value && bothcircuits.value.find((name: any) => name !== circuitsel.value)) {
|
||||
circuitsel.value = bothcircuits.value[0]
|
||||
if (
|
||||
bothcircuits.value &&
|
||||
bothcircuits.value.find((name: any) => name !== circuitsel.value)
|
||||
) {
|
||||
circuitsel.value = bothcircuits.value[0];
|
||||
}
|
||||
|
||||
if (props.qtydefault)
|
||||
qty.value = props.qtydefault
|
||||
if (props.qtydefault) qty.value = props.qtydefault;
|
||||
|
||||
if (props.sendRIS) {
|
||||
if (props.sendRIS !== '0')
|
||||
qty.value = props.sendRIS
|
||||
if (props.sendRIS !== '0') qty.value = props.sendRIS;
|
||||
}
|
||||
|
||||
await aggiorna()
|
||||
await aggiorna();
|
||||
|
||||
// Se quello scelto c'è ancora sulla lista, allora lo imposto
|
||||
|
||||
if (arrTypesAccounts.value.findIndex((rec: any) => rec.value === salvatoprec) >= 0) {
|
||||
tipoConto.value = salvatoprec
|
||||
if (
|
||||
arrTypesAccounts.value.findIndex((rec: any) => rec.value === salvatoprec) >= 0
|
||||
) {
|
||||
tipoConto.value = salvatoprec;
|
||||
} else {
|
||||
tipoConto.value = shared_consts.AccountType.USER
|
||||
tipoConto.value = shared_consts.AccountType.USER;
|
||||
}
|
||||
|
||||
// tipoConto.value = tools.getCookie(tools.COOK_TIPOCONTO, shared_consts.AccountType.USER, true)
|
||||
|
||||
showpage.value = true
|
||||
|
||||
showpage.value = true;
|
||||
fine_caricamento();
|
||||
}
|
||||
|
||||
if (props.to_group) {
|
||||
console.log('group', props.to_group)
|
||||
bothcircuits.value = userStore.getMyCircuitsInCommonByGroup(props.to_group)
|
||||
|
||||
console.log('bothcircuits', bothcircuits.value)
|
||||
bothcircuits.value = userStore.getMyCircuitsInCommonByGroup(props.to_group);
|
||||
|
||||
if (props.circuitname) {
|
||||
circuitsel.value = props.circuitname
|
||||
circuitsel.value = props.circuitname;
|
||||
} else {
|
||||
circuitsel.value = tools.getCookie(tools.CIRCUIT_USE, bothcircuits.value[0])
|
||||
circuitsel.value = tools.getCookie(tools.CIRCUIT_USE, bothcircuits.value[0]);
|
||||
}
|
||||
if (!userStore.IsMyCircuitByName(circuitsel.value)) {
|
||||
circuitsel.value = bothcircuits.value[0]
|
||||
circuitsel.value = bothcircuits.value[0];
|
||||
}
|
||||
|
||||
await aggiorna()
|
||||
await aggiorna();
|
||||
|
||||
showpage.value = true
|
||||
showpage.value = true;
|
||||
}
|
||||
|
||||
if (props.to_contocom) {
|
||||
bothcircuits.value = userStore.getMyCircuits()
|
||||
bothcircuits.value = userStore.getMyCircuits();
|
||||
|
||||
console.log('to_contocom', props.to_contocom)
|
||||
circuitsel.value = props.circuitname
|
||||
circuitsel.value = props.circuitname;
|
||||
if (!userStore.IsMyCircuitByName(circuitsel.value)) {
|
||||
circuitsel.value = bothcircuits.value[0]
|
||||
circuitsel.value = bothcircuits.value[0];
|
||||
}
|
||||
|
||||
await aggiorna()
|
||||
await aggiorna();
|
||||
|
||||
showpage.value = true
|
||||
showpage.value = true;
|
||||
}
|
||||
|
||||
loading.value = false
|
||||
emit('showed')
|
||||
loading.value = false;
|
||||
emit('showed');
|
||||
}
|
||||
|
||||
function hide() {
|
||||
emit('close', true)
|
||||
showpage.value = false
|
||||
emit('close', true);
|
||||
showpage.value = false;
|
||||
}
|
||||
|
||||
function sendCoin() {
|
||||
console.log('sendcoin', qty.value, props.to_group ? props.to_group.groupname : (props.to_user ? props.to_user.username : props.to_contocom))
|
||||
|
||||
const ok = (props.to_user && props.to_user.username) ||
|
||||
const ok =
|
||||
(to_user_real.value && to_user_real.value.username) ||
|
||||
(props.to_group && props.to_group.groupname) ||
|
||||
(props.to_contocom)
|
||||
|
||||
props.to_contocom;
|
||||
|
||||
if (ok && qty.value && circuitloaded.value) {
|
||||
const myrecsendcoin: ISendCoin = {
|
||||
@@ -371,122 +440,104 @@ export default defineComponent({
|
||||
causal: causal.value,
|
||||
symbol: circuitloaded.value.symbol,
|
||||
causalDest: props.causalDest,
|
||||
}
|
||||
};
|
||||
|
||||
myrecsendcoin.groupdest = props.to_group ? props.to_group.groupname : ''
|
||||
myrecsendcoin.contoComDest = props.to_contocom
|
||||
myrecsendcoin.grouporig = tipoConto.value === shared_consts.AccountType.CONTO_DI_GRUPPO ? from_groupname.value : ''
|
||||
myrecsendcoin.contoComOrig = tipoConto.value === shared_consts.AccountType.COMMUNITY_ACCOUNT ? from_contocom.value : ''
|
||||
|
||||
myrecsendcoin.dest = props.to_user ? props.to_user.username : ''
|
||||
myrecsendcoin.groupdest = props.to_group ? props.to_group.groupname : '';
|
||||
myrecsendcoin.contoComDest = props.to_contocom;
|
||||
myrecsendcoin.grouporig =
|
||||
tipoConto.value === shared_consts.AccountType.CONTO_DI_GRUPPO
|
||||
? from_groupname.value
|
||||
: '';
|
||||
myrecsendcoin.contoComOrig =
|
||||
tipoConto.value === shared_consts.AccountType.COMMUNITY_ACCOUNT
|
||||
? from_contocom.value
|
||||
: '';
|
||||
|
||||
myrecsendcoin.dest = to_user_real.value ? to_user_real.value.username : '';
|
||||
|
||||
if (myrecsendcoin) {
|
||||
tools.sendCoinsByCircuit($q, $router, circuitloaded.value, myrecsendcoin)
|
||||
tools
|
||||
.sendCoinsByCircuit($q, $router, circuitloaded.value, myrecsendcoin)
|
||||
.then((ris: any) => {
|
||||
if (ris) {
|
||||
showpage.value = false
|
||||
showpage.value = false;
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function ifNextCheck(actualstep: number) {
|
||||
|
||||
let fase1ok = false
|
||||
let fase1ok = false;
|
||||
|
||||
if (circuitloaded.value && !!circuitloaded.value._id) {
|
||||
fase1ok = !(
|
||||
!circuitloaded.value.transactionsEnabled ||
|
||||
(tipoConto.value === shared_consts.AccountType.USER &&
|
||||
props.to_user &&
|
||||
from_username.value === props.to_user.username) ||
|
||||
(tipoConto.value ===
|
||||
shared_consts.AccountType.CONTO_DI_GRUPPO &&
|
||||
to_user_real.value &&
|
||||
from_username.value === to_user_real.value.username) ||
|
||||
(tipoConto.value === shared_consts.AccountType.CONTO_DI_GRUPPO &&
|
||||
!from_groupname.value) ||
|
||||
(tipoConto.value ===
|
||||
shared_consts.AccountType.CONTO_DI_GRUPPO &&
|
||||
(tipoConto.value === shared_consts.AccountType.CONTO_DI_GRUPPO &&
|
||||
props.to_group &&
|
||||
from_groupname.value &&
|
||||
props.to_group.groupname === from_groupname.value) ||
|
||||
(tipoConto.value ===
|
||||
shared_consts.AccountType.COMMUNITY_ACCOUNT &&
|
||||
(tipoConto.value === shared_consts.AccountType.COMMUNITY_ACCOUNT &&
|
||||
!from_contocom.value)
|
||||
)
|
||||
}
|
||||
|
||||
if (actualstep === 0) {
|
||||
return fase1ok
|
||||
} else if (actualstep === 1) {
|
||||
return fase1ok && checkRisValid()
|
||||
} else if (actualstep === 2) {
|
||||
return fase1ok && checkRisValid()
|
||||
);
|
||||
}
|
||||
|
||||
return fase1ok && checkRisValid() && causal.value;
|
||||
}
|
||||
|
||||
function checkRisValid() {
|
||||
return qty.value ? qty.value && getQty() >= 0.01 && accountloaded.value
|
||||
&& getQty() <= circuitStore.getRemainingCoinsToSend(accountloaded.value) : false
|
||||
return qty.value
|
||||
? qty.value &&
|
||||
getQty() >= 0.01 &&
|
||||
accountloaded.value &&
|
||||
getQty() <= circuitStore.getRemainingCoinsToSend(accountloaded.value)
|
||||
: false;
|
||||
}
|
||||
|
||||
function getQty(): number {
|
||||
let myqty: number | null = null
|
||||
let myqty: number | null = null;
|
||||
|
||||
try {
|
||||
if (qty.value) {
|
||||
myqty = parseFloat(String(qty.value))
|
||||
myqty = parseFloat(String(qty.value));
|
||||
}
|
||||
} catch (e) {
|
||||
return 0
|
||||
return 0;
|
||||
}
|
||||
|
||||
return myqty ? myqty : 0
|
||||
return myqty ? myqty : 0;
|
||||
}
|
||||
|
||||
function getTitle(step: number) {
|
||||
|
||||
if (step === 0) {
|
||||
return 'Circuito'
|
||||
return 'Circuito';
|
||||
} else if (step === 1) {
|
||||
return 'Quantità'
|
||||
return 'Quantità';
|
||||
} else if (step === 2) {
|
||||
return 'Causale'
|
||||
return 'Causale';
|
||||
}
|
||||
}
|
||||
|
||||
function getIcon(step: number) {
|
||||
|
||||
if (step === 0) {
|
||||
return 'circuit'
|
||||
return 'circuit';
|
||||
} else if (step === 1) {
|
||||
return 'attach_money'
|
||||
return 'attach_money';
|
||||
} else if (step === 2) {
|
||||
return 'description'
|
||||
return 'description';
|
||||
}
|
||||
}
|
||||
|
||||
function clickAvanti(actualstep: number) {
|
||||
if (actualstep === 0) {
|
||||
step.value = 1
|
||||
} else if (actualstep === 1) {
|
||||
step.value = 2
|
||||
} else if (actualstep === 2) {
|
||||
sendCoin()
|
||||
}
|
||||
}
|
||||
function clickIndietro(actualstep: number) {
|
||||
if (actualstep === 1) {
|
||||
step.value = 0
|
||||
} else if (actualstep === 2) {
|
||||
step.value = 1
|
||||
} else if (actualstep === 0) {
|
||||
hide()
|
||||
}
|
||||
function setQty(value: string | number) {
|
||||
qty.value = value;
|
||||
}
|
||||
|
||||
|
||||
onMounted(mounted)
|
||||
onMounted(mounted);
|
||||
|
||||
return {
|
||||
t,
|
||||
@@ -522,12 +573,13 @@ export default defineComponent({
|
||||
shared_consts,
|
||||
step,
|
||||
ifNextCheck,
|
||||
clickIndietro,
|
||||
clickAvanti,
|
||||
getTitle,
|
||||
getIcon,
|
||||
sendCoinDialog,
|
||||
visubanner,
|
||||
}
|
||||
showKeyboard,
|
||||
setQty,
|
||||
to_user_real,
|
||||
};
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
@@ -5,375 +5,351 @@
|
||||
:maximized="$q.screen.lt.sm"
|
||||
@hide="hide"
|
||||
@show="qtyRef ? qtyRef.focus() : ''"
|
||||
transition-show="slide-up"
|
||||
transition-hide="slide-down"
|
||||
>
|
||||
<q-card
|
||||
class="dialog_card"
|
||||
style="display: flex; flex-direction: column; height: 100%"
|
||||
class="send-coins-dialog"
|
||||
:class="{ 'mobile-fullheight': $q.screen.lt.sm }"
|
||||
>
|
||||
<q-bar class="bg-primary text-white">
|
||||
{{ $t("circuit.sendcoins") }}
|
||||
<q-space />
|
||||
<q-btn flat round color="white" icon="close" v-close-popup></q-btn>
|
||||
</q-bar>
|
||||
<!-- Header con gradiente -->
|
||||
<q-card-section class="dialog-header q-pa-none">
|
||||
<div class="header-gradient">
|
||||
<!-- Top bar -->
|
||||
<div class="header-top-bar">
|
||||
<div class="header-title-wrapper">
|
||||
<div class="ris-coin-icon">
|
||||
<img
|
||||
v-if="circuitloaded.symbol === 'RIS'"
|
||||
src="/images/1ris_rosso_100.png"
|
||||
alt="RIS"
|
||||
class="ris-logo"
|
||||
/>
|
||||
<span v-else class="coin-symbol">{{ circuitloaded.symbol }}</span>
|
||||
</div>
|
||||
<span class="header-title">Invia {{ circuitloaded.symbol || 'Crediti' }}</span>
|
||||
</div>
|
||||
<q-btn
|
||||
flat
|
||||
round
|
||||
dense
|
||||
icon="close"
|
||||
color="white"
|
||||
class="close-btn"
|
||||
v-close-popup
|
||||
/>
|
||||
</div>
|
||||
|
||||
<q-card-section>
|
||||
<q-stepper
|
||||
v-model="step"
|
||||
ref="stepper"
|
||||
color="primary"
|
||||
animated
|
||||
class="mystepper"
|
||||
<!-- Balance Card compatto -->
|
||||
<div class="balance-card">
|
||||
<div class="balance-info">
|
||||
<div class="balance-main">
|
||||
<span class="balance-label">Saldo disponibile</span>
|
||||
<span class="balance-value">
|
||||
{{ accountloaded ? circuitStore.getRemainingCoinsToSend(accountloaded).toFixed(2) : '0.00' }}
|
||||
<span class="balance-symbol">{{ circuitloaded.symbol }}</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="balance-fido" v-if="accountloaded?.fidoConcesso > 0">
|
||||
<span class="fido-label">Fido</span>
|
||||
<span class="fido-value">+{{ accountloaded.fidoConcesso.toFixed(2) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</q-card-section>
|
||||
|
||||
<!-- Content -->
|
||||
<q-card-section
|
||||
class="dialog-content scroll"
|
||||
:style="$q.screen.lt.sm ? 'padding-bottom: 80px;' : ''"
|
||||
>
|
||||
<!-- Circuit Check -->
|
||||
<CCheckCircuitsEnabled
|
||||
:to_user="to_user_real"
|
||||
:to_group="to_group"
|
||||
/>
|
||||
|
||||
<!-- Circuit Selector -->
|
||||
<div v-if="circuitloaded.symbol && circuitname === ''" class="section-block">
|
||||
<q-select
|
||||
v-model="circuitsel"
|
||||
:options="bothcircuits"
|
||||
:behavior="$q.platform.is.ios === true ? 'dialog' : 'menu'"
|
||||
outlined
|
||||
dense
|
||||
label="Circuito"
|
||||
class="modern-select"
|
||||
popup-content-class="modern-select-popup"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<q-icon name="account_balance_wallet" color="primary" />
|
||||
</template>
|
||||
</q-select>
|
||||
</div>
|
||||
|
||||
<!-- Province Banner -->
|
||||
<q-banner
|
||||
v-if="showProvinceToSelect"
|
||||
rounded
|
||||
class="warning-banner q-mb-sm"
|
||||
>
|
||||
<q-step
|
||||
:name="0"
|
||||
:title="getTitle(0)"
|
||||
:icon="getIcon(0)"
|
||||
:done="ifNextCheck(0)"
|
||||
<template v-slot:avatar>
|
||||
<q-icon name="warning" color="white" />
|
||||
</template>
|
||||
{{ $t('circuit.insertprovince_text') }}
|
||||
</q-banner>
|
||||
|
||||
<!-- Sender Section -->
|
||||
<div v-if="circuitsel" class="section-block">
|
||||
<q-select
|
||||
v-if="arrTypesAccounts.length > 0"
|
||||
v-model="tipoConto"
|
||||
:options="arrTypesAccounts"
|
||||
outlined
|
||||
dense
|
||||
emit-value
|
||||
map-options
|
||||
label="Mittente"
|
||||
class="modern-select"
|
||||
popup-content-class="modern-select-popup"
|
||||
>
|
||||
<CCheckCircuitsEnabled :to_user="to_user" :to_group="to_group">
|
||||
</CCheckCircuitsEnabled>
|
||||
<template v-slot:prepend>
|
||||
<q-icon name="person" color="primary" />
|
||||
</template>
|
||||
</q-select>
|
||||
|
||||
<div v-if="circuitloaded.symbol">
|
||||
<q-select
|
||||
v-if="circuitname === ''"
|
||||
:behavior="$q.platform.is.ios === true ? 'dialog' : 'menu'"
|
||||
rounded
|
||||
dense
|
||||
outlined
|
||||
v-model="circuitsel"
|
||||
:options="bothcircuits"
|
||||
label="Circuito"
|
||||
>
|
||||
</q-select>
|
||||
<div v-else>{{ circuitname }}</div>
|
||||
</div>
|
||||
|
||||
<q-banner
|
||||
v-if="showProvinceToSelect"
|
||||
rounded
|
||||
class="bg-red text-white"
|
||||
style="text-align: center"
|
||||
>
|
||||
<div>
|
||||
<em style="font-weight: bold">{{
|
||||
$t("circuit.insertprovince_text")
|
||||
}}</em>
|
||||
</div>
|
||||
<br />
|
||||
</q-banner>
|
||||
<br />
|
||||
<div v-if="circuitsel">
|
||||
<q-banner
|
||||
rounded
|
||||
dense
|
||||
class="shadow-5 q-my-sm"
|
||||
color="primary q-title"
|
||||
style="text-align: center"
|
||||
>
|
||||
<div class="mybanner_left q-mb-sm">
|
||||
<q-select
|
||||
v-if="arrTypesAccounts.length > 0"
|
||||
v-model="tipoConto"
|
||||
class="my-custom-select"
|
||||
outlined
|
||||
bg-color="light-blue-2"
|
||||
emit-value
|
||||
map-options
|
||||
:options="arrTypesAccounts"
|
||||
:label="$t('circuit.sender')"
|
||||
></q-select>
|
||||
</div>
|
||||
<div
|
||||
v-if="
|
||||
tipoConto === shared_consts.AccountType.CONTO_DI_GRUPPO
|
||||
"
|
||||
>
|
||||
<q-select
|
||||
v-model="from_groupname"
|
||||
:options="arrGroupsList"
|
||||
:label="$t('circuit.choosecontocom')"
|
||||
rounded
|
||||
emit-value
|
||||
map-options
|
||||
>
|
||||
<!-- Mostra i gruppi su cui sei Admin -->
|
||||
</q-select>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="
|
||||
tipoConto === shared_consts.AccountType.COMMUNITY_ACCOUNT
|
||||
"
|
||||
>
|
||||
<q-input
|
||||
v-model="from_contocom"
|
||||
:label="$t('circuit.contocom')"
|
||||
readonly
|
||||
class="q-my-sm"
|
||||
>
|
||||
</q-input>
|
||||
</div>
|
||||
|
||||
<CSaldo
|
||||
v-if="circuitloaded && circuitloaded.symbol"
|
||||
:symbol="circuitloaded.symbol"
|
||||
:color="circuitloaded.color"
|
||||
:saldo="accountloaded ? accountloaded.saldo : 0"
|
||||
:qtarem="
|
||||
accountloaded
|
||||
? circuitStore.getRemainingCoinsToSend(accountloaded)
|
||||
: 0
|
||||
"
|
||||
>
|
||||
</CSaldo>
|
||||
</q-banner>
|
||||
|
||||
<q-banner
|
||||
rounded
|
||||
dense
|
||||
class="shadow-5 q-my-sm"
|
||||
color="primary q-title"
|
||||
>
|
||||
<div class="mybanner_left bg-green text-white q-mb-sm">
|
||||
{{ $t("circuit.dest") }}
|
||||
</div>
|
||||
|
||||
<!-- Destination -->
|
||||
<CMyUserOnlyView
|
||||
v-if="to_user"
|
||||
:mycontact="to_user"
|
||||
:visu="costanti.FIND_PEOPLE"
|
||||
@setCmd="tools.setCmd"
|
||||
>
|
||||
</CMyUserOnlyView>
|
||||
<CMyGroupOnlyView
|
||||
v-if="to_group"
|
||||
:mygrp="to_group"
|
||||
:visu="costanti.USER_GROUPS"
|
||||
:circuitname="circuitloaded.name"
|
||||
>
|
||||
</CMyGroupOnlyView>
|
||||
<CMyGroupOnlyView
|
||||
v-if="circuitloaded && !!circuitloaded._id && to_contocom"
|
||||
:mygrp="{ groupname: to_contocom }"
|
||||
:visu="costanti.USER_GROUPS"
|
||||
:circuitname="circuitloaded.name"
|
||||
>
|
||||
</CMyGroupOnlyView>
|
||||
</q-banner>
|
||||
</div>
|
||||
|
||||
<q-inner-loading id="spinner" :showing="loading">
|
||||
<q-spinner-tail size="6em" color="primary" />
|
||||
</q-inner-loading>
|
||||
</q-step>
|
||||
<q-step
|
||||
:name="1"
|
||||
:title="getTitle(1)"
|
||||
:icon="getIcon(1)"
|
||||
:done="ifNextCheck(1)"
|
||||
<!-- Group Account Selector -->
|
||||
<q-select
|
||||
v-if="tipoConto === shared_consts.AccountType.CONTO_DI_GRUPPO"
|
||||
v-model="from_groupname"
|
||||
:options="arrGroupsList"
|
||||
:label="$t('circuit.choosecontocom')"
|
||||
outlined
|
||||
dense
|
||||
emit-value
|
||||
map-options
|
||||
class="modern-select q-mt-sm"
|
||||
>
|
||||
<div v-if="circuitloaded && !!circuitloaded._id">
|
||||
<q-banner
|
||||
v-if="!circuitloaded.transactionsEnabled"
|
||||
rounded
|
||||
class="bg-red text-white"
|
||||
style="text-align: center"
|
||||
>
|
||||
<em style="font-weight: bold">{{
|
||||
$t("circuit.transactionsEnabled_text")
|
||||
}}</em
|
||||
><br />
|
||||
</q-banner>
|
||||
<template v-slot:prepend>
|
||||
<q-icon name="groups" color="primary" />
|
||||
</template>
|
||||
</q-select>
|
||||
|
||||
<q-input
|
||||
ref="qtyRef"
|
||||
class="q-py-sm text-h5"
|
||||
outlined
|
||||
v-model="qty"
|
||||
:type="$q.platform.is.mobile ? 'string' : 'number'"
|
||||
:rules="[
|
||||
(val) =>
|
||||
val <=
|
||||
circuitStore.getRemainingCoinsToSend(accountloaded) ||
|
||||
t('circuit.qta_remaining_to_send', {
|
||||
maxqta:
|
||||
circuitStore.getRemainingCoinsToSend(accountloaded),
|
||||
symbol: circuitloaded.symbol,
|
||||
}),
|
||||
(val) => val > 0 || t('circuit.qta_not_valid'),
|
||||
]"
|
||||
:label="
|
||||
t('movement.amount_to_send', {
|
||||
qtamax: circuitStore.getRemainingCoinsToSend(accountloaded)
|
||||
? circuitStore
|
||||
.getRemainingCoinsToSend(accountloaded)
|
||||
.toFixed(2)
|
||||
: 0 + ` ` + circuitloaded.symbol,
|
||||
})
|
||||
"
|
||||
input-class="text-right"
|
||||
input-style="padding-bottom: 24px !important;"
|
||||
v-on:keyup.enter="$event.target.nextElementSibling.focus()"
|
||||
>
|
||||
<!--val => val > circuitStore.getMaxCoinsToSend(accountloaded) || t('circuit.qta_max_to_send', { maxqta: tools.getRemainingCoinsToSend(accountloaded), symbol: circuitloaded.symbol })]" -->
|
||||
<template v-slot:append>
|
||||
<div class="text-h5">
|
||||
<em
|
||||
class="q-px-sm text-white rounded-borders"
|
||||
:style="
|
||||
`background-color: ` +
|
||||
(circuitloaded.color ? circuitloaded.color : '#ff5500')
|
||||
"
|
||||
>{{ circuitloaded.symbol }}</em
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
</q-input>
|
||||
<div class="q-mt-md">
|
||||
<CNumericKeyboard v-model="qty" :showInput="false" />
|
||||
</div>
|
||||
</div>
|
||||
</q-step>
|
||||
<q-step
|
||||
:name="2"
|
||||
:title="getTitle(2)"
|
||||
:icon="getIcon(2)"
|
||||
:done="ifNextCheck(2)"
|
||||
<!-- Community Account -->
|
||||
<q-input
|
||||
v-if="tipoConto === shared_consts.AccountType.COMMUNITY_ACCOUNT"
|
||||
v-model="from_contocom"
|
||||
:label="$t('circuit.contocom')"
|
||||
outlined
|
||||
dense
|
||||
readonly
|
||||
class="modern-input q-mt-sm"
|
||||
>
|
||||
<!-- Destination -->
|
||||
<CMyUserOnlyView
|
||||
v-if="to_user"
|
||||
:mycontact="to_user"
|
||||
:visu="costanti.FIND_PEOPLE"
|
||||
@setCmd="tools.setCmd"
|
||||
>
|
||||
</CMyUserOnlyView>
|
||||
<CMyGroupOnlyView
|
||||
v-if="to_group"
|
||||
:mygrp="to_group"
|
||||
:visu="costanti.USER_GROUPS"
|
||||
:circuitname="circuitloaded.name"
|
||||
>
|
||||
</CMyGroupOnlyView>
|
||||
<CMyGroupOnlyView
|
||||
v-if="circuitloaded && !!circuitloaded._id && to_contocom"
|
||||
:mygrp="{ groupname: to_contocom }"
|
||||
:visu="costanti.USER_GROUPS"
|
||||
:circuitname="circuitloaded.name"
|
||||
>
|
||||
</CMyGroupOnlyView>
|
||||
<template v-slot:prepend>
|
||||
<q-icon name="account_balance" color="primary" />
|
||||
</template>
|
||||
</q-input>
|
||||
</div>
|
||||
|
||||
<div v-if="causalDest">
|
||||
<q-field
|
||||
rounded
|
||||
filled
|
||||
:label="t('circuit.descrizione_destinatario')"
|
||||
stack-label
|
||||
>
|
||||
<template v-slot:append>
|
||||
<q-icon name="description" />
|
||||
</template>
|
||||
<template v-slot:control>
|
||||
<div class="self-center full-width no-outline" tabindex="0">
|
||||
{{ causalDest }}
|
||||
</div>
|
||||
</template>
|
||||
</q-field>
|
||||
</div>
|
||||
<!-- Recipient Section -->
|
||||
<div v-if="circuitsel" class="section-block">
|
||||
<label class="section-label">Destinatario</label>
|
||||
<div class="recipient-card">
|
||||
<div class="recipient-content">
|
||||
<!-- User Recipient -->
|
||||
<CMyUserOnlyView
|
||||
v-if="to_user_real"
|
||||
:mycontact="to_user_real"
|
||||
:visu="costanti.FIND_PEOPLE"
|
||||
@setCmd="tools.setCmd"
|
||||
class="recipient-view"
|
||||
/>
|
||||
|
||||
<!--<q-banner v-if="visubanner" rounded class="text-center text-bold">
|
||||
{{ t('circuit.descr_casuale') }}
|
||||
<template v-slot:action>
|
||||
<q-btn label="Chiudi" flat @click="visubanner = false"></q-btn>
|
||||
</template>
|
||||
</q-banner>-->
|
||||
<div class="q-mt-sm text-italic text-blue text-bold">
|
||||
{{ $t("circuit.descr_casuale") }}
|
||||
<!-- Group Recipient -->
|
||||
<CMyGroupOnlyView
|
||||
v-if="to_group"
|
||||
:mygrp="to_group"
|
||||
:visu="costanti.USER_GROUPS"
|
||||
:circuitname="circuitloaded.name"
|
||||
class="recipient-view"
|
||||
/>
|
||||
|
||||
<!-- Community Account Recipient -->
|
||||
<CMyGroupOnlyView
|
||||
v-if="circuitloaded && !!circuitloaded._id && to_contocom"
|
||||
:mygrp="{ groupname: to_contocom }"
|
||||
:visu="costanti.USER_GROUPS"
|
||||
:circuitname="circuitloaded.name"
|
||||
class="recipient-view"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Amount Section - Compatto -->
|
||||
<div v-if="circuitsel" class="section-block">
|
||||
<label class="section-label">Importo</label>
|
||||
|
||||
<div class="amount-input-row" @click="$q.screen.lt.sm ? showKeyboard = true : qtyRef?.focus()">
|
||||
<q-input
|
||||
ref="causalRef"
|
||||
v-model="causal"
|
||||
autogrow
|
||||
rounded
|
||||
filled
|
||||
maxlength="200"
|
||||
counter
|
||||
:label="$t('circuit.note')"
|
||||
class="q-my-sm full-width"
|
||||
ref="qtyRef"
|
||||
v-model="qty"
|
||||
:type="$q.screen.lt.sm ? 'text' : 'number'"
|
||||
outlined
|
||||
dense
|
||||
input-class="amount-input-field"
|
||||
:readonly="$q.screen.lt.sm"
|
||||
:rules="[
|
||||
(val) => !isNaN(parseFloat(val)) || t('circuit.qta_not_valid'),
|
||||
(val) => parseFloat(val) <= circuitStore.getRemainingCoinsToSend(accountloaded) || t('circuit.qta_remaining_to_send', { maxqta: circuitStore.getRemainingCoinsToSend(accountloaded), symbol: circuitloaded.symbol }),
|
||||
(val) => parseFloat(val) > 0 || t('circuit.qta_not_valid'),
|
||||
]"
|
||||
hide-bottom-space
|
||||
class="amount-input"
|
||||
@keyup.enter="causalRef?.focus()"
|
||||
>
|
||||
<template v-slot:after>
|
||||
<q-avatar>
|
||||
<img
|
||||
:src="
|
||||
userStore.my.profile
|
||||
? userStore.getImgByProfile(userStore.my)
|
||||
: ''
|
||||
"
|
||||
:alt="userStore.my.username"
|
||||
/>
|
||||
</q-avatar>
|
||||
</template>
|
||||
<template v-slot:prepend>
|
||||
<q-icon name="comment" />
|
||||
<span class="currency-symbol">€</span>
|
||||
</template>
|
||||
<template v-slot:append>
|
||||
<div class="coin-badge" :style="`background: ${circuitloaded.color || '#ff5500'}`">
|
||||
{{ circuitloaded.symbol }}
|
||||
</div>
|
||||
<q-btn
|
||||
v-if="$q.screen.lt.sm"
|
||||
flat
|
||||
round
|
||||
dense
|
||||
icon="keyboard"
|
||||
size="sm"
|
||||
class="keyboard-btn q-ml-xs"
|
||||
@click.stop="showKeyboard = true"
|
||||
/>
|
||||
</template>
|
||||
</q-input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sendris">
|
||||
{{
|
||||
$t("circuit.sendcoinsto", {
|
||||
qty,
|
||||
coin: circuitloaded.symbol,
|
||||
dest: to_group
|
||||
? to_group.groupname
|
||||
: to_user
|
||||
? tools.getNomeUtenteByRecUser(to_user)
|
||||
: to_contocom,
|
||||
})
|
||||
}}
|
||||
sul {{ circuitsel }}
|
||||
</div>
|
||||
</q-step>
|
||||
</q-stepper>
|
||||
<!-- Transactions Disabled Banner -->
|
||||
<q-banner
|
||||
v-if="circuitloaded && !!circuitloaded._id && !circuitloaded.transactionsEnabled"
|
||||
rounded
|
||||
class="error-banner q-mb-sm"
|
||||
>
|
||||
<template v-slot:avatar>
|
||||
<q-icon name="error" color="white" />
|
||||
</template>
|
||||
{{ $t('circuit.transactionsEnabled_text') }}
|
||||
</q-banner>
|
||||
|
||||
<!-- Note Section - Compatto -->
|
||||
<div v-if="circuitsel" class="section-block">
|
||||
<q-input
|
||||
ref="causalRef"
|
||||
v-model="causal"
|
||||
outlined
|
||||
dense
|
||||
type="textarea"
|
||||
rows="3"
|
||||
maxlength="200"
|
||||
counter
|
||||
label="Nota per il destinatario"
|
||||
placeholder="Scrivi un messaggio..."
|
||||
class="modern-textarea"
|
||||
:rules="[
|
||||
(val) => !!val?.trim() || 'Inserisci un messaggio',
|
||||
(val) => val.trim().length >= 2 || 'Minimo 2 caratteri',
|
||||
]"
|
||||
lazy-rules
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<q-icon name="message" color="grey-6" class="self-start q-mt-xs" />
|
||||
</template>
|
||||
<template v-slot:after>
|
||||
<q-avatar size="32px">
|
||||
<img
|
||||
:src="userStore.my.profile ? userStore.getImgByProfile(userStore.my) : ''"
|
||||
:alt="userStore.my.username"
|
||||
/>
|
||||
</q-avatar>
|
||||
</template>
|
||||
</q-input>
|
||||
</div>
|
||||
</q-card-section>
|
||||
<q-card-actions align="center" style="row justify-between">
|
||||
|
||||
<!-- Fixed Bottom Actions -->
|
||||
<q-card-actions
|
||||
class="dialog-actions"
|
||||
:class="{ 'fixed-bottom-actions': $q.screen.lt.sm }"
|
||||
>
|
||||
<q-btn
|
||||
class="col"
|
||||
flat
|
||||
:label="$t('dialog.indietro')"
|
||||
color="primary"
|
||||
icon="navigate_before"
|
||||
@click="clickIndietro(step)"
|
||||
></q-btn>
|
||||
:label="t('dialog.cancel')"
|
||||
class="cancel-btn"
|
||||
v-close-popup
|
||||
/>
|
||||
<q-btn
|
||||
class="col"
|
||||
:disable="!ifNextCheck(step)"
|
||||
:label="
|
||||
step === 0 || step === 1
|
||||
? t('dialog.avanti')
|
||||
: t('circuit.sendcoins', {
|
||||
qty,
|
||||
coin: circuitloaded.symbol,
|
||||
dest: to_group
|
||||
? to_group.groupname
|
||||
: to_user
|
||||
? tools.getNomeUtenteByRecUser(to_user)
|
||||
: to_contocom,
|
||||
})
|
||||
"
|
||||
color="positive"
|
||||
:icon-right="
|
||||
step === 2 ? 'img: /images/1ris_rosso_100.png' : 'navigate_next'
|
||||
"
|
||||
@click="clickAvanti(step)"
|
||||
></q-btn>
|
||||
class="send-btn"
|
||||
:class="{ 'btn-disabled': !ifNextCheck(step) }"
|
||||
@click="sendCoin"
|
||||
>
|
||||
<span class="send-btn-text">Invia {{ qty || 0 }} {{ circuitloaded.symbol }}</span>
|
||||
<img
|
||||
v-if="circuitloaded.symbol === 'RIS'"
|
||||
src="/images/1ris_rosso_100.png"
|
||||
alt="RIS"
|
||||
class="send-btn-icon"
|
||||
/>
|
||||
<q-icon v-else name="send" class="q-ml-sm" />
|
||||
</q-btn>
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
|
||||
<!-- Numeric Keyboard Dialog -->
|
||||
<q-dialog
|
||||
v-model="showKeyboard"
|
||||
position="bottom"
|
||||
seamless
|
||||
no-backdrop-dismiss
|
||||
>
|
||||
<q-card class="keyboard-dialog">
|
||||
<q-card-section class="keyboard-header">
|
||||
<div class="keyboard-header-content">
|
||||
<span class="keyboard-title">Inserisci importo</span>
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
label="Fatto"
|
||||
color="primary"
|
||||
class="done-btn"
|
||||
v-close-popup
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="keyboard-display">
|
||||
<span class="keyboard-amount">{{ qty || '0' }}</span>
|
||||
<div class="keyboard-coin-badge" :style="`background: ${circuitloaded.color || '#ff5500'}`">
|
||||
{{ circuitloaded.symbol }}
|
||||
</div>
|
||||
</div>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section class="keyboard-section q-pa-sm">
|
||||
<CNumericKeyboard
|
||||
v-model="qty"
|
||||
:showInput="false"
|
||||
@update:model-value="setQty"
|
||||
/>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" src="./CSendCoins.ts">
|
||||
</script>
|
||||
<script lang="ts" src="./CSendCoins.ts"></script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "./CSendCoins.scss";
|
||||
@import './CSendCoins.scss';
|
||||
</style>
|
||||
|
||||
62
src/components/checkemail/checkemail.scss
Executable file
62
src/components/checkemail/checkemail.scss
Executable file
@@ -0,0 +1,62 @@
|
||||
.check-email-page {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.check-email-container {
|
||||
max-width: 500px;
|
||||
margin: 0 auto;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.email-icon-wrapper {
|
||||
text-align: center;
|
||||
margin-bottom: 24px;
|
||||
|
||||
.q-icon {
|
||||
animation: pulse 2s ease-in-out infinite;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
opacity: 0.7;
|
||||
transform: scale(1.05);
|
||||
}
|
||||
}
|
||||
|
||||
.main-banner,
|
||||
.info-banner {
|
||||
.banner-content {
|
||||
font-size: 15px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
.resend-card {
|
||||
border-radius: 12px;
|
||||
|
||||
.countdown-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 12px;
|
||||
background: #f5f5f5;
|
||||
border-radius: 8px;
|
||||
|
||||
strong {
|
||||
font-family: monospace;
|
||||
font-size: 18px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.helpful-links {
|
||||
padding: 16px 0;
|
||||
}
|
||||
140
src/components/checkemail/checkemail.ts
Executable file
140
src/components/checkemail/checkemail.ts
Executable file
@@ -0,0 +1,140 @@
|
||||
import { defineComponent, ref, computed, onMounted, onUnmounted } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import { LandingFooter } from '@/components/LandingFooter';
|
||||
import { useUserStore } from '@store/UserStore';
|
||||
import { tools } from '@tools';
|
||||
import { Api } from '@api';
|
||||
|
||||
const RESEND_COOLDOWN_MINUTES = 1;
|
||||
const RESEND_COOLDOWN_MS = RESEND_COOLDOWN_MINUTES * 60 * 1000;
|
||||
const STORAGE_KEY = 'lastVerificationEmailSent';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'CheckEmail',
|
||||
components: { LandingFooter },
|
||||
|
||||
setup() {
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
const userStore = useUserStore();
|
||||
|
||||
// State
|
||||
const sending = ref(false);
|
||||
const emailSent = ref(false);
|
||||
const errorMessage = ref('');
|
||||
const timeLeft = ref(0);
|
||||
let countdownInterval: ReturnType<typeof setInterval> | null = null;
|
||||
|
||||
// Computed
|
||||
const canResend = computed(() => timeLeft.value <= 0);
|
||||
|
||||
const formattedTimeLeft = computed(() => {
|
||||
const minutes = Math.floor(timeLeft.value / 60);
|
||||
const seconds = timeLeft.value % 60;
|
||||
return `${minutes}:${seconds.toString().padStart(2, '0')}`;
|
||||
});
|
||||
|
||||
// Methods
|
||||
const getLastSentTime = (): number => {
|
||||
const stored = localStorage.getItem(STORAGE_KEY);
|
||||
return stored ? parseInt(stored, 10) : 0;
|
||||
};
|
||||
|
||||
const setLastSentTime = () => {
|
||||
localStorage.setItem(STORAGE_KEY, Date.now().toString());
|
||||
};
|
||||
|
||||
const calculateTimeLeft = (): number => {
|
||||
const lastSent = getLastSentTime();
|
||||
if (!lastSent) return 0;
|
||||
|
||||
const elapsed = Date.now() - lastSent;
|
||||
const remaining = RESEND_COOLDOWN_MS - elapsed;
|
||||
|
||||
return remaining > 0 ? Math.ceil(remaining / 1000) : 0;
|
||||
};
|
||||
|
||||
const startCountdown = () => {
|
||||
timeLeft.value = calculateTimeLeft();
|
||||
|
||||
if (timeLeft.value > 0) {
|
||||
countdownInterval = setInterval(() => {
|
||||
timeLeft.value = calculateTimeLeft();
|
||||
|
||||
if (timeLeft.value <= 0 && countdownInterval) {
|
||||
clearInterval(countdownInterval);
|
||||
countdownInterval = null;
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
};
|
||||
|
||||
const resendVerificationEmail = async () => {
|
||||
if (!canResend.value || sending.value) return;
|
||||
|
||||
sending.value = true;
|
||||
emailSent.value = false;
|
||||
errorMessage.value = '';
|
||||
|
||||
try {
|
||||
await userStore.resendVerificationEmail();
|
||||
|
||||
setLastSentTime();
|
||||
emailSent.value = true;
|
||||
startCountdown();
|
||||
|
||||
// Nascondi messaggio successo dopo 5 secondi
|
||||
setTimeout(() => {
|
||||
emailSent.value = false;
|
||||
}, 5000);
|
||||
} catch (error: any) {
|
||||
errorMessage.value =
|
||||
error?.message ||
|
||||
t('components.authentication.email_verification.errore_invio');
|
||||
|
||||
// Nascondi messaggio errore dopo 5 secondi
|
||||
setTimeout(() => {
|
||||
errorMessage.value = '';
|
||||
}, 5000);
|
||||
} finally {
|
||||
sending.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const goToChangeEmail = () => {
|
||||
router.push({ name: 'ChangeEmail' });
|
||||
};
|
||||
|
||||
const logout = async () => {
|
||||
await userStore.logout();
|
||||
router.push({ name: 'Home' });
|
||||
};
|
||||
|
||||
// Lifecycle
|
||||
onMounted(() => {
|
||||
startCountdown();
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
if (countdownInterval) {
|
||||
clearInterval(countdownInterval);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
t,
|
||||
tools,
|
||||
sending,
|
||||
emailSent,
|
||||
errorMessage,
|
||||
canResend,
|
||||
timeLeft,
|
||||
formattedTimeLeft,
|
||||
resendVerificationEmail,
|
||||
goToChangeEmail,
|
||||
logout,
|
||||
};
|
||||
},
|
||||
});
|
||||
156
src/components/checkemail/checkemail.vue
Executable file
156
src/components/checkemail/checkemail.vue
Executable file
@@ -0,0 +1,156 @@
|
||||
<template>
|
||||
<q-page
|
||||
v-if="tools.isLogged() && !tools.isEmailVerified()"
|
||||
padding
|
||||
class="check-email-page"
|
||||
>
|
||||
<div class="check-email-container">
|
||||
<!-- Icona principale -->
|
||||
<div class="email-icon-wrapper">
|
||||
<q-icon
|
||||
name="mark_email_unread"
|
||||
size="80px"
|
||||
color="warning"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Banner principale -->
|
||||
<q-banner
|
||||
rounded
|
||||
class="bg-warning text-black main-banner"
|
||||
>
|
||||
<template v-slot:avatar>
|
||||
<q-icon
|
||||
name="info"
|
||||
color="black"
|
||||
/>
|
||||
</template>
|
||||
<div
|
||||
class="banner-content"
|
||||
v-html="
|
||||
$t('components.authentication.email_verification2.link_sent', {
|
||||
botname: tools.getBotName(),
|
||||
})
|
||||
"
|
||||
></div>
|
||||
</q-banner>
|
||||
|
||||
<!-- Sezione Reinvio Email -->
|
||||
<q-card
|
||||
flat
|
||||
bordered
|
||||
class="resend-card q-mt-lg"
|
||||
>
|
||||
<q-card-section>
|
||||
<div class="text-subtitle1 text-weight-medium q-mb-sm">
|
||||
{{ t('components.authentication.email_verification2.non_ricevuta') }}
|
||||
</div>
|
||||
|
||||
<!-- Countdown attivo -->
|
||||
<div
|
||||
v-if="!canResend"
|
||||
class="countdown-section"
|
||||
>
|
||||
<q-icon
|
||||
name="schedule"
|
||||
size="20px"
|
||||
color="grey-6"
|
||||
class="q-mr-sm"
|
||||
/>
|
||||
<span class="text-grey-7">
|
||||
{{ t('components.authentication.email_verification2.attendi') }}
|
||||
<strong>{{ formattedTimeLeft }}</strong>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Bottone Reinvio -->
|
||||
<q-btn
|
||||
v-else
|
||||
:loading="sending"
|
||||
:disable="sending"
|
||||
color="primary"
|
||||
icon="send"
|
||||
:label="t('components.authentication.email_verification2.reinvia')"
|
||||
class="full-width q-mt-sm"
|
||||
@click="resendVerificationEmail"
|
||||
/>
|
||||
|
||||
<!-- Messaggio successo -->
|
||||
<q-banner
|
||||
v-if="emailSent"
|
||||
rounded
|
||||
dense
|
||||
class="bg-positive text-white q-mt-md"
|
||||
>
|
||||
<template v-slot:avatar>
|
||||
<q-icon
|
||||
name="check_circle"
|
||||
color="white"
|
||||
/>
|
||||
</template>
|
||||
{{ t('components.authentication.email_verification2.inviata_successo') }}
|
||||
</q-banner>
|
||||
|
||||
<!-- Messaggio errore -->
|
||||
<q-banner
|
||||
v-if="errorMessage"
|
||||
rounded
|
||||
dense
|
||||
class="bg-negative text-white q-mt-md"
|
||||
>
|
||||
<template v-slot:avatar>
|
||||
<q-icon
|
||||
name="error"
|
||||
color="white"
|
||||
/>
|
||||
</template>
|
||||
{{ errorMessage }}
|
||||
</q-banner>
|
||||
</q-card-section>
|
||||
<!-- Banner istruzioni -->
|
||||
<q-banner
|
||||
rounded
|
||||
class="bg-grey-3 text-black info-banner q-mt-md"
|
||||
>
|
||||
<template v-slot:avatar>
|
||||
<q-icon
|
||||
name="help_outline"
|
||||
color="grey-7"
|
||||
/>
|
||||
</template>
|
||||
<div
|
||||
class="banner-content"
|
||||
v-html="$t('components.authentication.email_verification2.se_non_ricevo')"
|
||||
></div>
|
||||
</q-banner>
|
||||
</q-card>
|
||||
|
||||
<!-- Link utili -->
|
||||
<div class="helpful-links q-mt-lg text-center">
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
color="primary"
|
||||
:label="t('components.authentication.email_verification2.cambia_email')"
|
||||
@click="goToChangeEmail"
|
||||
/>
|
||||
<span class="q-mx-sm text-grey-5">|</span>
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
color="grey-7"
|
||||
:label="t('components.authentication.email_verification2.logout')"
|
||||
@click="logout"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<LandingFooter />
|
||||
</q-page>
|
||||
</template>
|
||||
|
||||
<script lang="ts" src="./CheckEmail.ts"></script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import './CheckEmail.scss';
|
||||
</style>
|
||||
1
src/components/checkemail/index.ts
Executable file
1
src/components/checkemail/index.ts
Executable file
@@ -0,0 +1 @@
|
||||
export {default as CheckEmail} from './checkemail.vue'
|
||||
569
src/components/ollamachat/OllamaChat.vue
Normal file
569
src/components/ollamachat/OllamaChat.vue
Normal file
@@ -0,0 +1,569 @@
|
||||
<template>
|
||||
<q-card
|
||||
class="ollama-chat"
|
||||
:style="{ height: height }"
|
||||
>
|
||||
<!-- Header -->
|
||||
<q-card-section class="q-py-sm bg-primary text-white">
|
||||
<div class="row items-center justify-between">
|
||||
<div class="row items-center q-gutter-sm">
|
||||
<q-badge
|
||||
:color="isConnected ? 'green' : 'red'"
|
||||
rounded
|
||||
/>
|
||||
<span class="text-subtitle1 text-weight-medium"
|
||||
>{{ title }} - {{ settings.model }}</span
|
||||
>
|
||||
</div>
|
||||
<div class="row q-gutter-xs">
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
round
|
||||
icon="settings"
|
||||
@click="showSettings = true"
|
||||
>
|
||||
<q-tooltip>Impostazioni</q-tooltip>
|
||||
</q-btn>
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
round
|
||||
icon="delete_sweep"
|
||||
@click="clearChat"
|
||||
>
|
||||
<q-tooltip>Pulisci Chat</q-tooltip>
|
||||
</q-btn>
|
||||
</div>
|
||||
</div>
|
||||
</q-card-section>
|
||||
|
||||
<!-- Messages -->
|
||||
<q-card-section
|
||||
ref="messagesContainer"
|
||||
class="messages-container q-pa-md"
|
||||
>
|
||||
<div
|
||||
v-if="messages.length === 0"
|
||||
class="text-center text-grey-6 q-py-xl"
|
||||
>
|
||||
<q-icon
|
||||
name="chat"
|
||||
size="64px"
|
||||
color="grey-4"
|
||||
/>
|
||||
<p class="q-mt-md">Inizia una conversazione!</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-for="(msg, index) in messages"
|
||||
:key="index"
|
||||
class="message-wrapper q-mb-md"
|
||||
:class="msg.role === 'user' ? 'text-right' : 'text-left'"
|
||||
>
|
||||
<div
|
||||
class="message-bubble q-pa-sm q-px-md"
|
||||
:class="msg.role === 'user' ? 'bg-primary text-white' : 'bg-grey-3 text-dark'"
|
||||
>
|
||||
<!-- Puntini solo se streaming E contenuto vuoto -->
|
||||
<div
|
||||
v-if="msg.role === 'assistant' && msg.isStreaming && !msg.content"
|
||||
class="typing-indicator"
|
||||
>
|
||||
<span></span><span></span><span></span>
|
||||
</div>
|
||||
<!-- Contenuto messaggio (anche durante streaming se già arrivato) -->
|
||||
<div
|
||||
v-else
|
||||
class="message-content"
|
||||
>
|
||||
<div v-html="formatMessage(msg.content)"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-caption text-grey-6 q-mt-xs">
|
||||
{{ msg.role === 'user' ? 'Tu' : modelName }} • {{ formatTime(msg.timestamp) }}
|
||||
</div>
|
||||
</div>
|
||||
</q-card-section>
|
||||
|
||||
<!-- Input -->
|
||||
<q-card-section class="q-pa-sm border-top">
|
||||
<div class="row q-gutter-sm items-end">
|
||||
<q-input
|
||||
v-model="inputMessage"
|
||||
:disable="isGenerating"
|
||||
outlined
|
||||
dense
|
||||
autogrow
|
||||
class="col"
|
||||
placeholder="Scrivi un messaggio..."
|
||||
@keydown.enter.prevent="handleEnter"
|
||||
>
|
||||
<template v-slot:append>
|
||||
<q-btn
|
||||
v-if="isGenerating"
|
||||
flat
|
||||
dense
|
||||
round
|
||||
icon="stop"
|
||||
color="negative"
|
||||
@click="stopGeneration"
|
||||
>
|
||||
<q-tooltip>Ferma generazione</q-tooltip>
|
||||
</q-btn>
|
||||
</template>
|
||||
</q-input>
|
||||
<q-btn
|
||||
:loading="isGenerating"
|
||||
:disable="!inputMessage.trim() || isGenerating"
|
||||
color="primary"
|
||||
icon="send"
|
||||
@click="sendMessage"
|
||||
>
|
||||
<q-tooltip>Invia messaggio</q-tooltip>
|
||||
</q-btn>
|
||||
</div>
|
||||
</q-card-section>
|
||||
|
||||
<!-- Settings Dialog -->
|
||||
<q-dialog v-model="showSettings">
|
||||
<q-card style="min-width: 350px">
|
||||
<q-card-section class="row items-center q-pb-none">
|
||||
<div class="text-h6">Impostazioni</div>
|
||||
<q-space />
|
||||
<q-btn
|
||||
icon="close"
|
||||
flat
|
||||
round
|
||||
dense
|
||||
v-close-popup
|
||||
/>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section class="q-gutter-md">
|
||||
<q-input
|
||||
v-model="settings.baseUrl"
|
||||
outlined
|
||||
label="Ollama URL"
|
||||
hint="URL del server Ollama"
|
||||
/>
|
||||
|
||||
<q-select
|
||||
v-model="settings.model"
|
||||
:options="availableModels"
|
||||
outlined
|
||||
label="Modello"
|
||||
emit-value
|
||||
map-options
|
||||
/>
|
||||
|
||||
<div>
|
||||
<div class="text-caption q-mb-sm">
|
||||
Temperatura: {{ settings.temperature }}
|
||||
</div>
|
||||
<q-slider
|
||||
v-model="settings.temperature"
|
||||
:min="0"
|
||||
:max="2"
|
||||
:step="0.1"
|
||||
label
|
||||
color="primary"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<q-input
|
||||
v-model="settings.systemPrompt"
|
||||
outlined
|
||||
type="textarea"
|
||||
label="System Prompt (opzionale)"
|
||||
hint="Istruzioni per il comportamento dell'AI"
|
||||
/>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-actions align="right">
|
||||
<q-btn
|
||||
flat
|
||||
label="Annulla"
|
||||
color="grey"
|
||||
v-close-popup
|
||||
/>
|
||||
<q-btn
|
||||
flat
|
||||
label="Salva"
|
||||
color="primary"
|
||||
@click="saveSettings"
|
||||
v-close-popup
|
||||
/>
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
</q-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, reactive, computed, onMounted, nextTick, watch } from 'vue';
|
||||
import OllamaService from './OllamaService.js';
|
||||
|
||||
import { tools } from '@tools';
|
||||
|
||||
export default {
|
||||
name: 'OllamaChat',
|
||||
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: 'Chat AI',
|
||||
},
|
||||
height: {
|
||||
type: String,
|
||||
default: '600px',
|
||||
},
|
||||
baseUrl: {
|
||||
type: String,
|
||||
default: 'http://localhost:11434',
|
||||
},
|
||||
model: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
temperature: {
|
||||
type: Number,
|
||||
default: 0.7,
|
||||
},
|
||||
systemPrompt: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
initialMessages: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
|
||||
emits: ['message-sent', 'response-received', 'error', 'settings-changed'],
|
||||
|
||||
setup(props, { emit }) {
|
||||
// State
|
||||
const messages = ref([...props.initialMessages]);
|
||||
const inputMessage = ref('');
|
||||
const isGenerating = ref(false);
|
||||
const isConnected = ref(false);
|
||||
const showSettings = ref(false);
|
||||
const messagesContainer = ref(null);
|
||||
const abortController = ref(null);
|
||||
const availableModels = ref([]);
|
||||
|
||||
// Settings
|
||||
const settings = reactive({
|
||||
baseUrl: props.baseUrl,
|
||||
model: props.model,
|
||||
temperature: props.temperature,
|
||||
systemPrompt: props.systemPrompt,
|
||||
});
|
||||
|
||||
// Ollama service instance
|
||||
const ollama = new OllamaService(settings.baseUrl);
|
||||
|
||||
// Computed
|
||||
const modelName = computed(() => settings.model);
|
||||
|
||||
// Methods
|
||||
const scrollToBottom = async () => {
|
||||
await nextTick();
|
||||
if (messagesContainer.value) {
|
||||
const container = messagesContainer.value.$el || messagesContainer.value;
|
||||
container.scrollTop = container.scrollHeight;
|
||||
}
|
||||
};
|
||||
|
||||
const formatMessage = (content) => {
|
||||
if (!content) return '';
|
||||
return content
|
||||
.replace(
|
||||
/```(\w+)?\n([\s\S]*?)```/g,
|
||||
'<pre class="code-block"><code>$2</code></pre>'
|
||||
)
|
||||
.replace(/`([^`]+)`/g, '<code class="inline-code">$1</code>')
|
||||
.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>')
|
||||
.replace(/\*([^*]+)\*/g, '<em>$1</em>')
|
||||
.replace(/\n/g, '<br>');
|
||||
};
|
||||
|
||||
const formatTime = (timestamp) => {
|
||||
if (!timestamp) return '';
|
||||
return new Date(timestamp).toLocaleTimeString('it-IT', {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
});
|
||||
};
|
||||
|
||||
const handleEnter = (event) => {
|
||||
if (!event.shiftKey) {
|
||||
sendMessage();
|
||||
}
|
||||
};
|
||||
|
||||
const sendMessage = async () => {
|
||||
const content = inputMessage.value.trim();
|
||||
if (!content || isGenerating.value) return;
|
||||
|
||||
// Add user message
|
||||
const userMessage = {
|
||||
role: 'user',
|
||||
content,
|
||||
timestamp: new Date(),
|
||||
};
|
||||
messages.value.push(userMessage);
|
||||
inputMessage.value = '';
|
||||
emit('message-sent', userMessage);
|
||||
|
||||
// Add placeholder for assistant
|
||||
const assistantMessage = {
|
||||
role: 'assistant',
|
||||
content: '',
|
||||
timestamp: new Date(),
|
||||
isStreaming: true,
|
||||
};
|
||||
messages.value.push(assistantMessage);
|
||||
|
||||
const assistantIndex = messages.value.length - 1;
|
||||
|
||||
isGenerating.value = true;
|
||||
abortController.value = new AbortController();
|
||||
|
||||
try {
|
||||
ollama.setBaseUrl(settings.baseUrl);
|
||||
|
||||
const chatMessages = messages.value
|
||||
.filter((m) => !m.isStreaming)
|
||||
.map((m) => ({ role: m.role, content: m.content }));
|
||||
|
||||
await ollama.streamChat(
|
||||
{
|
||||
model: settings.model,
|
||||
messages: chatMessages,
|
||||
temperature: settings.temperature,
|
||||
system: settings.systemPrompt || undefined,
|
||||
},
|
||||
(chunk, full) => {
|
||||
messages.value[assistantIndex] = {
|
||||
...messages.value[assistantIndex],
|
||||
content: full,
|
||||
isStreaming: true,
|
||||
};
|
||||
assistantMessage.isStreaming = true;
|
||||
scrollToBottom();
|
||||
},
|
||||
(fullContent) => {
|
||||
assistantMessage.content = fullContent;
|
||||
assistantMessage.isStreaming = false;
|
||||
assistantMessage.timestamp = new Date();
|
||||
emit('response-received', assistantMessage);
|
||||
}
|
||||
);
|
||||
|
||||
isConnected.value = true;
|
||||
} catch (error) {
|
||||
assistantMessage.content = `❌ Errore: ${error.message}`;
|
||||
assistantMessage.isStreaming = false;
|
||||
isConnected.value = false;
|
||||
emit('error', error);
|
||||
}
|
||||
|
||||
isGenerating.value = false;
|
||||
scrollToBottom();
|
||||
};
|
||||
|
||||
const stopGeneration = () => {
|
||||
if (abortController.value) {
|
||||
abortController.value.abort();
|
||||
isGenerating.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const clearChat = () => {
|
||||
messages.value = [];
|
||||
};
|
||||
|
||||
const loadModels = async () => {
|
||||
try {
|
||||
ollama.setBaseUrl(settings.baseUrl);
|
||||
const models = await ollama.listModels();
|
||||
availableModels.value = models.map((m) => ({
|
||||
label: m.name,
|
||||
value: m.name,
|
||||
}));
|
||||
isConnected.value = true;
|
||||
|
||||
// prende dal cookie salvato
|
||||
const savedModel = tools.getCookie('ollama_model');
|
||||
if (savedModel) {
|
||||
settings.model = savedModel;
|
||||
}
|
||||
|
||||
const modelIndex = availableModels.value.findIndex(
|
||||
(m) => m.value === settings.model
|
||||
);
|
||||
if (modelIndex === -1) {
|
||||
settings.model = availableModels.value[0].value;
|
||||
}
|
||||
|
||||
scrollToBottom();
|
||||
} catch (error) {
|
||||
console.error('Error loadModels', error);
|
||||
isConnected.value = false;
|
||||
availableModels.value = [
|
||||
{ label: 'llama3.2', value: 'llama3.2' },
|
||||
{ label: 'llama3.1', value: 'llama3.1' },
|
||||
{ label: 'mistral', value: 'mistral' },
|
||||
{ label: 'codellama', value: 'codellama' },
|
||||
];
|
||||
}
|
||||
};
|
||||
|
||||
const saveSettings = () => {
|
||||
emit('settings-changed', { ...settings });
|
||||
};
|
||||
|
||||
// Lifecycle
|
||||
onMounted(() => {
|
||||
try {
|
||||
loadModels();
|
||||
} catch (e) {
|
||||
console.error('Error Mounted Chat:', e);
|
||||
}
|
||||
});
|
||||
|
||||
watch(
|
||||
() => settings.model,
|
||||
(newModel) => {
|
||||
tools.setCookie('ollama_model', newModel);
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
// Watch messages for scroll
|
||||
watch(messages, scrollToBottom, { deep: true });
|
||||
|
||||
return {
|
||||
messages,
|
||||
inputMessage,
|
||||
isGenerating,
|
||||
isConnected,
|
||||
showSettings,
|
||||
messagesContainer,
|
||||
settings,
|
||||
availableModels,
|
||||
modelName,
|
||||
formatMessage,
|
||||
formatTime,
|
||||
handleEnter,
|
||||
sendMessage,
|
||||
stopGeneration,
|
||||
clearChat,
|
||||
saveSettings,
|
||||
tools,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.ollama-chat {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.messages-container {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.message-bubble {
|
||||
display: inline-block;
|
||||
max-width: 80%;
|
||||
border-radius: 16px;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.text-right .message-bubble {
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
|
||||
.text-left .message-bubble {
|
||||
border-bottom-left-radius: 4px;
|
||||
}
|
||||
|
||||
.message-content :deep(pre.code-block) {
|
||||
background: #1e1e1e;
|
||||
color: #d4d4d4;
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
overflow-x: auto;
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.message-content :deep(.inline-code) {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.typing-indicator {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.typing-indicator span {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background: currentColor;
|
||||
border-radius: 50%;
|
||||
animation: typing 1.4s infinite;
|
||||
}
|
||||
|
||||
.typing-indicator span:nth-child(2) {
|
||||
animation-delay: 0.2s;
|
||||
}
|
||||
|
||||
.typing-indicator span:nth-child(3) {
|
||||
animation-delay: 0.4s;
|
||||
}
|
||||
|
||||
@keyframes typing {
|
||||
0%,
|
||||
60%,
|
||||
100% {
|
||||
opacity: 0.3;
|
||||
transform: scale(0.8);
|
||||
}
|
||||
30% {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.border-top {
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.streaming-cursor {
|
||||
display: inline-block;
|
||||
animation: blink-cursor 0.8s infinite;
|
||||
color: var(--q-primary);
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
@keyframes blink-cursor {
|
||||
0%,
|
||||
50% {
|
||||
opacity: 1;
|
||||
}
|
||||
51%,
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
388
src/components/ollamachat/OllamaService.js
Normal file
388
src/components/ollamachat/OllamaService.js
Normal file
@@ -0,0 +1,388 @@
|
||||
/**
|
||||
* OllamaService - Servizio per interagire con Ollama API
|
||||
* Usalo in Quasar/Vue.js per tutte le chiamate AI
|
||||
*/
|
||||
|
||||
class OllamaService {
|
||||
constructor(baseUrl = 'http://localhost:11434') {
|
||||
this.baseUrl = baseUrl.replace(/\/$/, '');
|
||||
this.defaultModel = '';
|
||||
this.defaultTemperature = 0.7;
|
||||
}
|
||||
|
||||
// Configura l'URL base
|
||||
setBaseUrl(url) {
|
||||
this.baseUrl = url.replace(/\/$/, '');
|
||||
}
|
||||
|
||||
// Configura il modello di default
|
||||
setDefaultModel(model) {
|
||||
this.defaultModel = model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Chat con cronologia messaggi
|
||||
* @param {Object} options - Opzioni della chat
|
||||
* @param {string} options.model - Nome del modello
|
||||
* @param {Array} options.messages - Array di messaggi [{role: 'user'|'assistant', content: '...'}]
|
||||
* @param {boolean} options.stream - Abilita streaming
|
||||
* @param {number} options.temperature - Temperatura (0-2)
|
||||
* @param {string} options.system - System prompt opzionale
|
||||
* @returns {Promise<string|Response>}
|
||||
*/
|
||||
async chat(options) {
|
||||
const {
|
||||
model = this.defaultModel,
|
||||
messages,
|
||||
stream = false,
|
||||
temperature = this.defaultTemperature,
|
||||
system = null,
|
||||
maxTokens = null,
|
||||
topP = null,
|
||||
topK = null,
|
||||
} = options;
|
||||
|
||||
const payload = {
|
||||
model,
|
||||
messages,
|
||||
stream,
|
||||
options: {
|
||||
temperature,
|
||||
...(maxTokens && { num_predict: maxTokens }),
|
||||
...(topP && { top_p: topP }),
|
||||
...(topK && { top_k: topK }),
|
||||
},
|
||||
};
|
||||
|
||||
if (system) {
|
||||
payload.system = system;
|
||||
}
|
||||
|
||||
const response = await fetch(`${this.baseUrl}/api2/chat`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Ollama API error: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
if (stream) return response;
|
||||
|
||||
const data = await response.json();
|
||||
return data.message.content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generazione testo semplice (senza cronologia)
|
||||
* @param {Object} options - Opzioni di generazione
|
||||
* @param {string} options.model - Nome del modello
|
||||
* @param {string} options.prompt - Prompt di input
|
||||
* @param {boolean} options.stream - Abilita streaming
|
||||
* @param {number} options.temperature - Temperatura (0-2)
|
||||
* @param {string} options.system - System prompt opzionale
|
||||
* @returns {Promise<string|Response>}
|
||||
*/
|
||||
async generate(options) {
|
||||
const {
|
||||
model = this.defaultModel,
|
||||
prompt,
|
||||
stream = false,
|
||||
temperature = this.defaultTemperature,
|
||||
system = null,
|
||||
maxTokens = null,
|
||||
} = options;
|
||||
|
||||
const payload = {
|
||||
model,
|
||||
prompt,
|
||||
stream,
|
||||
options: {
|
||||
temperature,
|
||||
...(maxTokens && { num_predict: maxTokens }),
|
||||
},
|
||||
};
|
||||
|
||||
if (system) {
|
||||
payload.system = system;
|
||||
}
|
||||
|
||||
const response = await fetch(`${this.baseUrl}/api2/generate`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Ollama API error: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
if (stream) return response;
|
||||
|
||||
const data = await response.json();
|
||||
return data.response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Chat con streaming e callback
|
||||
* @param {Object} options - Opzioni della chat
|
||||
* @param {Function} onChunk - Callback per ogni chunk (chunk, fullContent)
|
||||
* @param {Function} onComplete - Callback al completamento (fullContent)
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
async streamChat(options, onChunk, onComplete = null) {
|
||||
const response = await this.chat({ ...options, stream: true });
|
||||
const reader = response.body.getReader();
|
||||
const decoder = new TextDecoder();
|
||||
let fullContent = '';
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) break;
|
||||
|
||||
const chunk = decoder.decode(value);
|
||||
const lines = chunk.split('\n').filter((line) => line.trim());
|
||||
|
||||
for (const line of lines) {
|
||||
try {
|
||||
const json = JSON.parse(line);
|
||||
if (json.message?.content) {
|
||||
fullContent += json.message.content;
|
||||
if (onChunk) onChunk(json.message.content, fullContent);
|
||||
}
|
||||
} catch (e) {
|
||||
// Ignora linee non JSON
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
reader.releaseLock();
|
||||
}
|
||||
|
||||
if (onComplete) onComplete(fullContent);
|
||||
return fullContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generazione con streaming e callback
|
||||
* @param {Object} options - Opzioni di generazione
|
||||
* @param {Function} onChunk - Callback per ogni chunk
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
async streamGenerate(options, onChunk, onComplete = null) {
|
||||
const response = await this.generate({ ...options, stream: true });
|
||||
const reader = response.body.getReader();
|
||||
const decoder = new TextDecoder();
|
||||
let fullContent = '';
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) break;
|
||||
|
||||
const chunk = decoder.decode(value);
|
||||
const lines = chunk.split('\n').filter((line) => line.trim());
|
||||
|
||||
for (const line of lines) {
|
||||
try {
|
||||
const json = JSON.parse(line);
|
||||
if (json.response) {
|
||||
fullContent += json.response;
|
||||
if (onChunk) onChunk(json.response, fullContent);
|
||||
}
|
||||
} catch (e) {
|
||||
// Ignora linee non JSON
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
reader.releaseLock();
|
||||
}
|
||||
|
||||
if (onComplete) onComplete(fullContent);
|
||||
return fullContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lista modelli disponibili
|
||||
* @returns {Promise<Array>}
|
||||
*/
|
||||
async listModels() {
|
||||
const response = await fetch(`${this.baseUrl}/api2/models`);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Ollama API error: ${response.status}`);
|
||||
}
|
||||
const data = await response.json();
|
||||
return data.models || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Informazioni su un modello
|
||||
* @param {string} model - Nome del modello
|
||||
* @returns {Promise<Object>}
|
||||
*/
|
||||
async showModel(model) {
|
||||
const response = await fetch(`${this.baseUrl}/api2/show`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ name: model }),
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`Ollama API error: ${response.status}`);
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
|
||||
/**
|
||||
* Genera embeddings
|
||||
* @param {string} model - Nome del modello
|
||||
* @param {string|Array} prompt - Testo o array di testi
|
||||
* @returns {Promise<Array>}
|
||||
*/
|
||||
async embeddings(model, prompt) {
|
||||
const response = await fetch(`${this.baseUrl}/api2/embeddings`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ model, prompt }),
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`Ollama API error: ${response.status}`);
|
||||
}
|
||||
const data = await response.json();
|
||||
return data.embedding;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// METODI HELPER PER USI COMUNI
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* Genera testo creativo
|
||||
*/
|
||||
async generateText(prompt, options = {}) {
|
||||
return this.generate({
|
||||
prompt,
|
||||
temperature: 0.8,
|
||||
...options,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Genera codice
|
||||
*/
|
||||
async generateCode(prompt, language = 'javascript', options = {}) {
|
||||
return this.generate({
|
||||
prompt: `Scrivi codice ${language} per: ${prompt}\n\nRispondi solo con il codice, senza spiegazioni.`,
|
||||
temperature: 0.3,
|
||||
...options,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Traduci testo
|
||||
*/
|
||||
async translate(text, targetLang = 'english', options = {}) {
|
||||
return this.generate({
|
||||
prompt: `Traduci il seguente testo in ${targetLang}. Rispondi solo con la traduzione:\n\n${text}`,
|
||||
temperature: 0.3,
|
||||
...options,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Riassumi testo
|
||||
*/
|
||||
async summarize(text, options = {}) {
|
||||
return this.generate({
|
||||
prompt: `Riassumi il seguente testo in modo conciso:\n\n${text}`,
|
||||
temperature: 0.5,
|
||||
...options,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Rispondi a una domanda basata su un contesto
|
||||
*/
|
||||
async answerQuestion(question, context, options = {}) {
|
||||
return this.generate({
|
||||
prompt: `Contesto:\n${context}\n\nDomanda: ${question}\n\nRispondi basandoti solo sul contesto fornito.`,
|
||||
temperature: 0.3,
|
||||
...options,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Estrai informazioni strutturate (JSON)
|
||||
*/
|
||||
async extractJSON(text, schema, options = {}) {
|
||||
const response = await this.generate({
|
||||
prompt: `Estrai le informazioni dal seguente testo e restituisci un JSON valido con questa struttura: ${JSON.stringify(schema)}\n\nTesto:\n${text}\n\nRispondi SOLO con il JSON, senza altro testo.`,
|
||||
temperature: 0.1,
|
||||
...options,
|
||||
});
|
||||
|
||||
try {
|
||||
// Cerca di estrarre JSON dalla risposta
|
||||
const jsonMatch = response.match(/\{[\s\S]*\}/);
|
||||
if (jsonMatch) {
|
||||
return JSON.parse(jsonMatch[0]);
|
||||
}
|
||||
return JSON.parse(response);
|
||||
} catch (e) {
|
||||
throw new Error('Failed to parse JSON response: ' + response);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Analisi del sentiment
|
||||
*/
|
||||
async analyzeSentiment(text, options = {}) {
|
||||
const response = await this.generate({
|
||||
prompt: `Analizza il sentiment del seguente testo e rispondi SOLO con un JSON nel formato {"sentiment": "positive"|"negative"|"neutral", "confidence": 0.0-1.0, "explanation": "breve spiegazione"}\n\nTesto: ${text}`,
|
||||
temperature: 0.1,
|
||||
...options,
|
||||
});
|
||||
|
||||
try {
|
||||
const jsonMatch = response.match(/\{[\s\S]*\}/);
|
||||
if (jsonMatch) {
|
||||
return JSON.parse(jsonMatch[0]);
|
||||
}
|
||||
return JSON.parse(response);
|
||||
} catch (e) {
|
||||
return { sentiment: 'unknown', confidence: 0, raw: response };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Correggi grammatica
|
||||
*/
|
||||
async correctGrammar(text, language = 'italiano', options = {}) {
|
||||
return this.generate({
|
||||
prompt: `Correggi gli errori grammaticali nel seguente testo in ${language}. Rispondi solo con il testo corretto:\n\n${text}`,
|
||||
temperature: 0.2,
|
||||
...options,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Genera lista/bullet points
|
||||
*/
|
||||
async generateList(topic, count = 5, options = {}) {
|
||||
return this.generate({
|
||||
prompt: `Genera una lista di ${count} elementi su: ${topic}\n\nFormatta come lista puntata.`,
|
||||
temperature: 0.7,
|
||||
...options,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Export per ES6 modules
|
||||
export default OllamaService;
|
||||
|
||||
// Export per CommonJS
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = OllamaService;
|
||||
}
|
||||
178
src/components/ollamachat/useOllama.js
Normal file
178
src/components/ollamachat/useOllama.js
Normal file
@@ -0,0 +1,178 @@
|
||||
/**
|
||||
* useOllama - Composable Vue 3 per usare Ollama nelle tue applicazioni Quasar
|
||||
*
|
||||
* Esempio d'uso:
|
||||
*
|
||||
* import { useOllama } from './useOllama';
|
||||
*
|
||||
* const { generate, chat, isLoading, error } = useOllama({
|
||||
* baseUrl: 'http://localhost:11434',
|
||||
* model: 'llama3.2'
|
||||
* });
|
||||
*
|
||||
* const result = await generate('Scrivi una poesia');
|
||||
*/
|
||||
|
||||
import { ref, reactive } from 'vue';
|
||||
import OllamaService from './OllamaService.js';
|
||||
|
||||
export function useOllama(options = {}) {
|
||||
const {
|
||||
baseUrl = 'http://localhost:11434',
|
||||
model = 'llama3.2',
|
||||
temperature = 0.7,
|
||||
} = options;
|
||||
|
||||
// State
|
||||
const isLoading = ref(false);
|
||||
const error = ref(null);
|
||||
const streamingContent = ref('');
|
||||
const models = ref([]);
|
||||
|
||||
// Service instance
|
||||
const service = new OllamaService(baseUrl);
|
||||
service.setDefaultModel(model);
|
||||
|
||||
/**
|
||||
* Genera testo
|
||||
*/
|
||||
const generate = async (prompt, opts = {}) => {
|
||||
isLoading.value = true;
|
||||
error.value = null;
|
||||
streamingContent.value = '';
|
||||
|
||||
try {
|
||||
const result = await service.generate({
|
||||
prompt,
|
||||
temperature,
|
||||
...opts,
|
||||
});
|
||||
return result;
|
||||
} catch (e) {
|
||||
error.value = e.message;
|
||||
throw e;
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Genera testo con streaming
|
||||
*/
|
||||
const generateStream = async (prompt, opts = {}) => {
|
||||
isLoading.value = true;
|
||||
error.value = null;
|
||||
streamingContent.value = '';
|
||||
|
||||
try {
|
||||
const result = await service.streamGenerate(
|
||||
{ prompt, temperature, ...opts },
|
||||
(chunk, full) => {
|
||||
streamingContent.value = full;
|
||||
}
|
||||
);
|
||||
return result;
|
||||
} catch (e) {
|
||||
error.value = e.message;
|
||||
throw e;
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Chat con messaggi
|
||||
*/
|
||||
const chat = async (messages, opts = {}) => {
|
||||
isLoading.value = true;
|
||||
error.value = null;
|
||||
streamingContent.value = '';
|
||||
|
||||
try {
|
||||
const result = await service.chat({
|
||||
messages,
|
||||
temperature,
|
||||
...opts,
|
||||
});
|
||||
return result;
|
||||
} catch (e) {
|
||||
error.value = e.message;
|
||||
throw e;
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Chat con streaming
|
||||
*/
|
||||
const chatStream = async (messages, opts = {}) => {
|
||||
isLoading.value = true;
|
||||
error.value = null;
|
||||
streamingContent.value = '';
|
||||
|
||||
try {
|
||||
const result = await service.streamChat(
|
||||
{ messages, temperature, ...opts },
|
||||
(chunk, full) => {
|
||||
streamingContent.value = full;
|
||||
}
|
||||
);
|
||||
return result;
|
||||
} catch (e) {
|
||||
error.value = e.message;
|
||||
throw e;
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Carica modelli disponibili
|
||||
*/
|
||||
const loadModels = async () => {
|
||||
try {
|
||||
models.value = await service.listModels();
|
||||
return models.value;
|
||||
} catch (e) {
|
||||
error.value = e.message;
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
// Helper methods
|
||||
const generateText = (prompt, opts) => service.generateText(prompt, opts);
|
||||
const generateCode = (prompt, lang, opts) => service.generateCode(prompt, lang, opts);
|
||||
const translate = (text, lang, opts) => service.translate(text, lang, opts);
|
||||
const summarize = (text, opts) => service.summarize(text, opts);
|
||||
const extractJSON = (text, schema, opts) => service.extractJSON(text, schema, opts);
|
||||
const analyzeSentiment = (text, opts) => service.analyzeSentiment(text, opts);
|
||||
|
||||
return {
|
||||
// State
|
||||
isLoading,
|
||||
error,
|
||||
streamingContent,
|
||||
models,
|
||||
|
||||
// Core methods
|
||||
generate,
|
||||
generateStream,
|
||||
chat,
|
||||
chatStream,
|
||||
loadModels,
|
||||
|
||||
// Helper methods
|
||||
generateText,
|
||||
generateCode,
|
||||
translate,
|
||||
summarize,
|
||||
extractJSON,
|
||||
analyzeSentiment,
|
||||
|
||||
// Service access
|
||||
service,
|
||||
};
|
||||
}
|
||||
|
||||
export default useOllama;
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -56,6 +56,7 @@ body {
|
||||
color: #2c3e50;
|
||||
line-height: 1.7;
|
||||
/*background: linear-gradient(135deg, #f5f7fa 0%, #f3fff2 100%);*/
|
||||
background: linear-gradient(180deg, #f1f5f9 0%, #e2e8f0 100%);
|
||||
|
||||
//font-size: 1rem;
|
||||
@media (max-width: 600px) {
|
||||
|
||||
@@ -63,6 +63,7 @@ const msg_website_it = {
|
||||
nextzoom: 'Conferenze',
|
||||
requestresetpwd: 'Richiesta Reset Password',
|
||||
vreg: 'Verifica Reg',
|
||||
reverif_email: 'Riverifica Email',
|
||||
dashboard: 'Lavagna',
|
||||
statoattuale: 'Stato Attuale',
|
||||
posizione_in_programmazione: 'Lista d\'Imbarco',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { IToken } from '@model/other'
|
||||
import type { ICart, IOrderCart, IShareWithUs } from '@/model/Products'
|
||||
import type { IAccount, ICatGrp, ICircuit, IImgGallery, IMovement, IMyCircuit } from '@model/GlobalStore';
|
||||
import type { IAccount, ICatGrp, ICircuit, IImgGallery, IMovement, IMovVisu, IMyCircuit } from '@model/GlobalStore';
|
||||
import { IGallery } from '@model/GlobalStore'
|
||||
import type { IBookedEvent } from './Calendar'
|
||||
|
||||
@@ -197,7 +197,7 @@ export interface IUserProfile {
|
||||
refused_circuits: any[]
|
||||
manage_mycircuits: ICircuit[]
|
||||
useraccounts: IAccount[]
|
||||
last_my_transactions: IMovement[]
|
||||
last_my_transactions: IMovVisu[] // IMovement[]
|
||||
total_transactions?: number
|
||||
calc: ICalc
|
||||
}
|
||||
|
||||
@@ -26,6 +26,8 @@ import { shared_consts } from '@/common/shared_vuejs'
|
||||
import { CPresentazione } from '@/components'
|
||||
import MixinMetaTags from '@/mixins/mixin-metatags'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useQuasar } from 'quasar'
|
||||
import { watch } from 'vue'
|
||||
export default defineComponent({
|
||||
name: 'mainview',
|
||||
components: {
|
||||
@@ -39,9 +41,21 @@ export default defineComponent({
|
||||
const userStore = useUserStore()
|
||||
const { getValDb } = MixinBase()
|
||||
const notifStore = useNotifStore()
|
||||
const $q = useQuasar()
|
||||
|
||||
const isfinishLoading = computed(() => globalStore.finishLoading)
|
||||
|
||||
watch(() => globalStore.finishLoading, (newValue, oldValue) => {
|
||||
if (!newValue) {
|
||||
$q.loading.show({
|
||||
message: 'Caricamento sito ...',
|
||||
spinnerColor: 'primary',
|
||||
})
|
||||
} else {
|
||||
$q.loading.hide()
|
||||
}
|
||||
})
|
||||
|
||||
const { setmeta } = MixinMetaTags()
|
||||
|
||||
const { getRefLink } = MixinUsers()
|
||||
|
||||
@@ -23,7 +23,9 @@
|
||||
</CMyPageElem>
|
||||
</div>
|
||||
</div>
|
||||
<LandingFooter></LandingFooter>
|
||||
<div v-if="isfinishLoading">
|
||||
<LandingFooter></LandingFooter>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div v-if="isfinishLoading">
|
||||
|
||||
@@ -196,6 +196,15 @@
|
||||
mykey="Email"
|
||||
:myvalue="myuser.email"
|
||||
/>
|
||||
<CKeyAndValue
|
||||
mykey="Email Verificata"
|
||||
:myvalue="myuser.verified_email"
|
||||
:show-set-button="true"
|
||||
:on-set-value="userStore.setVerifiedEmail"
|
||||
:valuetoSet="true"
|
||||
:param2="myuser._id"
|
||||
button-tooltip="Verifica Email"
|
||||
/>
|
||||
<CKeyAndValue
|
||||
mykey="Versione"
|
||||
:myvalue="myuser.profile.version"
|
||||
|
||||
@@ -15,6 +15,18 @@ function getRoutesAI(site: ISites) {
|
||||
level_parent: 0,
|
||||
level_child: 0.5,
|
||||
},
|
||||
{
|
||||
active: true,
|
||||
order: 30,
|
||||
path: '/ai-ollama',
|
||||
materialIcon: 'fas fa-robot',
|
||||
name: 'mypages.ollamaVPS',
|
||||
component: () => import('@/views/toolsAI/ollama/ollama.vue'),
|
||||
inmenu: true,
|
||||
submenu: true,
|
||||
level_parent: 0,
|
||||
level_child: 0.5,
|
||||
},
|
||||
]
|
||||
|
||||
const routes_admin_ai: IListRoutes[] = [
|
||||
|
||||
@@ -805,6 +805,13 @@ function getRoutesAd(site: ISites) {
|
||||
name: 'pages.vreg',
|
||||
component: () => import('@/views/login/vreg/vreg.vue')
|
||||
},
|
||||
{
|
||||
active: true,
|
||||
order: 1000,
|
||||
path: '/reverif_email',
|
||||
name: 'pages.reverif_email',
|
||||
component: () => import('@/views/login/reverif_email/reverif_email.vue')
|
||||
},
|
||||
{
|
||||
active: true,
|
||||
order: 1000,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -50,7 +50,7 @@ export const useCircuitStore = defineStore('CircuitStore', {
|
||||
const account = userStore.my.profile.useraccounts.find(
|
||||
(rec: IAccount) => rec.circuitId === circuitId
|
||||
);
|
||||
if (account) return account.saldo;
|
||||
if (account) return tools.roundDec2(account.saldo, 2);
|
||||
else return 0;
|
||||
},
|
||||
|
||||
@@ -164,6 +164,24 @@ export const useCircuitStore = defineStore('CircuitStore', {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
getMaxAccumuloByUsername(
|
||||
myuser: IUserFields,
|
||||
circuitId: string,
|
||||
username: string,
|
||||
groupname?: string
|
||||
): number | string {
|
||||
if (myuser && myuser.profile.useraccounts) {
|
||||
const account = myuser.profile.useraccounts.find(
|
||||
(rec: IAccount) =>
|
||||
(rec.username === username ||
|
||||
(rec.groupname === groupname && groupname !== '')) &&
|
||||
rec.circuitId === circuitId
|
||||
);
|
||||
return account ? account.qta_maxConcessa : 0;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
|
||||
SonoDentroAdAlmeno1CircuitoConFido(): boolean {
|
||||
const userStore = useUserStore();
|
||||
@@ -334,7 +352,7 @@ export const useCircuitStore = defineStore('CircuitStore', {
|
||||
return false;
|
||||
},
|
||||
|
||||
updateListCircuit(visu: number) {
|
||||
updateListCircuit(visu: number, sortbyuser?: boolean) {
|
||||
const userStore = useUserStore();
|
||||
|
||||
let arr: any[] = [];
|
||||
@@ -367,6 +385,31 @@ export const useCircuitStore = defineStore('CircuitStore', {
|
||||
}
|
||||
}
|
||||
|
||||
if (sortbyuser) {
|
||||
// Ordina i circuiti prima per quello provinciale, poi quello Italia, poi tutti gli altri
|
||||
const circuitiMiaProvincia = this.getCircuitsByProvince(
|
||||
userStore.my.profile.resid_province
|
||||
);
|
||||
|
||||
const circuitiNazionali = this.getCircuitsNational();
|
||||
|
||||
// Crea Set di ID per lookup veloce
|
||||
const provinciaIds = new Set(circuitiMiaProvincia.map((c) => c._id));
|
||||
const nazionaliIds = new Set(circuitiNazionali.map((c) => c._id));
|
||||
|
||||
// Filtra arr in tre gruppi (mantenendo solo elementi già presenti in arr)
|
||||
const fromProvincia = arr.filter((rec) => provinciaIds.has(rec._id));
|
||||
const fromNazionali = arr.filter(
|
||||
(rec) => nazionaliIds.has(rec._id) && !provinciaIds.has(rec._id)
|
||||
);
|
||||
const others = arr.filter(
|
||||
(rec) => !provinciaIds.has(rec._id) && !nazionaliIds.has(rec._id)
|
||||
);
|
||||
|
||||
// Ricomponi l'array nell'ordine desiderato
|
||||
arr = [...fromProvincia, ...fromNazionali, ...others];
|
||||
}
|
||||
|
||||
return arr;
|
||||
},
|
||||
|
||||
@@ -1420,5 +1463,15 @@ export const useCircuitStore = defineStore('CircuitStore', {
|
||||
|
||||
return str;
|
||||
},
|
||||
|
||||
getTypeCircuit(circuit: ICircuit) {
|
||||
if (circuit.isCircItalia) {
|
||||
return 'Nazionale';
|
||||
} else if (circuit.circuitoIndipendente) {
|
||||
return 'Indipendente';
|
||||
} else if (!circuit.circuitiExtraProv) {
|
||||
return 'Provinciale';
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -7464,92 +7464,97 @@ export const tools = {
|
||||
$router: any,
|
||||
circuit: ICircuit,
|
||||
sendcoinrec: ISendCoin
|
||||
) {
|
||||
): Promise<void> {
|
||||
const userStore = useUserStore();
|
||||
const notifStore = useNotifStore();
|
||||
//T_TOLTO
|
||||
const { username } = userStore.my;
|
||||
|
||||
const username = userStore.my.username;
|
||||
// Origine e destinazione con fallback chain più leggibile
|
||||
const orig = sendcoinrec.grouporig || sendcoinrec.contoComOrig || '';
|
||||
const dest = sendcoinrec.groupdest || sendcoinrec.contoComDest || sendcoinrec.dest;
|
||||
|
||||
const orig = sendcoinrec.grouporig
|
||||
? sendcoinrec.grouporig
|
||||
: sendcoinrec.contoComOrig
|
||||
? sendcoinrec.contoComOrig
|
||||
: '';
|
||||
const dest = sendcoinrec.groupdest
|
||||
? sendcoinrec.groupdest
|
||||
: sendcoinrec.contoComDest
|
||||
? sendcoinrec.contoComDest
|
||||
: sendcoinrec.dest;
|
||||
// Parametri comuni per i messaggi
|
||||
const msgParams = {
|
||||
coin: circuit.symbol,
|
||||
dest,
|
||||
qty: sendcoinrec.qty,
|
||||
circuit: circuit.name,
|
||||
...(orig && { from: orig }), // Aggiunge 'from' solo se esiste
|
||||
};
|
||||
|
||||
let msg = '';
|
||||
if (orig) {
|
||||
msg = t('circuit.question_sendcoinsto_from', {
|
||||
coin: circuit.symbol,
|
||||
from: orig,
|
||||
dest,
|
||||
qty: sendcoinrec.qty,
|
||||
});
|
||||
} else {
|
||||
msg = t('circuit.question_sendcoinsto', {
|
||||
coin: circuit.symbol,
|
||||
dest,
|
||||
qty: sendcoinrec.qty,
|
||||
});
|
||||
}
|
||||
// Seleziona il messaggio appropriato
|
||||
const messageKey = orig
|
||||
? 'circuit.question_sendcoinsto_from'
|
||||
: 'circuit.question_sendcoinsto';
|
||||
|
||||
return $q
|
||||
.dialog({
|
||||
message: msg,
|
||||
// Mostra dialog di conferma
|
||||
return new Promise((resolve, reject) => {
|
||||
$q.dialog({
|
||||
title: t('db.domanda'),
|
||||
message: t(messageKey, msgParams),
|
||||
ok: {
|
||||
label: t('dialog.yes'),
|
||||
color: 'primary',
|
||||
push: true,
|
||||
},
|
||||
cancel: {
|
||||
label: t('dialog.cancel'),
|
||||
color: 'secondary',
|
||||
},
|
||||
title: t('db.domanda'),
|
||||
})
|
||||
.onOk(() => {
|
||||
return userStore
|
||||
.setCircuitCmd(
|
||||
$q,
|
||||
t,
|
||||
username,
|
||||
sendcoinrec.circuitname,
|
||||
shared_consts.CIRCUITCMD.SENDCOINS_REQ,
|
||||
true,
|
||||
sendcoinrec
|
||||
)
|
||||
.then((res: any) => {
|
||||
console.log('setCircuitCmd ', res);
|
||||
if (res && res.cansend) {
|
||||
if (res.useraccounts && res.useraccounts.length > 0) {
|
||||
userStore.my.profile.useraccounts = res.useraccounts;
|
||||
}
|
||||
$router.push('/circuits');
|
||||
tools.showPositiveNotif(
|
||||
$q,
|
||||
t('circuit.coins_sent', {
|
||||
qty: sendcoinrec.qty,
|
||||
symbol: circuit.symbol,
|
||||
dest,
|
||||
})
|
||||
);
|
||||
//tools.showPositiveNotif($q, t('circuit.coins_sendrequest_sent'))
|
||||
} else {
|
||||
tools.showNegativeNotif($q, res.errormsg);
|
||||
}
|
||||
notifStore.updateNotification = true;
|
||||
tools.updateMyData(res);
|
||||
});
|
||||
});
|
||||
.onOk(async () => {
|
||||
try {
|
||||
const res = await userStore.setCircuitCmd(
|
||||
$q,
|
||||
t,
|
||||
username,
|
||||
sendcoinrec.circuitname,
|
||||
shared_consts.CIRCUITCMD.SENDCOINS_REQ,
|
||||
true,
|
||||
sendcoinrec
|
||||
);
|
||||
|
||||
/* return await new Promise((resolve, reject) => {
|
||||
console.log('setCircuitCmd', res);
|
||||
|
||||
if (!res?.cansend) {
|
||||
tools.showNegativeNotif($q, res?.errormsg || t('errors.generic'));
|
||||
return resolve();
|
||||
}
|
||||
|
||||
// Aggiorna gli account utente se presenti
|
||||
if (res.useraccounts?.length > 0) {
|
||||
userStore.my.profile.useraccounts = res.useraccounts;
|
||||
}
|
||||
|
||||
// Aggiorna dati e naviga
|
||||
tools.updateMyData(res);
|
||||
notifStore.updateNotification = true;
|
||||
|
||||
tools.showPositiveNotif(
|
||||
$q,
|
||||
t('circuit.coins_sent', {
|
||||
qty: sendcoinrec.qty,
|
||||
symbol: circuit.symbol,
|
||||
dest,
|
||||
})
|
||||
);
|
||||
|
||||
$router.push('/circuits');
|
||||
resolve();
|
||||
} catch (error) {
|
||||
console.error('Errore invio coins:', error);
|
||||
tools.showNegativeNotif($q, t('errors.generic'));
|
||||
reject(error);
|
||||
}
|
||||
})
|
||||
.onCancel(() => resolve())
|
||||
.onDismiss(() => resolve());
|
||||
});
|
||||
},
|
||||
/* return await new Promise((resolve, reject) => {
|
||||
resolve(false)
|
||||
})
|
||||
*/
|
||||
},
|
||||
|
||||
cancelReqCircuit($q: any, username: string, circuitname: string, groupname?: string) {
|
||||
const userStore = useUserStore();
|
||||
|
||||
@@ -15,6 +15,7 @@ import type {
|
||||
ISignupIscrizioneConacreisOptions,
|
||||
IMovQuery,
|
||||
IGroup,
|
||||
IMovVisu,
|
||||
} from '@/model';
|
||||
import { IFriends, ISettings } from '@/model';
|
||||
import { tools } from '@tools';
|
||||
@@ -805,6 +806,10 @@ export const useUserStore = defineStore('UserStore', {
|
||||
return this.my.profile.teleg_id! > 0 || this.my.profile.teleg_id_old! > 0;
|
||||
},
|
||||
|
||||
isEmailVerified() {
|
||||
return this.my.verified_email;
|
||||
},
|
||||
|
||||
isUserOk(anchesenonammesso: boolean = false): boolean {
|
||||
const globalStore = useGlobalStore();
|
||||
|
||||
@@ -828,7 +833,7 @@ export const useUserStore = defineStore('UserStore', {
|
||||
this.isUsernameTelegOk()
|
||||
);
|
||||
} else {
|
||||
return this.my.verified_email!;
|
||||
return this.my.verified_email! || this.isTelegIdOk();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1028,7 +1033,7 @@ export const useUserStore = defineStore('UserStore', {
|
||||
mydata.password = String(hashedPassword);
|
||||
|
||||
return Api.SendReq('/updatepwd', 'POST', mydata, true, false, 1)
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
return { code: res.data.code, msg: res.data.msg };
|
||||
})
|
||||
.catch((error: Types.AxiosError) => {
|
||||
@@ -1057,7 +1062,7 @@ export const useUserStore = defineStore('UserStore', {
|
||||
};
|
||||
|
||||
return Api.SendReq('/setlang', 'PATCH', { data: mydata })
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
if (res) {
|
||||
return res.data.code === serv_constants.RIS_CODE_OK;
|
||||
}
|
||||
@@ -1076,8 +1081,8 @@ export const useUserStore = defineStore('UserStore', {
|
||||
this.setServerCode(tools.CALLING);
|
||||
|
||||
return Api.SendReq('/requestnewpwd', 'POST', usertosend)
|
||||
.then((res) => ({ code: res.data.code, msg: res.data.msg, link: res.data.link }))
|
||||
.catch((error) => {
|
||||
.then((res: any) => ({ code: res.data.code, msg: res.data.msg, link: res.data.link }))
|
||||
.catch((error: any) => {
|
||||
this.setErrorCatch(error);
|
||||
return this.getServerCode;
|
||||
});
|
||||
@@ -1094,12 +1099,12 @@ export const useUserStore = defineStore('UserStore', {
|
||||
paramquery.password = String(hashedPassword);
|
||||
|
||||
return Api.SendReq('/addNewSite', 'POST', paramquery)
|
||||
.then((res) => ({
|
||||
.then((res: any) => ({
|
||||
code: res.data.code,
|
||||
msg: res.data.msg,
|
||||
idapp: res.data.idapp,
|
||||
}))
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
this.setErrorCatch(error);
|
||||
return this.getServerCode;
|
||||
});
|
||||
@@ -1115,7 +1120,7 @@ export const useUserStore = defineStore('UserStore', {
|
||||
this.setServerCode(tools.CALLING);
|
||||
|
||||
return Api.SendReq('/vreg', 'POST', usertosend)
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
// console.log("RITORNO 2 ");
|
||||
// mutations.setServerCode(myres);
|
||||
if (res.data.code === serv_constants.RIS_CODE_EMAIL_VERIFIED) {
|
||||
@@ -1126,7 +1131,30 @@ export const useUserStore = defineStore('UserStore', {
|
||||
}
|
||||
return { code: res.data.code, msg: res.data.msg };
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
this.setErrorCatch(error);
|
||||
return { code: this.getServerCode, msg: error.getMsgError() };
|
||||
});
|
||||
},
|
||||
async reverif_email(paramquery: ILinkReg) {
|
||||
const usertosend = {
|
||||
idlink: paramquery.idlink,
|
||||
};
|
||||
console.log(usertosend);
|
||||
|
||||
this.setServerCode(tools.CALLING);
|
||||
|
||||
return Api.SendReq('/reverif_email', 'POST', usertosend)
|
||||
.then((res: any) => {
|
||||
if (res.data.code === serv_constants.RIS_CODE_EMAIL_VERIFIED) {
|
||||
console.log('VERIFICATO !!');
|
||||
tools.localStSetItem(toolsext.localStorage.verified_email, String(true));
|
||||
} else {
|
||||
console.log('Risultato di vreg: ', res.data.code);
|
||||
}
|
||||
return { code: res.data.code, msg: res.data.msg };
|
||||
})
|
||||
.catch((error: any) => {
|
||||
this.setErrorCatch(error);
|
||||
return { code: this.getServerCode, msg: error.getMsgError() };
|
||||
});
|
||||
@@ -1141,7 +1169,7 @@ export const useUserStore = defineStore('UserStore', {
|
||||
this.setServerCode(tools.CALLING);
|
||||
|
||||
return Api.SendReq('/ammetti', 'POST', usertosend)
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
// console.log("RITORNO 2 ");
|
||||
// mutations.setServerCode(myres);
|
||||
if (res.data.code === serv_constants.RIS_CODE_AMMESSO) {
|
||||
@@ -1151,7 +1179,7 @@ export const useUserStore = defineStore('UserStore', {
|
||||
}
|
||||
return { code: res.data.code, msg: res.data.msg };
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
this.setErrorCatch(error);
|
||||
return { code: this.getServerCode, msg: error.getMsgError() };
|
||||
});
|
||||
@@ -1170,7 +1198,7 @@ export const useUserStore = defineStore('UserStore', {
|
||||
this.setServerCode(tools.CALLING);
|
||||
|
||||
return Api.SendReq('/abcirc', 'POST', usertosend)
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
// console.log("RITORNO 2 ");
|
||||
// mutations.setServerCode(myres);
|
||||
if (res.data.code === serv_constants.RIS_CODE_AMMESSO) {
|
||||
@@ -1178,9 +1206,13 @@ export const useUserStore = defineStore('UserStore', {
|
||||
} else {
|
||||
console.log('Risultato di abilita: ', res.data.code);
|
||||
}
|
||||
return { code: res.data.code, msg: res.data.msg, circuitName: res.data.circuitName };
|
||||
return {
|
||||
code: res.data.code,
|
||||
msg: res.data.msg,
|
||||
circuitName: res.data.circuitName,
|
||||
};
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
this.setErrorCatch(error);
|
||||
return { code: this.getServerCode, msg: error.getMsgError() };
|
||||
});
|
||||
@@ -1188,7 +1220,7 @@ export const useUserStore = defineStore('UserStore', {
|
||||
|
||||
async unsubscribe(paramquery: any) {
|
||||
return Api.SendReq('/news/unsubscribe', 'POST', paramquery)
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
// console.log("RITORNO 2 ");
|
||||
// mutations.setServerCode(myres);
|
||||
if (res.data.code === serv_constants.RIS_UNSUBSCRIBED_OK) {
|
||||
@@ -1203,7 +1235,7 @@ export const useUserStore = defineStore('UserStore', {
|
||||
|
||||
async unsubscribe_news_on_fielduser(paramquery: any) {
|
||||
return Api.SendReq('/news/unsubscribe_user', 'POST', paramquery)
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
if (res.data.code === serv_constants.RIS_UNSUBSCRIBED_OK) {
|
||||
console.log('DESOTTOSCRITTO ALLA NEWSLETTER !!');
|
||||
} else {
|
||||
@@ -1216,16 +1248,16 @@ export const useUserStore = defineStore('UserStore', {
|
||||
|
||||
async importemail(paramquery: any) {
|
||||
return Api.SendReq('/news/import', 'POST', paramquery)
|
||||
.then((res) => res)
|
||||
.then((res: any) => res)
|
||||
.catch((error) => ({ numtot: 0, numadded: 0, numalreadyexisted: 0 }));
|
||||
},
|
||||
|
||||
async importExtraList(paramquery: any) {
|
||||
return Api.SendReq('/users/import_extralist', 'POST', paramquery)
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
return res;
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
return { numtot: 0, numadded: 0, numalreadyexisted: 0 };
|
||||
});
|
||||
},
|
||||
@@ -1244,22 +1276,22 @@ export const useUserStore = defineStore('UserStore', {
|
||||
null,
|
||||
{ timeout: 300000 }
|
||||
)
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
return res.data;
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
return false;
|
||||
});
|
||||
},
|
||||
|
||||
async execDbOpUser(paramquery: any) {
|
||||
return Api.SendReq('/users/dbopuser', 'POST', paramquery)
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
tools.updateMyData(res.data.ris);
|
||||
|
||||
return res.data;
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
return false;
|
||||
});
|
||||
},
|
||||
@@ -1327,6 +1359,31 @@ export const useUserStore = defineStore('UserStore', {
|
||||
}
|
||||
return await this.execDbOpUser({ mydata });
|
||||
},
|
||||
async setVerifiedEmail(val: boolean, userId?: string) {
|
||||
const mydata = {
|
||||
_id: userId ? userId : this.my._id,
|
||||
dbop: 'verifiedemail',
|
||||
value: val,
|
||||
};
|
||||
|
||||
if (userId) {
|
||||
} else {
|
||||
if (this.my.verified_email !== val) {
|
||||
this.my.verified_email = val;
|
||||
}
|
||||
}
|
||||
return await this.execDbOpUser({ mydata });
|
||||
},
|
||||
async resendVerificationEmail() {
|
||||
const mydata = {
|
||||
_id: this.my._id,
|
||||
dbop: 'resendVerificationEmail',
|
||||
value: this.my.email,
|
||||
};
|
||||
|
||||
return await this.execDbOpUser({ mydata });
|
||||
},
|
||||
|
||||
async setPwdComeQuellaDellAdmin(val: boolean, userId?: string) {
|
||||
const mydata = {
|
||||
_id: userId,
|
||||
@@ -1388,10 +1445,11 @@ export const useUserStore = defineStore('UserStore', {
|
||||
|
||||
async getProvincesForMap() {
|
||||
return Api.SendReq('/users/infomap', 'POST', null)
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
return res ? res.data.ris : [];
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((e: any) => {
|
||||
console.error('Err getProvincesForMap:', e);
|
||||
return null;
|
||||
});
|
||||
},
|
||||
@@ -1417,29 +1475,29 @@ export const useUserStore = defineStore('UserStore', {
|
||||
|
||||
return res.data;
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
return null;
|
||||
});
|
||||
},
|
||||
|
||||
async reportload(paramquery: any) {
|
||||
return Api.SendReq('/report/load', 'POST', paramquery)
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
// console.log('res', res)
|
||||
return res.data;
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
return null;
|
||||
});
|
||||
},
|
||||
|
||||
async newsletter_setactivate(paramquery: any) {
|
||||
return Api.SendReq('/news/setactivate', 'POST', paramquery)
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
// console.log('res', res)
|
||||
return res.data;
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
return null;
|
||||
});
|
||||
},
|
||||
@@ -1599,7 +1657,7 @@ export const useUserStore = defineStore('UserStore', {
|
||||
this.setServerCode(tools.CALLING);
|
||||
|
||||
return Api.SendReq('/users', 'POST', authData)
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
const newuser = res.data;
|
||||
|
||||
// console.log('newuser', newuser)
|
||||
@@ -1652,7 +1710,7 @@ export const useUserStore = defineStore('UserStore', {
|
||||
return { code: toolsext.ERR_GENERICO, msg: '' };
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
console.log('Err', error);
|
||||
this.setErrorCatch(error);
|
||||
return { code: this.getServerCode, msg: this.getMsg };
|
||||
@@ -1723,14 +1781,14 @@ export const useUserStore = defineStore('UserStore', {
|
||||
authData.userId = this.my._id;
|
||||
|
||||
return Api.SendReq('/iscritti_conacreis', 'POST', authData)
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
if (res.status === 200) {
|
||||
return { code: serv_constants.RIS_ISCRIZIONE_OK, msg: '' };
|
||||
} else {
|
||||
return { code: toolsext.ERR_GENERICO, msg: '' };
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
console.log('Err', error);
|
||||
this.setErrorCatch(error);
|
||||
return { code: this.getServerCode, msg: this.getMsg };
|
||||
@@ -1771,7 +1829,7 @@ export const useUserStore = defineStore('UserStore', {
|
||||
// console.log('executing login...')
|
||||
|
||||
return await Api.SendReq('/users/login', 'POST', usertosend, true, false, 0)
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
myres = res;
|
||||
|
||||
if (myres.status !== 200) {
|
||||
@@ -1779,7 +1837,7 @@ export const useUserStore = defineStore('UserStore', {
|
||||
}
|
||||
return myres;
|
||||
})
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
console.log(' Login res', res);
|
||||
|
||||
if (res.success) {
|
||||
@@ -1808,7 +1866,7 @@ export const useUserStore = defineStore('UserStore', {
|
||||
return code;
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
console.log('error', error);
|
||||
this.setErrorCatch(error);
|
||||
return this.getServerCode;
|
||||
@@ -1848,11 +1906,11 @@ export const useUserStore = defineStore('UserStore', {
|
||||
this.clearAuthData();
|
||||
|
||||
return await Api.SendReq('/users/me/token', 'DELETE', null)
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
console.log(res);
|
||||
})
|
||||
.then(() => this.clearAuthData())
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
this.setErrorCatch(error);
|
||||
return this.getServerCode;
|
||||
});
|
||||
@@ -1977,14 +2035,14 @@ export const useUserStore = defineStore('UserStore', {
|
||||
};
|
||||
|
||||
return await Api.SendReq('/users/profile', 'POST', data)
|
||||
.then((ris) => {
|
||||
.then((ris: any) => {
|
||||
if (this.my.username === ris.data.user.username) {
|
||||
// this.updateDataFr(ris.data.friends)
|
||||
}
|
||||
|
||||
return ris.data.user;
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
return {};
|
||||
});
|
||||
},
|
||||
@@ -2002,14 +2060,14 @@ export const useUserStore = defineStore('UserStore', {
|
||||
};
|
||||
|
||||
return await Api.SendReq('/users/activities', 'POST', data)
|
||||
.then((ris) => {
|
||||
.then((ris: any) => {
|
||||
if (this.my.username === ris.data.user.username) {
|
||||
// this.updateDataFr(ris.data.friends)
|
||||
}
|
||||
|
||||
return ris.data.user;
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
return {};
|
||||
});
|
||||
},
|
||||
@@ -2020,10 +2078,10 @@ export const useUserStore = defineStore('UserStore', {
|
||||
};
|
||||
|
||||
return Api.SendReq('/users/notifs', 'POST', data)
|
||||
.then((ris) => {
|
||||
.then((ris: any) => {
|
||||
return ris.data;
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
return {};
|
||||
});
|
||||
},
|
||||
@@ -2034,11 +2092,11 @@ export const useUserStore = defineStore('UserStore', {
|
||||
};
|
||||
|
||||
return Api.SendReq('/users/panel', 'POST', data)
|
||||
.then((ris) => {
|
||||
.then((ris: any) => {
|
||||
console.log('out:', ris);
|
||||
return ris.data;
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
return {};
|
||||
});
|
||||
},
|
||||
@@ -2050,11 +2108,11 @@ export const useUserStore = defineStore('UserStore', {
|
||||
};
|
||||
|
||||
return Api.SendReq('/users/receiveris', 'POST', data)
|
||||
.then((ris) => {
|
||||
.then((ris: any) => {
|
||||
console.log('out:', ris);
|
||||
return ris.data;
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
return {};
|
||||
});
|
||||
},
|
||||
@@ -2065,11 +2123,11 @@ export const useUserStore = defineStore('UserStore', {
|
||||
};
|
||||
|
||||
return Api.SendReq('/users/listlinkreg', 'POST', data)
|
||||
.then((ris) => {
|
||||
.then((ris: any) => {
|
||||
console.log('out:', ris);
|
||||
return ris.data;
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
return {};
|
||||
});
|
||||
},
|
||||
@@ -2081,10 +2139,10 @@ export const useUserStore = defineStore('UserStore', {
|
||||
};
|
||||
|
||||
return Api.SendReq('/mygroup/load', 'POST', data)
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
return { data: res.data, status: res.status };
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
return { data: null, status: error.status };
|
||||
});
|
||||
},
|
||||
@@ -2098,7 +2156,7 @@ export const useUserStore = defineStore('UserStore', {
|
||||
};
|
||||
|
||||
return Api.SendReq('/circuit/load', 'POST', data)
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
this.my.profile.last_circuitpath = path;
|
||||
if (res && res.data.arrrecnotif) {
|
||||
notifStore.updateArrRecNotifFromServer(res.data.arrrecnotif);
|
||||
@@ -2111,7 +2169,7 @@ export const useUserStore = defineStore('UserStore', {
|
||||
}
|
||||
return { data: res.data, status: res.status };
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
return { data: null, status: error.status };
|
||||
});
|
||||
},
|
||||
@@ -2122,11 +2180,11 @@ export const useUserStore = defineStore('UserStore', {
|
||||
};
|
||||
|
||||
return Api.SendReq('/myskills/page', 'POST', data)
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
console.log('res.data', res);
|
||||
return res.data;
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
return {};
|
||||
});
|
||||
},
|
||||
@@ -2139,10 +2197,10 @@ export const useUserStore = defineStore('UserStore', {
|
||||
};
|
||||
|
||||
return Api.SendReq('/mygen/page', 'POST', data)
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
return res.data;
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
console.error('err', error);
|
||||
return null;
|
||||
});
|
||||
@@ -2163,41 +2221,41 @@ export const useUserStore = defineStore('UserStore', {
|
||||
|
||||
async loadFriends() {
|
||||
return Api.SendReq('/users/friends', 'POST', null)
|
||||
.then((ris) => {
|
||||
.then((ris: any) => {
|
||||
this.updateDataFr(ris.data);
|
||||
return ris.data;
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
return {};
|
||||
});
|
||||
},
|
||||
|
||||
async loadGroups(username: string) {
|
||||
return Api.SendReq('/users/groups', 'POST', null)
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
return res.data;
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
return {};
|
||||
});
|
||||
},
|
||||
|
||||
async loadCircuits(nummovTodownload: number) {
|
||||
return Api.SendReq('/users/circuits', 'POST', { nummovTodownload })
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
return res.data;
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
return {};
|
||||
});
|
||||
},
|
||||
|
||||
async loadAllAccounts() {
|
||||
return Api.SendReq('/account/loadall', 'POST', null)
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
return res.data;
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
return {};
|
||||
});
|
||||
},
|
||||
@@ -2216,11 +2274,11 @@ export const useUserStore = defineStore('UserStore', {
|
||||
cmd,
|
||||
value,
|
||||
})
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
this.updateTables = true;
|
||||
return res.data;
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
tools.showNegativeNotif($q, t('db.recfailed'));
|
||||
return {};
|
||||
});
|
||||
@@ -2240,11 +2298,11 @@ export const useUserStore = defineStore('UserStore', {
|
||||
cmd,
|
||||
value,
|
||||
})
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
this.updateTables = true;
|
||||
return res.data;
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
tools.showNegativeNotif($q, t('db.recfailed'));
|
||||
return {};
|
||||
});
|
||||
@@ -2264,14 +2322,14 @@ export const useUserStore = defineStore('UserStore', {
|
||||
cmd,
|
||||
value,
|
||||
})
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
this.updateTables = true;
|
||||
// const notifStore = useNotifStore()
|
||||
|
||||
// notifStore.updateNotification = true
|
||||
return res.data;
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
tools.showNegativeNotif($q, t('db.recfailed'));
|
||||
return {};
|
||||
});
|
||||
@@ -2294,7 +2352,7 @@ export const useUserStore = defineStore('UserStore', {
|
||||
false,
|
||||
0
|
||||
)
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
this.updateTables = true;
|
||||
const notifStore = useNotifStore();
|
||||
if (res.data.recnotif) {
|
||||
@@ -2308,7 +2366,7 @@ export const useUserStore = defineStore('UserStore', {
|
||||
}
|
||||
return res.data;
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
tools.showNegativeNotif($q, t('db.recfailed'));
|
||||
return {};
|
||||
});
|
||||
@@ -2323,7 +2381,7 @@ export const useUserStore = defineStore('UserStore', {
|
||||
const globalStore = useGlobalStore();
|
||||
|
||||
return Api.SendReq('/users/mgt', 'POST', { mydata })
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
console.log('res', res);
|
||||
|
||||
let msgok =
|
||||
@@ -2354,7 +2412,7 @@ export const useUserStore = defineStore('UserStore', {
|
||||
}
|
||||
return false;
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
tools.showNegativeNotif($q, t('cal.err_sendmsg'));
|
||||
return {};
|
||||
});
|
||||
@@ -2399,7 +2457,7 @@ export const useUserStore = defineStore('UserStore', {
|
||||
}
|
||||
$q.loading.hide();
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
$q.loading.hide();
|
||||
tools.showNegativeNotif($q, t('db.recfailed'));
|
||||
return {};
|
||||
@@ -2421,7 +2479,7 @@ export const useUserStore = defineStore('UserStore', {
|
||||
tab,
|
||||
value,
|
||||
})
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
if (res && res.data.state === 1) {
|
||||
if (myrec) {
|
||||
if (!myrec.numfav) {
|
||||
@@ -2451,7 +2509,7 @@ export const useUserStore = defineStore('UserStore', {
|
||||
tools.showNegativeNotif($q, t('cmd.favorite_unset'));
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
tools.showNegativeNotif($q, t('db.recfailed'));
|
||||
return {};
|
||||
});
|
||||
@@ -2472,7 +2530,7 @@ export const useUserStore = defineStore('UserStore', {
|
||||
tab,
|
||||
value,
|
||||
})
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
if (res && res.data.state === 1) {
|
||||
if (!myrec.numattend) {
|
||||
myrec.numattend = 0;
|
||||
@@ -2498,7 +2556,7 @@ export const useUserStore = defineStore('UserStore', {
|
||||
tools.showNegativeNotif($q, t('cmd.attend_unset'));
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
tools.showNegativeNotif($q, t('db.recfailed'));
|
||||
return {};
|
||||
});
|
||||
@@ -2546,7 +2604,7 @@ export const useUserStore = defineStore('UserStore', {
|
||||
tab,
|
||||
value,
|
||||
})
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
if (res && res.data.state === 1) {
|
||||
if (!myrec.numbook) {
|
||||
myrec.numbook = 0;
|
||||
@@ -2572,7 +2630,7 @@ export const useUserStore = defineStore('UserStore', {
|
||||
tools.showNegativeNotif($q, t('cmd.bookmark_unset'));
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
console.error('error', error);
|
||||
tools.showNegativeNotif($q, t('db.recfailed'));
|
||||
return {};
|
||||
@@ -2624,7 +2682,7 @@ export const useUserStore = defineStore('UserStore', {
|
||||
tab,
|
||||
value,
|
||||
})
|
||||
.then((res) => {
|
||||
.then((res: any) => {
|
||||
if (res && res.data.state === 1) {
|
||||
if (value) {
|
||||
if (!myrec) {
|
||||
@@ -2651,7 +2709,7 @@ export const useUserStore = defineStore('UserStore', {
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch((error: any) => {
|
||||
console.error('error', error);
|
||||
return null;
|
||||
});
|
||||
@@ -2671,7 +2729,7 @@ export const useUserStore = defineStore('UserStore', {
|
||||
},
|
||||
|
||||
async eseguiFunzSulServer(mydata: {}) {
|
||||
return await this.execDbOp({ mydata }).then((ris) => {
|
||||
return await this.execDbOp({ mydata }).then((ris: any) => {
|
||||
return ris?.data;
|
||||
});
|
||||
},
|
||||
@@ -2739,5 +2797,25 @@ export const useUserStore = defineStore('UserStore', {
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
getLastRecentUserTransactions() {
|
||||
const arr = [];
|
||||
for (const rec of this.my.profile.last_my_transactions) {
|
||||
let myuser = null;
|
||||
|
||||
if (rec.userfrom && rec.userfrom.username !== this.my.username) {
|
||||
myuser = rec.userfrom;
|
||||
} else if (rec.userto && rec.userto.username !== this.my.username) {
|
||||
myuser = rec.userto;
|
||||
}
|
||||
|
||||
if (myuser) {
|
||||
arr.push(myuser);
|
||||
}
|
||||
}
|
||||
|
||||
const uniques = arr.filter((v, i, a) => a.findIndex(t => (t.username === v.username)) === i);
|
||||
return uniques;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
6
src/views/login/reverif_email/reverif_email.scss
Executable file
6
src/views/login/reverif_email/reverif_email.scss
Executable file
@@ -0,0 +1,6 @@
|
||||
.mypanel {
|
||||
padding: 10px;
|
||||
margin: 10px;
|
||||
|
||||
}
|
||||
|
||||
77
src/views/login/reverif_email/reverif_email.ts
Executable file
77
src/views/login/reverif_email/reverif_email.ts
Executable file
@@ -0,0 +1,77 @@
|
||||
import { defineComponent, ref } from 'vue'
|
||||
|
||||
import { serv_constants } from '../../../store/Modules/serv_constants'
|
||||
|
||||
import type { ILinkReg } from '../../../model/other';
|
||||
import { ICallResult } from '../../../model/other'
|
||||
import { CSigninNoreg } from '../../../components/CSigninNoreg'
|
||||
import { useQuasar } from 'quasar'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useGlobalStore } from '@store/globalStore'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useUserStore } from '@store/UserStore'
|
||||
import { tools } from '@tools'
|
||||
|
||||
|
||||
export default defineComponent({
|
||||
name: 'reverif_email',
|
||||
components: { CSigninNoreg },
|
||||
|
||||
setup(props) {
|
||||
const $q = useQuasar()
|
||||
const route = useRoute()
|
||||
const $router = useRouter()
|
||||
const { t } = useI18n()
|
||||
const globalStore = useGlobalStore()
|
||||
const userStore = useUserStore()
|
||||
|
||||
const risultato = ref('---')
|
||||
const riscode = ref(0)
|
||||
|
||||
function myrisultato() {
|
||||
return risultato
|
||||
}
|
||||
|
||||
function giaverificato() {
|
||||
return riscode.value !== serv_constants.RIS_CODE_EMAIL_VERIFIED
|
||||
}
|
||||
|
||||
function verificatook() {
|
||||
return riscode.value === serv_constants.RIS_CODE_EMAIL_VERIFIED
|
||||
}
|
||||
|
||||
function load() {
|
||||
console.log('load REFERIFY')
|
||||
let param: ILinkReg = { idlink: '' }
|
||||
if (route.query.idlink)
|
||||
param = { idlink: route.query.idlink.toString() }
|
||||
|
||||
return userStore.reverif_email(param)
|
||||
.then((ris: any) => {
|
||||
riscode.value = ris.code
|
||||
risultato.value = ris.msg
|
||||
console.log('RIS = ', ris)
|
||||
|
||||
if (verificatook()) {
|
||||
setTimeout(() => {
|
||||
$router.replace('/signin')
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
}).catch((err: any) => {
|
||||
console.log('ERR = ' + err)
|
||||
})
|
||||
}
|
||||
|
||||
load()
|
||||
|
||||
return {
|
||||
tools,
|
||||
verificatook,
|
||||
giaverificato,
|
||||
myrisultato,
|
||||
t,
|
||||
}
|
||||
},
|
||||
|
||||
})
|
||||
58
src/views/login/reverif_email/reverif_email.vue
Executable file
58
src/views/login/reverif_email/reverif_email.vue
Executable file
@@ -0,0 +1,58 @@
|
||||
<template>
|
||||
<q-page
|
||||
padding
|
||||
class="vreg"
|
||||
>
|
||||
<div class="q-pa-md q-gutter-sm">
|
||||
<q-banner
|
||||
rounded
|
||||
class="bg-primary text-white"
|
||||
color="primary q-title"
|
||||
style="text-align: center"
|
||||
>
|
||||
<span class="mybanner">{{ t('reg.title_verif_email') }}</span>
|
||||
</q-banner>
|
||||
<br />
|
||||
|
||||
<transition
|
||||
enter-active-class="animated fadeIn"
|
||||
leave-active-class="animated fadeOut"
|
||||
appear
|
||||
>
|
||||
<div>
|
||||
<q-banner
|
||||
rounded
|
||||
class="bg-warning text-black"
|
||||
style="text-align: center"
|
||||
v-if="giaverificato()"
|
||||
>
|
||||
<span class="mybanner">{{ myrisultato() }}</span>
|
||||
</q-banner>
|
||||
<q-banner
|
||||
class="bg-positive text-white"
|
||||
style="text-align: center"
|
||||
rounded
|
||||
v-if="verificatook()"
|
||||
>
|
||||
<span class="mybanner">{{ myrisultato() }}</span>
|
||||
</q-banner>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<div class="text-center q-mt-md">
|
||||
<q-btn
|
||||
rounded
|
||||
size="lg"
|
||||
color="primary"
|
||||
@click="tools.openrighttoolbar()"
|
||||
>{{ t('login.enter') }}
|
||||
</q-btn>
|
||||
</div>
|
||||
</div>
|
||||
</q-page>
|
||||
</template>
|
||||
|
||||
<script lang="ts" src="./reverif_email.ts"></script>
|
||||
<style lang="scss" scoped>
|
||||
@import './reverif_email.scss';
|
||||
</style>
|
||||
1
src/views/toolsAI/ollama/index.ts
Executable file
1
src/views/toolsAI/ollama/index.ts
Executable file
@@ -0,0 +1 @@
|
||||
export {default as ollama} from './ollama.vue'
|
||||
25
src/views/toolsAI/ollama/ollama.scss
Executable file
25
src/views/toolsAI/ollama/ollama.scss
Executable file
@@ -0,0 +1,25 @@
|
||||
$heightBtn: 100%;
|
||||
|
||||
.card .product-image {
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.container{
|
||||
margin-top: 4px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.prod_trov{
|
||||
font-style: italic;
|
||||
color: blue;
|
||||
}
|
||||
|
||||
.fixed-group {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background-color: #ffffff; /* Customize the background color as needed */
|
||||
z-index: 1000; /* Adjust the z-index to ensure it's above other elements */
|
||||
transition: all 1s ease;
|
||||
}
|
||||
162
src/views/toolsAI/ollama/ollama.ts
Executable file
162
src/views/toolsAI/ollama/ollama.ts
Executable file
@@ -0,0 +1,162 @@
|
||||
import { defineComponent, onMounted, ref, watch, computed, onBeforeUnmount } from 'vue'
|
||||
import { tools } from '@tools'
|
||||
import { useUserStore } from '@store/UserStore'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useGlobalStore } from '@store/globalStore'
|
||||
import { useProducts } from '@store/Products'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { toolsext } from '@store/Modules/toolsext'
|
||||
import { useQuasar } from 'quasar'
|
||||
import { costanti } from '@costanti'
|
||||
|
||||
import { shared_consts } from '@/common/shared_vuejs'
|
||||
import OllamaChat from '@/components/OllamaChat/OllamaChat.vue'
|
||||
import type { IProduct } from '@/model'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ollama',
|
||||
components: { OllamaChat },
|
||||
props: {},
|
||||
setup() {
|
||||
const userStore = useUserStore()
|
||||
const globalStore = useGlobalStore()
|
||||
const productStore = useProducts()
|
||||
const router = useRouter()
|
||||
const $q = useQuasar()
|
||||
const { t } = useI18n()
|
||||
|
||||
const search = ref('')
|
||||
|
||||
const cosa = ref(0)
|
||||
const cat = ref('')
|
||||
const loadpage = ref(false)
|
||||
const refreshpage = ref(false)
|
||||
|
||||
const arrProducts = ref<any>([])
|
||||
|
||||
// Create a ref for the component to fix
|
||||
const componentToFixRef = ref(<any>null);
|
||||
|
||||
const isFixed = ref(false);
|
||||
|
||||
// Register the scroll event on component mount
|
||||
const handleScroll = () => {
|
||||
const scrollTop = window.scrollY || document.documentElement.scrollTop;
|
||||
|
||||
// Set a threshold value based on how much scroll is needed to fix the components
|
||||
const threshold = 300;
|
||||
|
||||
// Update the isFixed ref based on the scroll position
|
||||
isFixed.value = scrollTop > threshold;
|
||||
};
|
||||
|
||||
watch(() => cat.value, (newval, oldval) => {
|
||||
calcArrProducts()
|
||||
})
|
||||
watch(() => search.value, (newval, oldval) => {
|
||||
calcArrProducts()
|
||||
if (tools.scrollTop() > 300) {
|
||||
tools.scrollToTopValue(300)
|
||||
}
|
||||
})
|
||||
|
||||
watch(() => cosa.value, (newval, oldval) => {
|
||||
tools.setCookie(tools.COOK_COSA_PRODOTTI, cosa.value.toString())
|
||||
if (cosa.value !== shared_consts.PROD.TUTTI)
|
||||
cat.value = ''
|
||||
calcArrProducts()
|
||||
})
|
||||
|
||||
function calcArrProducts() {
|
||||
refreshpage.value = true
|
||||
let arrprod = productStore.getProducts(cosa.value)
|
||||
const catstr = cat.value;
|
||||
const lowerSearchText = search.value.toLowerCase().trim();
|
||||
if ((!lowerSearchText || (lowerSearchText && lowerSearchText.length < 2)) && !catstr) {
|
||||
|
||||
} else {
|
||||
|
||||
arrprod = arrprod.filter((product: IProduct) => {
|
||||
const lowerName = product.productInfo.name!.toLowerCase();
|
||||
const hasCategoria = !catstr || (catstr && product.productInfo.idCatProds?.includes(catstr));
|
||||
|
||||
// Use a regular expression to match whole words
|
||||
const codeMatch = new RegExp(`\\b${lowerSearchText}\\b`, 'i');
|
||||
const nameMatch = new RegExp(`\\b${lowerSearchText}`, 'i');
|
||||
|
||||
// Check if any word in lowerName starts with lowerSearchText
|
||||
const anyWordStartsWithSearch = lowerName.split(/\s+/).some(word => nameMatch.test(word));
|
||||
|
||||
return (codeMatch.test(product.productInfo.code) || anyWordStartsWithSearch) && hasCategoria;
|
||||
});
|
||||
}
|
||||
|
||||
arrProducts.value = arrprod
|
||||
refreshpage.value = false
|
||||
}
|
||||
|
||||
/*function getProducts() {
|
||||
let arrprod = productStore.getProducts(cosa.value)
|
||||
if (!search.value) {
|
||||
return arrprod
|
||||
}
|
||||
|
||||
let lowerSearchText = search.value.toLowerCase();
|
||||
let catstr = cat.value;
|
||||
|
||||
return arrprod.filter((product: IProduct) => {
|
||||
let lowerName = product.productInfo.name!.toLowerCase();
|
||||
const hasCategoria = !catstr || (catstr && product.productInfo.idCatProds?.includes(catstr));
|
||||
return (product.productInfo.code!.includes(search.value) || lowerName.includes(lowerSearchText)) && hasCategoria
|
||||
});
|
||||
}*/
|
||||
|
||||
async function mounted() {
|
||||
loadpage.value = false
|
||||
await productStore.loadProducts(true)
|
||||
cosa.value = tools.getCookie(tools.COOK_COSA_PRODOTTI, shared_consts.PROD.TUTTI, true)
|
||||
// Inizializza
|
||||
loadpage.value = true
|
||||
window.addEventListener('scroll', handleScroll);
|
||||
|
||||
calcArrProducts()
|
||||
}
|
||||
|
||||
// Remove the event listener on component destroy
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('scroll', handleScroll);
|
||||
});
|
||||
|
||||
function getCatProds() {
|
||||
const arrcat = productStore.getCatProds(cosa.value)
|
||||
const riscat: any = [{ label: 'Tutti', value: '', icon: undefined, color: undefined }]
|
||||
for (const rec of arrcat) {
|
||||
riscat.push({ label: rec.name, value: rec._id, icon: rec.icon, color: rec.color })
|
||||
}
|
||||
|
||||
return riscat
|
||||
}
|
||||
|
||||
onMounted(mounted)
|
||||
|
||||
return {
|
||||
userStore,
|
||||
costanti,
|
||||
tools,
|
||||
toolsext,
|
||||
search,
|
||||
cosa,
|
||||
shared_consts,
|
||||
getCatProds,
|
||||
cat,
|
||||
productStore,
|
||||
t,
|
||||
loadpage,
|
||||
refreshpage,
|
||||
componentToFixRef,
|
||||
isFixed,
|
||||
arrProducts,
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
18
src/views/toolsAI/ollama/ollama.vue
Executable file
18
src/views/toolsAI/ollama/ollama.vue
Executable file
@@ -0,0 +1,18 @@
|
||||
<template>
|
||||
<q-page class="column">
|
||||
<div class="text-center">
|
||||
<q-spinner v-if="!loadpage" color="primary" size="3em" :thickness="2" />
|
||||
</div>
|
||||
<div v-if="loadpage && (tools.isUserOk() && tools.isLogged())">
|
||||
<OllamaChat :baseUrl="tools.getServerHost()" height="100%"
|
||||
></OllamaChat>
|
||||
</div>
|
||||
</q-page>
|
||||
</template>
|
||||
|
||||
<script lang="ts" src="./ollama.ts">
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import './ollama.scss';
|
||||
</style>
|
||||
@@ -1,249 +1,295 @@
|
||||
import { CMyFieldDb } from '@/components/CMyFieldDb'
|
||||
import { CMyFieldRec } from '@/components/CMyFieldRec'
|
||||
import { CTitleBanner } from '@/components/CTitleBanner'
|
||||
import { CProfile } from '@/components/CProfile'
|
||||
import { CLabel } from '@/components/CLabel'
|
||||
import { CCopyBtn } from '@/components/CCopyBtn'
|
||||
import { CSkill } from '@/components/CSkill'
|
||||
import { CDateTime } from '@/components/CDateTime'
|
||||
import { CMyGroup } from '@/components/CMyGroup'
|
||||
import { CUserNote } from '@/components/CUserNote'
|
||||
import { CMyCircuit } from '@/components/CMyCircuit'
|
||||
import { CNotifAtTop } from '@/components/CNotifAtTop'
|
||||
import { CMyActivities } from '@/components/CMyActivities'
|
||||
import { CSendCoins } from '@/components/CSendCoins'
|
||||
import { CContactUser } from '@/components/CContactUser'
|
||||
import { CTimeAgo } from '@/components/CTimeAgo'
|
||||
import { CMyUser } from '@/components/CMyUser'
|
||||
import { CUserNonVerif } from '@/components/CUserNonVerif'
|
||||
import { CCheckIfIsLogged } from '@/components/CCheckIfIsLogged'
|
||||
import CPageUserNotFound from '@/components/CPageUserNotFound/CPageUserNotFound.vue'
|
||||
import { tools } from '@tools'
|
||||
import { computed, defineComponent, onMounted, ref, watch } from 'vue'
|
||||
import { useUserStore } from '@store/UserStore'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useGlobalStore } from '@store/globalStore'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { toolsext } from '@store/Modules/toolsext'
|
||||
import { useQuasar } from 'quasar'
|
||||
import { costanti } from '@costanti'
|
||||
import { CMyFieldDb } from '@/components/CMyFieldDb';
|
||||
import { CMyFieldRec } from '@/components/CMyFieldRec';
|
||||
import { CTitleBanner } from '@/components/CTitleBanner';
|
||||
import { CProfile } from '@/components/CProfile';
|
||||
import { CLabel } from '@/components/CLabel';
|
||||
import { CCopyBtn } from '@/components/CCopyBtn';
|
||||
import { CSkill } from '@/components/CSkill';
|
||||
import { CDateTime } from '@/components/CDateTime';
|
||||
import { CMyGroup } from '@/components/CMyGroup';
|
||||
import { CUserNote } from '@/components/CUserNote';
|
||||
import { CMyCircuit } from '@/components/CMyCircuit';
|
||||
import { CNotifAtTop } from '@/components/CNotifAtTop';
|
||||
import { CMyActivities } from '@/components/CMyActivities';
|
||||
import { CSendCoins } from '@/components/CSendCoins';
|
||||
import { CContactUser } from '@/components/CContactUser';
|
||||
import { CTimeAgo } from '@/components/CTimeAgo';
|
||||
import { CMyUser } from '@/components/CMyUser';
|
||||
import { CUserNonVerif } from '@/components/CUserNonVerif';
|
||||
import { CCheckIfIsLogged } from '@/components/CCheckIfIsLogged';
|
||||
import CPageUserNotFound from '@/components/CPageUserNotFound/CPageUserNotFound.vue';
|
||||
import { tools } from '@tools';
|
||||
import { computed, defineComponent, onMounted, ref, watch } from 'vue';
|
||||
import { useUserStore } from '@store/UserStore';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useGlobalStore } from '@store/globalStore';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { toolsext } from '@store/Modules/toolsext';
|
||||
import { useQuasar } from 'quasar';
|
||||
import { costanti } from '@costanti';
|
||||
import type { IMyCircuit, IMyGroup, IUserFields } from 'model';
|
||||
import { ICircuit, IFriends } from 'model'
|
||||
import { shared_consts } from '@/common/shared_vuejs'
|
||||
import { static_data } from '@/db/static_data'
|
||||
import { fieldsTable } from '@store/Modules/fieldsTable'
|
||||
import { useNotifStore } from '@store/NotifStore'
|
||||
import MixinUsers from '@/mixins/mixin-users'
|
||||
|
||||
import { ICircuit, IFriends } from 'model';
|
||||
import { shared_consts } from '@/common/shared_vuejs';
|
||||
import { static_data } from '@/db/static_data';
|
||||
import { fieldsTable } from '@store/Modules/fieldsTable';
|
||||
import { useNotifStore } from '@store/NotifStore';
|
||||
import MixinUsers from '@/mixins/mixin-users';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'myprofile',
|
||||
components: {
|
||||
CProfile, CTitleBanner, CMyFieldDb, CSkill, CDateTime, CCopyBtn, CUserNonVerif, CMyFieldRec, CMyUser,
|
||||
CMyGroup, CLabel, CMyCircuit, CSendCoins, CNotifAtTop,
|
||||
CCheckIfIsLogged, CTimeAgo, CContactUser, CMyActivities, CUserNote, CPageUserNotFound,
|
||||
CProfile,
|
||||
CTitleBanner,
|
||||
CMyFieldDb,
|
||||
CSkill,
|
||||
CDateTime,
|
||||
CCopyBtn,
|
||||
CUserNonVerif,
|
||||
CMyFieldRec,
|
||||
CMyUser,
|
||||
CMyGroup,
|
||||
CLabel,
|
||||
CMyCircuit,
|
||||
CSendCoins,
|
||||
CNotifAtTop,
|
||||
CCheckIfIsLogged,
|
||||
CTimeAgo,
|
||||
CContactUser,
|
||||
CMyActivities,
|
||||
CUserNote,
|
||||
CPageUserNotFound,
|
||||
},
|
||||
props: {},
|
||||
setup() {
|
||||
const userStore = useUserStore()
|
||||
const globalStore = useGlobalStore()
|
||||
const $route = useRoute()
|
||||
const $q = useQuasar()
|
||||
const { t } = useI18n()
|
||||
const userStore = useUserStore();
|
||||
const globalStore = useGlobalStore();
|
||||
const $route = useRoute();
|
||||
const $q = useQuasar();
|
||||
const { t } = useI18n();
|
||||
|
||||
const site = ref(globalStore.site)
|
||||
const site = ref(globalStore.site);
|
||||
|
||||
const { getRefLink } = MixinUsers()
|
||||
const { getRefLink } = MixinUsers();
|
||||
|
||||
const animation = ref('fade')
|
||||
const spinner_visible = ref(false)
|
||||
const shownote = ref(false)
|
||||
const usersList = ref({ show: false, title: '', list: [] })
|
||||
const animation = ref('fade');
|
||||
const shownote = ref(false);
|
||||
const usersList = ref({ show: false, title: '', list: [] });
|
||||
|
||||
const username = computed(() => $route.params.username ? $route.params.username.toString() : userStore.my.username)
|
||||
const idnotif = computed(() => $route.query.idnotif ? $route.query.idnotif.toString() : '')
|
||||
const isDebugOn = computed(() => tools.isDebugOn())
|
||||
const username = computed(() =>
|
||||
$route.params.username ? $route.params.username.toString() : userStore.my.username
|
||||
);
|
||||
const idnotif = computed(() =>
|
||||
$route.query.idnotif ? $route.query.idnotif.toString() : ''
|
||||
);
|
||||
const isDebugOn = computed(() => tools.isDebugOn());
|
||||
|
||||
const sendRIS = computed(() => $route.query.sr ? $route.query.sr : '')
|
||||
const causalDest = computed(() => $route.query.cd ? $route.query.cd : '')
|
||||
const sendRIS = computed(() => ($route.query.sr ? $route.query.sr : ''));
|
||||
const causalDest = computed(() => ($route.query.cd ? $route.query.cd : ''));
|
||||
|
||||
const $router = useRouter()
|
||||
const filtroutente = ref(<any[]>[])
|
||||
const showPic = ref(false)
|
||||
const caricato = ref(false)
|
||||
const showsendCoinTo = ref(false)
|
||||
const showinghand = ref(false)
|
||||
const $router = useRouter();
|
||||
const filtroutente = ref(<any[]>[]);
|
||||
const showPic = ref(false);
|
||||
const caricato = ref(false);
|
||||
const showsendCoinTo = ref(false);
|
||||
const showinghand = ref(false);
|
||||
|
||||
const actualcard = ref('mygoods')
|
||||
const mostranota = ref(false)
|
||||
const actualcard = ref('mygoods');
|
||||
const mostranota = ref(false);
|
||||
|
||||
const notifStore = useNotifStore()
|
||||
const notifStore = useNotifStore();
|
||||
|
||||
const quantiHandShake = computed(() => (userStore.userprofile.profile.handshake ? userStore.userprofile.profile.handshake.length : 0) + ' ' + t('handshake.strettedimano'))
|
||||
const handshake_inCommon = computed(() => userStore.getMyHandshakeInCommon(userStore.userprofile))
|
||||
const quanteHandShakeInCommon = computed(() => (handshake_inCommon.value ? handshake_inCommon.value.length : 0) + ' ' + t('handshake.incommon'))
|
||||
const quantiHandShake = computed(
|
||||
() =>
|
||||
(userStore.userprofile.profile.handshake
|
||||
? userStore.userprofile.profile.handshake.length
|
||||
: 0) +
|
||||
' ' +
|
||||
t('handshake.strettedimano')
|
||||
);
|
||||
const handshake_inCommon = computed(() =>
|
||||
userStore.getMyHandshakeInCommon(userStore.userprofile)
|
||||
);
|
||||
const quanteHandShakeInCommon = computed(
|
||||
() =>
|
||||
(handshake_inCommon.value ? handshake_inCommon.value.length : 0) +
|
||||
' ' +
|
||||
t('handshake.incommon')
|
||||
);
|
||||
|
||||
const mycards = computed(() => {
|
||||
return costanti.MAINCARDS.filter((rec: any) => rec.table)
|
||||
})
|
||||
return costanti.MAINCARDS.filter((rec: any) => rec.table);
|
||||
});
|
||||
|
||||
const listgroupsfiltered = ref(<IMyGroup[]>[])
|
||||
const listcircuitsfiltered = ref(<IMyCircuit[]>[])
|
||||
const listgroupsfiltered = ref(<IMyGroup[]>[]);
|
||||
const listcircuitsfiltered = ref(<IMyCircuit[]>[]);
|
||||
|
||||
const tab = ref('')
|
||||
const tab = ref('');
|
||||
|
||||
function profile() {
|
||||
return userStore.my.profile
|
||||
return userStore.my.profile;
|
||||
}
|
||||
|
||||
function myusername() {
|
||||
return userStore.my.username
|
||||
return userStore.my.username;
|
||||
}
|
||||
|
||||
async function loadProfile() {
|
||||
console.log('loadProfile...', username.value)
|
||||
console.log('loadProfile...', username.value);
|
||||
try {
|
||||
caricato.value = false;
|
||||
|
||||
caricato.value = false
|
||||
|
||||
if (sendRIS.value)
|
||||
spinner_visible.value = true
|
||||
if (sendRIS.value) {
|
||||
$q.loading.show({
|
||||
message: 'Caricamento in corso...',
|
||||
spinnerColor: 'white',
|
||||
backgroundColor: 'black',
|
||||
messageColor: 'white',
|
||||
});
|
||||
}
|
||||
|
||||
// Carica il profilo di quest'utente
|
||||
if (username.value) {
|
||||
await userStore.loadUserProfile({ username: username.value, idnotif: idnotif.value }).then((ris) => {
|
||||
console.log('loadUserProfile = ', ris)
|
||||
userStore.userprofile = ris
|
||||
if (userStore.userprofile) {
|
||||
filtroutente.value = [{ userId: userStore.userprofile._id }]
|
||||
notifStore.setAsRead(idnotif.value)
|
||||
await userStore
|
||||
.loadUserProfile({ username: username.value, idnotif: idnotif.value })
|
||||
.then((ris) => {
|
||||
console.log('loadUserProfile = ', ris);
|
||||
userStore.userprofile = ris;
|
||||
if (userStore.userprofile) {
|
||||
filtroutente.value = [{ userId: userStore.userprofile._id }];
|
||||
notifStore.setAsRead(idnotif.value);
|
||||
|
||||
try {
|
||||
if (userStore.userprofile)
|
||||
listgroupsfiltered.value = globalStore.mygroups.filter(
|
||||
(grp: IMyGroup) =>
|
||||
userStore.userprofile.profile.mygroups.findIndex(
|
||||
(rec: IMyGroup) => rec.groupname === grp.groupname
|
||||
) >= 0
|
||||
);
|
||||
} catch (e) {
|
||||
listgroupsfiltered.value = [];
|
||||
}
|
||||
|
||||
try {
|
||||
if (userStore.userprofile)
|
||||
listgroupsfiltered.value = globalStore.mygroups.filter((grp: IMyGroup) => userStore.userprofile.profile.mygroups.findIndex((rec: IMyGroup) => rec.groupname === grp.groupname) >= 0)
|
||||
} catch (e) {
|
||||
listgroupsfiltered.value = []
|
||||
try {
|
||||
listcircuitsfiltered.value = userStore.userprofile.profile.mycircuits;
|
||||
} catch (e) {
|
||||
listcircuitsfiltered.value = [];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
listcircuitsfiltered.value = userStore.userprofile.profile.mycircuits
|
||||
} catch (e) {
|
||||
listcircuitsfiltered.value = []
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
caricato.value = true
|
||||
caricato.value = true;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('ERR loadProfile', e)
|
||||
console.error('ERR loadProfile', e);
|
||||
}
|
||||
}
|
||||
|
||||
watch(() => username.value, (to: any, from: any) => {
|
||||
loadProfile()
|
||||
})
|
||||
watch(
|
||||
() => username.value,
|
||||
(to: any, from: any) => {
|
||||
loadProfile();
|
||||
}
|
||||
);
|
||||
|
||||
watch(() => actualcard.value, (to: any, from: any) => {
|
||||
loadProfile()
|
||||
})
|
||||
watch(
|
||||
() => actualcard.value,
|
||||
(to: any, from: any) => {
|
||||
loadProfile();
|
||||
}
|
||||
);
|
||||
|
||||
function mounted() {
|
||||
tab.value = tools.isRisoApp() ? 'attivita' : 'info'
|
||||
loadProfile()
|
||||
tab.value = tools.isRisoApp() ? 'attivita' : 'info';
|
||||
loadProfile();
|
||||
}
|
||||
|
||||
function getImgUser() {
|
||||
if (userStore.userprofile)
|
||||
return userStore.getImgByProfile(userStore.userprofile)
|
||||
else
|
||||
return ''
|
||||
if (userStore.userprofile) return userStore.getImgByProfile(userStore.userprofile);
|
||||
else return '';
|
||||
}
|
||||
|
||||
function checkifShow(col: string) {
|
||||
//++Todo: checkifShow Permessi !
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
|
||||
function isMyRecord(username: string) {
|
||||
return username === userStore.my.username
|
||||
return username === userStore.my.username;
|
||||
}
|
||||
|
||||
function getLinkWebSite() {
|
||||
if (userStore.userprofile) {
|
||||
let mysite = userStore.userprofile.profile.website
|
||||
let mysite = userStore.userprofile.profile.website;
|
||||
if (mysite) {
|
||||
if (!mysite.startsWith('http')) {
|
||||
mysite = 'https://' + mysite
|
||||
mysite = 'https://' + mysite;
|
||||
}
|
||||
}
|
||||
return mysite
|
||||
return mysite;
|
||||
} else {
|
||||
return ''
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(mounted)
|
||||
onMounted(mounted);
|
||||
|
||||
function gotoPage(link: string) {
|
||||
$router.push(link)
|
||||
$router.push(link);
|
||||
}
|
||||
|
||||
function getlinkpage() {
|
||||
if (userStore.userprofile)
|
||||
return self.location.host + '/my/' + userStore.userprofile.username
|
||||
else
|
||||
return ''
|
||||
return self.location.host + '/my/' + userStore.userprofile.username;
|
||||
else return '';
|
||||
}
|
||||
|
||||
function showed() {
|
||||
spinner_visible.value = false
|
||||
$q.loading.hide()
|
||||
|
||||
}
|
||||
|
||||
function salvaUserProv(userprofile: IUserFields) {
|
||||
if (userprofile)
|
||||
userStore.userprofile = userprofile
|
||||
if (userprofile) userStore.userprofile = userprofile;
|
||||
}
|
||||
|
||||
function saveDaContattare() {
|
||||
const globalStore = useGlobalStore()
|
||||
const { t } = useI18n()
|
||||
const globalStore = useGlobalStore();
|
||||
const { t } = useI18n();
|
||||
|
||||
const mydatatosave = {
|
||||
id: userStore.userprofile._id,
|
||||
table: 'users',
|
||||
fieldsvalue: { 'profile.da_contattare': userStore.userprofile.profile.da_contattare }
|
||||
}
|
||||
fieldsvalue: {
|
||||
'profile.da_contattare': userStore.userprofile.profile.da_contattare,
|
||||
},
|
||||
};
|
||||
|
||||
globalStore.saveFieldValue(mydatatosave).then((esito) => {
|
||||
if (esito) {
|
||||
tools.showPositiveNotif($q, t('db.recupdated'))
|
||||
tools.showPositiveNotif($q, t('db.recupdated'));
|
||||
} else {
|
||||
tools.showNegativeNotif($q, t('db.recfailed'))
|
||||
tools.showNegativeNotif($q, t('db.recfailed'));
|
||||
}
|
||||
})
|
||||
|
||||
});
|
||||
}
|
||||
function savePerm() {
|
||||
const globalStore = useGlobalStore()
|
||||
const { t } = useI18n()
|
||||
const globalStore = useGlobalStore();
|
||||
const { t } = useI18n();
|
||||
|
||||
const mydatatosave = {
|
||||
id: userStore.userprofile._id,
|
||||
table: 'users',
|
||||
fieldsvalue: { 'perm': userStore.userprofile.perm }
|
||||
}
|
||||
fieldsvalue: { perm: userStore.userprofile.perm },
|
||||
};
|
||||
|
||||
globalStore.saveFieldValue(mydatatosave).then((esito) => {
|
||||
if (esito) {
|
||||
tools.showPositiveNotif($q, t('db.recupdated'))
|
||||
tools.showPositiveNotif($q, t('db.recupdated'));
|
||||
} else {
|
||||
tools.showNegativeNotif($q, t('db.recfailed'))
|
||||
tools.showNegativeNotif($q, t('db.recfailed'));
|
||||
}
|
||||
})
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -285,7 +331,6 @@ export default defineComponent({
|
||||
gotoPage,
|
||||
sendRIS,
|
||||
causalDest,
|
||||
spinner_visible,
|
||||
showed,
|
||||
tab,
|
||||
shownote,
|
||||
@@ -293,6 +338,6 @@ export default defineComponent({
|
||||
salvaUserProv,
|
||||
saveDaContattare,
|
||||
savePerm,
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
<template>
|
||||
<div v-if="isDebugOn && false" class="bg-red text-white">
|
||||
<div
|
||||
v-if="isDebugOn && false"
|
||||
class="bg-red text-white"
|
||||
>
|
||||
getImgUser(): {{ getImgUser() }}
|
||||
<span v-if="!!tools.isLogged()">Logged: {{ tools.isLogged() }}</span> -
|
||||
<span v-if="!!tools.isUserOk()">UserOk: {{ tools.isUserOk() }}</span> -
|
||||
<span v-if="!!userStore.userprofile.date_reg">Date_Reg: {{ tools.getstrDate(userStore.userprofile.date_reg) }}</span> -
|
||||
<span>tools.isEmailVerified(): {{ tools.isEmailVerified() }}</span> -
|
||||
<span v-if="!!userStore.userprofile.date_reg"
|
||||
>Date_Reg: {{ tools.getstrDate(userStore.userprofile.date_reg) }}</span
|
||||
>
|
||||
- <span>tools.isEmailVerified(): {{ tools.isEmailVerified() }}</span> -
|
||||
<span
|
||||
>tools.getLinkUserTelegramByUser():
|
||||
{{ tools.getLinkUserTelegramByUser(userStore.userprofile) }}</span
|
||||
@@ -18,8 +23,17 @@
|
||||
v-if="!caricato"
|
||||
class="fit column no-wrap justify-evenly items-center content-start"
|
||||
>
|
||||
<q-skeleton type="QAvatar" size="140px" height="140px" animation="fade" />
|
||||
<q-card flat bordered style="width: 250px">
|
||||
<q-skeleton
|
||||
type="QAvatar"
|
||||
size="140px"
|
||||
height="140px"
|
||||
animation="fade"
|
||||
/>
|
||||
<q-card
|
||||
flat
|
||||
bordered
|
||||
style="width: 250px"
|
||||
>
|
||||
<div class="text-h6">
|
||||
<q-skeleton :animation="animation" />
|
||||
</div>
|
||||
@@ -62,9 +76,7 @@
|
||||
>online</q-badge
|
||||
>
|
||||
<q-badge
|
||||
v-if="
|
||||
userStore.IsHandShakeByUsername(userStore.userprofile.username)
|
||||
"
|
||||
v-if="userStore.IsHandShakeByUsername(userStore.userprofile.username)"
|
||||
align="bottom"
|
||||
floating
|
||||
color="red"
|
||||
@@ -101,9 +113,7 @@
|
||||
{{ userStore.userprofile.username }}
|
||||
</div>
|
||||
<div
|
||||
v-if="
|
||||
userStore.userprofile && userStore.userprofile.profile.qualifica
|
||||
"
|
||||
v-if="userStore.userprofile && userStore.userprofile.profile.qualifica"
|
||||
class="col-12 text-h8 q-mt-sm"
|
||||
>
|
||||
<span v-if="userStore.userprofile.profile.qualifica">
|
||||
@@ -115,9 +125,7 @@
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="
|
||||
userStore.userprofile && userStore.userprofile.profile.biografia
|
||||
"
|
||||
v-if="userStore.userprofile && userStore.userprofile.profile.biografia"
|
||||
class="col-12 text-h8 q-mt-sm"
|
||||
>
|
||||
{{ userStore.userprofile.profile.biografia }}
|
||||
@@ -185,19 +193,12 @@
|
||||
</CTitleBanner>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<q-inner-loading :showing="spinner_visible">
|
||||
<q-spinner-tail size="3em" color="primary" />
|
||||
</q-inner-loading>
|
||||
</div>
|
||||
|
||||
<div v-if="site && site.confpages && site.confpages.showNameSurname">
|
||||
<div class="text-h6">
|
||||
<span v-if="checkifShow('name') && userStore.userprofile.name">
|
||||
{{ userStore.userprofile.name }}</span
|
||||
>
|
||||
<span
|
||||
v-if="checkifShow('surname') && userStore.userprofile.surname"
|
||||
<span v-if="checkifShow('surname') && userStore.userprofile.surname"
|
||||
> {{ userStore.userprofile.surname }}</span
|
||||
>
|
||||
</div>
|
||||
@@ -206,10 +207,7 @@
|
||||
{{ userStore.userprofile.username }}
|
||||
</div>
|
||||
<div
|
||||
v-if="
|
||||
userStore.userprofile.profile.qualifica &&
|
||||
userStore.userprofile._id
|
||||
"
|
||||
v-if="userStore.userprofile.profile.qualifica && userStore.userprofile._id"
|
||||
class="col-12 text-h8 q-mt-sm"
|
||||
>
|
||||
<span v-if="userStore.userprofile.profile.qualifica">
|
||||
@@ -258,14 +256,28 @@
|
||||
"
|
||||
class="col-12 text-h8 q-mt-sm"
|
||||
>
|
||||
<div v-if="!mostranota" class="text-center">
|
||||
<q-btn label="Note" @click="mostranota = true" color="green">
|
||||
<q-badge color="red" floating>1</q-badge>
|
||||
<div
|
||||
v-if="!mostranota"
|
||||
class="text-center"
|
||||
>
|
||||
<q-btn
|
||||
label="Note"
|
||||
@click="mostranota = true"
|
||||
color="green"
|
||||
>
|
||||
<q-badge
|
||||
color="red"
|
||||
floating
|
||||
>1</q-badge
|
||||
>
|
||||
</q-btn>
|
||||
</div>
|
||||
<div v-else>
|
||||
<strong>Note del Facilitatore</strong>:<br />
|
||||
<q-banner rounded class="bg-green-8 text-white">
|
||||
<q-banner
|
||||
rounded
|
||||
class="bg-green-8 text-white"
|
||||
>
|
||||
<div class="text-h7 text-center">
|
||||
{{ userStore.userprofile.profile.note }}
|
||||
</div>
|
||||
@@ -329,9 +341,7 @@
|
||||
<q-chip
|
||||
v-if="
|
||||
userStore.IsHandShakeByMe(userStore.userprofile) &&
|
||||
userStore.IsHandShakeByUsername(
|
||||
userStore.userprofile.username
|
||||
)
|
||||
userStore.IsHandShakeByUsername(userStore.userprofile.username)
|
||||
"
|
||||
color="green"
|
||||
dense
|
||||
@@ -341,11 +351,9 @@
|
||||
icon="fas fa-handshake"
|
||||
>
|
||||
<span
|
||||
> <em
|
||||
class="q-pa-xxs text-white rounded-borders shadow-2"
|
||||
>
|
||||
> <em class="q-pa-xxs text-white rounded-borders shadow-2">
|
||||
{{
|
||||
$t("db.both_fiducia", {
|
||||
$t('db.both_fiducia', {
|
||||
username: userStore.userprofile.username,
|
||||
})
|
||||
}}
|
||||
@@ -355,9 +363,7 @@
|
||||
<q-chip
|
||||
v-else-if="
|
||||
!userStore.IsHandShakeByMe(userStore.userprofile) &&
|
||||
userStore.IsHandShakeByUsername(
|
||||
userStore.userprofile.username
|
||||
)
|
||||
userStore.IsHandShakeByUsername(userStore.userprofile.username)
|
||||
"
|
||||
color="blue"
|
||||
dense
|
||||
@@ -367,11 +373,9 @@
|
||||
icon="fas fa-handshake"
|
||||
>
|
||||
<span
|
||||
> <em
|
||||
class="q-pa-xxs text-white rounded-borders shadow-2"
|
||||
>
|
||||
> <em class="q-pa-xxs text-white rounded-borders shadow-2">
|
||||
{{
|
||||
$t("db.handshake_him", {
|
||||
$t('db.handshake_him', {
|
||||
username: userStore.userprofile.username,
|
||||
})
|
||||
}}
|
||||
@@ -381,9 +385,7 @@
|
||||
<q-chip
|
||||
v-else-if="
|
||||
userStore.IsHandShakeByMe(userStore.userprofile) &&
|
||||
!userStore.IsHandShakeByUsername(
|
||||
userStore.userprofile.username
|
||||
)
|
||||
!userStore.IsHandShakeByUsername(userStore.userprofile.username)
|
||||
"
|
||||
color="blue"
|
||||
dense
|
||||
@@ -393,11 +395,9 @@
|
||||
icon="fas fa-handshake"
|
||||
>
|
||||
<span
|
||||
> <em
|
||||
class="q-pa-xxs text-white rounded-borders shadow-2"
|
||||
>
|
||||
> <em class="q-pa-xxs text-white rounded-borders shadow-2">
|
||||
{{
|
||||
$t("db.handshake_you", {
|
||||
$t('db.handshake_you', {
|
||||
username: userStore.userprofile.username,
|
||||
})
|
||||
}}
|
||||
@@ -407,21 +407,13 @@
|
||||
</div>
|
||||
|
||||
<!--HANDSHAKE-->
|
||||
<div
|
||||
v-if="
|
||||
!isMyRecord(userStore.userprofile.username) && tools.isUserOk()
|
||||
"
|
||||
>
|
||||
<div v-if="!isMyRecord(userStore.userprofile.username) && tools.isUserOk()">
|
||||
<div
|
||||
class="row centeritems q-pa-sm"
|
||||
v-if="!userStore.IsHandShakeByMe(userStore.userprofile)"
|
||||
>
|
||||
<q-btn
|
||||
v-if="
|
||||
userStore.IsHandShakeByUsername(
|
||||
userStore.userprofile.username
|
||||
)
|
||||
"
|
||||
v-if="userStore.IsHandShakeByUsername(userStore.userprofile.username)"
|
||||
icon="fas fa-handshake"
|
||||
color="positive"
|
||||
dense
|
||||
@@ -461,9 +453,7 @@
|
||||
class="row centeritems q-ma-sm q-pa-sm"
|
||||
v-if="
|
||||
costanti.ENABLE_FRIENDS &&
|
||||
userStore.IsReqFriendByUsername(
|
||||
userStore.userprofile.username
|
||||
)
|
||||
userStore.IsReqFriendByUsername(userStore.userprofile.username)
|
||||
"
|
||||
>
|
||||
<q-btn
|
||||
@@ -497,12 +487,8 @@
|
||||
<q-btn
|
||||
v-if="
|
||||
costanti.ENABLE_FRIENDS &&
|
||||
!userStore.IsMyFriendByUsername(
|
||||
userStore.userprofile.username
|
||||
) &&
|
||||
!userStore.IsAskedFriendByUsername(
|
||||
userStore.userprofile.username
|
||||
)
|
||||
!userStore.IsMyFriendByUsername(userStore.userprofile.username) &&
|
||||
!userStore.IsAskedFriendByUsername(userStore.userprofile.username)
|
||||
"
|
||||
icon="fas fa-user-plus"
|
||||
color="primary"
|
||||
@@ -523,9 +509,8 @@
|
||||
<div class="row justify-center">
|
||||
<q-btn
|
||||
v-if="
|
||||
userStore.IsMyFriendByUsername(
|
||||
userStore.userprofile.username
|
||||
) || userStore.IsHandShakeByMe(userStore.userprofile)
|
||||
userStore.IsMyFriendByUsername(userStore.userprofile.username) ||
|
||||
userStore.IsHandShakeByMe(userStore.userprofile)
|
||||
"
|
||||
class="text-center"
|
||||
rounded
|
||||
@@ -553,15 +538,13 @@
|
||||
/>
|
||||
</q-item-section>
|
||||
<q-item-section>{{
|
||||
$t("handshake.remove_from_myhandshake")
|
||||
$t('handshake.remove_from_myhandshake')
|
||||
}}</q-item-section>
|
||||
</q-item>
|
||||
<q-item
|
||||
v-if="
|
||||
costanti.ENABLE_FRIENDS &&
|
||||
userStore.IsMyFriendByUsername(
|
||||
userStore.userprofile.username
|
||||
)
|
||||
userStore.IsMyFriendByUsername(userStore.userprofile.username)
|
||||
"
|
||||
clickable
|
||||
icon="fas fa-user-minus"
|
||||
@@ -576,17 +559,18 @@
|
||||
"
|
||||
>
|
||||
<q-item-section avatar>
|
||||
<q-icon color="negative" name="fas fa-user-minus" />
|
||||
<q-icon
|
||||
color="negative"
|
||||
name="fas fa-user-minus"
|
||||
/>
|
||||
</q-item-section>
|
||||
<q-item-section>{{
|
||||
$t("friends.remove_from_myfriends")
|
||||
$t('friends.remove_from_myfriends')
|
||||
}}</q-item-section>
|
||||
</q-item>
|
||||
<q-item
|
||||
v-if="
|
||||
userStore.IsMyFriendByUsername(
|
||||
userStore.userprofile.username
|
||||
)
|
||||
userStore.IsMyFriendByUsername(userStore.userprofile.username)
|
||||
"
|
||||
clickable
|
||||
icon="fas fa-ban"
|
||||
@@ -600,17 +584,16 @@
|
||||
"
|
||||
>
|
||||
<q-item-section avatar>
|
||||
<q-icon color="negative" name="fas fa-ban" />
|
||||
<q-icon
|
||||
color="negative"
|
||||
name="fas fa-ban"
|
||||
/>
|
||||
</q-item-section>
|
||||
<q-item-section>{{
|
||||
$t("friends.block_user")
|
||||
}}</q-item-section>
|
||||
<q-item-section>{{ $t('friends.block_user') }}</q-item-section>
|
||||
</q-item>
|
||||
<q-item
|
||||
v-if="
|
||||
userStore.IsMyFriendByUsername(
|
||||
userStore.userprofile.username
|
||||
)
|
||||
userStore.IsMyFriendByUsername(userStore.userprofile.username)
|
||||
"
|
||||
clickable
|
||||
v-close-popup
|
||||
@@ -623,11 +606,12 @@
|
||||
"
|
||||
>
|
||||
<q-item-section avatar>
|
||||
<q-icon color="negative" name="fas fa-flag" />
|
||||
<q-icon
|
||||
color="negative"
|
||||
name="fas fa-flag"
|
||||
/>
|
||||
</q-item-section>
|
||||
<q-item-section>{{
|
||||
$t("friends.report_user")
|
||||
}}</q-item-section>
|
||||
<q-item-section>{{ $t('friends.report_user') }}</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-menu>
|
||||
@@ -636,12 +620,8 @@
|
||||
<q-btn
|
||||
v-if="
|
||||
costanti.ENABLE_FRIENDS &&
|
||||
userStore.IsAskedFriendByUsername(
|
||||
userStore.userprofile.username
|
||||
) &&
|
||||
!userStore.IsMyFriendByUsername(
|
||||
userStore.userprofile.username
|
||||
)
|
||||
userStore.IsAskedFriendByUsername(userStore.userprofile.username) &&
|
||||
!userStore.IsMyFriendByUsername(userStore.userprofile.username)
|
||||
"
|
||||
icon="fas fa-user-minus"
|
||||
outline
|
||||
@@ -677,7 +657,11 @@
|
||||
/>
|
||||
</q-tabs>
|
||||
|
||||
<q-tab-panels v-model="tab" animated keep-alive>
|
||||
<q-tab-panels
|
||||
v-model="tab"
|
||||
animated
|
||||
keep-alive
|
||||
>
|
||||
<q-tab-panel name="attivita">
|
||||
<CMyActivities
|
||||
:username_prop="userStore.userprofile.username"
|
||||
@@ -687,8 +671,7 @@
|
||||
<q-tab-panel name="info">
|
||||
<div
|
||||
v-if="
|
||||
userStore.userprofile._id &&
|
||||
userStore.userprofile.profile.biografia
|
||||
userStore.userprofile._id && userStore.userprofile.profile.biografia
|
||||
"
|
||||
class="col-12 text-h8 q-mt-sm"
|
||||
>
|
||||
@@ -698,9 +681,7 @@
|
||||
|
||||
<div
|
||||
v-if="
|
||||
userStore.userprofile &&
|
||||
userStore.userprofile._id &&
|
||||
tools.isUserOk()
|
||||
userStore.userprofile && userStore.userprofile._id && tools.isUserOk()
|
||||
"
|
||||
>
|
||||
<div
|
||||
@@ -713,12 +694,18 @@
|
||||
v-bind="$attrs"
|
||||
:copy="false"
|
||||
:value="
|
||||
userStore.userprofile.profile.resid_str_comune + (userStore.userprofile.profile.resid_province ? ' (' + userStore.userprofile.profile.resid_province + ')' : '')
|
||||
userStore.userprofile.profile.resid_str_comune +
|
||||
(userStore.userprofile.profile.resid_province
|
||||
? ' (' + userStore.userprofile.profile.resid_province + ')'
|
||||
: '')
|
||||
"
|
||||
label="Comune"
|
||||
/>
|
||||
<CLabel
|
||||
v-if="!!userStore.userprofile.profile.resid_province && !userStore.userprofile.profile.resid_str_comune"
|
||||
v-if="
|
||||
!!userStore.userprofile.profile.resid_province &&
|
||||
!userStore.userprofile.profile.resid_str_comune
|
||||
"
|
||||
v-bind="$attrs"
|
||||
:copy="false"
|
||||
:value="
|
||||
@@ -752,9 +739,7 @@
|
||||
label="Sito Web"
|
||||
>
|
||||
<span
|
||||
v-html="
|
||||
tools.getlinkhref(getLinkWebSite(), getLinkWebSite())
|
||||
"
|
||||
v-html="tools.getlinkhref(getLinkWebSite(), getLinkWebSite())"
|
||||
/>
|
||||
</CLabel>
|
||||
|
||||
@@ -801,7 +786,10 @@
|
||||
</q-tab-panels>
|
||||
</div>
|
||||
</div>
|
||||
<q-page-sticky position="top-right" :offset="[18, 18]" class="z-top">
|
||||
<q-page-sticky
|
||||
position="top-right"
|
||||
:offset="[18, 18]"
|
||||
>
|
||||
<q-fab
|
||||
icon="fas fa-ellipsis-v"
|
||||
color="accent"
|
||||
@@ -837,14 +825,12 @@
|
||||
v-if="userStore.isFacilitatore || userStore.isAdmin"
|
||||
color="green"
|
||||
:icon="
|
||||
userStore.userprofile.profile &&
|
||||
userStore.userprofile.profile.da_contattare
|
||||
userStore.userprofile.profile && userStore.userprofile.profile.da_contattare
|
||||
? 'fas fa-user-slash'
|
||||
: 'fas fa-comment'
|
||||
"
|
||||
:label="
|
||||
userStore.userprofile.profile &&
|
||||
userStore.userprofile.profile.da_contattare
|
||||
userStore.userprofile.profile && userStore.userprofile.profile.da_contattare
|
||||
? t('profile.togli_da_contattare')
|
||||
: t('profile.da_contattare')
|
||||
"
|
||||
@@ -892,8 +878,16 @@
|
||||
/>
|
||||
</q-fab>
|
||||
</q-page-sticky>
|
||||
<q-dialog v-model="showPic" full-height full-width>
|
||||
<img :src="getImgUser()" :alt="username" class="full-width" />
|
||||
<q-dialog
|
||||
v-model="showPic"
|
||||
full-height
|
||||
full-width
|
||||
>
|
||||
<img
|
||||
:src="getImgUser()"
|
||||
:alt="username"
|
||||
class="full-width"
|
||||
/>
|
||||
</q-dialog>
|
||||
|
||||
<div
|
||||
@@ -909,17 +903,23 @@
|
||||
style="z-index: 1"
|
||||
>
|
||||
<q-menu>
|
||||
<q-list v-if="true" style="min-width: 200px">
|
||||
<q-list
|
||||
v-if="true"
|
||||
style="min-width: 200px"
|
||||
>
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click.stop="gotoPage('/editprofile')"
|
||||
>
|
||||
<q-item-section avatar>
|
||||
<q-icon color="blue" name="fas fa-pencil-alt" />
|
||||
<q-icon
|
||||
color="blue"
|
||||
name="fas fa-pencil-alt"
|
||||
/>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
{{ $t("shared.edit_profile") }}
|
||||
{{ $t('shared.edit_profile') }}
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
@@ -950,11 +950,20 @@
|
||||
<q-toolbar-title>
|
||||
{{ usersList.title }}
|
||||
</q-toolbar-title>
|
||||
<q-btn flat round color="white" icon="close" v-close-popup></q-btn>
|
||||
<q-btn
|
||||
flat
|
||||
round
|
||||
color="white"
|
||||
icon="close"
|
||||
v-close-popup
|
||||
></q-btn>
|
||||
</q-toolbar>
|
||||
|
||||
<q-card-section class="inset-shadow">
|
||||
<div v-for="(rec, i) in usersList.list" :key="i">
|
||||
<div
|
||||
v-for="(rec, i) in usersList.list"
|
||||
:key="i"
|
||||
>
|
||||
<CMyUser
|
||||
:mycontact="rec"
|
||||
:visu="costanti.FIND_PEOPLE"
|
||||
@@ -975,10 +984,8 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" src="./myprofile.ts">
|
||||
</script>
|
||||
<script lang="ts" src="./myprofile.ts"></script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "./myprofile.scss";
|
||||
@import './myprofile.scss';
|
||||
</style>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user