pukaad-ui-lib 1.75.0 → 1.76.0
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/dist/module.json +1 -1
- package/dist/module.mjs +1 -0
- package/dist/runtime/components/card/card-profile-about.d.vue.ts +2 -2
- package/dist/runtime/components/card/card-profile-about.vue +3 -3
- package/dist/runtime/components/card/card-profile-about.vue.d.ts +2 -2
- package/dist/runtime/components/card/card-reaction.d.vue.ts +39 -1
- package/dist/runtime/components/card/card-reaction.vue +108 -14
- package/dist/runtime/components/card/card-reaction.vue.d.ts +39 -1
- package/dist/runtime/components/card/card-user-blog.d.vue.ts +26 -7
- package/dist/runtime/components/card/card-user-blog.vue +24 -26
- package/dist/runtime/components/card/card-user-blog.vue.d.ts +26 -7
- package/dist/runtime/components/input/input-autocomplete.d.vue.ts +1 -1
- package/dist/runtime/components/input/input-autocomplete.vue.d.ts +1 -1
- package/dist/runtime/components/input/input-date-picker.vue +6 -1
- package/dist/runtime/components/input/input-tag.d.vue.ts +1 -1
- package/dist/runtime/components/input/input-tag.vue +71 -64
- package/dist/runtime/components/input/input-tag.vue.d.ts +1 -1
- package/dist/runtime/components/modal/modal-password-confirmed.d.vue.ts +15 -6
- package/dist/runtime/components/modal/modal-password-confirmed.vue +50 -36
- package/dist/runtime/components/modal/modal-password-confirmed.vue.d.ts +15 -6
- package/dist/runtime/components/picker/picker-option-menu/picker-option-menu-user.d.vue.ts +4 -4
- package/dist/runtime/components/picker/picker-option-menu/picker-option-menu-user.vue.d.ts +4 -4
- package/dist/runtime/plugins/format.d.ts +9 -0
- package/dist/runtime/plugins/format.js +29 -0
- package/package.json +1 -1
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -81,6 +81,7 @@ const module$1 = defineNuxtModule({
|
|
|
81
81
|
addPlugin(resolver.resolve("./runtime/plugins/loadingPage"));
|
|
82
82
|
addPlugin(resolver.resolve("./runtime/plugins/alert"));
|
|
83
83
|
addPlugin(resolver.resolve("./runtime/plugins/toast"));
|
|
84
|
+
addPlugin(resolver.resolve("./runtime/plugins/format"));
|
|
84
85
|
addPlugin(resolver.resolve("./runtime/plugins/quill.client"));
|
|
85
86
|
_nuxt.hook("nitro:config", (nitroConfig) => {
|
|
86
87
|
nitroConfig.publicAssets ||= [];
|
|
@@ -18,12 +18,12 @@ export interface CardProfileAboutItem {
|
|
|
18
18
|
links: CardProfileAboutLink[];
|
|
19
19
|
}
|
|
20
20
|
type __VLS_Props = {
|
|
21
|
-
|
|
21
|
+
isMyProfile?: boolean;
|
|
22
22
|
item?: CardProfileAboutItem;
|
|
23
23
|
};
|
|
24
24
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
25
25
|
item: CardProfileAboutItem;
|
|
26
|
-
|
|
26
|
+
isMyProfile: boolean;
|
|
27
27
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
28
28
|
declare const _default: typeof __VLS_export;
|
|
29
29
|
export default _default;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<Card title="ข้อมูลทั่วไป" class="flex-col flex gap-[16px]">
|
|
3
|
-
<template v-if="props.
|
|
3
|
+
<template v-if="props.isMyProfile && !isEmpty" #header>
|
|
4
4
|
<div class="flex justify-between items-center">
|
|
5
5
|
<div class="font-title-medium-prominent">ข้อมูลทั่วไป</div>
|
|
6
6
|
<Button variant="text" color="primary" @click="isShowEdit = true">
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
</div>
|
|
11
11
|
</template>
|
|
12
12
|
<div
|
|
13
|
-
v-if="props.
|
|
13
|
+
v-if="props.isMyProfile && isEmpty"
|
|
14
14
|
class="flex flex-col gap-[8px] font-body-large"
|
|
15
15
|
>
|
|
16
16
|
<Button class="w-full" @click="isShowEdit = true">
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
<script setup>
|
|
86
86
|
import { ref, computed } from "vue";
|
|
87
87
|
const props = defineProps({
|
|
88
|
-
|
|
88
|
+
isMyProfile: { type: Boolean, required: false, default: false },
|
|
89
89
|
item: { type: Object, required: false, default: () => ({
|
|
90
90
|
description: "",
|
|
91
91
|
category: 0,
|
|
@@ -18,12 +18,12 @@ export interface CardProfileAboutItem {
|
|
|
18
18
|
links: CardProfileAboutLink[];
|
|
19
19
|
}
|
|
20
20
|
type __VLS_Props = {
|
|
21
|
-
|
|
21
|
+
isMyProfile?: boolean;
|
|
22
22
|
item?: CardProfileAboutItem;
|
|
23
23
|
};
|
|
24
24
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
25
25
|
item: CardProfileAboutItem;
|
|
26
|
-
|
|
26
|
+
isMyProfile: boolean;
|
|
27
27
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
28
28
|
declare const _default: typeof __VLS_export;
|
|
29
29
|
export default _default;
|
|
@@ -1,3 +1,41 @@
|
|
|
1
|
-
|
|
1
|
+
interface Count {
|
|
2
|
+
liked?: number;
|
|
3
|
+
bookmarked?: number;
|
|
4
|
+
viewed?: number;
|
|
5
|
+
commented?: number;
|
|
6
|
+
shared?: number;
|
|
7
|
+
}
|
|
8
|
+
interface Reacted {
|
|
9
|
+
liked?: boolean;
|
|
10
|
+
bookmarked?: boolean;
|
|
11
|
+
}
|
|
12
|
+
type __VLS_Props = {
|
|
13
|
+
itemCount?: Count;
|
|
14
|
+
itemActive?: Reacted;
|
|
15
|
+
padding?: string | number;
|
|
16
|
+
disabledPadding?: boolean;
|
|
17
|
+
disabledDividerTop?: boolean;
|
|
18
|
+
disabledDividerBottom?: boolean;
|
|
19
|
+
disabled?: boolean;
|
|
20
|
+
iconSize?: number | string;
|
|
21
|
+
};
|
|
22
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
23
|
+
"update:liked": (value: boolean) => any;
|
|
24
|
+
"update:bookmarked": (value: boolean) => any;
|
|
25
|
+
share: () => any;
|
|
26
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
27
|
+
"onUpdate:liked"?: ((value: boolean) => any) | undefined;
|
|
28
|
+
"onUpdate:bookmarked"?: ((value: boolean) => any) | undefined;
|
|
29
|
+
onShare?: (() => any) | undefined;
|
|
30
|
+
}>, {
|
|
31
|
+
disabled: boolean;
|
|
32
|
+
disabledPadding: boolean;
|
|
33
|
+
itemCount: Count;
|
|
34
|
+
itemActive: Reacted;
|
|
35
|
+
padding: string | number;
|
|
36
|
+
disabledDividerTop: boolean;
|
|
37
|
+
disabledDividerBottom: boolean;
|
|
38
|
+
iconSize: number | string;
|
|
39
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
2
40
|
declare const _default: typeof __VLS_export;
|
|
3
41
|
export default _default;
|
|
@@ -1,35 +1,129 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
|
|
2
|
+
<div>
|
|
3
3
|
<Divider v-if="!props.disabledDividerTop" :height="0" />
|
|
4
4
|
<div class="flex justify-between w-full font-body-large text-gray">
|
|
5
5
|
<div
|
|
6
6
|
v-for="(react, i) in listReaction"
|
|
7
7
|
:key="i"
|
|
8
|
-
:class="[
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
:style="{
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
:aria-
|
|
8
|
+
:class="[
|
|
9
|
+
'flex items-center gap-[4px] justify-center w-full',
|
|
10
|
+
react.action && 'cursor-pointer hover:bg-bright',
|
|
11
|
+
props.disabled && 'pointer-events-none'
|
|
12
|
+
]"
|
|
13
|
+
:style="{
|
|
14
|
+
padding: `${computedPadding}px`
|
|
15
|
+
}"
|
|
16
|
+
:aria-disabled="props.disabled || !react.action"
|
|
17
17
|
@click="react.action"
|
|
18
18
|
>
|
|
19
19
|
<Icon
|
|
20
20
|
:name="react.reacted ? react.iconReacted : react.icon"
|
|
21
|
-
:size="props.
|
|
21
|
+
:size="props.iconSize"
|
|
22
22
|
/>
|
|
23
23
|
<div :class="[react.reacted && 'text-primary']">
|
|
24
|
-
{{ react.count }}
|
|
24
|
+
{{ $format.number(react.count) }}
|
|
25
25
|
</div>
|
|
26
26
|
</div>
|
|
27
27
|
</div>
|
|
28
28
|
<Divider v-if="!props.disabledDividerBottom" :height="0" />
|
|
29
|
+
<ModalShare v-model="isOpenModalShare" />
|
|
29
30
|
</div>
|
|
30
|
-
<ModalShare v-model="isOpenModalShare" /> -->
|
|
31
31
|
</template>
|
|
32
32
|
|
|
33
33
|
<script setup>
|
|
34
|
-
|
|
34
|
+
import { computed, reactive, ref, watch } from "vue";
|
|
35
|
+
import { useNuxtApp } from "nuxt/app";
|
|
36
|
+
const { $format } = useNuxtApp();
|
|
37
|
+
const isOpenModalShare = ref(false);
|
|
38
|
+
const props = defineProps({
|
|
39
|
+
itemCount: { type: Object, required: false, default: () => ({
|
|
40
|
+
liked: 0,
|
|
41
|
+
bookmarked: 0,
|
|
42
|
+
viewed: 0,
|
|
43
|
+
commented: 0,
|
|
44
|
+
shared: 0
|
|
45
|
+
}) },
|
|
46
|
+
itemActive: { type: Object, required: false, default: () => ({
|
|
47
|
+
liked: false,
|
|
48
|
+
bookmarked: false
|
|
49
|
+
}) },
|
|
50
|
+
padding: { type: [String, Number], required: false, default: 16 },
|
|
51
|
+
disabledPadding: { type: Boolean, required: false, default: false },
|
|
52
|
+
disabledDividerTop: { type: Boolean, required: false, default: false },
|
|
53
|
+
disabledDividerBottom: { type: Boolean, required: false, default: false },
|
|
54
|
+
disabled: { type: Boolean, required: false, default: false },
|
|
55
|
+
iconSize: { type: [Number, String], required: false, default: 20 }
|
|
56
|
+
});
|
|
57
|
+
const emit = defineEmits(["update:liked", "update:bookmarked", "share"]);
|
|
58
|
+
const computedPadding = computed(
|
|
59
|
+
() => props.disabledPadding ? 0 : props.padding
|
|
60
|
+
);
|
|
61
|
+
const counts = reactive({ ...props.itemCount });
|
|
62
|
+
const reaction = reactive({ ...props.itemActive });
|
|
63
|
+
watch(
|
|
64
|
+
() => props.itemCount,
|
|
65
|
+
(newVal) => {
|
|
66
|
+
Object.assign(counts, newVal);
|
|
67
|
+
},
|
|
68
|
+
{ immediate: true, deep: true }
|
|
69
|
+
);
|
|
70
|
+
watch(
|
|
71
|
+
() => props.itemActive,
|
|
72
|
+
(newVal) => {
|
|
73
|
+
Object.assign(reaction, newVal);
|
|
74
|
+
},
|
|
75
|
+
{ immediate: true, deep: true }
|
|
76
|
+
);
|
|
77
|
+
const listReaction = computed(() => {
|
|
78
|
+
const keys = Object.keys(props.itemCount || {});
|
|
79
|
+
const showAll = keys.length === 0;
|
|
80
|
+
return reactions.filter((re) => showAll || keys.includes(re.name)).map((re) => {
|
|
81
|
+
return {
|
|
82
|
+
...re,
|
|
83
|
+
count: counts[re.name] ?? 0,
|
|
84
|
+
reacted: reaction[re.name] ?? false
|
|
85
|
+
};
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
const reactions = [
|
|
89
|
+
{
|
|
90
|
+
name: "liked",
|
|
91
|
+
icon: "pukaad:thumbs-up-regular",
|
|
92
|
+
iconReacted: "pukaad:thumbs-up-solid",
|
|
93
|
+
action: toggleLike
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: "bookmarked",
|
|
97
|
+
icon: "lucide:bookmark",
|
|
98
|
+
iconReacted: "pukaad:bookmark-solid",
|
|
99
|
+
action: toggleBookmark
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
name: "viewed",
|
|
103
|
+
icon: "lucide:eye"
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: "commented",
|
|
107
|
+
icon: "lucide:message-circle-more"
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
name: "shared",
|
|
111
|
+
icon: "uil:share",
|
|
112
|
+
action: toggleShared
|
|
113
|
+
}
|
|
114
|
+
];
|
|
115
|
+
function toggleLike() {
|
|
116
|
+
reaction.liked = !reaction.liked;
|
|
117
|
+
counts.liked += reaction.liked ? 1 : -1;
|
|
118
|
+
emit("update:liked", reaction.liked);
|
|
119
|
+
}
|
|
120
|
+
function toggleBookmark() {
|
|
121
|
+
reaction.bookmarked = !reaction.bookmarked;
|
|
122
|
+
counts.bookmarked += reaction.bookmarked ? 1 : -1;
|
|
123
|
+
emit("update:bookmarked", reaction.bookmarked);
|
|
124
|
+
}
|
|
125
|
+
function toggleShared() {
|
|
126
|
+
isOpenModalShare.value = !isOpenModalShare.value;
|
|
127
|
+
emit("share");
|
|
128
|
+
}
|
|
35
129
|
</script>
|
|
@@ -1,3 +1,41 @@
|
|
|
1
|
-
|
|
1
|
+
interface Count {
|
|
2
|
+
liked?: number;
|
|
3
|
+
bookmarked?: number;
|
|
4
|
+
viewed?: number;
|
|
5
|
+
commented?: number;
|
|
6
|
+
shared?: number;
|
|
7
|
+
}
|
|
8
|
+
interface Reacted {
|
|
9
|
+
liked?: boolean;
|
|
10
|
+
bookmarked?: boolean;
|
|
11
|
+
}
|
|
12
|
+
type __VLS_Props = {
|
|
13
|
+
itemCount?: Count;
|
|
14
|
+
itemActive?: Reacted;
|
|
15
|
+
padding?: string | number;
|
|
16
|
+
disabledPadding?: boolean;
|
|
17
|
+
disabledDividerTop?: boolean;
|
|
18
|
+
disabledDividerBottom?: boolean;
|
|
19
|
+
disabled?: boolean;
|
|
20
|
+
iconSize?: number | string;
|
|
21
|
+
};
|
|
22
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
23
|
+
"update:liked": (value: boolean) => any;
|
|
24
|
+
"update:bookmarked": (value: boolean) => any;
|
|
25
|
+
share: () => any;
|
|
26
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
27
|
+
"onUpdate:liked"?: ((value: boolean) => any) | undefined;
|
|
28
|
+
"onUpdate:bookmarked"?: ((value: boolean) => any) | undefined;
|
|
29
|
+
onShare?: (() => any) | undefined;
|
|
30
|
+
}>, {
|
|
31
|
+
disabled: boolean;
|
|
32
|
+
disabledPadding: boolean;
|
|
33
|
+
itemCount: Count;
|
|
34
|
+
itemActive: Reacted;
|
|
35
|
+
padding: string | number;
|
|
36
|
+
disabledDividerTop: boolean;
|
|
37
|
+
disabledDividerBottom: boolean;
|
|
38
|
+
iconSize: number | string;
|
|
39
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
2
40
|
declare const _default: typeof __VLS_export;
|
|
3
41
|
export default _default;
|
|
@@ -1,18 +1,37 @@
|
|
|
1
|
-
|
|
1
|
+
interface User {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
avatar: string;
|
|
5
|
+
path_name: string;
|
|
6
|
+
verified?: boolean;
|
|
7
|
+
view_count: number;
|
|
8
|
+
}
|
|
9
|
+
interface Content {
|
|
10
|
+
create_at: string;
|
|
11
|
+
title: string;
|
|
12
|
+
description: string;
|
|
13
|
+
image?: string;
|
|
14
|
+
likes_count: number;
|
|
15
|
+
comments_count: number;
|
|
16
|
+
shares_count: number;
|
|
17
|
+
liked?: boolean;
|
|
18
|
+
}
|
|
19
|
+
interface CardUserBlogProps {
|
|
20
|
+
id: string;
|
|
21
|
+
ispinned?: boolean;
|
|
22
|
+
user: User;
|
|
23
|
+
content: Content;
|
|
24
|
+
}
|
|
2
25
|
type __VLS_Props = {
|
|
3
26
|
item: CardUserBlogProps;
|
|
4
|
-
|
|
27
|
+
isMyProfile?: boolean;
|
|
5
28
|
};
|
|
6
29
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
7
|
-
"blog-pin": () => any;
|
|
8
|
-
"blog-unpin": () => any;
|
|
9
30
|
"blog-edit": (item: CardUserBlogProps) => any;
|
|
10
31
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
11
|
-
"onBlog-pin"?: (() => any) | undefined;
|
|
12
|
-
"onBlog-unpin"?: (() => any) | undefined;
|
|
13
32
|
"onBlog-edit"?: ((item: CardUserBlogProps) => any) | undefined;
|
|
14
33
|
}>, {
|
|
15
|
-
|
|
34
|
+
isMyProfile: boolean;
|
|
16
35
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
17
36
|
declare const _default: typeof __VLS_export;
|
|
18
37
|
export default _default;
|
|
@@ -1,43 +1,42 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
3
|
<div
|
|
4
|
-
class="
|
|
4
|
+
class="flex flex-col gap-[16px] w-[668px] border-mercury border-b-[1px]"
|
|
5
5
|
>
|
|
6
6
|
<div class="flex gap-[16px] items-center w-full">
|
|
7
7
|
<div class="flex gap-[8px] items-center w-full">
|
|
8
|
-
|
|
8
|
+
<Avatar
|
|
9
|
+
:src="props.item.user.avatar"
|
|
10
|
+
:size="40"
|
|
11
|
+
class="cursor-pointer"
|
|
12
|
+
@click="onProfileClick"
|
|
13
|
+
/>
|
|
9
14
|
<div class="flex flex-col gap-[4px]">
|
|
10
|
-
<div
|
|
11
|
-
<
|
|
15
|
+
<div>
|
|
16
|
+
<span
|
|
12
17
|
class="font-body-large cursor-pointer"
|
|
13
18
|
@click="onProfileClick"
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
</div>
|
|
17
|
-
<Icon
|
|
19
|
+
>{{ props.item.user.name }}</span
|
|
20
|
+
><Icon
|
|
18
21
|
v-if="props.item.user.verified"
|
|
19
22
|
name="pukaad:verify"
|
|
20
23
|
:size="16"
|
|
24
|
+
class="inline-block align-middle ml-[8px]"
|
|
21
25
|
/>
|
|
22
26
|
</div>
|
|
23
27
|
<div class="text-gray font-body-small flex gap-[4px] items-center">
|
|
24
28
|
<div>{{ props.item.content.create_at }}</div>
|
|
25
29
|
<div>•</div>
|
|
26
|
-
<div>{{ props.item.
|
|
30
|
+
<div>{{ $format.number(props.item.user.view_count) }} วิว</div>
|
|
27
31
|
</div>
|
|
28
32
|
</div>
|
|
29
33
|
</div>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
variant="text"
|
|
34
|
-
:icon-size="20"
|
|
35
|
-
disabled-padding
|
|
36
|
-
color="black"
|
|
37
|
-
/>
|
|
34
|
+
|
|
35
|
+
<Icon v-if="isPinned" name="lucide:pin" :size="20" />
|
|
36
|
+
|
|
38
37
|
<PickerOptionMenuUser
|
|
39
38
|
:state="
|
|
40
|
-
props.
|
|
39
|
+
props.isMyProfile ? isPinned ? 'my-blog-pined' : 'my-blog' : 'report-announce'
|
|
41
40
|
"
|
|
42
41
|
disabled-padding
|
|
43
42
|
@blog-unpin="onBlogUnpin"
|
|
@@ -55,11 +54,13 @@
|
|
|
55
54
|
<div class="font-title-medium-prominent">
|
|
56
55
|
{{ props.item.content.title }}
|
|
57
56
|
</div>
|
|
58
|
-
<div
|
|
57
|
+
<div
|
|
58
|
+
v-if="!props.item.content.image"
|
|
59
|
+
class="text-gray font-body-large line-clamp-4"
|
|
60
|
+
>
|
|
59
61
|
{{ props.item.content.description }}
|
|
60
62
|
</div>
|
|
61
63
|
<CardReaction
|
|
62
|
-
padding="0"
|
|
63
64
|
disabled-divider-top
|
|
64
65
|
disabled-divider-bottom
|
|
65
66
|
:item-count="{
|
|
@@ -67,7 +68,7 @@
|
|
|
67
68
|
commented: props.item.content.comments_count,
|
|
68
69
|
shared: props.item.content.shares_count
|
|
69
70
|
}"
|
|
70
|
-
:
|
|
71
|
+
:itemActive="{
|
|
71
72
|
liked: props.item.content.liked
|
|
72
73
|
}"
|
|
73
74
|
/>
|
|
@@ -76,15 +77,14 @@
|
|
|
76
77
|
</template>
|
|
77
78
|
|
|
78
79
|
<script setup>
|
|
79
|
-
import Image from "../image/image.vue";
|
|
80
80
|
import { useRouter } from "vue-router";
|
|
81
81
|
import { ref, watch } from "vue";
|
|
82
82
|
const props = defineProps({
|
|
83
83
|
item: { type: Object, required: true },
|
|
84
|
-
|
|
84
|
+
isMyProfile: { type: Boolean, required: false, default: false }
|
|
85
85
|
});
|
|
86
86
|
const router = useRouter();
|
|
87
|
-
const emit = defineEmits(["blog-
|
|
87
|
+
const emit = defineEmits(["blog-edit"]);
|
|
88
88
|
const isPinned = ref(props.item.ispinned);
|
|
89
89
|
watch(
|
|
90
90
|
() => props.item.ispinned,
|
|
@@ -97,11 +97,9 @@ const onProfileClick = () => {
|
|
|
97
97
|
};
|
|
98
98
|
const onBlogPin = () => {
|
|
99
99
|
isPinned.value = true;
|
|
100
|
-
emit("blog-pin");
|
|
101
100
|
};
|
|
102
101
|
const onBlogUnpin = () => {
|
|
103
102
|
isPinned.value = false;
|
|
104
|
-
emit("blog-unpin");
|
|
105
103
|
};
|
|
106
104
|
const onBlogEdit = () => {
|
|
107
105
|
emit("blog-edit", props.item);
|
|
@@ -1,18 +1,37 @@
|
|
|
1
|
-
|
|
1
|
+
interface User {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
avatar: string;
|
|
5
|
+
path_name: string;
|
|
6
|
+
verified?: boolean;
|
|
7
|
+
view_count: number;
|
|
8
|
+
}
|
|
9
|
+
interface Content {
|
|
10
|
+
create_at: string;
|
|
11
|
+
title: string;
|
|
12
|
+
description: string;
|
|
13
|
+
image?: string;
|
|
14
|
+
likes_count: number;
|
|
15
|
+
comments_count: number;
|
|
16
|
+
shares_count: number;
|
|
17
|
+
liked?: boolean;
|
|
18
|
+
}
|
|
19
|
+
interface CardUserBlogProps {
|
|
20
|
+
id: string;
|
|
21
|
+
ispinned?: boolean;
|
|
22
|
+
user: User;
|
|
23
|
+
content: Content;
|
|
24
|
+
}
|
|
2
25
|
type __VLS_Props = {
|
|
3
26
|
item: CardUserBlogProps;
|
|
4
|
-
|
|
27
|
+
isMyProfile?: boolean;
|
|
5
28
|
};
|
|
6
29
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
7
|
-
"blog-pin": () => any;
|
|
8
|
-
"blog-unpin": () => any;
|
|
9
30
|
"blog-edit": (item: CardUserBlogProps) => any;
|
|
10
31
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
11
|
-
"onBlog-pin"?: (() => any) | undefined;
|
|
12
|
-
"onBlog-unpin"?: (() => any) | undefined;
|
|
13
32
|
"onBlog-edit"?: ((item: CardUserBlogProps) => any) | undefined;
|
|
14
33
|
}>, {
|
|
15
|
-
|
|
34
|
+
isMyProfile: boolean;
|
|
16
35
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
17
36
|
declare const _default: typeof __VLS_export;
|
|
18
37
|
export default _default;
|
|
@@ -36,9 +36,9 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
36
36
|
id: string;
|
|
37
37
|
name: string;
|
|
38
38
|
description: string;
|
|
39
|
+
limit: number;
|
|
39
40
|
options: AutocompleteOption[] | string[] | number[];
|
|
40
41
|
placeholder: string;
|
|
41
|
-
limit: number;
|
|
42
42
|
disabledErrorMessage: boolean;
|
|
43
43
|
disabledBorder: boolean;
|
|
44
44
|
showCounter: boolean;
|
|
@@ -36,9 +36,9 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
36
36
|
id: string;
|
|
37
37
|
name: string;
|
|
38
38
|
description: string;
|
|
39
|
+
limit: number;
|
|
39
40
|
options: AutocompleteOption[] | string[] | number[];
|
|
40
41
|
placeholder: string;
|
|
41
|
-
limit: number;
|
|
42
42
|
disabledErrorMessage: boolean;
|
|
43
43
|
disabledBorder: boolean;
|
|
44
44
|
showCounter: boolean;
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
</ShadFormLabel>
|
|
18
18
|
|
|
19
19
|
<ShadFormControl>
|
|
20
|
-
<Popover>
|
|
20
|
+
<Popover v-model:open="isPopoverOpen">
|
|
21
21
|
<PopoverTrigger as-child>
|
|
22
22
|
<Button
|
|
23
23
|
variant="outline"
|
|
@@ -151,6 +151,7 @@ const minCalendarValue = computed(() => {
|
|
|
151
151
|
});
|
|
152
152
|
const modelValue = defineModel({ type: null, ...{ default: void 0 } });
|
|
153
153
|
const fieldRef = ref();
|
|
154
|
+
const isPopoverOpen = ref(false);
|
|
154
155
|
const hours = Array.from({ length: 24 }, (_, i) => i);
|
|
155
156
|
const minutes = Array.from({ length: 12 }, (_, i) => i * 5);
|
|
156
157
|
const selectedHour = computed(() => modelValue.value?.getHours() ?? -1);
|
|
@@ -172,6 +173,9 @@ const calendarValue = computed({
|
|
|
172
173
|
newDate.setMinutes(modelValue.value.getMinutes());
|
|
173
174
|
}
|
|
174
175
|
modelValue.value = newDate;
|
|
176
|
+
if (!props.showTime) {
|
|
177
|
+
isPopoverOpen.value = false;
|
|
178
|
+
}
|
|
175
179
|
} else {
|
|
176
180
|
modelValue.value = void 0;
|
|
177
181
|
}
|
|
@@ -184,6 +188,7 @@ function handleTimeChange(type, value) {
|
|
|
184
188
|
newDate.setHours(value);
|
|
185
189
|
} else if (type === "minute") {
|
|
186
190
|
newDate.setMinutes(value);
|
|
191
|
+
isPopoverOpen.value = false;
|
|
187
192
|
}
|
|
188
193
|
modelValue.value = newDate;
|
|
189
194
|
}
|
|
@@ -18,8 +18,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
|
|
|
18
18
|
"onUpdate:modelValue"?: ((value: string[]) => any) | undefined;
|
|
19
19
|
}>, {
|
|
20
20
|
name: string;
|
|
21
|
-
placeholder: string;
|
|
22
21
|
limit: number;
|
|
22
|
+
placeholder: string;
|
|
23
23
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
24
24
|
declare const _default: typeof __VLS_export;
|
|
25
25
|
export default _default;
|
|
@@ -58,23 +58,12 @@
|
|
|
58
58
|
v-for="tag in filteredPopularTags"
|
|
59
59
|
:key="tag.value"
|
|
60
60
|
:value="tag.value"
|
|
61
|
-
|
|
62
|
-
:class="[
|
|
63
|
-
'flex w-full justify-between',
|
|
64
|
-
isOptionDisabled(tag.value) && 'cursor-not-allowed opacity-50'
|
|
65
|
-
]"
|
|
61
|
+
class="flex w-full justify-between"
|
|
66
62
|
@select="onSelectTag(tag)"
|
|
67
63
|
>
|
|
68
64
|
<span class="font-body-medium">{{ tag.label }}</span>
|
|
69
|
-
<div class="
|
|
70
|
-
|
|
71
|
-
{{ tag.postCount }}
|
|
72
|
-
</div>
|
|
73
|
-
<Icon
|
|
74
|
-
v-if="isSelected(tag.value)"
|
|
75
|
-
name="lucide:check"
|
|
76
|
-
class="h-4 w-4"
|
|
77
|
-
/>
|
|
65
|
+
<div class="font-body-small text-gray">
|
|
66
|
+
{{ $format.number(tag.postCount) }} โพสต์
|
|
78
67
|
</div>
|
|
79
68
|
</ShadCommandItem>
|
|
80
69
|
</ShadCommandGroup>
|
|
@@ -97,23 +86,12 @@
|
|
|
97
86
|
v-for="tag in filteredLatestTags"
|
|
98
87
|
:key="tag.value"
|
|
99
88
|
:value="tag.value"
|
|
100
|
-
|
|
101
|
-
:class="[
|
|
102
|
-
'flex w-full justify-between',
|
|
103
|
-
isOptionDisabled(tag.value) && 'cursor-not-allowed opacity-50'
|
|
104
|
-
]"
|
|
89
|
+
class="flex w-full justify-between"
|
|
105
90
|
@select="onSelectTag(tag)"
|
|
106
91
|
>
|
|
107
92
|
<span class="font-body-medium">{{ tag.label }}</span>
|
|
108
|
-
<div class="
|
|
109
|
-
|
|
110
|
-
{{ tag.postCount }}
|
|
111
|
-
</div>
|
|
112
|
-
<Icon
|
|
113
|
-
v-if="isSelected(tag.value)"
|
|
114
|
-
name="lucide:check"
|
|
115
|
-
class="h-4 w-4"
|
|
116
|
-
/>
|
|
93
|
+
<div class="font-body-small text-gray">
|
|
94
|
+
{{ $format.number(tag.postCount) }} โพสต์
|
|
117
95
|
</div>
|
|
118
96
|
</ShadCommandItem>
|
|
119
97
|
</ShadCommandGroup>
|
|
@@ -134,7 +112,7 @@
|
|
|
134
112
|
</template>
|
|
135
113
|
|
|
136
114
|
<script setup>
|
|
137
|
-
import { ref, computed,
|
|
115
|
+
import { ref, computed, onMounted } from "vue";
|
|
138
116
|
const props = defineProps({
|
|
139
117
|
name: { type: String, required: false, default: "input-tag" },
|
|
140
118
|
rules: { type: [Object, String, Function], required: false },
|
|
@@ -151,28 +129,59 @@ const popoverOpen = ref(false);
|
|
|
151
129
|
const currentTab = ref("popular");
|
|
152
130
|
const searchQuery = ref("");
|
|
153
131
|
const inputRef = ref();
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
132
|
+
const isLoading = ref(false);
|
|
133
|
+
const allTags = ref([]);
|
|
134
|
+
const popularTags = ref([]);
|
|
135
|
+
const latestTags = ref([]);
|
|
136
|
+
const mockFetchTags = () => {
|
|
137
|
+
return new Promise((resolve) => {
|
|
138
|
+
setTimeout(() => {
|
|
139
|
+
resolve({
|
|
140
|
+
popular: [
|
|
141
|
+
{ label: "\u0E1A\u0E38\u0E23\u0E35\u0E23\u0E31\u0E21\u0E22\u0E4C", value: "buriram", postCount: 4500 },
|
|
142
|
+
{ label: "\u0E01\u0E23\u0E38\u0E07\u0E40\u0E17\u0E1E", value: "bangkok", postCount: 120300 },
|
|
143
|
+
{
|
|
144
|
+
label: "\u0E40\u0E0A\u0E35\u0E22\u0E07\u0E43\u0E2B\u0E21\u0E48",
|
|
145
|
+
value: "chiangmai",
|
|
146
|
+
postCount: 85200
|
|
147
|
+
},
|
|
148
|
+
{ label: "\u0E20\u0E39\u0E40\u0E01\u0E47\u0E15", value: "phuket", postCount: 72100 },
|
|
149
|
+
{ label: "\u0E1E\u0E31\u0E17\u0E22\u0E32", value: "pattaya", postCount: 55800 },
|
|
150
|
+
{ label: "\u0E2B\u0E31\u0E27\u0E2B\u0E34\u0E19", value: "huahin", postCount: 34600 },
|
|
151
|
+
{ label: "\u0E02\u0E2D\u0E19\u0E41\u0E01\u0E48\u0E19", value: "khonkaen", postCount: 28400 },
|
|
152
|
+
{ label: "\u0E19\u0E04\u0E23\u0E23\u0E32\u0E0A\u0E2A\u0E35\u0E21\u0E32", value: "korat", postCount: 22900 }
|
|
153
|
+
],
|
|
154
|
+
latest: [
|
|
155
|
+
{
|
|
156
|
+
label: "\u0E2A\u0E38\u0E02\u0E38\u0E21\u0E27\u0E34\u0E17",
|
|
157
|
+
value: "sukhumvit",
|
|
158
|
+
postCount: 12300
|
|
159
|
+
},
|
|
160
|
+
{ label: "\u0E2A\u0E22\u0E32\u0E21", value: "siam", postCount: 8700 },
|
|
161
|
+
{ label: "\u0E2D\u0E32\u0E23\u0E35\u0E22\u0E4C", value: "ari", postCount: 6200 },
|
|
162
|
+
{ label: "\u0E17\u0E2D\u0E07\u0E2B\u0E25\u0E48\u0E2D", value: "thonglor", postCount: 15400 },
|
|
163
|
+
{ label: "\u0E40\u0E2D\u0E01\u0E21\u0E31\u0E22", value: "ekkamai", postCount: 9800 },
|
|
164
|
+
{ label: "\u0E2D\u0E42\u0E28\u0E01", value: "asoke", postCount: 11200 },
|
|
165
|
+
{ label: "\u0E2A\u0E35\u0E25\u0E21", value: "silom", postCount: 18600 },
|
|
166
|
+
{ label: "\u0E23\u0E31\u0E0A\u0E14\u0E32", value: "ratchada", postCount: 7500 }
|
|
167
|
+
]
|
|
168
|
+
});
|
|
169
|
+
}, 500);
|
|
170
|
+
});
|
|
171
|
+
};
|
|
172
|
+
onMounted(async () => {
|
|
173
|
+
isLoading.value = true;
|
|
174
|
+
try {
|
|
175
|
+
const response = await mockFetchTags();
|
|
176
|
+
popularTags.value = response.popular;
|
|
177
|
+
latestTags.value = response.latest;
|
|
178
|
+
allTags.value = [...response.popular, ...response.latest];
|
|
179
|
+
} catch (error) {
|
|
180
|
+
console.error("Failed to fetch tags:", error);
|
|
181
|
+
} finally {
|
|
182
|
+
isLoading.value = false;
|
|
183
|
+
}
|
|
184
|
+
});
|
|
176
185
|
const selectedTags = computed(() => {
|
|
177
186
|
return modelValue.value.map((value) => allTags.value.find((tag) => tag.value === value)).filter((tag) => tag !== void 0);
|
|
178
187
|
});
|
|
@@ -199,28 +208,25 @@ const handleInteractOutside = (event) => {
|
|
|
199
208
|
}
|
|
200
209
|
};
|
|
201
210
|
const filteredPopularTags = computed(() => {
|
|
202
|
-
|
|
211
|
+
const availableTags = popularTags.value.filter(
|
|
212
|
+
(tag) => !modelValue.value.includes(tag.value)
|
|
213
|
+
);
|
|
214
|
+
if (!searchQuery.value) return availableTags;
|
|
203
215
|
const query = searchQuery.value.toLowerCase();
|
|
204
|
-
return
|
|
216
|
+
return availableTags.filter(
|
|
205
217
|
(tag) => tag.label.toLowerCase().includes(query) || tag.value.toLowerCase().includes(query)
|
|
206
218
|
);
|
|
207
219
|
});
|
|
208
220
|
const filteredLatestTags = computed(() => {
|
|
209
|
-
|
|
221
|
+
const availableTags = latestTags.value.filter(
|
|
222
|
+
(tag) => !modelValue.value.includes(tag.value)
|
|
223
|
+
);
|
|
224
|
+
if (!searchQuery.value) return availableTags;
|
|
210
225
|
const query = searchQuery.value.toLowerCase();
|
|
211
|
-
return
|
|
226
|
+
return availableTags.filter(
|
|
212
227
|
(tag) => tag.label.toLowerCase().includes(query) || tag.value.toLowerCase().includes(query)
|
|
213
228
|
);
|
|
214
229
|
});
|
|
215
|
-
const isSelected = (value) => {
|
|
216
|
-
return modelValue.value.includes(value);
|
|
217
|
-
};
|
|
218
|
-
const isOptionDisabled = (value) => {
|
|
219
|
-
if (isLimitReached.value && !isSelected(value)) {
|
|
220
|
-
return true;
|
|
221
|
-
}
|
|
222
|
-
return false;
|
|
223
|
-
};
|
|
224
230
|
const onSelectTag = (tag) => {
|
|
225
231
|
if (modelValue.value.includes(tag.value)) {
|
|
226
232
|
modelValue.value = modelValue.value.filter((v) => v !== tag.value);
|
|
@@ -229,6 +235,7 @@ const onSelectTag = (tag) => {
|
|
|
229
235
|
return;
|
|
230
236
|
}
|
|
231
237
|
modelValue.value = [...modelValue.value, tag.value];
|
|
238
|
+
popoverOpen.value = false;
|
|
232
239
|
}
|
|
233
240
|
searchQuery.value = "";
|
|
234
241
|
};
|
|
@@ -18,8 +18,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
|
|
|
18
18
|
"onUpdate:modelValue"?: ((value: string[]) => any) | undefined;
|
|
19
19
|
}>, {
|
|
20
20
|
name: string;
|
|
21
|
-
placeholder: string;
|
|
22
21
|
limit: number;
|
|
22
|
+
placeholder: string;
|
|
23
23
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
24
24
|
declare const _default: typeof __VLS_export;
|
|
25
25
|
export default _default;
|
|
@@ -1,22 +1,31 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
interface Props {
|
|
2
|
+
title?: string;
|
|
3
|
+
confirmText?: string;
|
|
4
|
+
loginToken?: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
disabledForgotPassword?: boolean;
|
|
7
|
+
}
|
|
8
|
+
type __VLS_Props = Props;
|
|
3
9
|
type __VLS_ModelProps = {
|
|
4
10
|
modelValue?: boolean;
|
|
5
11
|
};
|
|
6
12
|
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
7
13
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
8
14
|
"update:modelValue": (value: boolean) => any;
|
|
9
|
-
|
|
10
|
-
|
|
15
|
+
complete: (data: {
|
|
16
|
+
secId: string;
|
|
17
|
+
}) => any;
|
|
11
18
|
close: () => any;
|
|
12
19
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
13
20
|
"onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
|
|
14
|
-
onComplete?: ((
|
|
21
|
+
onComplete?: ((data: {
|
|
22
|
+
secId: string;
|
|
23
|
+
}) => any) | undefined;
|
|
15
24
|
onClose?: (() => any) | undefined;
|
|
16
25
|
}>, {
|
|
17
26
|
title: string;
|
|
18
|
-
confirmedText: string;
|
|
19
27
|
disabledForgotPassword: boolean;
|
|
28
|
+
confirmText: string;
|
|
20
29
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
21
30
|
declare const _default: typeof __VLS_export;
|
|
22
31
|
export default _default;
|
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<Modal
|
|
3
3
|
:title="props.title"
|
|
4
|
-
:loading="
|
|
5
|
-
@close="emit('close')"
|
|
6
|
-
@submit="onVerifyPassword"
|
|
4
|
+
:loading="loading"
|
|
7
5
|
v-model="isOpen"
|
|
6
|
+
@close="emit('close')"
|
|
7
|
+
@submit="handleSubmit"
|
|
8
8
|
>
|
|
9
9
|
<div v-if="props.description" class="font-body-large">
|
|
10
10
|
{{ props.description }}
|
|
11
11
|
</div>
|
|
12
12
|
<InputPassword
|
|
13
|
+
ref="inputRef"
|
|
14
|
+
disabled-forgot-password
|
|
15
|
+
required
|
|
13
16
|
label="รหัสผ่าน"
|
|
14
17
|
placeholder="กรอกรหัสผ่าน"
|
|
15
18
|
v-model="password"
|
|
16
19
|
/>
|
|
20
|
+
|
|
17
21
|
<template #footer="{ meta }">
|
|
18
22
|
<Button
|
|
19
23
|
type="submit"
|
|
@@ -21,52 +25,62 @@
|
|
|
21
25
|
class="w-full"
|
|
22
26
|
:disabled="!meta.valid"
|
|
23
27
|
>
|
|
24
|
-
{{ props.
|
|
28
|
+
{{ props.confirmText }}
|
|
25
29
|
</Button>
|
|
26
30
|
</template>
|
|
27
31
|
</Modal>
|
|
28
32
|
</template>
|
|
29
33
|
|
|
30
34
|
<script setup>
|
|
31
|
-
import {
|
|
32
|
-
import { useRuntimeConfig } from "nuxt/app";
|
|
33
|
-
const { BASE_URL_API } = useRuntimeConfig().public;
|
|
34
|
-
const emit = defineEmits(["close", "complete"]);
|
|
35
|
+
import { ref, computed, watch } from "vue";
|
|
36
|
+
import { useNuxtApp, useRuntimeConfig } from "nuxt/app";
|
|
35
37
|
const props = defineProps({
|
|
36
|
-
confirmedText: { type: String, required: false, default: "\u0E22\u0E37\u0E19\u0E22\u0E31\u0E19" },
|
|
37
38
|
title: { type: String, required: false, default: "\u0E22\u0E37\u0E19\u0E22\u0E31\u0E19\u0E23\u0E2B\u0E31\u0E2A\u0E1C\u0E48\u0E32\u0E19" },
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
confirmText: { type: String, required: false, default: "\u0E22\u0E37\u0E19\u0E22\u0E31\u0E19" },
|
|
40
|
+
loginToken: { type: String, required: false },
|
|
41
|
+
description: { type: String, required: false },
|
|
42
|
+
disabledForgotPassword: { type: Boolean, required: false, default: false }
|
|
40
43
|
});
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const
|
|
44
|
+
const emit = defineEmits(["complete", "close"]);
|
|
45
|
+
const { $toast } = useNuxtApp();
|
|
46
|
+
const config = useRuntimeConfig();
|
|
47
|
+
const isOpen = defineModel({ type: Boolean, ...{ default: false } });
|
|
48
|
+
const apiPath = computed(
|
|
49
|
+
() => config.public.APP_TYPE === "office" ? "/office/auth/password/verify" : "/user/auth/password/verify"
|
|
50
|
+
);
|
|
51
|
+
const loading = ref(false);
|
|
45
52
|
const password = ref("");
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
53
|
+
const inputRef = ref();
|
|
54
|
+
watch(isOpen, (open) => {
|
|
55
|
+
if (!open) {
|
|
56
|
+
password.value = "";
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
const handleSubmit = async () => {
|
|
60
|
+
if (!props.loginToken) {
|
|
61
|
+
$toast?.error?.("\u0E44\u0E21\u0E48\u0E1E\u0E1A login token");
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
loading.value = true;
|
|
49
65
|
try {
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
password: password.value
|
|
57
|
-
}
|
|
66
|
+
const res = await $fetch(`${config.public.BASE_URL_API}${apiPath.value}`, {
|
|
67
|
+
method: "POST",
|
|
68
|
+
credentials: "include",
|
|
69
|
+
body: {
|
|
70
|
+
login_token: props.loginToken,
|
|
71
|
+
password: password.value
|
|
58
72
|
}
|
|
59
|
-
);
|
|
60
|
-
if (
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
73
|
+
});
|
|
74
|
+
if (res.code === 200 && res.data) {
|
|
75
|
+
emit("complete", { secId: res.data.sec_id });
|
|
76
|
+
isOpen.value = false;
|
|
77
|
+
} else {
|
|
78
|
+
inputRef.value?.setErrors?.(res.message || "\u0E23\u0E2B\u0E31\u0E2A\u0E1C\u0E48\u0E32\u0E19\u0E44\u0E21\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07");
|
|
79
|
+
}
|
|
80
|
+
} catch (e) {
|
|
81
|
+
inputRef.value?.setErrors?.(e?.data?.message || "\u0E23\u0E2B\u0E31\u0E2A\u0E1C\u0E48\u0E32\u0E19\u0E44\u0E21\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07");
|
|
65
82
|
} finally {
|
|
66
|
-
|
|
83
|
+
loading.value = false;
|
|
67
84
|
}
|
|
68
85
|
};
|
|
69
|
-
watch(isOpen, (value) => {
|
|
70
|
-
password.value = "";
|
|
71
|
-
});
|
|
72
86
|
</script>
|
|
@@ -1,22 +1,31 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
interface Props {
|
|
2
|
+
title?: string;
|
|
3
|
+
confirmText?: string;
|
|
4
|
+
loginToken?: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
disabledForgotPassword?: boolean;
|
|
7
|
+
}
|
|
8
|
+
type __VLS_Props = Props;
|
|
3
9
|
type __VLS_ModelProps = {
|
|
4
10
|
modelValue?: boolean;
|
|
5
11
|
};
|
|
6
12
|
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
7
13
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
8
14
|
"update:modelValue": (value: boolean) => any;
|
|
9
|
-
|
|
10
|
-
|
|
15
|
+
complete: (data: {
|
|
16
|
+
secId: string;
|
|
17
|
+
}) => any;
|
|
11
18
|
close: () => any;
|
|
12
19
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
13
20
|
"onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
|
|
14
|
-
onComplete?: ((
|
|
21
|
+
onComplete?: ((data: {
|
|
22
|
+
secId: string;
|
|
23
|
+
}) => any) | undefined;
|
|
15
24
|
onClose?: (() => any) | undefined;
|
|
16
25
|
}>, {
|
|
17
26
|
title: string;
|
|
18
|
-
confirmedText: string;
|
|
19
27
|
disabledForgotPassword: boolean;
|
|
28
|
+
confirmText: string;
|
|
20
29
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
21
30
|
declare const _default: typeof __VLS_export;
|
|
22
31
|
export default _default;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { PickerOptionMenuUserProps } from "@/types/components/picker/picker-option-menu/picker-option-menu-user";
|
|
2
2
|
declare const __VLS_export: import("vue").DefineComponent<PickerOptionMenuUserProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
3
|
-
"blog-pin": () => any;
|
|
4
|
-
"blog-unpin": () => any;
|
|
5
3
|
"blog-edit": () => any;
|
|
6
4
|
"report-announce": () => any;
|
|
5
|
+
"blog-unpin": () => any;
|
|
6
|
+
"blog-pin": () => any;
|
|
7
7
|
"profile-edit": () => any;
|
|
8
8
|
"profile-share": () => any;
|
|
9
9
|
"profile-follower-delete": () => any;
|
|
@@ -18,10 +18,10 @@ declare const __VLS_export: import("vue").DefineComponent<PickerOptionMenuUserPr
|
|
|
18
18
|
"review-delete": () => any;
|
|
19
19
|
archive: () => any;
|
|
20
20
|
}, string, import("vue").PublicProps, Readonly<PickerOptionMenuUserProps> & Readonly<{
|
|
21
|
-
"onBlog-pin"?: (() => any) | undefined;
|
|
22
|
-
"onBlog-unpin"?: (() => any) | undefined;
|
|
23
21
|
"onBlog-edit"?: (() => any) | undefined;
|
|
24
22
|
"onReport-announce"?: (() => any) | undefined;
|
|
23
|
+
"onBlog-unpin"?: (() => any) | undefined;
|
|
24
|
+
"onBlog-pin"?: (() => any) | undefined;
|
|
25
25
|
"onProfile-edit"?: (() => any) | undefined;
|
|
26
26
|
"onProfile-share"?: (() => any) | undefined;
|
|
27
27
|
"onProfile-follower-delete"?: (() => any) | undefined;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { PickerOptionMenuUserProps } from "@/types/components/picker/picker-option-menu/picker-option-menu-user";
|
|
2
2
|
declare const __VLS_export: import("vue").DefineComponent<PickerOptionMenuUserProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
3
|
-
"blog-pin": () => any;
|
|
4
|
-
"blog-unpin": () => any;
|
|
5
3
|
"blog-edit": () => any;
|
|
6
4
|
"report-announce": () => any;
|
|
5
|
+
"blog-unpin": () => any;
|
|
6
|
+
"blog-pin": () => any;
|
|
7
7
|
"profile-edit": () => any;
|
|
8
8
|
"profile-share": () => any;
|
|
9
9
|
"profile-follower-delete": () => any;
|
|
@@ -18,10 +18,10 @@ declare const __VLS_export: import("vue").DefineComponent<PickerOptionMenuUserPr
|
|
|
18
18
|
"review-delete": () => any;
|
|
19
19
|
archive: () => any;
|
|
20
20
|
}, string, import("vue").PublicProps, Readonly<PickerOptionMenuUserProps> & Readonly<{
|
|
21
|
-
"onBlog-pin"?: (() => any) | undefined;
|
|
22
|
-
"onBlog-unpin"?: (() => any) | undefined;
|
|
23
21
|
"onBlog-edit"?: (() => any) | undefined;
|
|
24
22
|
"onReport-announce"?: (() => any) | undefined;
|
|
23
|
+
"onBlog-unpin"?: (() => any) | undefined;
|
|
24
|
+
"onBlog-pin"?: (() => any) | undefined;
|
|
25
25
|
"onProfile-edit"?: (() => any) | undefined;
|
|
26
26
|
"onProfile-share"?: (() => any) | undefined;
|
|
27
27
|
"onProfile-follower-delete"?: (() => any) | undefined;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { defineNuxtPlugin } from "nuxt/app";
|
|
2
|
+
export class Format {
|
|
3
|
+
number(num) {
|
|
4
|
+
if (num >= 1e6) {
|
|
5
|
+
const value = Math.floor(num / 1e6 * 10) / 10;
|
|
6
|
+
return value.toString().replace(/\.0$/, "") + " \u0E25\u0E49\u0E32\u0E19";
|
|
7
|
+
}
|
|
8
|
+
if (num >= 1e5) {
|
|
9
|
+
const value = Math.floor(num / 1e5 * 10) / 10;
|
|
10
|
+
return value.toString().replace(/\.0$/, "") + " \u0E41\u0E2A\u0E19";
|
|
11
|
+
}
|
|
12
|
+
if (num >= 1e4) {
|
|
13
|
+
const value = Math.floor(num / 1e4 * 10) / 10;
|
|
14
|
+
return value.toString().replace(/\.0$/, "") + " \u0E2B\u0E21\u0E37\u0E48\u0E19";
|
|
15
|
+
}
|
|
16
|
+
if (num >= 1e3) {
|
|
17
|
+
const value = Math.floor(num / 1e3 * 10) / 10;
|
|
18
|
+
return value.toString().replace(/\.0$/, "") + " \u0E1E\u0E31\u0E19";
|
|
19
|
+
}
|
|
20
|
+
return num.toString();
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export default defineNuxtPlugin(() => {
|
|
24
|
+
return {
|
|
25
|
+
provide: {
|
|
26
|
+
format: new Format()
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
});
|