Merge pull request 'dev/lion/chatbot' (#48) from dev/lion/chatbot into main
Reviewed-on: Targo/targo_frontend#48
This commit is contained in:
commit
ff25cf5082
75
package-lock.json
generated
75
package-lock.json
generated
|
|
@ -12,6 +12,7 @@
|
||||||
"@quasar/extras": "^1.17.0",
|
"@quasar/extras": "^1.17.0",
|
||||||
"axios": "^1.11.0",
|
"axios": "^1.11.0",
|
||||||
"chart.js": "^4.5.0",
|
"chart.js": "^4.5.0",
|
||||||
|
"markdown-it": "^14.1.0",
|
||||||
"pinia": "^3.0.3",
|
"pinia": "^3.0.3",
|
||||||
"pinia-plugin-persistedstate": "^4.4.1",
|
"pinia-plugin-persistedstate": "^4.4.1",
|
||||||
"quasar": "^2.18.2",
|
"quasar": "^2.18.2",
|
||||||
|
|
@ -24,6 +25,7 @@
|
||||||
"@eslint/js": "^9.14.0",
|
"@eslint/js": "^9.14.0",
|
||||||
"@intlify/unplugin-vue-i18n": "^4.0.0",
|
"@intlify/unplugin-vue-i18n": "^4.0.0",
|
||||||
"@quasar/app-vite": "^2.1.0",
|
"@quasar/app-vite": "^2.1.0",
|
||||||
|
"@types/markdown-it": "^14.1.2",
|
||||||
"@types/node": "^20.5.9",
|
"@types/node": "^20.5.9",
|
||||||
"@vue/eslint-config-typescript": "^14.4.0",
|
"@vue/eslint-config-typescript": "^14.4.0",
|
||||||
"@vue/test-utils": "^2.4.6",
|
"@vue/test-utils": "^2.4.6",
|
||||||
|
|
@ -1900,6 +1902,31 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/linkify-it": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@types/markdown-it": {
|
||||||
|
"version": "14.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz",
|
||||||
|
"integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/linkify-it": "^5",
|
||||||
|
"@types/mdurl": "^2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/mdurl": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@types/mime": {
|
"node_modules/@types/mime": {
|
||||||
"version": "1.3.5",
|
"version": "1.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
|
||||||
|
|
@ -2900,7 +2927,6 @@
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||||
"dev": true,
|
|
||||||
"license": "Python-2.0"
|
"license": "Python-2.0"
|
||||||
},
|
},
|
||||||
"node_modules/array-flatten": {
|
"node_modules/array-flatten": {
|
||||||
|
|
@ -6540,6 +6566,15 @@
|
||||||
"url": "https://github.com/sponsors/antonk52"
|
"url": "https://github.com/sponsors/antonk52"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/linkify-it": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"uc.micro": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/lint-staged": {
|
"node_modules/lint-staged": {
|
||||||
"version": "16.1.2",
|
"version": "16.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.1.2.tgz",
|
||||||
|
|
@ -7057,6 +7092,23 @@
|
||||||
"@jridgewell/sourcemap-codec": "^1.5.0"
|
"@jridgewell/sourcemap-codec": "^1.5.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/markdown-it": {
|
||||||
|
"version": "14.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz",
|
||||||
|
"integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"argparse": "^2.0.1",
|
||||||
|
"entities": "^4.4.0",
|
||||||
|
"linkify-it": "^5.0.0",
|
||||||
|
"mdurl": "^2.0.0",
|
||||||
|
"punycode.js": "^2.3.1",
|
||||||
|
"uc.micro": "^2.1.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"markdown-it": "bin/markdown-it.mjs"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/math-intrinsics": {
|
"node_modules/math-intrinsics": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||||
|
|
@ -7066,6 +7118,12 @@
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mdurl": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/media-typer": {
|
"node_modules/media-typer": {
|
||||||
"version": "0.3.0",
|
"version": "0.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||||
|
|
@ -7971,6 +8029,15 @@
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/punycode.js": {
|
||||||
|
"version": "2.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
|
||||||
|
"integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/qs": {
|
"node_modules/qs": {
|
||||||
"version": "6.14.0",
|
"version": "6.14.0",
|
||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
|
||||||
|
|
@ -9634,6 +9701,12 @@
|
||||||
"typescript": ">=4.8.4 <5.9.0"
|
"typescript": ">=4.8.4 <5.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/uc.micro": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/ufo": {
|
"node_modules/ufo": {
|
||||||
"version": "1.6.1",
|
"version": "1.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz",
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
"@quasar/extras": "^1.17.0",
|
"@quasar/extras": "^1.17.0",
|
||||||
"axios": "^1.11.0",
|
"axios": "^1.11.0",
|
||||||
"chart.js": "^4.5.0",
|
"chart.js": "^4.5.0",
|
||||||
|
"markdown-it": "^14.1.0",
|
||||||
"pinia": "^3.0.3",
|
"pinia": "^3.0.3",
|
||||||
"pinia-plugin-persistedstate": "^4.4.1",
|
"pinia-plugin-persistedstate": "^4.4.1",
|
||||||
"quasar": "^2.18.2",
|
"quasar": "^2.18.2",
|
||||||
|
|
@ -29,6 +30,7 @@
|
||||||
"@eslint/js": "^9.14.0",
|
"@eslint/js": "^9.14.0",
|
||||||
"@intlify/unplugin-vue-i18n": "^4.0.0",
|
"@intlify/unplugin-vue-i18n": "^4.0.0",
|
||||||
"@quasar/app-vite": "^2.1.0",
|
"@quasar/app-vite": "^2.1.0",
|
||||||
|
"@types/markdown-it": "^14.1.2",
|
||||||
"@types/node": "^20.5.9",
|
"@types/node": "^20.5.9",
|
||||||
"@vue/eslint-config-typescript": "^14.4.0",
|
"@vue/eslint-config-typescript": "^14.4.0",
|
||||||
"@vue/test-utils": "^2.4.6",
|
"@vue/test-utils": "^2.4.6",
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,15 @@
|
||||||
export default {
|
export default {
|
||||||
|
chatbot: {
|
||||||
|
chat_header: "AI Assistant",
|
||||||
|
chat_initial_message: "Welcome to your technical assistant.\nPlease provide the Customer ID to get a diagnostic report",
|
||||||
|
chat_placeholder: "Enter a Message",
|
||||||
|
chat_thinking: "Thinking...",
|
||||||
|
error: {
|
||||||
|
NO_REPLY_RECEIVED: "encountered an error while waiting for chatbot to reply",
|
||||||
|
SEND_MESSAGE_FAILED: "unable to send message to chatbot",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
dashboard: {
|
dashboard: {
|
||||||
carousel: {
|
carousel: {
|
||||||
welcome_title: "Welcome to the new Targo Application!",
|
welcome_title: "Welcome to the new Targo Application!",
|
||||||
|
|
@ -8,6 +19,7 @@ export default {
|
||||||
},
|
},
|
||||||
useful_links: "useful links",
|
useful_links: "useful links",
|
||||||
},
|
},
|
||||||
|
|
||||||
help: {
|
help: {
|
||||||
label: "Centre d'aide",
|
label: "Centre d'aide",
|
||||||
tutorial: {
|
tutorial: {
|
||||||
|
|
@ -59,6 +71,7 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
employee_list: {
|
employee_list: {
|
||||||
page_header: "Employee Directory",
|
page_header: "Employee Directory",
|
||||||
table: {
|
table: {
|
||||||
|
|
@ -110,6 +123,7 @@ export default {
|
||||||
personal_profile: "profile",
|
personal_profile: "profile",
|
||||||
timesheets: "timesheets",
|
timesheets: "timesheets",
|
||||||
timesheets_approval: "timesheet approval",
|
timesheets_approval: "timesheet approval",
|
||||||
|
chatbot: "chatbot",
|
||||||
user_access: "module access",
|
user_access: "module access",
|
||||||
by_role: "by role",
|
by_role: "by role",
|
||||||
by_module: "by module",
|
by_module: "by module",
|
||||||
|
|
@ -127,7 +141,7 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
error :{
|
error: {
|
||||||
not_found_header: "page not found",
|
not_found_header: "page not found",
|
||||||
not_found_description: "You may have entered the wrong URL, or you may not have access to this page",
|
not_found_description: "You may have entered the wrong URL, or you may not have access to this page",
|
||||||
go_back: "go back",
|
go_back: "go back",
|
||||||
|
|
@ -369,7 +383,7 @@ export default {
|
||||||
verified: "approved",
|
verified: "approved",
|
||||||
unverified: "pending",
|
unverified: "pending",
|
||||||
inactive: "inactive",
|
inactive: "inactive",
|
||||||
regular: "regular",
|
regular: "regular",
|
||||||
evening: "evening",
|
evening: "evening",
|
||||||
emergency: "emergency",
|
emergency: "emergency",
|
||||||
overtime: "overtime",
|
overtime: "overtime",
|
||||||
|
|
@ -390,6 +404,7 @@ export default {
|
||||||
unapprove: "remove approval",
|
unapprove: "remove approval",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
descriptions: {
|
descriptions: {
|
||||||
dashboard: {
|
dashboard: {
|
||||||
menu: "To access the main menu, click the button located in the upper-left corner. This menu allows you to navigate through the entire application.",
|
menu: "To access the main menu, click the button located in the upper-left corner. This menu allows you to navigate through the entire application.",
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,15 @@
|
||||||
export default {
|
export default {
|
||||||
|
chatbot: {
|
||||||
|
chat_header: "Agent IA",
|
||||||
|
chat_initial_message: "Bienvenue à votre assistant technique.\nVeuillez fournir le ID du Client pour avoir un diagnostique",
|
||||||
|
chat_placeholder: "Entrez un Message",
|
||||||
|
chat_thinking: "Réflexion en cours...",
|
||||||
|
error: {
|
||||||
|
NO_REPLY_RECEIVED: "Une erreur est survenu lors de la réception de la réponse du chatbot",
|
||||||
|
SEND_MESSAGE_FAILED: "Une erreur est survenu lors de l'envoi de votre message",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
dashboard: {
|
dashboard: {
|
||||||
carousel: {
|
carousel: {
|
||||||
welcome_title: "Bienvenue dans la nouvelle application Targo!",
|
welcome_title: "Bienvenue dans la nouvelle application Targo!",
|
||||||
|
|
@ -8,6 +19,7 @@ export default {
|
||||||
},
|
},
|
||||||
useful_links: "liens utiles",
|
useful_links: "liens utiles",
|
||||||
},
|
},
|
||||||
|
|
||||||
help: {
|
help: {
|
||||||
label: "Centre d'aide",
|
label: "Centre d'aide",
|
||||||
tutorial: {
|
tutorial: {
|
||||||
|
|
@ -59,6 +71,7 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
employee_list: {
|
employee_list: {
|
||||||
page_header: "Répertoire du personnel",
|
page_header: "Répertoire du personnel",
|
||||||
table: {
|
table: {
|
||||||
|
|
@ -110,6 +123,7 @@ export default {
|
||||||
personal_profile: "profil personnel",
|
personal_profile: "profil personnel",
|
||||||
timesheets: "carte de temps",
|
timesheets: "carte de temps",
|
||||||
timesheets_approval: "validation cartes de temps",
|
timesheets_approval: "validation cartes de temps",
|
||||||
|
chatbot: "chatbot",
|
||||||
user_access: "module access",
|
user_access: "module access",
|
||||||
by_role: "par rôle",
|
by_role: "par rôle",
|
||||||
by_module: "par module",
|
by_module: "par module",
|
||||||
|
|
@ -200,7 +214,6 @@ export default {
|
||||||
tab_title: "horaire",
|
tab_title: "horaire",
|
||||||
selected_schedule: "Horaire Sélectionné",
|
selected_schedule: "Horaire Sélectionné",
|
||||||
new_preset: "Construire un nouvel horaire",
|
new_preset: "Construire un nouvel horaire",
|
||||||
|
|
||||||
},
|
},
|
||||||
errors: {
|
errors: {
|
||||||
must_enter_birthdate: "Vous devez entrer une date de naissance valide",
|
must_enter_birthdate: "Vous devez entrer une date de naissance valide",
|
||||||
|
|
@ -391,6 +404,7 @@ export default {
|
||||||
unapprove: "enlever status approuvé",
|
unapprove: "enlever status approuvé",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
descriptions: {
|
descriptions: {
|
||||||
dashboard: {
|
dashboard: {
|
||||||
menu: "Pour accéder au menu principal, cliquez sur le bouton situé dans le coin supérieur gauche. Ce menu vous permet de naviguer à travers l'ensemble de l'application.",
|
menu: "Pour accéder au menu principal, cliquez sur le bouton situé dans le coin supérieur gauche. Ce menu vous permet de naviguer à travers l'ensemble de l'application.",
|
||||||
|
|
@ -462,5 +476,4 @@ export default {
|
||||||
calendar: "Le calendrier facilite la navigation. Il vous permet de sélectionner une date précise et d'afficher la période de paie qui inclut cette date.",
|
calendar: "Le calendrier facilite la navigation. Il vous permet de sélectionner une date précise et d'afficher la période de paie qui inclut cette date.",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
@ -17,4 +17,4 @@
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</q-footer>
|
</q-footer>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,14 @@
|
||||||
setup
|
setup
|
||||||
>
|
>
|
||||||
import { useUiStore } from 'src/stores/ui-store';
|
import { useUiStore } from 'src/stores/ui-store';
|
||||||
|
import { useAuthStore } from 'src/stores/auth-store';
|
||||||
|
import { useChatbotStore } from 'src/stores/chatbot-store';
|
||||||
|
|
||||||
// import HeaderBarNotification from './main-layout-header-bar-notification.vue';
|
// import HeaderBarNotification from './main-layout-header-bar-notification.vue';
|
||||||
|
|
||||||
const uiStore = useUiStore();
|
const uiStore = useUiStore();
|
||||||
|
const chatbot_store = useChatbotStore();
|
||||||
|
const auth_store = useAuthStore();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -19,7 +24,11 @@
|
||||||
@click="uiStore.toggleRightDrawer"
|
@click="uiStore.toggleRightDrawer"
|
||||||
class="q-px-none"
|
class="q-px-none"
|
||||||
>
|
>
|
||||||
<q-icon name="menu" size="lg" class="q-mr-lg"/>
|
<q-icon
|
||||||
|
name="menu"
|
||||||
|
size="lg"
|
||||||
|
class="q-mr-lg"
|
||||||
|
/>
|
||||||
<q-img
|
<q-img
|
||||||
src="src/assets/logo-targo-white.svg"
|
src="src/assets/logo-targo-white.svg"
|
||||||
fit="contain"
|
fit="contain"
|
||||||
|
|
@ -28,8 +37,18 @@
|
||||||
/>
|
/>
|
||||||
</q-btn>
|
</q-btn>
|
||||||
</q-toolbar-title>
|
</q-toolbar-title>
|
||||||
|
|
||||||
<q-item class="q-pa-none">
|
<q-item class="q-pa-none">
|
||||||
<!-- <HeaderBarNotification /> -->
|
<!-- <HeaderBarNotification /> -->
|
||||||
|
<q-btn
|
||||||
|
v-if="auth_store.user?.user_module_access.includes('chatbot')"
|
||||||
|
flat
|
||||||
|
color="transparant"
|
||||||
|
icon="las la-robot"
|
||||||
|
size="lg"
|
||||||
|
@click="chatbot_store.is_showing_chatbot = !chatbot_store.is_showing_chatbot"
|
||||||
|
style="--q-icon-size: 28px; min-width: auto;"
|
||||||
|
/>
|
||||||
</q-item>
|
</q-item>
|
||||||
</q-toolbar>
|
</q-toolbar>
|
||||||
</q-header>
|
</q-header>
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
import HeaderBar from 'src/layouts/components/main-layout-header-bar.vue';
|
import HeaderBar from 'src/layouts/components/main-layout-header-bar.vue';
|
||||||
import FooterBar from 'src/layouts/components/main-layout-footer-bar.vue';
|
import FooterBar from 'src/layouts/components/main-layout-footer-bar.vue';
|
||||||
import LeftDrawer from 'src/layouts/components/main-layout-left-drawer.vue';
|
import LeftDrawer from 'src/layouts/components/main-layout-left-drawer.vue';
|
||||||
|
import ChatbotDrawer from 'src/modules/chatbot/components/chatbot-drawer.vue';
|
||||||
|
|
||||||
import { onMounted, watch, ref } from 'vue';
|
import { onMounted, watch, ref } from 'vue';
|
||||||
import { RouterView } from 'vue-router';
|
import { RouterView } from 'vue-router';
|
||||||
|
|
@ -35,10 +36,12 @@
|
||||||
|
|
||||||
<LeftDrawer />
|
<LeftDrawer />
|
||||||
|
|
||||||
|
<ChatbotDrawer />
|
||||||
|
|
||||||
<q-page-container>
|
<q-page-container>
|
||||||
<router-view />
|
<router-view />
|
||||||
</q-page-container>
|
</q-page-container>
|
||||||
|
|
||||||
<FooterBar v-if="!$q.platform.is.mobile" />
|
<FooterBar v-if="!$q.platform.is.mobile" />
|
||||||
</q-layout>
|
</q-layout>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
75
src/modules/chatbot/components/chatbot-drawer.vue
Normal file
75
src/modules/chatbot/components/chatbot-drawer.vue
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
<script
|
||||||
|
setup
|
||||||
|
lang="ts"
|
||||||
|
>
|
||||||
|
import DialogueContent from "./dialogue-content.vue";
|
||||||
|
|
||||||
|
import { onMounted, ref } from "vue";
|
||||||
|
import { useChatbotStore } from "src/stores/chatbot-store";
|
||||||
|
import { useChatbotApi } from "src/modules/chatbot/composables/chatbot-api";
|
||||||
|
|
||||||
|
const chatbot_api = useChatbotApi();
|
||||||
|
const chatbot_store = useChatbotStore();
|
||||||
|
|
||||||
|
const text = ref('');
|
||||||
|
|
||||||
|
const handleSend = async () => {
|
||||||
|
await chatbot_api.sendMessage(text.value.trim());
|
||||||
|
text.value = '';
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
chatbot_store.showInstructionsOnce();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<q-drawer
|
||||||
|
v-model="chatbot_store.is_showing_chatbot"
|
||||||
|
overlay
|
||||||
|
side="right"
|
||||||
|
:width="500"
|
||||||
|
class="column justify-end no-wrap"
|
||||||
|
>
|
||||||
|
<div class="col q-px-md relative-position">
|
||||||
|
<DialogueContent class="absolute-full" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<q-form
|
||||||
|
submit="handleSend"
|
||||||
|
class="col-auto row"
|
||||||
|
>
|
||||||
|
<q-input
|
||||||
|
v-model="text"
|
||||||
|
borderless
|
||||||
|
:label="$t('chatbot.chat_placeholder')"
|
||||||
|
:autogrow="false"
|
||||||
|
dark
|
||||||
|
label-color="white"
|
||||||
|
class="col q-px-md"
|
||||||
|
style="background: rgba(0, 0, 0, 0.3);"
|
||||||
|
@keyup.enter="handleSend"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- <q-input
|
||||||
|
v-model="custId"
|
||||||
|
:label="'Customer Id'"
|
||||||
|
:autogrow="false"
|
||||||
|
class="col"
|
||||||
|
style="margin-left: 8px;"
|
||||||
|
@keyup.enter="handleCustomerId"
|
||||||
|
/> -->
|
||||||
|
</q-form>
|
||||||
|
|
||||||
|
<!-- <div
|
||||||
|
class="drag-handle"
|
||||||
|
@mousedown.prevent="startDrag"
|
||||||
|
></div> -->
|
||||||
|
</q-drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
:deep(.q-drawer) {
|
||||||
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
47
src/modules/chatbot/components/dialogue-content.vue
Normal file
47
src/modules/chatbot/components/dialogue-content.vue
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
<script
|
||||||
|
setup
|
||||||
|
lang="ts"
|
||||||
|
>
|
||||||
|
import DialoguePhrase from './dialogue-phrase.vue';
|
||||||
|
|
||||||
|
import { ref, watch } from 'vue';
|
||||||
|
import { useChatbotStore } from 'src/stores/chatbot-store';
|
||||||
|
import type { QScrollArea } from 'quasar';
|
||||||
|
|
||||||
|
|
||||||
|
const chatbot_store = useChatbotStore();
|
||||||
|
const scroll_area = ref<QScrollArea | null>(null);
|
||||||
|
|
||||||
|
watch(chatbot_store.messages, () => {
|
||||||
|
if (scroll_area.value) {
|
||||||
|
scroll_area.value.setScrollPercentage('vertical', 1.0, 500);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<q-scroll-area ref="scroll_area">
|
||||||
|
<div
|
||||||
|
v-for="(msg, index) in chatbot_store.messages"
|
||||||
|
:key="index"
|
||||||
|
class="q-px-md"
|
||||||
|
>
|
||||||
|
<DialoguePhrase
|
||||||
|
v-if="!msg.isThinking"
|
||||||
|
:message="msg"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- thinking bubble while awaiting chatbot reply -->
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
class="row flex-center q-px-md q-py-sm"
|
||||||
|
>
|
||||||
|
<q-spinner-dots
|
||||||
|
size="20px"
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
|
<span class="q-ml-sm text-grey-7">{{ $t('chatbot.chat_thinking') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</q-scroll-area>
|
||||||
|
</template>
|
||||||
50
src/modules/chatbot/components/dialogue-phrase.vue
Normal file
50
src/modules/chatbot/components/dialogue-phrase.vue
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
<script
|
||||||
|
setup
|
||||||
|
lang="ts"
|
||||||
|
>
|
||||||
|
import { computed } from 'vue';
|
||||||
|
import MarkdownIt from 'markdown-it'
|
||||||
|
import { useAuthStore } from 'src/stores/auth-store';
|
||||||
|
import type { Message } from 'src/modules/chatbot/models/dialogue-message.model';
|
||||||
|
|
||||||
|
const {t}
|
||||||
|
const auth_store = useAuthStore();
|
||||||
|
|
||||||
|
const { message } = defineProps<{
|
||||||
|
message: Message;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
// Initialize Markdown parser
|
||||||
|
const md = new MarkdownIt({
|
||||||
|
breaks: false, // Support line breaks
|
||||||
|
linkify: true, // Make URLs clickable
|
||||||
|
html: false // Prevent raw HTML injection
|
||||||
|
})
|
||||||
|
|
||||||
|
// Removes all the h1,h2,h3 to make the Md more user friendly
|
||||||
|
const cleanMarkdown = (markdown: string): string => {
|
||||||
|
if (!markdown) return ''
|
||||||
|
return markdown
|
||||||
|
.replace(/\r\n/g, '\n') // normalize Windows line endings
|
||||||
|
.replace(/([.!?])(\s+)(?=[A-Z])/g, '$1\n') // insert line break after sentence-ending punctuation
|
||||||
|
.replace(/\n{3,}/g, '\n\n') // squash triple+ line breaks
|
||||||
|
.replace(/^#{1,3}\s(.*)$/gm, '#### $1') // downgrade headings
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute parsed content
|
||||||
|
const parsedText = computed((): string => {
|
||||||
|
const cleaned = cleanMarkdown(message.text || '')
|
||||||
|
return md.render(cleaned);
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<q-chat-message
|
||||||
|
:sent="message.sent"
|
||||||
|
:name="message.sent ? auth_store.user?.first_name : 'TargoBot'"
|
||||||
|
:bg-color="message.sent ? 'accent' : 'white'"
|
||||||
|
:text-color="message.sent ? 'white' : ''"
|
||||||
|
>
|
||||||
|
<div v-html="parsedText"></div>
|
||||||
|
</q-chat-message>
|
||||||
|
</template>
|
||||||
30
src/modules/chatbot/composables/chatbot-api.ts
Normal file
30
src/modules/chatbot/composables/chatbot-api.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
// composables/chat-api.ts
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useChatbotStore } from "src/stores/chatbot-store";
|
||||||
|
|
||||||
|
export const useChatbotApi = () => {
|
||||||
|
const chatbot_store = useChatbotStore();
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const sendMessage = async (user_message: string) => {
|
||||||
|
// push user input
|
||||||
|
chatbot_store.messages.push({
|
||||||
|
text: user_message,
|
||||||
|
sent: true,
|
||||||
|
isThinking: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
// automatically push chatbot pending reply
|
||||||
|
chatbot_store.messages.push({
|
||||||
|
text: t('chatbot.chat_thinking'),
|
||||||
|
sent: false,
|
||||||
|
isThinking: true
|
||||||
|
})
|
||||||
|
|
||||||
|
await chatbot_store.sendChatMessage(user_message);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
sendMessage,
|
||||||
|
};
|
||||||
|
};
|
||||||
5
src/modules/chatbot/models/dialogue-message.model.ts
Normal file
5
src/modules/chatbot/models/dialogue-message.model.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
export interface Message {
|
||||||
|
text: string;
|
||||||
|
sent: boolean;
|
||||||
|
isThinking: boolean;
|
||||||
|
}
|
||||||
111
src/modules/chatbot/models/page-context.model.ts
Normal file
111
src/modules/chatbot/models/page-context.model.ts
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
import { RouteNames } from "src/router/router-constants";
|
||||||
|
|
||||||
|
export interface chatbotPageContext {
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
features: string[];
|
||||||
|
path: RouteNames | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const dashboardContext: chatbotPageContext = {
|
||||||
|
name: "Dashboard",
|
||||||
|
description: "Landing page containing useful links and a carousel showcasing recent news, as well as a local weather widget in the top right corner",
|
||||||
|
features: [
|
||||||
|
"Used as a landing platform and navigate the left drawer",
|
||||||
|
"Access the AI chatbot from the header",
|
||||||
|
"Access common external tools using the links below the news Carousel",
|
||||||
|
],
|
||||||
|
path: RouteNames.DASHBOARD,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const leftDrawerContext: chatbotPageContext = {
|
||||||
|
name: "Left Drawer",
|
||||||
|
description: "A drawer that acts as a navigation bar, routes to different parts of the website. Some icons will be hidden according to user access",
|
||||||
|
features: [
|
||||||
|
"The user can navigate to the home page.",
|
||||||
|
"Can review and approve timesheets. requires access to timesheet_approval module.",
|
||||||
|
"By default, the user can see the full list of employees. Requires user_management module access to edit, add, or view detailed profiles.",
|
||||||
|
"Can access the timesheet interface to input employee hours.",
|
||||||
|
"Can access your user profile to view information or change your UI preferences (light/dark mode and display language)",
|
||||||
|
"Can access the Help page to view common Q&A regarding different modules",
|
||||||
|
"Can logout",
|
||||||
|
],
|
||||||
|
path: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const profileContext: chatbotPageContext = {
|
||||||
|
name: "Profile",
|
||||||
|
description: "Display and edit user information",
|
||||||
|
features: [
|
||||||
|
"View personal information such as first and last name, phone, birthdate and address.",
|
||||||
|
"View Career information such as job title, company, supervisor, email and hiring date.",
|
||||||
|
"Edit available preferences such as Display options of light and dark mode, as well as display language",
|
||||||
|
],
|
||||||
|
path: RouteNames.PROFILE,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const employeeListContext: chatbotPageContext = {
|
||||||
|
name: "Employee List",
|
||||||
|
description: "View all the hired and currently active Staff",
|
||||||
|
features: [
|
||||||
|
"View the list of hired and active employees",
|
||||||
|
"Access an individual employee's detailed profile if user has user_management module access",
|
||||||
|
"Add, edit, or remove an employee if user has user_management module access",
|
||||||
|
"Add, edit, or remove module access for any given employee if user has user_managmenet module access",
|
||||||
|
"Add, edit, or remove schedule presets and assign those presets to employees. These presets can then be applied to the employee's timesheet with a single click. Requires user_management module access."
|
||||||
|
],
|
||||||
|
path: RouteNames.EMPLOYEE_LIST,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const timesheetApprovalContext: chatbotPageContext = {
|
||||||
|
name: "Timesheet Approval",
|
||||||
|
description: "Page where employee hours and shifts are approved for accounting purposes. Requires timesheet_approval module access.",
|
||||||
|
features: [
|
||||||
|
"See a grid or list view of total hours for all employees in the given 2-week pay period.",
|
||||||
|
"Access different periods thanks to the pay period navigator buttons (previous, next, date picker)",
|
||||||
|
"Approve the hours for the cards displayed.",
|
||||||
|
"Open a detailed dialog window for any employee",
|
||||||
|
"The detailed dialog window includes bar and circle charts to visually see employee hours worked daily, the type of shifts worked, and expenses accrued",
|
||||||
|
"The detailed dialog window allows the user to edit the any employee's timesheets or expenses",
|
||||||
|
],
|
||||||
|
path: RouteNames.TIMESHEET_APPROVALS,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const timesheetContext: chatbotPageContext = {
|
||||||
|
name: "Timesheet",
|
||||||
|
description:
|
||||||
|
"Page where an employee can enter their hours for their day and week. Display in 2-week pay periods.",
|
||||||
|
features: [
|
||||||
|
"Enter your in and out times per day",
|
||||||
|
"Add and edit what kind of hours your shift was example regular, overtime, vacation etc.",
|
||||||
|
"Edit your own shift hours",
|
||||||
|
"Delete your shift hours",
|
||||||
|
"List your expenses for the week",
|
||||||
|
"Add expenses for the week, along with attached files for said expenses",
|
||||||
|
],
|
||||||
|
path: RouteNames.TIMESHEET,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const helpContext: chatbotPageContext = {
|
||||||
|
name: "Help",
|
||||||
|
description: "page containing common Q&A segments regarding website functionalities",
|
||||||
|
features: [
|
||||||
|
"Browse by module for common questions and answers",
|
||||||
|
"The modules displayed will only be those the user has access to.",
|
||||||
|
"Each module consists of a series of Expanding Items. Clicking on a question item reveals the answer beneath.",
|
||||||
|
"Each Expanding Item also has its own support image that appears next to the items.",
|
||||||
|
],
|
||||||
|
path: RouteNames.HELP,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PageContexts: Record<RouteNames, chatbotPageContext | null> = {
|
||||||
|
"login": null,
|
||||||
|
"login-success": null,
|
||||||
|
"error": null,
|
||||||
|
"/": dashboardContext,
|
||||||
|
"employees": employeeListContext,
|
||||||
|
"profile": profileContext,
|
||||||
|
"timesheet": timesheetContext,
|
||||||
|
"timesheet-approvals": timesheetApprovalContext,
|
||||||
|
"help": helpContext,
|
||||||
|
}
|
||||||
15
src/modules/chatbot/pages/chatbot-page.vue
Normal file
15
src/modules/chatbot/pages/chatbot-page.vue
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import ConversationBox from "../components/conversation-box.vue";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<ConversationBox></ConversationBox>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.box-settings {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
28
src/modules/chatbot/services/chatbot.service.ts
Normal file
28
src/modules/chatbot/services/chatbot.service.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
import type { chatbotPageContext } from "src/modules/chatbot/models/page-context.model";
|
||||||
|
import type { Message } from "src/modules/chatbot/models/dialogue-message.model";
|
||||||
|
import { api } from "src/boot/axios";
|
||||||
|
|
||||||
|
export const chatbotService = {
|
||||||
|
// Function to send the message to the backend
|
||||||
|
sendChatMessage: async (userInput: string): Promise<Message> => {
|
||||||
|
const response = await api.post("/chatbot", { userInput });
|
||||||
|
return response.data as Message;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Function to send context to backend
|
||||||
|
sendPageContext: async (context: chatbotPageContext): Promise<string> => {
|
||||||
|
const response = await api.post("/chatbot/context", context);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Function to send user credentials to the backend to communicate with n8n.
|
||||||
|
sendUserCredentials: async (email: string, role: string): Promise<boolean> => {
|
||||||
|
const response = await api.post("/chatbot/user", { email, role });
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
retrieveCustomerDiagnostics: async (id: string): Promise<string> => {
|
||||||
|
const response = await api.get(`/chat/customer/${id}`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
@ -128,6 +128,7 @@ export const employee_access_options: QSelectOption<UserModuleAccess>[] = [
|
||||||
{ label: 'timesheets', value: 'timesheets' },
|
{ label: 'timesheets', value: 'timesheets' },
|
||||||
{ label: 'employee_management', value: 'employee_management' },
|
{ label: 'employee_management', value: 'employee_management' },
|
||||||
{ label: 'timesheets_approval', value: 'timesheets_approval' },
|
{ label: 'timesheets_approval', value: 'timesheets_approval' },
|
||||||
|
{ label: 'chatbot', value: 'chatbot' },
|
||||||
]
|
]
|
||||||
|
|
||||||
export const employee_access_presets: Record<ModuleAccessPreset, UserModuleAccess[]> = {
|
export const employee_access_presets: Record<ModuleAccessPreset, UserModuleAccess[]> = {
|
||||||
|
|
@ -145,5 +146,6 @@ export const getEmployeeAccessOptionIcon = (module: UserModuleAccess): string =>
|
||||||
case 'personal_profile': return 'las la-id-card';
|
case 'personal_profile': return 'las la-id-card';
|
||||||
case 'timesheets': return 'punch_clock';
|
case 'timesheets': return 'punch_clock';
|
||||||
case 'timesheets_approval': return 'event_available';
|
case 'timesheets_approval': return 'event_available';
|
||||||
|
case 'chatbot': return 'las la-robot';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
employee_list: default_employee_list,
|
employee_list: default_employee_list,
|
||||||
employee_management: default_employee_management,
|
employee_management: default_employee_management,
|
||||||
timesheets_approval: default_validation_page,
|
timesheets_approval: default_validation_page,
|
||||||
|
chatbot: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
import type { HelpModuleOptions } from 'src/modules/help/models/help-module.model';
|
import type { HelpModuleOptions } from 'src/modules/help/models/help-module.model';
|
||||||
|
|
|
||||||
|
|
@ -134,9 +134,6 @@ export const timesheets_approval_options: HelpModuleOptions[] = [
|
||||||
{ label: 'help.tutorial.shared.calendar', path: calendar, description: calendar_nav_desc, icon: 'calendar_month' },
|
{ label: 'help.tutorial.shared.calendar', path: calendar, description: calendar_nav_desc, icon: 'calendar_month' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const help_module_details: Options = {
|
export const help_module_details: Options = {
|
||||||
dashboard: [],
|
dashboard: [],
|
||||||
personal_profile: profile_options,
|
personal_profile: profile_options,
|
||||||
|
|
@ -144,6 +141,7 @@ export const help_module_details: Options = {
|
||||||
employee_list: employee_list_options,
|
employee_list: employee_list_options,
|
||||||
employee_management: employee_management_options,
|
employee_management: employee_management_options,
|
||||||
timesheets_approval: timesheets_approval_options,
|
timesheets_approval: timesheets_approval_options,
|
||||||
|
chatbot: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ export const ModuleNames = {
|
||||||
PERSONAL_PROFILE: 'personal_profile',
|
PERSONAL_PROFILE: 'personal_profile',
|
||||||
TIMESHEETS: 'timesheets',
|
TIMESHEETS: 'timesheets',
|
||||||
TIMESHEETS_APPROVAL: 'timesheets_approval',
|
TIMESHEETS_APPROVAL: 'timesheets_approval',
|
||||||
|
CHATBOT: 'chatbot',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export type UserModuleAccess = typeof ModuleNames[keyof typeof ModuleNames];
|
export type UserModuleAccess = typeof ModuleNames[keyof typeof ModuleNames];
|
||||||
|
|
@ -4,8 +4,8 @@
|
||||||
>
|
>
|
||||||
import MenuEmployee from 'src/modules/profile/components/employee/menu-employee.vue';
|
import MenuEmployee from 'src/modules/profile/components/employee/menu-employee.vue';
|
||||||
import { useAuthStore } from 'src/stores/auth-store';
|
import { useAuthStore } from 'src/stores/auth-store';
|
||||||
import { useEmployeeStore } from 'src/stores/employee-store';
|
import { useEmployeeStore } from 'src/stores/employee-store';
|
||||||
import { onMounted } from 'vue';
|
import { onMounted } from 'vue';
|
||||||
|
|
||||||
const auth_store = useAuthStore();
|
const auth_store = useAuthStore();
|
||||||
const employee_store = useEmployeeStore();
|
const employee_store = useEmployeeStore();
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@
|
||||||
const { user } = useAuthStore();
|
const { user } = useAuthStore();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-page
|
<q-page
|
||||||
class="column bg-secondary items-center"
|
class="column bg-secondary items-center"
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { createMemoryHistory, createRouter, createWebHashHistory, createWebHisto
|
||||||
import routes from './routes';
|
import routes from './routes';
|
||||||
import { useAuthStore } from 'src/stores/auth-store';
|
import { useAuthStore } from 'src/stores/auth-store';
|
||||||
import { RouteNames } from 'src/router/router-constants';
|
import { RouteNames } from 'src/router/router-constants';
|
||||||
|
import { useChatbotStore } from 'src/stores/chatbot-store';
|
||||||
import type { UserModuleAccess } from 'src/modules/shared/models/user.models';
|
import type { UserModuleAccess } from 'src/modules/shared/models/user.models';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -44,5 +45,14 @@ export default defineRouter(function (/* { store, ssrContext } */) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Router.afterEach( async (destination_page) => {
|
||||||
|
const auth_store = useAuthStore();
|
||||||
|
|
||||||
|
if (auth_store.user?.user_module_access.includes('chatbot')) {
|
||||||
|
const chatbot_store = useChatbotStore();
|
||||||
|
await chatbot_store.updatePageContext(destination_page.name as RouteNames);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return Router;
|
return Router;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
59
src/stores/chatbot-store.ts
Normal file
59
src/stores/chatbot-store.ts
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { defineStore } from "pinia";
|
||||||
|
import { chatbotService } from "src/modules/chatbot/services/chatbot.service";
|
||||||
|
import type { Message } from "src/modules/chatbot/models/dialogue-message.model";
|
||||||
|
import type { RouteNames } from "src/router/router-constants";
|
||||||
|
import { PageContexts } from "src/modules/chatbot/models/page-context.model";
|
||||||
|
|
||||||
|
export const useChatbotStore = defineStore("chatbot", () => {
|
||||||
|
const messages = ref<Message[]>([]);
|
||||||
|
const has_shown_instructions = ref(false);
|
||||||
|
const is_showing_chatbot = ref(false);
|
||||||
|
|
||||||
|
const sendChatMessage = async (user_message: string) => {
|
||||||
|
const last_chatbot_message = messages.value.at(messages.value.length - 1)!;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const chatbot_response = await chatbotService.sendChatMessage(user_message);
|
||||||
|
if (chatbot_response) {
|
||||||
|
last_chatbot_message.text = chatbot_response.text;
|
||||||
|
last_chatbot_message.isThinking = false;
|
||||||
|
} else {
|
||||||
|
last_chatbot_message.text = 'chatbot.error.NO_REPLY_RECEIVED';
|
||||||
|
last_chatbot_message.isThinking = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
last_chatbot_message.text = 'chatbot.error.SEND_MESSAGE_FAILED';
|
||||||
|
last_chatbot_message.isThinking = false;
|
||||||
|
console.error('error sending message: ', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const updatePageContext = async (page_name: RouteNames) => {
|
||||||
|
const chatbot_page_context = PageContexts[page_name];
|
||||||
|
|
||||||
|
if (chatbot_page_context)
|
||||||
|
await chatbotService.sendPageContext(chatbot_page_context);
|
||||||
|
};
|
||||||
|
|
||||||
|
const showInstructionsOnce = () => {
|
||||||
|
if (!has_shown_instructions.value) {
|
||||||
|
messages.value.push({
|
||||||
|
text: "chatbot.chat_initial_message",
|
||||||
|
sent: false,
|
||||||
|
isThinking: false,
|
||||||
|
});
|
||||||
|
has_shown_instructions.value = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
messages,
|
||||||
|
has_shown_instructions,
|
||||||
|
is_showing_chatbot,
|
||||||
|
sendChatMessage,
|
||||||
|
updatePageContext,
|
||||||
|
showInstructionsOnce,
|
||||||
|
};
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue
Block a user