Changed menu that dialogues can be opened too; added random chat

This commit is contained in:
Torsten Schulz
2025-07-17 16:52:11 +02:00
parent 89cf12a7a8
commit 6062570fe8
5 changed files with 415 additions and 251 deletions

View File

@@ -1,6 +1,6 @@
<template>
<DialogWidget ref="dialog" title="randomchat.title" icon="dice24.png" :show-close=true :buttons="buttons"
:modal=false :isTitleTranslated=true @close="closeDialog" name="RandomChat">
<DialogWidget ref="dialog" title="randomchat.title" icon="dice24.png" :show-close="true" :buttons="buttons"
:modal="false" :isTitleTranslated="true" @close="closeDialog" name="RandomChat">
<div v-if="chatIsRunning" class="randomchat">
<div class="headline">
{{ $t("randomchat.agerange") }}
@@ -12,36 +12,42 @@
<div>
<label><input type="checkbox" v-model="searchmale" />{{ $t("randomchat.gender.male") }}</label>
<label><input type="checkbox" v-model="searchfemale" />{{ $t("randomchat.gender.female")
}}</label>
}}</label>
</div>
</span>
<label><input type="checkbox" v-model="camonlysearch" />{{ $t("randomchat.camonly") }}</label>
<label><input type="checkbox" v-model="showcam" />{{ $t("randomchat.showcam") }}</label>
<img v-if="isLoggedIn" src="/images/icons/friendsadd16.png" ::tooltip="$t('randomchat.addfriend')" />
<img v-if="isLoggedIn" src="/images/icons/friendsadd16.png" :tooltip="$t('randomchat.addfriend')" />
<label><input type="checkbox" v-model="autosearch" />{{ $t("randomchat.autosearch") }}</label>
<button @click="nextUser" v-if="partner != null">{{ $t("randomchat.jumptonext") }}</button>
<button @click="startSearch" v-if="partner == null && !searching">{{ $t("randomchat.startsearch") }}</button>
<button @click="startSearch" v-if="partner == null && !searching">{{ $t("randomchat.startsearch")
}}</button>
</div>
<div class="output">
<div v-for="message in messages" v-html="renderMessage(message)">
</div>
<div v-for="message in messages" v-html="renderMessage(message)" />
</div>
<div class="inputline">
<label>{{ $t("randomchat.input") }}&nbsp;<input type="text" v-model="inputtext" @keyup.enter="sendMessage" /></label>
<label>
{{ $t("randomchat.input") }}&nbsp;
<input type="text" v-model="inputtext" @keyup.enter="sendMessage" />
</label>
<img src="/images/icons/enter16.png" @click="sendMessage" />
<img src="/images/icons/dice16.png" />
</div>
</div>
<div v-else>
<div>
<label>{{ $t("randomchat.age") }} <input type="number" v-model="age" min="18" max="150"
value="18" /></label>
<label>{{ $t("randomchat.age") }}
<input type="number" v-model="age" min="18" max="150" value="18" />
</label>
</div>
<div>
<label>{{ $t("randomchat.gender.title") }} <select v-model="gender">
<label>{{ $t("randomchat.gender.title") }}
<select v-model="gender">
<option value="f">{{ $t("randomchat.gender.female") }}</option>
<option value="m">{{ $t("randomchat.gender.male") }}</option>
</select></label>
</select>
</label>
</div>
<div>
<button @click="startRandomChat()">{{ $t("randomchat.start") }}</button>
@@ -51,7 +57,7 @@
</template>
<script>
import DialogWidget from '@/components/DialogWidget.vue';
import DialogWidget from '@/components/DialogWidget.vue';
import { mapGetters } from 'vuex';
import axios from 'axios';
@@ -61,122 +67,165 @@ export default {
DialogWidget,
},
computed: {
...mapGetters(['isLoggedIn']),
...mapGetters(['isLoggedIn', 'user']),
buttons() {
return [{ text: this.$t("randomchat.close")}];
return [{ text: this.$t('randomchat.close') }];
},
},
data() {
return {
chatIsRunning: false,
age: 18,
gender: "f",
gender: 'f',
agefromsearch: 18,
agetosearch: 150,
searchmale: true,
searchfemale: true,
camonlysearch: false,
showcam: false,
autosearch: false,
inputtext: '',
searching: false,
userId: null,
userId: null, // ID, die vom Chat-Backend beim Register zurückkommt
searchInterval: null,
messages: [],
partner: null,
messagesInterval: null,
}
};
},
methods: {
async open() {
if (this.user && Array.isArray(this.user.param)) {
const bdParam = this.user.param.find(p => p.name === 'birthdate')?.value;
if (bdParam) {
const birth = new Date(bdParam);
const ageYears = Math.floor(
(Date.now() - birth.getTime()) / (365.25 * 24 * 60 * 60 * 1000)
);
this.age = ageYears;
}
const gParam = this.user.param.find(p => p.name === 'gender')?.value;
if (gParam != null) {
// value==='1' ⇒ männlich
this.gender = gParam === '1' ? 'm' : 'f';
}
}
this.$refs.dialog.open();
},
async closeDialog() {
// ① Stoppe alle laufenden Intervalle
if (this.searchInterval) {
clearInterval(this.searchInterval);
this.searchInterval = null;
}
if (this.messagesInterval) {
clearInterval(this.messagesInterval);
this.messagesInterval = null;
}
// ② verlasse Chat auf Server-Seite
this.$refs.dialog.close();
await axios.post('/api/chat/exit', { id: this.userId });
await this.removeUserFromChat();
// Reset-Status
this.chatIsRunning = false;
this.partner = null;
this.messages = [];
},
async registerUser() {
try {
const response = await axios.post('/api/chat/register', {
gender: this.gender,
age: this.age
age: this.age,
});
this.userId = response.data.id;
this.userId = response.data.id;
} catch (error) {
console.error('Error registering user:', error);
}
},
async closeDialog() {
this.$refs.dialog.close();
await axios.push('/api/chat/exit', { id: this.userId })
await axios.post('/api/chat/exit', { id: this.userId });
await this.removeUserFromChat();
},
async startRandomChat() {
this.chatIsRunning = true;
await this.registerUser();
await this.startSearch();
},
async startSearch() {
this.searching = true;
await this.findMatch();
this.messages.push({ type: "system", tr: "randomchat.waitingForMatch" })
this.messages.push({ type: 'system', tr: 'randomchat.waitingForMatch' });
this.searchInterval = setInterval(this.findMatch, 500);
},
async findMatch() {
try {
const response = await axios.post('/api/chat/findMatch', {
genders: this.getSearchGenders(),
age: {
min: this.agefromsearch,
max: this.agetosearch
},
id: this.userId
age: { min: this.agefromsearch, max: this.agetosearch },
id: this.userId,
});
if (response.data.status && response.data.status === 'matched') {
if (response.data.status === 'matched') {
this.searching = false;
if (this.searchInterval) {
clearInterval(this.searchInterval);
this.searchInterval = null;
}
const initText = this.$t("randomchat.chatpartner")
.replace("<gender>", this.$t(`randomchat.partnergender${response.data.user.gender}`))
.replace("<age>", response.data.user.age);
this.messages = [];
this.messages.push({ "type": "system", text: initText })
clearInterval(this.searchInterval);
const initText = this.$t('randomchat.chatpartner')
.replace(
'<gender>',
this.$t(`randomchat.partnergender${response.data.user.gender}`)
)
.replace('<age>', response.data.user.age);
this.messages = [{ type: 'system', text: initText }];
this.partner = response.data.user;
this.messagesInterval = setInterval(this.getNewMessages, 250);
} else {
if (this.autosearch && !this.searching && ! this.searchInterval) {
this.searchInterval = setInterval(this.findMatch, 500);
}
} else if (this.autosearch && !this.searchInterval) {
this.searchInterval = setInterval(this.findMatch, 500);
}
} catch (error) {
console.error('Error finding match:', error);
}
},
getSearchGenders() {
const genders = [];
if (this.searchmale) genders.push('m');
if (this.searchfemale) genders.push('f');
return genders;
},
async sendMessage() {
if (this.inputtext.trim() !== '') {
const response = await axios.post('/api/chat/sendMessage', { from: this.userId, to: this.partner.id, text: this.inputtext });
this.messages.push({ type: "self", text: response.data.text });
this.inputtext = '';
}
if (!this.inputtext.trim()) return;
const response = await axios.post('/api/chat/sendMessage', {
from: this.userId,
to: this.partner.id,
text: this.inputtext,
});
this.messages.push({ type: 'self', text: response.data.text });
this.inputtext = '';
},
async getNewMessages() {
if (!this.partner) {
return;
}
const response = await axios.post('/api/chat/getMessages', { to: this.userId, from: this.partner.id });
const messages = response.data.filter(item => !item.activity);
const activities = response.data.filter(item => item.activity);
for (let i = 0; i < activities.length; ++i) {
const activity = activities[i];
if (activity.activity === 'otheruserleft') {
if (!this.partner) return;
const response = await axios.post('/api/chat/getMessages', {
to: this.userId,
from: this.partner.id,
});
const newMsgs = response.data.filter((m) => !m.activity);
const activities = response.data.filter((m) => m.activity);
activities.forEach((act) => {
if (act.activity === 'otheruserleft') {
this.partner = null;
this.messages.push({ type: 'system', tr: 'randomchat.userleftchat' });
}
}
this.messages.push(...messages);
});
this.messages.push(...newMsgs);
},
async removeUserFromChat() {
try {
await axios.post('/api/chat/remove', { id: this.userId });
@@ -184,31 +233,27 @@ export default {
console.error('Error removing user from chat:', error);
}
},
async nextUser() {
await axios.post('/api/chat/leave', { id: this.userId });
this.partner = null;
this.messages.push({ type: 'system', tr: 'randomchat.selfstopped' });
if (this.autosearch) {
this.searchInterval = setInterval(this.findMatch, 500);
this.messages.push({ type: "system", tr: "randomchat.waitingForMatch" })
this.messages.push({ type: 'system', tr: 'randomchat.waitingForMatch' });
}
},
renderMessage(message) {
let className = '';
let tr = '';
if (message.type === 'system') {
const text = message.tr ? this.$t(message.tr) : message.text;
return `<span class="rc-system">${text}</span>`;
} else if (message.type === 'self') {
className = 'rc-self';
tr = this.$t('randomchat.self');
} else {
className = 'rc-partner';
tr = this.$t('randomchat.partner');
const txt = message.tr ? this.$t(message.tr) : message.text;
return `<span class="rc-system">${txt}</span>`;
}
return `<span class="${className}">${tr}: </span>${message.text}`;
}
}
const cls = message.type === 'self' ? 'rc-self' : 'rc-partner';
const who = message.type === 'self' ? this.$t('randomchat.self') : this.$t('randomchat.partner');
return `<span class="${cls}">${who}: </span>${message.text}`;
},
},
};
</script>
@@ -271,5 +316,4 @@ export default {
.inputline>label>input {
flex: 1;
}
</style>