publication v-1

This commit is contained in:
HAM!DREZA
2024-07-03 14:34:21 +03:30
parent d2f71b6b14
commit 1518075cc6
21 changed files with 247 additions and 185 deletions
+9 -7
View File
@@ -3,11 +3,11 @@
<div class="relative text-center h-[56.154vw] md:h-[11.406vw]">
<p
class="text-black post w-[30.769vw] md:w-[6.979vw] h-[9.487vw] md:h-[2.24vw] flexBox text-[3.59vw] md:text-[0.938vw] absolute left-0 bottom-0 bg-white rounded-tr-[3.59vw] md:rounded-tr-[0.781vw]">
{{ props.item?.price > 0 ? numberFormat(props.item?.price) + 'تومان' : 'رایگان' }}
{{ props.item?.item.price > 0 ? numberFormat(props.item?.item.price) + 'تومان' : 'رایگان' }}
</p>
<NuxtImg style="object-fit: cover;" :src="props.item?.image"
<NuxtImg style="object-fit: cover;" :src="props.item?.item.image"
:placeholder="[30, 20]"
alt="laravel"
class="h-[56.154vw] md:h-[11.406vw] w-full rounded-[3.846vw] md:rounded-[0.781vw]"
@@ -20,7 +20,7 @@
<p @click="change"
class="cursor-pointer mb-[15vw] md:mb-[2.5vw] text-[14px] md:text-[0.833vw] text-[#383E43] ] mt-[4vw] md:mt-[1.042vw] ms-[3vw] md:ms-[0.625vw]"
>
{{ props.item?.name }}
{{ props.item?.item.name }}
</p>
<div
@@ -28,13 +28,14 @@
>
<div class="flex justify-between w-full mb-[0.417vw]">
<p class="text-[2.836vw] md:text-[0.658vw] text-[#383E43]">میزان مشاهده</p>
<p class="text-[3.19vw] md:text-[0.741vw] text-[#383E43]">0 %</p>
<p class="text-[3.19vw] md:text-[0.741vw] text-[#383E43]">{{ Math.floor(props.item.completionPercentage) }} %</p>
</div>
<div
id="progressbar"
class="mt-[3vw] md:mt-[0vw] h-[2.051vw] md:h-[0.26vw] rounded-[2vw] md:rounded-[0.521vw]"
>
<div
:style="{ width: activeClass + '%' }"
class="rounded-[2vw] md:rounded-[0.521vw] h-[2.051vw] md:h-[0.26vw]"
></div>
</div>
@@ -45,10 +46,12 @@
<script setup>
const props = defineProps(['item']);
const activeClass = ref(props.item.completionPercentage);
const router = useRouter()
const route = useRoute()
const change = () =>{
router.replace(`/${props.item.id}`)
router.replace(`/${props.item.item.id}`)
}
</script>
@@ -80,7 +83,6 @@ const change = () =>{
}
#progressbar > div {
background-color: #0d3f40;
width: 77%;
float: left;
left: 0;
+5 -7
View File
@@ -10,11 +10,11 @@
>
درباره ما
</h2>
<p
class="about text-[#383E43] max-w-[766px] text-[3.59vw] md:text-[1.335vw] mt-[4vw] md:mt-[1.354vw] mb-[6vw] md:mb-0 leading-[7.179vw] md:leading-[2.865vw]"
<div
v-html="info.data.value.about"
class="about text-[#383E43] max-w-[766px] text-[3.59vw] md:text-[16px] mt-[4vw] md:mt-[1.354vw] mb-[6vw] md:mb-0 leading-[7.179vw] font-light md:leading-[1.865vw]"
>
</p>
</div>
</div>
<div class="relative basis-1/1 md:basis-1/2">
@@ -29,9 +29,7 @@
</template>
<script setup>
const info = await useFetch('/api/settings')
if (process.client) {
document.querySelector('.about').innerHTML = info.data.value.about
}
</script>
<style>
+2 -2
View File
@@ -3,7 +3,7 @@
<div
class="courses"
>
<div class="category">
<div class="hidden md:block category">
<h3
class="font-semibold text-[#383E43] text-[5.11vw] md:text-[1.69vw] mt-[4.103vw] md:mt-[3.49vw] ms-0 md:ms-[1.563vw]"
>
@@ -21,7 +21,7 @@
</div>
<!-- <home-page-courses-sectionCategories /> -->
<div
class="suggestions px-[1vw] md:px-[1.042vw] mt-[12vw] md:mt-[3.2vw] md:bg-white rounded-[0.781vw] flex flex-col gap-[0.417vw] pb-[1.667vw]"
class="suggestions px-[1vw] md:px-[1.042vw] mt-[8vw] md:mt-[3.2vw] md:bg-white rounded-[0.781vw] flex flex-col gap-[0.417vw] pb-[1.667vw]"
>
<h5
class="border-b pb-[1.5vw] text-[4.544vw] mt-[1.5vw] md:mt-[1.6vw] md:text-[1.481vw] text-[#383E43] font-bold"
+5 -4
View File
@@ -42,7 +42,7 @@
</button>
<p v-if="timer > 0" class="text-[3vw] md:text-[0.7vw] px-[2vw] md:px-[1vw] text-primaryGreen">
0{{ timer }} : 00
00:{{ timer < 10 ? '0' + timer : timer }}
</p>
<p
v-else
@@ -129,7 +129,7 @@ const code = ref(null);
const errors = ref([]);
const loading = ref(false);
const phoneNumber = useState("phoneNumber");
const timer = ref(5);
const timer = ref(59);
async function checkOtp() {
if (code.value == null) {
@@ -151,6 +151,7 @@ const timer = ref(5);
if (data.status === "Active") {
toast.success("ورود با موفقیت انجام شد")
authUser.value = data;
location.reload()
navigateTo("/");
}
loading.value = false;
@@ -173,7 +174,7 @@ async function resendSMS() {
});
loading.value = false;
toast.success("کد مجدد برای شما ارسال شد")
timer.value = 5;
timer.value = 59;
options.value = false;
} catch (error) {
loading.value = false;
@@ -194,7 +195,7 @@ async function resendCall() {
},
});
toast.success("درحال تماس با شما هستیم...")
timer.value = 5;
timer.value = 59;
options.value = false;
loading.value = false;
} catch (error) {
+103 -70
View File
@@ -45,19 +45,20 @@
<h1>{{ activeHead?.description }}</h1>
<p
@click="nextHandler(item)"
class="hidden animate-bounce next text-[0.75vw] cursor-pointer flex items-center gap-[0.3vw] pe-[1vw]"
class="hidden animate-bounce next text-[2.5vw] absolute md:top-0 left-0 top-[7vw] md:text-[0.75vw] cursor-pointer flex items-center gap-[0.3vw] md:pe-[1vw]"
>
مشاهده قسمت بعد
<img
src="/public/images/next-svgrepo-com.svg"
alt=""
class="h-[0.8vw] rotate-180"
class="h-[3vw] md:h-[0.8vw] rotate-180"
/>
</p>
</div>
<div class="absolute gap-[2vw] flex md:hidden left-0">
<svg
@click="copyUrl"
class="h-[5.641vw] w-[5.641vw]"
viewBox="0 0 24 22"
fill="none"
@@ -113,45 +114,47 @@
</clipPath>
</defs>
</svg>
<a :href="url" class="h-[5.641vw] w-[5.641vw]">
<svg
<svg
class="h-[5.641vw] w-[5.641vw]"
viewBox="0 0 22 22"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clip-path="url(#clip0_1_6599)">
<path
d="M8.54333 10.7068L10.89 13.0535L13.2367 10.7068"
stroke="#383E43"
stroke-width="1.5"
stroke-miterlimit="10"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M10.89 3.66675V12.9892"
stroke="#383E43"
stroke-width="1.5"
stroke-miterlimit="10"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M18.3334 11.165C18.3334 15.2167 15.5834 18.4984 11 18.4984C6.41669 18.4984 3.66669 15.2167 3.66669 11.165"
stroke="#383E43"
stroke-width="1.5"
stroke-miterlimit="10"
stroke-linecap="round"
stroke-linejoin="round"
/>
</g>
<defs>
<clipPath id="clip0_1_6599">
<rect width="22" height="22" fill="white" />
</clipPath>
</defs>
</svg>
class="h-[5.641vw] w-[5.641vw]"
viewBox="0 0 22 22"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clip-path="url(#clip0_1_6599)">
<path
d="M8.54333 10.7068L10.89 13.0535L13.2367 10.7068"
stroke="#383E43"
stroke-width="1.5"
stroke-miterlimit="10"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M10.89 3.66675V12.9892"
stroke="#383E43"
stroke-width="1.5"
stroke-miterlimit="10"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M18.3334 11.165C18.3334 15.2167 15.5834 18.4984 11 18.4984C6.41669 18.4984 3.66669 15.2167 3.66669 11.165"
stroke="#383E43"
stroke-width="1.5"
stroke-miterlimit="10"
stroke-linecap="round"
stroke-linejoin="round"
/>
</g>
<defs>
<clipPath id="clip0_1_6599">
<rect width="22" height="22" fill="white" />
</clipPath>
</defs>
</svg>
</a>
</div>
</div>
</div>
@@ -273,9 +276,8 @@
</div>
<div
v-for="item in activeHead.Comment"
v-show="item.status === 'Active'"
:key="item.id"
class="mt-[1vw] relative bg-[#F8F8F8] rounded-[3.846vw] md:rounded-[0.781vw] flex justify-between p-[4vw] md:p-[1.55vw]"
class="mt-[1vw] relative bg-[#F8F8F8] rounded-[3.846vw] md:rounded-[0.781vw] flex justify-between p-[4vw] md:p-[1.55vw]"
>
<img
v-if="item.user?.avatarMedia"
@@ -295,9 +297,9 @@
<p class="text-[3.59vw] md:text-[0.938vw] text-[#383E43]">
{{ item.user.name ? item.user.name : "کاربر مهمان" }}
</p>
<div class="thin">
<div class="thin mt-[4vw] md:mt-0">
<p class="text-[2.836vw] md:text-[0.741vw] text-[#878787]">
{{ jDate(item.createdAt) }}
</p>
<p
class="w-[98%] text-[3.19vw] md:text-[0.833vw] text-[#383E43] leading-[4.785vw] md:leading-[1.25vw] mt-[2vw] md:mt-[0.5vw]"
@@ -307,7 +309,7 @@
</div>
</div>
<svg
<!-- <svg
@click="reply(item.id)"
class="cursor-pointer absolute md:left-[2vw] left-[5vw] h-[4.615vw] w-[4.615vw] md:h-[1.25vw] md:w-[1.25vw]"
viewBox="0 0 24 24"
@@ -329,7 +331,7 @@
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</svg> -->
</div>
<div
class="bg-[#F8F8F8] p-[4vw] md:p-[1vw] rounded-[3.846vw] md:rounded-[0.781vw] mt-[6vw] md:mt-[2vw]"
@@ -337,8 +339,8 @@
<div class="space-y-[5vw] md:space-y-[1vw]">
<div class="flex gap-[1vw]">
<img
v-if="authUser.avatarMedia"
:src="authUser.avatarMedia"
v-if="authUser.user.avatarMedia"
:src="authUser.user.avatarMedia"
alt=""
class="h-[10.256vw0] md:h-[3.385vw] w-[10.256vw] md:w-[3.385vw] rounded-[50%]"
/>
@@ -352,7 +354,7 @@
class="space-y-[4vw] mt-[1vw] md:mt-0 ms-[1vw] md:ms-0 md:space-y-0"
>
<p class="text-[3.59vw] md:text-[0.938vw]">
{{ authUser?.name ? authUser.name : "کاربر مهمان" }}
{{ authUser?.user.name ? authUser.user.name : "کاربر مهمان" }}
</p>
<p class="text-[2.836vw] md:text-[0.741vw] text-[#878787]">
پرسش جدید
@@ -474,6 +476,14 @@
</template>
<script setup>
watchEffect(() =>{
if (process.client) {
window.scrollTo({
top: 0,
});
}
})
import { useToast } from "vue-toastification";
const route = useRoute();
const router = useRouter();
@@ -485,21 +495,45 @@ const toast = useToast();
const comment = ref(null);
const index = ref(0);
query.value = route.query;
const { authUser } = useAuth();
const { data: progress, refresh: reload } = await useFetch("/api/progress", {
method: "POST",
body: {
id: route.params.product,
userId: authUser.value.id,
},
});
const activeClass = ref(progress.value.completionPercentage);
const episodeId = ref(null)
const { data, refresh } = await useFetch("/api/courseHeadlines", {
query: {
id: route.params.product,
},
});
const { authUser } = useAuth();
async function addToProgress() {
await $fetch("/api/progressCounter", {
method: "POST",
body: {
id: episodeId.value,
},
});
}
watchEffect(() =>{
if (route.query.episode === undefined) {
episodeId.value = data.value[0].id
}else{
episodeId.value = route.query.episode
}
})
console.log('route', episodeId.value);
console.log(data.value[0].id);
const { data: progress, refresh: reload } = await useFetch("/api/progress", {
query: {
id: route.params.product,
userId: authUser.value.user.id,
},
});
const activeClass = ref(progress.value.completionPercentage);
watchEffect(()=>{
activeClass.value = progress.value.completionPercentage;
})
function convertStoMs(seconds) {
let minutes = Math.floor(seconds / 60);
let extraSeconds = seconds % 60;
@@ -513,19 +547,13 @@ function convertStoMs(seconds) {
);
}
async function addToProgress() {
await $fetch("/api/progressCounter", {
method: "POST",
body: {
id: route.query.episode,
},
});
}
import progressAlert from "@/components/progressAlert.vue";
const handleVideoEnded = async () => {
activeClass.value = progress.value.completionPercentage;
addToProgress();
reload();
refresh();
if (process.client) {
document.querySelector(".next").classList.remove("hidden");
}
@@ -596,6 +624,10 @@ if (query.value.hasOwnProperty("episode")) {
async function chengeVideo(item) {
if (process.client) {
document.querySelector(".next").classList.add("hidden");
window.scrollTo({
top: 0,
behavior: "smooth",
});
}
query.value = { ...route.query, episode: item.id };
activeHead.value = item;
@@ -615,6 +647,7 @@ async function chengeVideo(item) {
}
async function nextHandler() {
addToProgress();
if (process.client) {
document.querySelector(".next").classList.add("hidden");
}
@@ -627,7 +660,7 @@ async function nextHandler() {
// id: route.query.episode,
// },
// });
addToProgress();
activeHead.value = data.value[index.value];
const getUrl = await useFetch("/api/checkMedia", {
query: {
@@ -636,7 +669,7 @@ async function nextHandler() {
});
url.value = getUrl.data.value.url;
video.value.load();
activeClass.value = progress.value.completionPercentage;
// activeClass.value = progress.value.completionPercentage;
refresh();
reload();
router.push({
@@ -113,7 +113,7 @@
حجم فایل ها
</p>
<p class="text-[#383E43] font-semibold">
{{ props.props[0].totalFileSize }}
{{ props.props[0].totalFileSize }} گیگابایت
</p>
</div>
<div class="py-[3vw] md:py-[0.9vw] w-full border-b flex justify-between">
@@ -197,7 +197,9 @@
زبان
</p>
<p class="text-[#383E43] font-semibold">{{ props.props[0].language }}</p>
<p class="text-[#383E43] font-semibold">
{{ props.props[0].language }}
</p>
</div>
<div class="py-[3vw] md:py-[0.9vw] w-full border-b flex justify-between">
<p class="flex items-center gap-[0.8vw] ps-[2vw]">سطح رضایت</p>
@@ -251,7 +253,7 @@
stroke-linejoin="round"
/>
</svg>
{{ props.props[1] ? 'مشاهده دوره' : 'شرکت در دوره' }}
{{ props.props[1] ? "مشاهده دوره" : "شرکت در دوره" }}
</button>
</div>
</div>
@@ -263,32 +265,29 @@ import { useToast } from "vue-toastification";
const { authUser } = useAuth();
const props = defineProps(["props"], ["access"]);
const toast = useToast()
const router = useRouter()
const toast = useToast();
const router = useRouter();
const paymentHandler = (id) => {
if (authUser.value === null) {
return router.push({
path: '/login'
})
}
const data = useFetch("/api/user/registerCourse", {
method: "POST",
body: {
courseId: id,
code: "",
},
if (authUser.value === null) {
return router.push({
path: "/login",
});
if (data.data.value?.status === 406 || data.data.value?.status === 500) {
toast.error(data.data.value.message
)
} else {
toast.success('ثبت نام انجام شد')
}
}
const data = useFetch("/api/user/registerCourse", {
method: "POST",
body: {
courseId: id,
code: "",
},
});
if (data.data.value?.status === 406 || data.data.value?.status === 500) {
toast.error(data.data.value.message);
} else {
toast.success("ثبت نام انجام شد");
}
setTimeout(() => {
location.reload();
}, 1000);
};
</script>
@@ -17,7 +17,7 @@
>توضیحات</span
>
</div>
<div class="descriptions mt-[4vw] md:mt-[2.1vw] thin">
<div v-html="props.props.description" class="descriptions mt-[4vw] md:mt-[2.1vw] thin">
</div>
</template>
@@ -25,7 +25,4 @@
<script setup>
const props = defineProps(['props'])
if (process.client) {
document.querySelector('.descriptions').innerHTML = props.props.description;
}
</script>
@@ -14,6 +14,7 @@
{{ props.props?.categories[0].name }}
</p>
<div
v-html="describe"
class="descriptios hidden md:block w-[39.896vw] text-[1.055vw] leading-[1.582vw] mt-[1.2vw]"
></div>
<p
@@ -199,18 +200,16 @@
const props = defineProps(["props"]);
import {jDate} from "@/utils/jDate"
if (process.client) {
const des = props?.props.description;
function hideEndOfString(inputString) {
const words = inputString.split(" ");
if (words.length > 50) {
const truncatedWords = words.slice(0, 50);
return truncatedWords.join(" ") + "...";
} else {
return inputString;
function hideEndOfString(inputString) {
const words = inputString.split(" ");
if (words.length > 50) {
const truncatedWords = words.slice(0, 30);
return truncatedWords.join(" ") + "...";
} else {
return inputString;
}
}
}
const data = hideEndOfString(des);
document.querySelector(".descriptios").innerHTML = data;
}
const describe = hideEndOfString(props.props.description);
</script>
@@ -30,10 +30,8 @@
</span>
<h2 class="border-r ps-[2.2vw]">{{ headline.headline }}</h2>
</div>
<div class="hidden md:flex items-center text-[0.833vw] w-full md:basis-2/6">
<span>08:55</span>
<span>{{ convertStoMs(headline.time) }}</span>
<svg
class="ms-[0.3vw] h-[1.042vw] w-[1.042vw]"
viewBox="0 0 20 20"
@@ -124,6 +122,18 @@ import { useToast } from 'vue-toastification'
const toast = useToast()
const props = defineProps(['props'])
const download = (val) => toast.warning(`برای ${val} باید در دوره شرکت کنید`);
function convertStoMs(seconds) {
let minutes = Math.floor(seconds / 60);
let extraSeconds = seconds % 60;
minutes = minutes < 10 ? "0" + minutes : minutes;
return (
minutes +
":" +
(extraSeconds < 10
? "0" + Math.floor(extraSeconds)
: Math.floor(extraSeconds))
);
}
</script>