contactstudiocstools 1.0.224
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +94 -0
- package/dist/module.cjs +5 -0
- package/dist/module.d.ts +7 -0
- package/dist/module.json +5 -0
- package/dist/module.mjs +72 -0
- package/dist/runtime/components/Atom.Alert.vue +46 -0
- package/dist/runtime/components/Atom.Auth.vue +37 -0
- package/dist/runtime/components/Atom.BannerChatEmpty.vue +18 -0
- package/dist/runtime/components/Atom.BannerPage404.vue +28 -0
- package/dist/runtime/components/Atom.BannerPageUnauthorized.vue +18 -0
- package/dist/runtime/components/Atom.Breadcrumb.vue +26 -0
- package/dist/runtime/components/Atom.ChatContact.vue +136 -0
- package/dist/runtime/components/Atom.ChatContactSchedule.vue +87 -0
- package/dist/runtime/components/Atom.ChatMessageFooter.vue +25 -0
- package/dist/runtime/components/Atom.DarkMode.vue +67 -0
- package/dist/runtime/components/Atom.DraggableWindow.vue +102 -0
- package/dist/runtime/components/Atom.Dropdown.vue +9 -0
- package/dist/runtime/components/Atom.DropdownSearchable.vue +25 -0
- package/dist/runtime/components/Atom.Fetch.vue +46 -0
- package/dist/runtime/components/Atom.Field.vue +43 -0
- package/dist/runtime/components/Atom.FieldDate.vue +19 -0
- package/dist/runtime/components/Atom.FieldNumber.vue +19 -0
- package/dist/runtime/components/Atom.FieldPhone.vue +92 -0
- package/dist/runtime/components/Atom.FieldSelect.vue +28 -0
- package/dist/runtime/components/Atom.FieldSelectMultiple.vue +49 -0
- package/dist/runtime/components/Atom.FieldText.vue +19 -0
- package/dist/runtime/components/Atom.FieldTextarea.vue +41 -0
- package/dist/runtime/components/Atom.Loading.vue +80 -0
- package/dist/runtime/components/Atom.Notification.vue +48 -0
- package/dist/runtime/components/Atom.Ringtone.vue +23 -0
- package/dist/runtime/components/Atom.SelectTreeField.vue +49 -0
- package/dist/runtime/components/Atom.Snapshot.vue +33 -0
- package/dist/runtime/components/Atom.Tabs.vue +60 -0
- package/dist/runtime/components/Molecule.ChatMessageFile.vue +102 -0
- package/dist/runtime/components/Molecule.ChatMessageOption.vue +85 -0
- package/dist/runtime/components/Molecule.ChatMessageText.vue +36 -0
- package/dist/runtime/components/Molecule.ClientHistory.vue +62 -0
- package/dist/runtime/components/Molecule.DropdownDDI.vue +333 -0
- package/dist/runtime/components/Molecule.FieldGroup.vue +73 -0
- package/dist/runtime/components/Molecule.FieldSelectMultiple.vue +19 -0
- package/dist/runtime/components/Molecule.File.vue +84 -0
- package/dist/runtime/components/Molecule.SelectTreeSearchable.vue +126 -0
- package/dist/runtime/components/Molecule.Status.vue +154 -0
- package/dist/runtime/components/Molecule.TimeDaily.vue +9 -0
- package/dist/runtime/components/Organism.Attachments.vue +139 -0
- package/dist/runtime/components/Organism.ChatMessages.vue +31 -0
- package/dist/runtime/components/Organism.ChatRoom.vue +342 -0
- package/dist/runtime/components/Organism.ChatSchedule.vue +110 -0
- package/dist/runtime/components/Organism.ClientHistoryTable.vue +85 -0
- package/dist/runtime/components/Organism.ClientHistoryTimeline.vue +77 -0
- package/dist/runtime/components/Organism.FAQ.vue +88 -0
- package/dist/runtime/components/Organism.Form.vue +67 -0
- package/dist/runtime/components/Organism.FormMailing.vue +112 -0
- package/dist/runtime/components/Organism.HeaderMain.vue +79 -0
- package/dist/runtime/components/Organism.Manifestation.vue +146 -0
- package/dist/runtime/components/Organism.Nav.vue +27 -0
- package/dist/runtime/components/Organism.NavMain.vue +187 -0
- package/dist/runtime/components/Organism.PageContainer.vue +22 -0
- package/dist/runtime/components/Organism.Schedule.vue +170 -0
- package/dist/runtime/components/Organism.Tabulation.vue +237 -0
- package/dist/runtime/components/types/dto.d.ts +16 -0
- package/dist/runtime/components/types/dto.mjs +236 -0
- package/dist/runtime/components/types/helpers.d.ts +39 -0
- package/dist/runtime/components/types/helpers.mjs +295 -0
- package/dist/runtime/components/types/index.d.ts +4 -0
- package/dist/runtime/components/types/index.mjs +4 -0
- package/dist/runtime/components/types/types.d.ts +198 -0
- package/dist/runtime/components/types/types.mjs +35 -0
- package/dist/runtime/index.css +1 -0
- package/dist/runtime/plugins/clickOutside.d.ts +2 -0
- package/dist/runtime/plugins/clickOutside.mjs +16 -0
- package/dist/runtime/plugins/emitter.d.ts +2 -0
- package/dist/runtime/plugins/emitter.mjs +17 -0
- package/dist/runtime/public/192x192.png +0 -0
- package/dist/runtime/public/404.svg +1 -0
- package/dist/runtime/public/512x512.png +0 -0
- package/dist/runtime/public/chat.svg +138 -0
- package/dist/runtime/public/chatbg.png +0 -0
- package/dist/runtime/public/dev-sw.d.ts +0 -0
- package/dist/runtime/public/dev-sw.mjs +0 -0
- package/dist/runtime/public/empty.svg +1 -0
- package/dist/runtime/public/loading.svg +1 -0
- package/dist/runtime/public/messages.svg +1 -0
- package/dist/runtime/public/privacy.svg +1 -0
- package/dist/runtime/public/ringtone.mp3 +0 -0
- package/dist/runtime/public/security.svg +188 -0
- package/dist/runtime/public/snapshot.d.ts +15 -0
- package/dist/runtime/public/snapshot.mjs +77 -0
- package/dist/runtime/public/unauthorized.svg +1 -0
- package/dist/types.d.ts +10 -0
- package/package.json +50 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<label class="input max-h-none flex cursor-pointer justify-between">
|
|
3
|
+
<span
|
|
4
|
+
v-if="nodesIsEmpty"
|
|
5
|
+
class="pl-2"
|
|
6
|
+
>Selecione</span>
|
|
7
|
+
|
|
8
|
+
<div class="flex flex-wrap">
|
|
9
|
+
<span
|
|
10
|
+
v-for="(node, i) in nodes"
|
|
11
|
+
:key="i"
|
|
12
|
+
class="badge badge-soft-secondary mx-1 my-1 leading-3"
|
|
13
|
+
@click="del(node)"
|
|
14
|
+
>
|
|
15
|
+
<span v-text="node.label" />
|
|
16
|
+
<i class="bi-x-circle-fill text-red-500 ml-2" />
|
|
17
|
+
</span>
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
<i class="bi-chevron-down ml-4" />
|
|
21
|
+
</label>
|
|
22
|
+
</template>
|
|
23
|
+
|
|
24
|
+
<script setup lang="ts">
|
|
25
|
+
import { computed } from "vue";
|
|
26
|
+
import { INodes, INode } from "./types";
|
|
27
|
+
|
|
28
|
+
// props
|
|
29
|
+
interface IProps {
|
|
30
|
+
nodes: INodes;
|
|
31
|
+
}
|
|
32
|
+
const props = defineProps<IProps>();
|
|
33
|
+
|
|
34
|
+
// emits
|
|
35
|
+
interface IEmits {
|
|
36
|
+
(e: "delete", node: INode): void;
|
|
37
|
+
}
|
|
38
|
+
const emit = defineEmits<IEmits>();
|
|
39
|
+
|
|
40
|
+
// computed
|
|
41
|
+
const nodesIsEmpty = computed<boolean>(() => !props.nodes.length);
|
|
42
|
+
|
|
43
|
+
// methods
|
|
44
|
+
function del(node: INode): void {
|
|
45
|
+
emit("delete", node);
|
|
46
|
+
}
|
|
47
|
+
</script>
|
|
48
|
+
|
|
49
|
+
<style scoped></style>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div />
|
|
3
|
+
</template>
|
|
4
|
+
|
|
5
|
+
<script setup lang="ts">
|
|
6
|
+
import { onMounted } from "vue";
|
|
7
|
+
import { logout } from "./types";
|
|
8
|
+
import { useNuxtApp, useRuntimeConfig } from "#app";
|
|
9
|
+
|
|
10
|
+
// data
|
|
11
|
+
const { $emit } = useNuxtApp();
|
|
12
|
+
const { BASE_URL } = useRuntimeConfig().public;
|
|
13
|
+
|
|
14
|
+
// methods
|
|
15
|
+
function initSnapshot(): void {
|
|
16
|
+
const snapshot = new Worker(`${BASE_URL}/snapshot.js`);
|
|
17
|
+
snapshot.postMessage("");
|
|
18
|
+
snapshot.onmessage = ({ data }) => {
|
|
19
|
+
if (data.error) {
|
|
20
|
+
logout();
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
$emit("snapshot:update", data.data);
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
onMounted(() => {
|
|
29
|
+
initSnapshot();
|
|
30
|
+
});
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<style scoped></style>
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<ul class="tabs sticky top-0 bg-white dark:bg-slate-900 z-10">
|
|
4
|
+
<template v-for="(show, tab) in tabs">
|
|
5
|
+
<li
|
|
6
|
+
v-if="show"
|
|
7
|
+
:key="tab"
|
|
8
|
+
:class="{ active: tab === tabActive }"
|
|
9
|
+
class="tab"
|
|
10
|
+
@click="change(tab)"
|
|
11
|
+
>
|
|
12
|
+
<slot :name="`h${tab}`" />
|
|
13
|
+
</li>
|
|
14
|
+
</template>
|
|
15
|
+
</ul>
|
|
16
|
+
|
|
17
|
+
<article>
|
|
18
|
+
<template v-for="(show, tab) in tabs">
|
|
19
|
+
<div
|
|
20
|
+
v-if="show"
|
|
21
|
+
v-show="tab === tabActive"
|
|
22
|
+
:key="tab"
|
|
23
|
+
>
|
|
24
|
+
<slot :name="tab" />
|
|
25
|
+
</div>
|
|
26
|
+
</template>
|
|
27
|
+
</article>
|
|
28
|
+
</div>
|
|
29
|
+
</template>
|
|
30
|
+
|
|
31
|
+
<script setup lang="ts">
|
|
32
|
+
import { ref } from "vue";
|
|
33
|
+
|
|
34
|
+
// props
|
|
35
|
+
interface IProps {
|
|
36
|
+
tabs: { [index: string]: boolean };
|
|
37
|
+
}
|
|
38
|
+
const props = defineProps<IProps>();
|
|
39
|
+
|
|
40
|
+
// emits
|
|
41
|
+
interface IEmits {
|
|
42
|
+
(e: "change", tab: string): void;
|
|
43
|
+
}
|
|
44
|
+
const emit = defineEmits<IEmits>();
|
|
45
|
+
|
|
46
|
+
// data
|
|
47
|
+
const tabActive = ref<string>(Object.keys(props.tabs)[0]);
|
|
48
|
+
|
|
49
|
+
// methods
|
|
50
|
+
function change(tab: string | number): void {
|
|
51
|
+
if (typeof tab === "number") return
|
|
52
|
+
tabActive.value = tab;
|
|
53
|
+
emit("change", tab);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// expose
|
|
57
|
+
defineExpose({ change });
|
|
58
|
+
</script>
|
|
59
|
+
|
|
60
|
+
<style scoped></style>
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
:class="getTypeClass"
|
|
4
|
+
class="text-xs p-2 m-2"
|
|
5
|
+
>
|
|
6
|
+
<audio
|
|
7
|
+
v-if="isAudioFile"
|
|
8
|
+
controls
|
|
9
|
+
autobuffer
|
|
10
|
+
class="h-8 max-w-full"
|
|
11
|
+
>
|
|
12
|
+
<source
|
|
13
|
+
:src="message.primitive.content.message.url"
|
|
14
|
+
type="audio/ogg"
|
|
15
|
+
>
|
|
16
|
+
</audio>
|
|
17
|
+
<MoleculeFile
|
|
18
|
+
v-else
|
|
19
|
+
:file="attachment.file"
|
|
20
|
+
:status="attachment.status"
|
|
21
|
+
class="w-full"
|
|
22
|
+
/>
|
|
23
|
+
<AtomChatMessageFooter
|
|
24
|
+
:message="message"
|
|
25
|
+
class="mt-2"
|
|
26
|
+
/>
|
|
27
|
+
</div>
|
|
28
|
+
</template>
|
|
29
|
+
|
|
30
|
+
<script setup lang="ts">
|
|
31
|
+
import { onMounted, computed, reactive } from "vue";
|
|
32
|
+
import { IChatMessage, EFieldStatus, logger } from "./types";
|
|
33
|
+
|
|
34
|
+
// props
|
|
35
|
+
interface IProps {
|
|
36
|
+
message: IChatMessage;
|
|
37
|
+
}
|
|
38
|
+
const props = defineProps<IProps>();
|
|
39
|
+
|
|
40
|
+
// mounted
|
|
41
|
+
onMounted(async () => {
|
|
42
|
+
try {
|
|
43
|
+
await getFileData();
|
|
44
|
+
} catch (e) {
|
|
45
|
+
logger.error("AtomChatMessageFile:GetFileData", { e });
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// computed
|
|
50
|
+
const getTypeClass = computed<string>(() => {
|
|
51
|
+
if (props.message.primary)
|
|
52
|
+
return "primary badge badge-soft-secondary ml-14 float-right";
|
|
53
|
+
return "badge badge-outline-secondary mr-14 float-left bg-white dark:bg-slate-900";
|
|
54
|
+
});
|
|
55
|
+
const isAudioFile = computed<boolean>(
|
|
56
|
+
() => !!props.message.primitive.content.message.content_type.match(/audio/)
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
// data
|
|
60
|
+
const attachment = reactive<any>({
|
|
61
|
+
ID: props.message.primitive.message_id,
|
|
62
|
+
file: new File([], ""),
|
|
63
|
+
status: EFieldStatus.loading,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// methods
|
|
67
|
+
async function getFileData(): Promise<void> {
|
|
68
|
+
const url = props.message.primitive.content.message.url;
|
|
69
|
+
const caption = props.message.primitive.content.message.caption;
|
|
70
|
+
const type = props.message.primitive.content.message.content_type;
|
|
71
|
+
const res = await fetch(url);
|
|
72
|
+
const blob = await res.blob();
|
|
73
|
+
attachment.file = new File([blob], caption, { type });
|
|
74
|
+
attachment.status = EFieldStatus.none;
|
|
75
|
+
}
|
|
76
|
+
</script>
|
|
77
|
+
|
|
78
|
+
<style scoped>
|
|
79
|
+
audio::-webkit-media-controls-play-button,
|
|
80
|
+
audio::-webkit-media-controls-panel {
|
|
81
|
+
background-color: white;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.primary audio::-webkit-media-controls-play-button,
|
|
85
|
+
.primary audio::-webkit-media-controls-panel {
|
|
86
|
+
background-color: #f1f5f9;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.dark audio {
|
|
90
|
+
color-scheme: dark;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.dark audio::-webkit-media-controls-play-button,
|
|
94
|
+
.dark audio::-webkit-media-controls-panel {
|
|
95
|
+
background-color: #0f172a;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.dark .primary audio::-webkit-media-controls-play-button,
|
|
99
|
+
.dark .primary audio::-webkit-media-controls-panel {
|
|
100
|
+
background-color: #1e293b;
|
|
101
|
+
}
|
|
102
|
+
</style>
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
:class="getPositionClass"
|
|
4
|
+
class="text-xs"
|
|
5
|
+
>
|
|
6
|
+
<!-- message -->
|
|
7
|
+
<article
|
|
8
|
+
:class="getBadgeClass"
|
|
9
|
+
class="p-2 m-2 mb-1"
|
|
10
|
+
>
|
|
11
|
+
<div
|
|
12
|
+
class="markdown whitespace-pre-wrap"
|
|
13
|
+
v-html="marked(message.primitive.content.message.caption || '')"
|
|
14
|
+
/>
|
|
15
|
+
<AtomChatMessageFooter
|
|
16
|
+
:message="message"
|
|
17
|
+
class="-mt-2"
|
|
18
|
+
/>
|
|
19
|
+
</article>
|
|
20
|
+
|
|
21
|
+
<!-- options -->
|
|
22
|
+
<aside
|
|
23
|
+
:disabled="selected"
|
|
24
|
+
class="flex flex-wrap gap-1 mx-2"
|
|
25
|
+
>
|
|
26
|
+
<button
|
|
27
|
+
v-for="(option, i) in getOptions"
|
|
28
|
+
:key="i"
|
|
29
|
+
:class="getButtonClass"
|
|
30
|
+
class="text-center flex-auto p-2"
|
|
31
|
+
@click="select(option)"
|
|
32
|
+
v-text="option.label"
|
|
33
|
+
/>
|
|
34
|
+
</aside>
|
|
35
|
+
</div>
|
|
36
|
+
</template>
|
|
37
|
+
|
|
38
|
+
<script setup lang="ts">
|
|
39
|
+
import { marked } from "marked";
|
|
40
|
+
import { computed, ref } from "vue";
|
|
41
|
+
import { IChatMessage, IFieldSelectOption, IFieldSelectOptions } from "./types";
|
|
42
|
+
|
|
43
|
+
// props
|
|
44
|
+
interface IProps {
|
|
45
|
+
message: IChatMessage;
|
|
46
|
+
}
|
|
47
|
+
const props = defineProps<IProps>();
|
|
48
|
+
|
|
49
|
+
// emits
|
|
50
|
+
interface IEmits {
|
|
51
|
+
(e: "select", option: IFieldSelectOption): void;
|
|
52
|
+
}
|
|
53
|
+
const emit = defineEmits<IEmits>();
|
|
54
|
+
|
|
55
|
+
// computed
|
|
56
|
+
const getPositionClass = computed<string>(() => {
|
|
57
|
+
if (props.message.primary) return "float-right ml-14";
|
|
58
|
+
return "float-left mr-14";
|
|
59
|
+
});
|
|
60
|
+
const getBadgeClass = computed<string>(() => {
|
|
61
|
+
if (props.message.primary) return "badge badge-soft-secondary";
|
|
62
|
+
return "badge badge-outline-secondary bg-white dark:bg-slate-900";
|
|
63
|
+
});
|
|
64
|
+
const getButtonClass = computed<string>(() => {
|
|
65
|
+
if (props.message.primary) return "btn btn-soft-primary";
|
|
66
|
+
return "btn btn-outline-primary bg-white dark:bg-slate-900";
|
|
67
|
+
});
|
|
68
|
+
const getOptions = computed<IFieldSelectOptions>(() => {
|
|
69
|
+
const options = props.message.primitive.content.message.options;
|
|
70
|
+
return options.map(({ text, value }: any) => ({
|
|
71
|
+
label: text,
|
|
72
|
+
value,
|
|
73
|
+
}));
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// data
|
|
77
|
+
const selected = ref<boolean>(!!props.message.selected);
|
|
78
|
+
|
|
79
|
+
function select(option: IFieldSelectOption): void {
|
|
80
|
+
selected.value = true;
|
|
81
|
+
emit("select", option);
|
|
82
|
+
}
|
|
83
|
+
</script>
|
|
84
|
+
|
|
85
|
+
<style scoped></style>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
:class="getTypeClass"
|
|
4
|
+
class="text-xs p-2 m-2"
|
|
5
|
+
>
|
|
6
|
+
<div
|
|
7
|
+
class="markdown whitespace-pre-wrap"
|
|
8
|
+
v-html="marked(message.primitive.content.message.text || '')"
|
|
9
|
+
/>
|
|
10
|
+
<AtomChatMessageFooter
|
|
11
|
+
:message="message"
|
|
12
|
+
class="-mt-2"
|
|
13
|
+
/>
|
|
14
|
+
</div>
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<script setup lang="ts">
|
|
18
|
+
import { computed } from "vue";
|
|
19
|
+
import { marked } from "marked";
|
|
20
|
+
import { IChatMessage } from "./types";
|
|
21
|
+
|
|
22
|
+
// props
|
|
23
|
+
interface IProps {
|
|
24
|
+
message: IChatMessage;
|
|
25
|
+
}
|
|
26
|
+
const props = defineProps<IProps>();
|
|
27
|
+
|
|
28
|
+
// computed
|
|
29
|
+
const getTypeClass = computed<string>(() => {
|
|
30
|
+
if (props.message.primary)
|
|
31
|
+
return "badge badge-soft-secondary ml-14 float-right";
|
|
32
|
+
return "badge badge-outline-secondary mr-14 float-left bg-white dark:bg-slate-900";
|
|
33
|
+
});
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<style scoped></style>
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
v-if="!histories.length"
|
|
4
|
+
class="w-full text-center mt-4"
|
|
5
|
+
>
|
|
6
|
+
Nenhuma ocorrĂȘncia encontrada
|
|
7
|
+
</div>
|
|
8
|
+
<section
|
|
9
|
+
v-else
|
|
10
|
+
class="p-4"
|
|
11
|
+
>
|
|
12
|
+
<template
|
|
13
|
+
v-for="(tab, i) in tabs"
|
|
14
|
+
:key="i"
|
|
15
|
+
>
|
|
16
|
+
<span
|
|
17
|
+
v-show="tab === tabActive"
|
|
18
|
+
class="badge badge-outline-secondary bg-slate-100 dark:bg-slate-800 float-right cursor-pointer text-xs py-1.5 !rounded-tl-none !rounded-bl-none"
|
|
19
|
+
@click="change(tab)"
|
|
20
|
+
>
|
|
21
|
+
<i class="bi bi-arrow-left-right" />
|
|
22
|
+
</span>
|
|
23
|
+
|
|
24
|
+
<span
|
|
25
|
+
v-show="tab === tabActive"
|
|
26
|
+
class="badge badge-outline-secondary float-right cursor-pointer text-xs py-1.5 !border-r-0 dark:!border-r-0 !rounded-tr-none !rounded-br-none"
|
|
27
|
+
@click="change(tab)"
|
|
28
|
+
>
|
|
29
|
+
<slot :name="`h${tab}`" />
|
|
30
|
+
</span>
|
|
31
|
+
|
|
32
|
+
<article v-show="tab === tabActive">
|
|
33
|
+
<slot :name="tab" />
|
|
34
|
+
</article>
|
|
35
|
+
</template>
|
|
36
|
+
</section>
|
|
37
|
+
</template>
|
|
38
|
+
|
|
39
|
+
<script setup lang="ts">
|
|
40
|
+
import { ref } from "vue";
|
|
41
|
+
import { IClientHistories } from "./types";
|
|
42
|
+
|
|
43
|
+
// props
|
|
44
|
+
interface IProps {
|
|
45
|
+
histories: IClientHistories;
|
|
46
|
+
tabs: string[];
|
|
47
|
+
}
|
|
48
|
+
const props = defineProps<IProps>();
|
|
49
|
+
|
|
50
|
+
// data
|
|
51
|
+
const tabActive = ref<string>(props.tabs[0]);
|
|
52
|
+
|
|
53
|
+
// methods
|
|
54
|
+
function change(tab: string): void {
|
|
55
|
+
const index = props.tabs.indexOf(tab);
|
|
56
|
+
const limit = props.tabs.length - 1;
|
|
57
|
+
|
|
58
|
+
tabActive.value = props.tabs[index < limit ? index + 1 : 0];
|
|
59
|
+
}
|
|
60
|
+
</script>
|
|
61
|
+
|
|
62
|
+
<style scoped></style>
|