pukaad-ui-lib 1.298.0 → 1.300.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/runtime/components/card/card-place-item.d.vue.ts +24 -0
- package/dist/runtime/components/card/card-place-item.vue +108 -0
- package/dist/runtime/components/card/card-place-item.vue.d.ts +24 -0
- package/dist/runtime/components/card/card-review.vue +93 -93
- package/dist/runtime/components/drawer/drawer-post-review.vue +70 -70
- package/dist/runtime/components/drawer/drawer-profile-network.d.vue.ts +1 -1
- package/dist/runtime/components/drawer/drawer-profile-network.vue +157 -47
- package/dist/runtime/components/drawer/drawer-profile-network.vue.d.ts +1 -1
- package/dist/runtime/components/drawer/drawer-suggest-place/suggest-place-form.vue +124 -124
- 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/package.json +1 -1
- /package/dist/runtime/assets/svg/socials/{Whatsapp.svg → WhatsApp.svg} +0 -0
package/dist/module.json
CHANGED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface PlaceItem {
|
|
2
|
+
id?: string;
|
|
3
|
+
name?: string;
|
|
4
|
+
cover_image?: string;
|
|
5
|
+
rating?: number;
|
|
6
|
+
review_count?: number;
|
|
7
|
+
like_count?: number;
|
|
8
|
+
address?: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
is_liked?: boolean;
|
|
11
|
+
}
|
|
12
|
+
type __VLS_ModelProps = {
|
|
13
|
+
modelValue?: PlaceItem;
|
|
14
|
+
};
|
|
15
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
16
|
+
"update:modelValue": (value: PlaceItem) => any;
|
|
17
|
+
} & {
|
|
18
|
+
"require-auth": () => any;
|
|
19
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_ModelProps> & Readonly<{
|
|
20
|
+
"onUpdate:modelValue"?: ((value: PlaceItem) => any) | undefined;
|
|
21
|
+
"onRequire-auth"?: (() => any) | undefined;
|
|
22
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
23
|
+
declare const _default: typeof __VLS_export;
|
|
24
|
+
export default _default;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="flex gap-[16px] items-start justify-between" @click="onClickCard">
|
|
3
|
+
<div class="flex gap-[8px] cursor-pointer flex-1 min-w-0">
|
|
4
|
+
<Image
|
|
5
|
+
v-if="modelValue?.cover_image"
|
|
6
|
+
:src="modelValue.cover_image"
|
|
7
|
+
width="114"
|
|
8
|
+
height="64"
|
|
9
|
+
class="rounded-[4px] object-cover flex-shrink-0"
|
|
10
|
+
/>
|
|
11
|
+
<div
|
|
12
|
+
v-else
|
|
13
|
+
class="w-[114px] h-[64px] bg-mercury flex items-center justify-center rounded-[4px] flex-shrink-0"
|
|
14
|
+
>
|
|
15
|
+
<Icon name="fa6-solid:map-location-dot" size="24" class="text-gray" />
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<div class="flex flex-col gap-[4px] min-w-0">
|
|
19
|
+
<div class="font-body-large-prominent truncate">
|
|
20
|
+
{{ modelValue?.name }}
|
|
21
|
+
</div>
|
|
22
|
+
<div
|
|
23
|
+
class="flex gap-[4px] items-center text-gray font-body-small flex-wrap"
|
|
24
|
+
>
|
|
25
|
+
<InputRating
|
|
26
|
+
:size="10"
|
|
27
|
+
readonly
|
|
28
|
+
:model-value="modelValue?.rating || 0"
|
|
29
|
+
/>
|
|
30
|
+
<div>
|
|
31
|
+
{{ $convert.convertNumber(modelValue?.review_count || 0) }}
|
|
32
|
+
</div>
|
|
33
|
+
<div>•</div>
|
|
34
|
+
<div>
|
|
35
|
+
ถูกใจ {{ $convert.convertNumber(modelValue?.like_count || 0) }}
|
|
36
|
+
</div>
|
|
37
|
+
<div>•</div>
|
|
38
|
+
<div class="truncate">{{ modelValue?.address }}</div>
|
|
39
|
+
</div>
|
|
40
|
+
<div class="font-body-small text-gray line-clamp-2">
|
|
41
|
+
{{ modelValue?.description }}
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<Button
|
|
47
|
+
:variant="modelValue?.is_liked ? 'default' : 'outline'"
|
|
48
|
+
:color="modelValue?.is_liked ? 'default' : 'primary'"
|
|
49
|
+
class="flex-shrink-0"
|
|
50
|
+
@click.stop="onLikeToggle"
|
|
51
|
+
>
|
|
52
|
+
{{ modelValue?.is_liked ? "\u0E16\u0E39\u0E01\u0E43\u0E08\u0E41\u0E25\u0E49\u0E27" : "\u0E16\u0E39\u0E01\u0E43\u0E08" }}
|
|
53
|
+
</Button>
|
|
54
|
+
</div>
|
|
55
|
+
</template>
|
|
56
|
+
|
|
57
|
+
<script setup>
|
|
58
|
+
import { ref } from "vue";
|
|
59
|
+
import { useRouter } from "vue-router";
|
|
60
|
+
import { useCookie, useRuntimeConfig } from "nuxt/app";
|
|
61
|
+
import { useApi } from "../../composables/useApi";
|
|
62
|
+
const modelValue = defineModel({ type: Object, ...{ default: () => ({}) } });
|
|
63
|
+
const emit = defineEmits(["require-auth"]);
|
|
64
|
+
const router = useRouter();
|
|
65
|
+
const api = useApi();
|
|
66
|
+
const config = useRuntimeConfig();
|
|
67
|
+
const isLoading = ref(false);
|
|
68
|
+
const onClickCard = () => {
|
|
69
|
+
if (modelValue.value?.id) {
|
|
70
|
+
router.push(`/place/${modelValue.value.id}`);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
const onLikeToggle = async () => {
|
|
74
|
+
const { APP_TYPE } = config.public;
|
|
75
|
+
const secId = useCookie(APP_TYPE === "OFFICE" ? "OFFICE_SEC_ID" : "SEC_ID");
|
|
76
|
+
if (!secId.value) {
|
|
77
|
+
emit("require-auth");
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (!modelValue.value?.id) return;
|
|
81
|
+
if (isLoading.value) return;
|
|
82
|
+
const placeId = modelValue.value.id;
|
|
83
|
+
const currentLiked = !!modelValue.value.is_liked;
|
|
84
|
+
modelValue.value.is_liked = !currentLiked;
|
|
85
|
+
if (modelValue.value.like_count !== void 0) {
|
|
86
|
+
modelValue.value.like_count += !currentLiked ? 1 : -1;
|
|
87
|
+
}
|
|
88
|
+
isLoading.value = true;
|
|
89
|
+
try {
|
|
90
|
+
const method = currentLiked ? "DELETE" : "POST";
|
|
91
|
+
const response = await api(`/personal/suggest-places/${placeId}/like`, { method });
|
|
92
|
+
if (response.data) {
|
|
93
|
+
modelValue.value.is_liked = response.data.is_liked;
|
|
94
|
+
if (modelValue.value.like_count !== void 0) {
|
|
95
|
+
modelValue.value.like_count = response.data.like_count;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
} catch (error) {
|
|
99
|
+
modelValue.value.is_liked = currentLiked;
|
|
100
|
+
if (modelValue.value.like_count !== void 0) {
|
|
101
|
+
modelValue.value.like_count += currentLiked ? 1 : -1;
|
|
102
|
+
}
|
|
103
|
+
console.error("Like toggle failed:", error);
|
|
104
|
+
} finally {
|
|
105
|
+
isLoading.value = false;
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
</script>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface PlaceItem {
|
|
2
|
+
id?: string;
|
|
3
|
+
name?: string;
|
|
4
|
+
cover_image?: string;
|
|
5
|
+
rating?: number;
|
|
6
|
+
review_count?: number;
|
|
7
|
+
like_count?: number;
|
|
8
|
+
address?: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
is_liked?: boolean;
|
|
11
|
+
}
|
|
12
|
+
type __VLS_ModelProps = {
|
|
13
|
+
modelValue?: PlaceItem;
|
|
14
|
+
};
|
|
15
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
16
|
+
"update:modelValue": (value: PlaceItem) => any;
|
|
17
|
+
} & {
|
|
18
|
+
"require-auth": () => any;
|
|
19
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_ModelProps> & Readonly<{
|
|
20
|
+
"onUpdate:modelValue"?: ((value: PlaceItem) => any) | undefined;
|
|
21
|
+
"onRequire-auth"?: (() => any) | undefined;
|
|
22
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
23
|
+
declare const _default: typeof __VLS_export;
|
|
24
|
+
export default _default;
|
|
@@ -1,98 +1,98 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="py-[16px] border-b-[1px] border-mercury flex gap-[16px] w-full">
|
|
3
|
-
<div v-if="props.item.user.avatar">
|
|
4
|
-
<Avatar
|
|
5
|
-
:src="props.item.user.avatar"
|
|
6
|
-
alt="profile_myProfile"
|
|
7
|
-
:size="30"
|
|
8
|
-
class="cursor-pointer"
|
|
9
|
-
@click="navigateToProfile(props.item.user.path_name)"
|
|
10
|
-
/>
|
|
11
|
-
</div>
|
|
12
|
-
<div class="flex flex-col gap-[24px] w-full">
|
|
13
|
-
<div class="flex flex-col gap-[8px]">
|
|
14
|
-
<div class="flex flex-col gap-[6px]">
|
|
15
|
-
<div class="flex flex-col gap-[4px]">
|
|
16
|
-
<div class="flex justify-between items-center">
|
|
17
|
-
<div
|
|
18
|
-
class="font-body-large cursor-pointer"
|
|
19
|
-
@click="navigateToProfile(props.item.user.path_name)"
|
|
20
|
-
>
|
|
21
|
-
{{ props.item.user?.name }}
|
|
22
|
-
</div>
|
|
23
|
-
<div class="flex gap-[8px] items-center">
|
|
24
|
-
<Button
|
|
25
|
-
variant="text"
|
|
26
|
-
:color="liked ? 'primary' : 'default'"
|
|
27
|
-
:disabled="props.disabledLike"
|
|
28
|
-
:aria-pressed="liked"
|
|
29
|
-
@click="toggleLike"
|
|
30
|
-
>
|
|
31
|
-
<Icon
|
|
2
|
+
<div class="py-[16px] border-b-[1px] border-mercury flex gap-[16px] w-full">
|
|
3
|
+
<div v-if="props.item.user.avatar">
|
|
4
|
+
<Avatar
|
|
5
|
+
:src="props.item.user.avatar"
|
|
6
|
+
alt="profile_myProfile"
|
|
7
|
+
:size="30"
|
|
8
|
+
class="cursor-pointer"
|
|
9
|
+
@click="navigateToProfile(props.item.user.path_name)"
|
|
10
|
+
/>
|
|
11
|
+
</div>
|
|
12
|
+
<div class="flex flex-col gap-[24px] w-full">
|
|
13
|
+
<div class="flex flex-col gap-[8px]">
|
|
14
|
+
<div class="flex flex-col gap-[6px]">
|
|
15
|
+
<div class="flex flex-col gap-[4px]">
|
|
16
|
+
<div class="flex justify-between items-center">
|
|
17
|
+
<div
|
|
18
|
+
class="font-body-large cursor-pointer"
|
|
19
|
+
@click="navigateToProfile(props.item.user.path_name)"
|
|
20
|
+
>
|
|
21
|
+
{{ props.item.user?.name }}
|
|
22
|
+
</div>
|
|
23
|
+
<div class="flex gap-[8px] items-center">
|
|
24
|
+
<Button
|
|
25
|
+
variant="text"
|
|
26
|
+
:color="liked ? 'primary' : 'default'"
|
|
27
|
+
:disabled="props.disabledLike"
|
|
28
|
+
:aria-pressed="liked"
|
|
29
|
+
@click="toggleLike"
|
|
30
|
+
>
|
|
31
|
+
<Icon
|
|
32
32
|
:name="
|
|
33
33
|
liked ? 'pukaad:thumbs-up-solid' : 'pukaad:thumbs-up-regular'
|
|
34
|
-
"
|
|
35
|
-
:size="20"
|
|
36
|
-
/>
|
|
37
|
-
{{ convertNumber(likeCount) }}
|
|
38
|
-
</Button>
|
|
39
|
-
<PickerOptionMenuUser
|
|
40
|
-
v-if="!props.disabledMenu"
|
|
41
|
-
:state="menuType"
|
|
42
|
-
disabled-padding
|
|
43
|
-
@review-edit="emit('edit', props.item)"
|
|
44
|
-
@review-delete="emit('delete', props.item)"
|
|
45
|
-
/>
|
|
46
|
-
</div>
|
|
47
|
-
</div>
|
|
48
|
-
<div class="text-gray font-body-small">
|
|
49
|
-
{{ convertNumber(props.item.user?.review_count ?? 0) }} รีวิว •
|
|
50
|
-
{{ convertNumber(props.item.user?.like_count ?? 0) }} ชื่นชอบรีวิว
|
|
51
|
-
</div>
|
|
52
|
-
</div>
|
|
53
|
-
<div class="flex gap-[8px] items-center">
|
|
54
|
-
<InputRating
|
|
55
|
-
:size="11"
|
|
56
|
-
readonly
|
|
57
|
-
:model-value="props.item.review?.rating"
|
|
58
|
-
/>
|
|
59
|
-
<div class="text-gray font-body-small">
|
|
60
|
-
{{
|
|
61
|
-
</div>
|
|
62
|
-
</div>
|
|
63
|
-
</div>
|
|
64
|
-
|
|
65
|
-
<div v-if="props.item.review?.description" class="font-body-large">
|
|
66
|
-
{{ props.item.review?.description }}
|
|
67
|
-
</div>
|
|
68
|
-
|
|
69
|
-
<div v-if="props.item.review?.images?.length" class="flex gap-[8px]">
|
|
70
|
-
<DisplayImageReview
|
|
71
|
-
:items="props.item.review?.images"
|
|
72
|
-
@select="selectImage"
|
|
73
|
-
/>
|
|
74
|
-
</div>
|
|
75
|
-
</div>
|
|
76
|
-
|
|
77
|
-
<div v-if="props.item.replies">
|
|
78
|
-
<div class="p-[16px] rounded-sm bg-bright">
|
|
79
|
-
<div class="text-gray font-body-large">
|
|
80
|
-
การตอบกลับจาก {{ props.item.replies?.author }}
|
|
81
|
-
</div>
|
|
82
|
-
<div class="font-body-large">
|
|
83
|
-
{{ props.item.replies?.description }}
|
|
84
|
-
</div>
|
|
85
|
-
</div>
|
|
86
|
-
</div>
|
|
87
|
-
</div>
|
|
88
|
-
</div>
|
|
89
|
-
|
|
90
|
-
<ModalMediaView
|
|
91
|
-
v-model="isOpen"
|
|
92
|
-
:items="props.item.review?.images"
|
|
93
|
-
:start-index="startIndex"
|
|
94
|
-
title="รูปภาพรีวิว"
|
|
95
|
-
/>
|
|
34
|
+
"
|
|
35
|
+
:size="20"
|
|
36
|
+
/>
|
|
37
|
+
{{ convertNumber(likeCount) }}
|
|
38
|
+
</Button>
|
|
39
|
+
<PickerOptionMenuUser
|
|
40
|
+
v-if="!props.disabledMenu"
|
|
41
|
+
:state="menuType"
|
|
42
|
+
disabled-padding
|
|
43
|
+
@review-edit="emit('edit', props.item)"
|
|
44
|
+
@review-delete="emit('delete', props.item)"
|
|
45
|
+
/>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
<div class="text-gray font-body-small">
|
|
49
|
+
{{ convertNumber(props.item.user?.review_count ?? 0) }} รีวิว •
|
|
50
|
+
{{ convertNumber(props.item.user?.like_count ?? 0) }} ชื่นชอบรีวิว
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
<div class="flex gap-[8px] items-center">
|
|
54
|
+
<InputRating
|
|
55
|
+
:size="11"
|
|
56
|
+
readonly
|
|
57
|
+
:model-value="props.item.review?.rating"
|
|
58
|
+
/>
|
|
59
|
+
<div class="text-gray font-body-small">
|
|
60
|
+
{{ convertDateTime(props.item.review?.created_at ?? "") }}
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
<div v-if="props.item.review?.description" class="font-body-large">
|
|
66
|
+
{{ props.item.review?.description }}
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
<div v-if="props.item.review?.images?.length" class="flex gap-[8px]">
|
|
70
|
+
<DisplayImageReview
|
|
71
|
+
:items="props.item.review?.images"
|
|
72
|
+
@select="selectImage"
|
|
73
|
+
/>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
|
|
77
|
+
<div v-if="props.item.replies">
|
|
78
|
+
<div class="p-[16px] rounded-sm bg-bright">
|
|
79
|
+
<div class="text-gray font-body-large">
|
|
80
|
+
การตอบกลับจาก {{ props.item.replies?.author }}
|
|
81
|
+
</div>
|
|
82
|
+
<div class="font-body-large">
|
|
83
|
+
{{ props.item.replies?.description }}
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
</div>
|
|
89
|
+
|
|
90
|
+
<ModalMediaView
|
|
91
|
+
v-model="isOpen"
|
|
92
|
+
:items="props.item.review?.images"
|
|
93
|
+
:start-index="startIndex"
|
|
94
|
+
title="รูปภาพรีวิว"
|
|
95
|
+
/>
|
|
96
96
|
</template>
|
|
97
97
|
|
|
98
98
|
<script setup>
|
|
@@ -100,7 +100,7 @@ import { computed, ref, watch } from "vue";
|
|
|
100
100
|
import { useRouter } from "vue-router";
|
|
101
101
|
import { useConvert } from "../../composables/useConvert";
|
|
102
102
|
const router = useRouter();
|
|
103
|
-
const { convertNumber,
|
|
103
|
+
const { convertNumber, convertDateTime } = useConvert();
|
|
104
104
|
const props = defineProps({
|
|
105
105
|
item: { type: Object, required: true, default: () => ({
|
|
106
106
|
review_id: "0",
|
|
@@ -1,74 +1,74 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<Drawer
|
|
3
|
-
class="w-[748px]"
|
|
4
|
-
:title="drawerTitle"
|
|
5
|
-
@close="onClose"
|
|
6
|
-
disabled-auto-close
|
|
7
|
-
@submit="onSubmit"
|
|
8
|
-
v-model="isOpen"
|
|
9
|
-
>
|
|
10
|
-
<div class="flex flex-col gap-[16px]">
|
|
11
|
-
<div class="flex gap-[16px]">
|
|
12
|
-
<div class="w-[178px] h-[100px] rounded-[8px] overflow-hidden flex-shrink-0">
|
|
13
|
-
<Image
|
|
14
|
-
v-if="form.coverImage"
|
|
15
|
-
:src="form.coverImage"
|
|
16
|
-
width="auto"
|
|
17
|
-
height="auto"
|
|
18
|
-
fit="cover"
|
|
19
|
-
/>
|
|
20
|
-
</div>
|
|
21
|
-
<div class="flex flex-col gap-[4px]">
|
|
22
|
-
<div class="font-body-large-prominent">{{ form.placeName }}</div>
|
|
23
|
-
<div class="font-body-small text-gray">{{ form.address }}</div>
|
|
24
|
-
</div>
|
|
25
|
-
</div>
|
|
26
|
-
|
|
27
|
-
<div class="flex items-center justify-center py-[16px]">
|
|
28
|
-
<InputRating v-model="form.rating" :size="28" />
|
|
29
|
-
</div>
|
|
30
|
-
|
|
31
|
-
<InputTextarea
|
|
32
|
-
name="description"
|
|
33
|
-
label="คำอธิบาย"
|
|
34
|
-
placeholder="เขียนรีวิวของคุณ"
|
|
35
|
-
showCounter
|
|
36
|
-
v-model="form.description"
|
|
37
|
-
class="min-h-[120px]"
|
|
38
|
-
/>
|
|
39
|
-
|
|
40
|
-
<div class="flex flex-col gap-[8px]">
|
|
41
|
-
<div class="flex flex-col gap-[4px]">
|
|
42
|
-
<div class="text-gray font-body-large">เพิ่มภาพถ่าย</div>
|
|
43
|
-
<div class="text-gray font-body-small">อัปโหลด 9 รายการ</div>
|
|
44
|
-
</div>
|
|
45
|
-
<InputFile
|
|
46
|
-
:limit="9"
|
|
47
|
-
name="photos"
|
|
48
|
-
accept="image/jpeg,image/png,image/webp,image/bmp,image/gif"
|
|
49
|
-
v-model="form.photos"
|
|
50
|
-
/>
|
|
51
|
-
<div class="flex flex-col text-gray font-body-small">
|
|
52
|
-
<div>รองรับไฟล์ *.jpg *.jpeg *.png *.webp *.bmp *.gif</div>
|
|
53
|
-
<div>ขนาดไฟล์สูงสุด 30 mb</div>
|
|
54
|
-
</div>
|
|
55
|
-
</div>
|
|
56
|
-
</div>
|
|
57
|
-
|
|
58
|
-
<template #footer>
|
|
59
|
-
<div class="flex justify-end gap-[16px] items-center">
|
|
60
|
-
<Button variant="outline" @click="onClose" :disabled="isSubmitting">ยกเลิก</Button>
|
|
61
|
-
<Button
|
|
62
|
-
type="submit"
|
|
63
|
-
color="primary"
|
|
64
|
-
:disabled="form.rating === 0 || isSubmitting"
|
|
65
|
-
:loading="isSubmitting"
|
|
66
|
-
>
|
|
67
|
-
ยืนยัน
|
|
68
|
-
</Button>
|
|
69
|
-
</div>
|
|
70
|
-
</template>
|
|
71
|
-
</Drawer>
|
|
2
|
+
<Drawer
|
|
3
|
+
class="w-[748px]"
|
|
4
|
+
:title="drawerTitle"
|
|
5
|
+
@close="onClose"
|
|
6
|
+
disabled-auto-close
|
|
7
|
+
@submit="onSubmit"
|
|
8
|
+
v-model="isOpen"
|
|
9
|
+
>
|
|
10
|
+
<div class="flex flex-col gap-[16px]">
|
|
11
|
+
<div class="flex gap-[16px]">
|
|
12
|
+
<div class="w-[178px] h-[100px] rounded-[8px] overflow-hidden flex-shrink-0">
|
|
13
|
+
<Image
|
|
14
|
+
v-if="form.coverImage"
|
|
15
|
+
:src="form.coverImage"
|
|
16
|
+
width="auto"
|
|
17
|
+
height="auto"
|
|
18
|
+
fit="cover"
|
|
19
|
+
/>
|
|
20
|
+
</div>
|
|
21
|
+
<div class="flex flex-col gap-[4px]">
|
|
22
|
+
<div class="font-body-large-prominent">{{ form.placeName }}</div>
|
|
23
|
+
<div class="font-body-small text-gray">{{ form.address }}</div>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<div class="flex items-center justify-center py-[16px]">
|
|
28
|
+
<InputRating v-model="form.rating" :size="28" />
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<InputTextarea
|
|
32
|
+
name="description"
|
|
33
|
+
label="คำอธิบาย"
|
|
34
|
+
placeholder="เขียนรีวิวของคุณ"
|
|
35
|
+
showCounter
|
|
36
|
+
v-model="form.description"
|
|
37
|
+
class="min-h-[120px]"
|
|
38
|
+
/>
|
|
39
|
+
|
|
40
|
+
<div class="flex flex-col gap-[8px]">
|
|
41
|
+
<div class="flex flex-col gap-[4px]">
|
|
42
|
+
<div class="text-gray font-body-large">เพิ่มภาพถ่าย</div>
|
|
43
|
+
<div class="text-gray font-body-small">อัปโหลด 9 รายการ</div>
|
|
44
|
+
</div>
|
|
45
|
+
<InputFile
|
|
46
|
+
:limit="9"
|
|
47
|
+
name="photos"
|
|
48
|
+
accept="image/jpeg,image/png,image/webp,image/bmp,image/gif"
|
|
49
|
+
v-model="form.photos"
|
|
50
|
+
/>
|
|
51
|
+
<div class="flex flex-col text-gray font-body-small">
|
|
52
|
+
<div>รองรับไฟล์ *.jpg *.jpeg *.png *.webp *.bmp *.gif</div>
|
|
53
|
+
<div>ขนาดไฟล์สูงสุด 30 mb</div>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<template #footer>
|
|
59
|
+
<div class="flex justify-end gap-[16px] items-center">
|
|
60
|
+
<Button variant="outline" @click="onClose" :disabled="isSubmitting">ยกเลิก</Button>
|
|
61
|
+
<Button
|
|
62
|
+
type="submit"
|
|
63
|
+
color="primary"
|
|
64
|
+
:disabled="form.rating === 0 || isSubmitting"
|
|
65
|
+
:loading="isSubmitting"
|
|
66
|
+
>
|
|
67
|
+
ยืนยัน
|
|
68
|
+
</Button>
|
|
69
|
+
</div>
|
|
70
|
+
</template>
|
|
71
|
+
</Drawer>
|
|
72
72
|
</template>
|
|
73
73
|
|
|
74
74
|
<script setup>
|
|
@@ -17,13 +17,19 @@
|
|
|
17
17
|
<ShadTabs v-model="activeTab" class="flex-1 flex flex-col h-full">
|
|
18
18
|
<ShadTabsList>
|
|
19
19
|
<ShadTabsTrigger value="followers" class="px-[16px] py-[8px]">
|
|
20
|
-
ผู้ติดตาม ({{
|
|
20
|
+
ผู้ติดตาม ({{
|
|
21
|
+
$convert.convertNumber(profileData?.follower_count || 0)
|
|
22
|
+
}})
|
|
21
23
|
</ShadTabsTrigger>
|
|
22
24
|
<ShadTabsTrigger value="following" class="px-[16px] py-[8px]">
|
|
23
|
-
กำลังติดตาม ({{
|
|
25
|
+
กำลังติดตาม ({{
|
|
26
|
+
$convert.convertNumber(profileData?.following_count || 0)
|
|
27
|
+
}})
|
|
24
28
|
</ShadTabsTrigger>
|
|
25
29
|
<ShadTabsTrigger value="favorites" class="px-[16px] py-[8px]">
|
|
26
|
-
สถานที่โปรด ({{
|
|
30
|
+
สถานที่โปรด ({{
|
|
31
|
+
$convert.convertNumber(profileData?.like_place_count || 0)
|
|
32
|
+
}})
|
|
27
33
|
</ShadTabsTrigger>
|
|
28
34
|
</ShadTabsList>
|
|
29
35
|
|
|
@@ -32,33 +38,62 @@
|
|
|
32
38
|
<ShadTabsContent value="followers" class="flex flex-col mt-0">
|
|
33
39
|
<template v-if="tabState.followers.loading">
|
|
34
40
|
<div class="flex justify-center py-[40px]">
|
|
35
|
-
<Icon
|
|
41
|
+
<Icon
|
|
42
|
+
name="lucide:loader-2"
|
|
43
|
+
size="24"
|
|
44
|
+
class="animate-spin text-gray"
|
|
45
|
+
/>
|
|
36
46
|
</div>
|
|
37
47
|
</template>
|
|
38
48
|
<template v-else-if="followers.length > 0">
|
|
39
49
|
<div class="flex flex-col gap-[16px]">
|
|
40
|
-
<template
|
|
41
|
-
|
|
50
|
+
<template
|
|
51
|
+
v-for="(user, index) in followers"
|
|
52
|
+
:key="user.id || index"
|
|
53
|
+
>
|
|
54
|
+
<CardUserItem
|
|
55
|
+
v-model="followers[index]"
|
|
56
|
+
@require-auth="emit('require-auth')"
|
|
57
|
+
/>
|
|
42
58
|
<Divider v-if="index !== followers.length - 1" />
|
|
43
59
|
</template>
|
|
44
60
|
</div>
|
|
45
|
-
<div
|
|
46
|
-
|
|
61
|
+
<div
|
|
62
|
+
v-if="tabState.followers.loadingMore"
|
|
63
|
+
class="flex justify-center py-[16px]"
|
|
64
|
+
>
|
|
65
|
+
<Icon
|
|
66
|
+
name="lucide:loader-2"
|
|
67
|
+
size="20"
|
|
68
|
+
class="animate-spin text-gray"
|
|
69
|
+
/>
|
|
47
70
|
</div>
|
|
48
71
|
</template>
|
|
49
72
|
<template v-else>
|
|
50
|
-
<div
|
|
51
|
-
|
|
73
|
+
<div
|
|
74
|
+
v-if="isMyProfile"
|
|
75
|
+
class="h-[200px] flex flex-col gap-[8px] items-center justify-center"
|
|
76
|
+
>
|
|
77
|
+
<div class="font-title-medium-prominent text-black">
|
|
78
|
+
กำลังมองหาผู้ติดตามอยู่ใช่ไหม
|
|
79
|
+
</div>
|
|
52
80
|
<div class="flex flex-col font-body-large text-gray items-center">
|
|
53
81
|
<div>เมื่อมีคนติดตามบัญชีนี้ ข้อมูลจะแสดงที่นี่</div>
|
|
54
82
|
<div>การโพสต์และการโต้ตอบกับผู้อื่นจะช่วยเพิ่มผู้ติดตาม</div>
|
|
55
83
|
</div>
|
|
56
84
|
</div>
|
|
57
|
-
<div
|
|
58
|
-
|
|
85
|
+
<div
|
|
86
|
+
v-else
|
|
87
|
+
class="h-[200px] flex flex-col gap-[8px] items-center justify-center"
|
|
88
|
+
>
|
|
89
|
+
<div
|
|
90
|
+
class="font-title-medium-prominent text-black flex gap-[4px]"
|
|
91
|
+
>
|
|
59
92
|
{{ profileData?.name }} ยังไม่มีผู้ติดตาม
|
|
60
93
|
</div>
|
|
61
|
-
<div class="font-body-large text-gray"
|
|
94
|
+
<div class="font-body-large text-gray">
|
|
95
|
+
เมื่อมีคนติดตามบัญชีนี้ ข้อมูลจะแสดงที่นี่
|
|
96
|
+
</div>
|
|
62
97
|
</div>
|
|
63
98
|
</template>
|
|
64
99
|
</ShadTabsContent>
|
|
@@ -67,36 +102,71 @@
|
|
|
67
102
|
<ShadTabsContent value="following" class="flex flex-col mt-0">
|
|
68
103
|
<template v-if="tabState.following.loading">
|
|
69
104
|
<div class="flex justify-center py-[40px]">
|
|
70
|
-
<Icon
|
|
105
|
+
<Icon
|
|
106
|
+
name="lucide:loader-2"
|
|
107
|
+
size="24"
|
|
108
|
+
class="animate-spin text-gray"
|
|
109
|
+
/>
|
|
71
110
|
</div>
|
|
72
111
|
</template>
|
|
73
112
|
<template v-else-if="following.length > 0">
|
|
74
113
|
<div class="flex flex-col gap-[16px]">
|
|
75
|
-
<template
|
|
76
|
-
|
|
114
|
+
<template
|
|
115
|
+
v-for="(user, index) in following"
|
|
116
|
+
:key="user.id || index"
|
|
117
|
+
>
|
|
118
|
+
<CardUserItem
|
|
119
|
+
v-model="following[index]"
|
|
120
|
+
@require-auth="emit('require-auth')"
|
|
121
|
+
/>
|
|
77
122
|
<Divider v-if="index !== following.length - 1" />
|
|
78
123
|
</template>
|
|
79
124
|
</div>
|
|
80
|
-
<div
|
|
81
|
-
|
|
125
|
+
<div
|
|
126
|
+
v-if="tabState.following.loadingMore"
|
|
127
|
+
class="flex justify-center py-[16px]"
|
|
128
|
+
>
|
|
129
|
+
<Icon
|
|
130
|
+
name="lucide:loader-2"
|
|
131
|
+
size="20"
|
|
132
|
+
class="animate-spin text-gray"
|
|
133
|
+
/>
|
|
82
134
|
</div>
|
|
83
135
|
</template>
|
|
84
136
|
<template v-else>
|
|
85
|
-
<div
|
|
137
|
+
<div
|
|
138
|
+
v-if="isMyProfile"
|
|
139
|
+
class="flex flex-col gap-[24px] items-center justify-center h-[200px]"
|
|
140
|
+
>
|
|
86
141
|
<div class="flex flex-col gap-[8px] items-center">
|
|
87
|
-
<div class="font-title-medium-prominent text-black"
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
142
|
+
<div class="font-title-medium-prominent text-black">
|
|
143
|
+
ทันเหตุการณ์
|
|
144
|
+
</div>
|
|
145
|
+
<div
|
|
146
|
+
class="flex flex-col font-body-large text-gray items-center"
|
|
147
|
+
>
|
|
148
|
+
<div>
|
|
149
|
+
การติดตามบัญชีเป็นวิธีที่ง่ายในการสร้างลำดับเหตุการณ์
|
|
150
|
+
</div>
|
|
151
|
+
<div>
|
|
152
|
+
ของคุณและรู้ว่ามีอะไรเกิดขึ้นบ้างกับหัวข้อและผู้ที่คุณสนใจ
|
|
153
|
+
</div>
|
|
91
154
|
</div>
|
|
92
155
|
</div>
|
|
93
|
-
<Button color="primary" @click="emit('explore-profiles')"
|
|
156
|
+
<Button color="primary" @click="emit('explore-profiles')"
|
|
157
|
+
>ติดตามใครดี</Button
|
|
158
|
+
>
|
|
94
159
|
</div>
|
|
95
|
-
<div
|
|
160
|
+
<div
|
|
161
|
+
v-else
|
|
162
|
+
class="h-[200px] flex flex-col gap-[8px] items-center justify-center"
|
|
163
|
+
>
|
|
96
164
|
<div class="font-title-medium-prominent text-black">
|
|
97
165
|
{{ profileData?.name }} ไม่ได้กำลังติดตามใคร
|
|
98
166
|
</div>
|
|
99
|
-
<div class="font-body-large text-gray"
|
|
167
|
+
<div class="font-body-large text-gray">
|
|
168
|
+
เมื่อพวกเขาติดตามบัญชี ข้อมูลจะแสดงที่นี่
|
|
169
|
+
</div>
|
|
100
170
|
</div>
|
|
101
171
|
</template>
|
|
102
172
|
</ShadTabsContent>
|
|
@@ -105,30 +175,65 @@
|
|
|
105
175
|
<ShadTabsContent value="favorites" class="flex flex-col mt-0">
|
|
106
176
|
<template v-if="tabState.favorites.loading">
|
|
107
177
|
<div class="flex justify-center py-[40px]">
|
|
108
|
-
<Icon
|
|
178
|
+
<Icon
|
|
179
|
+
name="lucide:loader-2"
|
|
180
|
+
size="24"
|
|
181
|
+
class="animate-spin text-gray"
|
|
182
|
+
/>
|
|
109
183
|
</div>
|
|
110
184
|
</template>
|
|
111
185
|
<template v-else-if="favorites.length > 0">
|
|
112
|
-
<div class="flex flex-col
|
|
113
|
-
|
|
186
|
+
<div class="flex flex-col gap-[16px]">
|
|
187
|
+
<template
|
|
188
|
+
v-for="(place, index) in favorites"
|
|
189
|
+
:key="place.id || index"
|
|
190
|
+
>
|
|
191
|
+
<CardPlaceItem
|
|
192
|
+
v-model="favorites[index]"
|
|
193
|
+
@require-auth="emit('require-auth')"
|
|
194
|
+
/>
|
|
195
|
+
<Divider v-if="index !== favorites.length - 1" />
|
|
196
|
+
</template>
|
|
114
197
|
</div>
|
|
115
|
-
|
|
116
|
-
|
|
198
|
+
|
|
199
|
+
<div
|
|
200
|
+
v-if="tabState.favorites.loadingMore"
|
|
201
|
+
class="flex justify-center py-[16px]"
|
|
202
|
+
>
|
|
203
|
+
<Icon
|
|
204
|
+
name="lucide:loader-2"
|
|
205
|
+
size="20"
|
|
206
|
+
class="animate-spin text-gray"
|
|
207
|
+
/>
|
|
117
208
|
</div>
|
|
118
209
|
</template>
|
|
119
210
|
<template v-else>
|
|
120
|
-
<div
|
|
211
|
+
<div
|
|
212
|
+
v-if="isMyProfile"
|
|
213
|
+
class="flex flex-col gap-[24px] items-center justify-center h-[200px]"
|
|
214
|
+
>
|
|
121
215
|
<div class="flex flex-col gap-[8px] items-center">
|
|
122
|
-
<div class="font-title-medium-prominent text-black"
|
|
123
|
-
|
|
216
|
+
<div class="font-title-medium-prominent text-black">
|
|
217
|
+
ยังไม่มีสถานที่โปรด
|
|
218
|
+
</div>
|
|
219
|
+
<div class="font-body-large text-gray">
|
|
220
|
+
กดหัวใจที่สถานที่ใดก็ได้เพื่อบันทึกไว้ที่นี่
|
|
221
|
+
</div>
|
|
124
222
|
</div>
|
|
125
|
-
<Button color="primary" @click="emit('explore-places')"
|
|
223
|
+
<Button color="primary" @click="emit('explore-places')"
|
|
224
|
+
>ที่ไหนน่าสนใจ</Button
|
|
225
|
+
>
|
|
126
226
|
</div>
|
|
127
|
-
<div
|
|
227
|
+
<div
|
|
228
|
+
v-else
|
|
229
|
+
class="h-[200px] flex flex-col gap-[8px] items-center justify-center"
|
|
230
|
+
>
|
|
128
231
|
<div class="font-title-medium-prominent text-black">
|
|
129
232
|
@{{ profileData?.name }} ยังไม่มีสถานที่โปรด
|
|
130
233
|
</div>
|
|
131
|
-
<div class="font-body-large text-gray"
|
|
234
|
+
<div class="font-body-large text-gray">
|
|
235
|
+
เมื่อเขาบันทึกสถานที่ไว้จะแสดงที่นี่
|
|
236
|
+
</div>
|
|
132
237
|
</div>
|
|
133
238
|
</template>
|
|
134
239
|
</ShadTabsContent>
|
|
@@ -179,9 +284,12 @@ const fetchFollowers = async (isLoadMore = false) => {
|
|
|
179
284
|
s.page = 1;
|
|
180
285
|
}
|
|
181
286
|
try {
|
|
182
|
-
const res = await api(
|
|
183
|
-
|
|
184
|
-
|
|
287
|
+
const res = await api(
|
|
288
|
+
`/profiles/${props.profileId}/followers`,
|
|
289
|
+
{
|
|
290
|
+
query: { page: s.page, page_size: PAGE_SIZE }
|
|
291
|
+
}
|
|
292
|
+
);
|
|
185
293
|
if (res.meta) s.hasMore = s.page < res.meta.total_pages;
|
|
186
294
|
if (res.data?.profile) syncProfile(res.data.profile);
|
|
187
295
|
const items = res.data?.items || [];
|
|
@@ -204,9 +312,12 @@ const fetchFollowing = async (isLoadMore = false) => {
|
|
|
204
312
|
s.page = 1;
|
|
205
313
|
}
|
|
206
314
|
try {
|
|
207
|
-
const res = await api(
|
|
208
|
-
|
|
209
|
-
|
|
315
|
+
const res = await api(
|
|
316
|
+
`/profiles/${props.profileId}/following`,
|
|
317
|
+
{
|
|
318
|
+
query: { page: s.page, page_size: PAGE_SIZE }
|
|
319
|
+
}
|
|
320
|
+
);
|
|
210
321
|
if (res.meta) s.hasMore = s.page < res.meta.total_pages;
|
|
211
322
|
if (res.data?.profile) syncProfile(res.data.profile);
|
|
212
323
|
const items = res.data?.items || [];
|
|
@@ -229,10 +340,9 @@ const fetchFavorites = async (isLoadMore = false) => {
|
|
|
229
340
|
s.page = 1;
|
|
230
341
|
}
|
|
231
342
|
try {
|
|
232
|
-
const res = await api(
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
);
|
|
343
|
+
const res = await api(`/profiles/${props.profileId}/liked-places`, {
|
|
344
|
+
query: { page: s.page, page_size: PAGE_SIZE }
|
|
345
|
+
});
|
|
236
346
|
if (res.meta) s.hasMore = s.page < res.meta.total_pages;
|
|
237
347
|
if (res.data?.profile) syncProfile(res.data.profile);
|
|
238
348
|
const items = res.data?.items || [];
|
|
@@ -1,130 +1,130 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="flex gap-[16px] w-full">
|
|
3
|
-
<!-- กรอกข้อมูล -->
|
|
4
|
-
<div class="flex flex-col gap-[16px] w-[490px]">
|
|
5
|
-
<InputAddress name="address" v-model="modelValue.address" :fixed-province-id="props.fixedProvinceId" />
|
|
6
|
-
<template v-if="isAddressCompleted">
|
|
7
|
-
<div class="font-body-large-prominent">รายละเอียด</div>
|
|
8
|
-
<div class="flex flex-col gap-[4px]">
|
|
9
|
-
<InputAutocomplete
|
|
10
|
-
name="businessName"
|
|
11
|
-
v-model="modelValue.businessName"
|
|
12
|
-
label="ชื่อสถานที่ธุรกิจ"
|
|
13
|
-
placeholder="กรอกชื่อสถานที่"
|
|
14
|
-
required
|
|
15
|
-
show-counter
|
|
16
|
-
:limit="180"
|
|
17
|
-
:free-text="true"
|
|
18
|
-
:fetch-fn="fetchApprovedPlaces"
|
|
19
|
-
value-key="business_name"
|
|
20
|
-
label-key="business_name"
|
|
21
|
-
/>
|
|
22
|
-
<InputTextField
|
|
23
|
-
v-if="extraNameCount >= 1"
|
|
24
|
-
name="nameTh"
|
|
25
|
-
v-model="modelValue.nameTh"
|
|
26
|
-
label="ชื่อภาษาไทย"
|
|
27
|
-
placeholder="ใส่ในกรณีที่ต่างจากชื่อหลัก"
|
|
28
|
-
show-counter
|
|
29
|
-
:limit="180"
|
|
30
|
-
/>
|
|
31
|
-
<InputTextField
|
|
32
|
-
v-if="extraNameCount >= 2"
|
|
33
|
-
name="nameEn"
|
|
34
|
-
v-model="modelValue.nameEn"
|
|
35
|
-
label="ชื่อภาษาอังกฤษ"
|
|
36
|
-
placeholder="ใส่ในกรณีที่ต่างจากชื่อหลัก"
|
|
37
|
-
show-counter
|
|
38
|
-
:limit="180"
|
|
39
|
-
/>
|
|
40
|
-
<Button v-if="extraNameCount < 2" variant="text" color="primary" class="w-[145px]" @click="extraNameCount++">
|
|
41
|
-
<Icon name="lucide:plus" />
|
|
42
|
-
เพิ่มชื่อสถานที่
|
|
43
|
-
</Button>
|
|
44
|
-
</div>
|
|
45
|
-
<InputCombobox
|
|
46
|
-
name="categories"
|
|
47
|
-
v-model="modelValue.categories"
|
|
48
|
-
label="หมวดหมู่"
|
|
49
|
-
placeholder="เพิ่มหมวดหมู่ที่เกี่ยวข้องกับสถานที่"
|
|
50
|
-
:limit="3"
|
|
51
|
-
show-counter
|
|
52
|
-
:options="categoryOptions"
|
|
53
|
-
required
|
|
54
|
-
multiple
|
|
55
|
-
/>
|
|
56
|
-
<InputTextarea
|
|
57
|
-
name="description"
|
|
58
|
-
v-model="modelValue.description"
|
|
59
|
-
label="คำอธิบาย"
|
|
60
|
-
placeholder="คำอธิบายเกี่ยวกับสถานที่ (สูงสุด 220 ตัวอักษร)"
|
|
61
|
-
:limit="220"
|
|
62
|
-
show-counter
|
|
63
|
-
/>
|
|
64
|
-
<InputDateOpening name="openingHours" v-model="modelValue.openingHours" />
|
|
65
|
-
<div class="flex flex-col gap-[8px]">
|
|
66
|
-
<InputTextField name="phone" v-model="modelValue.phone" label="เบอร์โทรศัพท์" placeholder="กรอกเบอร์โทรศัพท์" />
|
|
67
|
-
<InputTextField
|
|
68
|
-
v-for="(_, index) in modelValue.extraPhones"
|
|
69
|
-
:key="index"
|
|
70
|
-
:name="`extraPhone-${index}`"
|
|
71
|
-
label="เบอร์โทรศัพท์"
|
|
72
|
-
placeholder="กรอกเบอร์โทรศัพท์"
|
|
73
|
-
v-model="modelValue.extraPhones[index]"
|
|
74
|
-
/>
|
|
75
|
-
<Button variant="text" color="primary" class="w-[145px]" @click="modelValue.extraPhones.push('')">
|
|
76
|
-
<Icon name="lucide:plus" />
|
|
77
|
-
เพิ่มเบอร์โทรศัพท์
|
|
78
|
-
</Button>
|
|
79
|
-
<InputLink name="contactChannels" format="contact_channel" default-first v-model="modelValue.contactChannels" />
|
|
80
|
-
</div>
|
|
81
|
-
<template v-if="props.state === 'personal'">
|
|
82
|
-
<div class="flex flex-col gap-[16px]">
|
|
83
|
-
<InputCheckbox name="isReview" v-model="modelValue.isReview" label="คุณต้องการรีวิวสถานที่นี้" />
|
|
84
|
-
<template v-if="modelValue.isReview">
|
|
85
|
-
<InputRating name="rating" v-model="modelValue.rating" class="flex py-4 justify-center" />
|
|
86
|
-
<InputTextarea
|
|
87
|
-
name="reviewDescription"
|
|
88
|
-
v-model="modelValue.reviewDescription"
|
|
89
|
-
label="คำอธิบาย"
|
|
90
|
-
placeholder="คำอธิบายเกี่ยวกับสถานที่"
|
|
91
|
-
show-counter
|
|
92
|
-
/>
|
|
93
|
-
<div class="flex flex-col gap-[8px]">
|
|
94
|
-
<div class="flex flex-col gap-[4px]">
|
|
95
|
-
<div class="font-body-large-prominent text-gray">เพิ่มภาพถ่าย</div>
|
|
96
|
-
<div class="font-body-small text-gray">สูงสุด 9 รายการ</div>
|
|
97
|
-
</div>
|
|
98
|
-
<InputFile name="reviewPhotos" v-model="modelValue.reviewPhotos" accept="image/*" :limit="9" />
|
|
99
|
-
<div class="font-body-small text-gray w-[250px]">
|
|
100
|
-
รองรับไฟล์ *.jpg *.jpeg *.png *.webp *.bmp *.gif ขนาดไฟล์ไม่เกิน 30 mb
|
|
101
|
-
</div>
|
|
102
|
-
</div>
|
|
103
|
-
</template>
|
|
104
|
-
</div>
|
|
105
|
-
</template>
|
|
106
|
-
</template>
|
|
107
|
-
</div>
|
|
108
|
-
|
|
109
|
-
<!-- แสดง polygon -->
|
|
110
|
-
<div class="flex flex-col gap-[16px] w-[334px] sticky top-0 self-start">
|
|
111
|
-
<SuggestPlaceMap
|
|
112
|
-
:province-id="modelValue.address?.province_id"
|
|
113
|
-
:amphur-id="modelValue.address?.amphur_id"
|
|
114
|
-
:tambon-id="modelValue.address?.tambon_id"
|
|
115
|
-
@update:lat-lng="modelValue.latLng = $event"
|
|
116
|
-
/>
|
|
117
|
-
<InputTextField
|
|
118
|
-
name="latitude-longitude"
|
|
119
|
-
icon-prepend="lucide:locate-fixed"
|
|
120
|
-
readonly
|
|
121
|
-
placeholder="ละติจูด, ลองจิจูด"
|
|
2
|
+
<div class="flex gap-[16px] w-full">
|
|
3
|
+
<!-- กรอกข้อมูล -->
|
|
4
|
+
<div class="flex flex-col gap-[16px] w-[490px]">
|
|
5
|
+
<InputAddress name="address" v-model="modelValue.address" :fixed-province-id="props.fixedProvinceId" />
|
|
6
|
+
<template v-if="isAddressCompleted">
|
|
7
|
+
<div class="font-body-large-prominent">รายละเอียด</div>
|
|
8
|
+
<div class="flex flex-col gap-[4px]">
|
|
9
|
+
<InputAutocomplete
|
|
10
|
+
name="businessName"
|
|
11
|
+
v-model="modelValue.businessName"
|
|
12
|
+
label="ชื่อสถานที่ธุรกิจ"
|
|
13
|
+
placeholder="กรอกชื่อสถานที่"
|
|
14
|
+
required
|
|
15
|
+
show-counter
|
|
16
|
+
:limit="180"
|
|
17
|
+
:free-text="true"
|
|
18
|
+
:fetch-fn="fetchApprovedPlaces"
|
|
19
|
+
value-key="business_name"
|
|
20
|
+
label-key="business_name"
|
|
21
|
+
/>
|
|
22
|
+
<InputTextField
|
|
23
|
+
v-if="extraNameCount >= 1"
|
|
24
|
+
name="nameTh"
|
|
25
|
+
v-model="modelValue.nameTh"
|
|
26
|
+
label="ชื่อภาษาไทย"
|
|
27
|
+
placeholder="ใส่ในกรณีที่ต่างจากชื่อหลัก"
|
|
28
|
+
show-counter
|
|
29
|
+
:limit="180"
|
|
30
|
+
/>
|
|
31
|
+
<InputTextField
|
|
32
|
+
v-if="extraNameCount >= 2"
|
|
33
|
+
name="nameEn"
|
|
34
|
+
v-model="modelValue.nameEn"
|
|
35
|
+
label="ชื่อภาษาอังกฤษ"
|
|
36
|
+
placeholder="ใส่ในกรณีที่ต่างจากชื่อหลัก"
|
|
37
|
+
show-counter
|
|
38
|
+
:limit="180"
|
|
39
|
+
/>
|
|
40
|
+
<Button v-if="extraNameCount < 2" variant="text" color="primary" class="w-[145px]" @click="extraNameCount++">
|
|
41
|
+
<Icon name="lucide:plus" />
|
|
42
|
+
เพิ่มชื่อสถานที่
|
|
43
|
+
</Button>
|
|
44
|
+
</div>
|
|
45
|
+
<InputCombobox
|
|
46
|
+
name="categories"
|
|
47
|
+
v-model="modelValue.categories"
|
|
48
|
+
label="หมวดหมู่"
|
|
49
|
+
placeholder="เพิ่มหมวดหมู่ที่เกี่ยวข้องกับสถานที่"
|
|
50
|
+
:limit="3"
|
|
51
|
+
show-counter
|
|
52
|
+
:options="categoryOptions"
|
|
53
|
+
required
|
|
54
|
+
multiple
|
|
55
|
+
/>
|
|
56
|
+
<InputTextarea
|
|
57
|
+
name="description"
|
|
58
|
+
v-model="modelValue.description"
|
|
59
|
+
label="คำอธิบาย"
|
|
60
|
+
placeholder="คำอธิบายเกี่ยวกับสถานที่ (สูงสุด 220 ตัวอักษร)"
|
|
61
|
+
:limit="220"
|
|
62
|
+
show-counter
|
|
63
|
+
/>
|
|
64
|
+
<InputDateOpening name="openingHours" v-model="modelValue.openingHours" />
|
|
65
|
+
<div class="flex flex-col gap-[8px]">
|
|
66
|
+
<InputTextField name="phone" v-model="modelValue.phone" label="เบอร์โทรศัพท์" placeholder="กรอกเบอร์โทรศัพท์" />
|
|
67
|
+
<InputTextField
|
|
68
|
+
v-for="(_, index) in modelValue.extraPhones"
|
|
69
|
+
:key="index"
|
|
70
|
+
:name="`extraPhone-${index}`"
|
|
71
|
+
label="เบอร์โทรศัพท์"
|
|
72
|
+
placeholder="กรอกเบอร์โทรศัพท์"
|
|
73
|
+
v-model="modelValue.extraPhones[index]"
|
|
74
|
+
/>
|
|
75
|
+
<Button variant="text" color="primary" class="w-[145px]" @click="modelValue.extraPhones.push('')">
|
|
76
|
+
<Icon name="lucide:plus" />
|
|
77
|
+
เพิ่มเบอร์โทรศัพท์
|
|
78
|
+
</Button>
|
|
79
|
+
<InputLink name="contactChannels" format="contact_channel" default-first v-model="modelValue.contactChannels" />
|
|
80
|
+
</div>
|
|
81
|
+
<template v-if="props.state === 'personal'">
|
|
82
|
+
<div class="flex flex-col gap-[16px]">
|
|
83
|
+
<InputCheckbox name="isReview" v-model="modelValue.isReview" label="คุณต้องการรีวิวสถานที่นี้" />
|
|
84
|
+
<template v-if="modelValue.isReview">
|
|
85
|
+
<InputRating name="rating" v-model="modelValue.rating" class="flex py-4 justify-center" />
|
|
86
|
+
<InputTextarea
|
|
87
|
+
name="reviewDescription"
|
|
88
|
+
v-model="modelValue.reviewDescription"
|
|
89
|
+
label="คำอธิบาย"
|
|
90
|
+
placeholder="คำอธิบายเกี่ยวกับสถานที่"
|
|
91
|
+
show-counter
|
|
92
|
+
/>
|
|
93
|
+
<div class="flex flex-col gap-[8px]">
|
|
94
|
+
<div class="flex flex-col gap-[4px]">
|
|
95
|
+
<div class="font-body-large-prominent text-gray">เพิ่มภาพถ่าย</div>
|
|
96
|
+
<div class="font-body-small text-gray">สูงสุด 9 รายการ</div>
|
|
97
|
+
</div>
|
|
98
|
+
<InputFile name="reviewPhotos" v-model="modelValue.reviewPhotos" accept="image/*" :limit="9" />
|
|
99
|
+
<div class="font-body-small text-gray w-[250px]">
|
|
100
|
+
รองรับไฟล์ *.jpg *.jpeg *.png *.webp *.bmp *.gif ขนาดไฟล์ไม่เกิน 30 mb
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
</template>
|
|
104
|
+
</div>
|
|
105
|
+
</template>
|
|
106
|
+
</template>
|
|
107
|
+
</div>
|
|
108
|
+
|
|
109
|
+
<!-- แสดง polygon -->
|
|
110
|
+
<div class="flex flex-col gap-[16px] w-[334px] sticky top-0 self-start">
|
|
111
|
+
<SuggestPlaceMap
|
|
112
|
+
:province-id="modelValue.address?.province_id"
|
|
113
|
+
:amphur-id="modelValue.address?.amphur_id"
|
|
114
|
+
:tambon-id="modelValue.address?.tambon_id"
|
|
115
|
+
@update:lat-lng="modelValue.latLng = $event"
|
|
116
|
+
/>
|
|
117
|
+
<InputTextField
|
|
118
|
+
name="latitude-longitude"
|
|
119
|
+
icon-prepend="lucide:locate-fixed"
|
|
120
|
+
readonly
|
|
121
|
+
placeholder="ละติจูด, ลองจิจูด"
|
|
122
122
|
:model-value="
|
|
123
123
|
modelValue.latLng ? `${modelValue.latLng.lat.toFixed(6)}, ${modelValue.latLng.lng.toFixed(6)}` : ''
|
|
124
|
-
"
|
|
125
|
-
/>
|
|
126
|
-
</div>
|
|
127
|
-
</div>
|
|
124
|
+
"
|
|
125
|
+
/>
|
|
126
|
+
</div>
|
|
127
|
+
</div>
|
|
128
128
|
</template>
|
|
129
129
|
|
|
130
130
|
<script setup>
|
|
@@ -48,8 +48,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
48
48
|
pageSize: number;
|
|
49
49
|
id: string;
|
|
50
50
|
name: string;
|
|
51
|
-
description: string;
|
|
52
51
|
options: AutocompleteOption[] | string[] | number[];
|
|
52
|
+
description: string;
|
|
53
53
|
limit: number;
|
|
54
54
|
placeholder: string;
|
|
55
55
|
disabledErrorMessage: boolean;
|
|
@@ -48,8 +48,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
48
48
|
pageSize: number;
|
|
49
49
|
id: string;
|
|
50
50
|
name: string;
|
|
51
|
-
description: string;
|
|
52
51
|
options: AutocompleteOption[] | string[] | number[];
|
|
52
|
+
description: string;
|
|
53
53
|
limit: number;
|
|
54
54
|
placeholder: string;
|
|
55
55
|
disabledErrorMessage: boolean;
|
package/package.json
CHANGED
|
File without changes
|