complete every routes v-1
This commit is contained in:
Vendored
+8
@@ -7,19 +7,25 @@ export {}
|
|||||||
/* prettier-ignore */
|
/* prettier-ignore */
|
||||||
declare module 'vue' {
|
declare module 'vue' {
|
||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
|
AddVideo: typeof import('./src/components/AddVideo.vue')['default']
|
||||||
Avatar: typeof import('primevue/avatar')['default']
|
Avatar: typeof import('primevue/avatar')['default']
|
||||||
|
Badge: typeof import('primevue/badge')['default']
|
||||||
Button: typeof import('primevue/button')['default']
|
Button: typeof import('primevue/button')['default']
|
||||||
Card: typeof import('primevue/card')['default']
|
Card: typeof import('primevue/card')['default']
|
||||||
CategoryForm: typeof import('./src/components/CategoryForm.vue')['default']
|
CategoryForm: typeof import('./src/components/CategoryForm.vue')['default']
|
||||||
|
Checkbox: typeof import('primevue/checkbox')['default']
|
||||||
Column: typeof import('primevue/column')['default']
|
Column: typeof import('primevue/column')['default']
|
||||||
|
copy: typeof import('./src/components/ProductDetails copy.vue')['default']
|
||||||
CouponDetails: typeof import('./src/components/CouponDetails.vue')['default']
|
CouponDetails: typeof import('./src/components/CouponDetails.vue')['default']
|
||||||
DataTable: typeof import('primevue/datatable')['default']
|
DataTable: typeof import('primevue/datatable')['default']
|
||||||
Dropdown: typeof import('primevue/dropdown')['default']
|
Dropdown: typeof import('primevue/dropdown')['default']
|
||||||
Editor: typeof import('primevue/editor')['default']
|
Editor: typeof import('primevue/editor')['default']
|
||||||
Fieldset: typeof import('primevue/fieldset')['default']
|
Fieldset: typeof import('primevue/fieldset')['default']
|
||||||
|
FileUpload: typeof import('primevue/fileupload')['default']
|
||||||
FirstStep: typeof import('./src/components/ProductFormSteps/FirstStep.vue')['default']
|
FirstStep: typeof import('./src/components/ProductFormSteps/FirstStep.vue')['default']
|
||||||
FloatLabel: typeof import('primevue/floatlabel')['default']
|
FloatLabel: typeof import('primevue/floatlabel')['default']
|
||||||
Galleria: typeof import('primevue/galleria')['default']
|
Galleria: typeof import('primevue/galleria')['default']
|
||||||
|
HeadlineDetail: typeof import('./src/components/HeadlineDetail.vue')['default']
|
||||||
HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
|
HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
|
||||||
IconCommunity: typeof import('./src/components/icons/IconCommunity.vue')['default']
|
IconCommunity: typeof import('./src/components/icons/IconCommunity.vue')['default']
|
||||||
IconDocumentation: typeof import('./src/components/icons/IconDocumentation.vue')['default']
|
IconDocumentation: typeof import('./src/components/icons/IconDocumentation.vue')['default']
|
||||||
@@ -35,8 +41,10 @@ declare module 'vue' {
|
|||||||
Paginator: typeof import('primevue/paginator')['default']
|
Paginator: typeof import('primevue/paginator')['default']
|
||||||
Panel: typeof import('primevue/panel')['default']
|
Panel: typeof import('primevue/panel')['default']
|
||||||
PanelMenu: typeof import('primevue/panelmenu')['default']
|
PanelMenu: typeof import('primevue/panelmenu')['default']
|
||||||
|
Password: typeof import('primevue/password')['default']
|
||||||
ProductDetails: typeof import('./src/components/ProductDetails.vue')['default']
|
ProductDetails: typeof import('./src/components/ProductDetails.vue')['default']
|
||||||
ProductForm: typeof import('./src/components/ProductForm.vue')['default']
|
ProductForm: typeof import('./src/components/ProductForm.vue')['default']
|
||||||
|
ProgressBar: typeof import('primevue/progressbar')['default']
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
SecondStep: typeof import('./src/components/ProductFormSteps/SecondStep.vue')['default']
|
SecondStep: typeof import('./src/components/ProductFormSteps/SecondStep.vue')['default']
|
||||||
|
|||||||
@@ -0,0 +1,314 @@
|
|||||||
|
|
||||||
|
<template>
|
||||||
|
<section class="flex flex-col gap-4 pt-7">
|
||||||
|
<div class="flex gap-7">
|
||||||
|
<div class="flex flex-col gap-7 items-center">
|
||||||
|
<div class="flex flex-col gap-1 w-96">
|
||||||
|
<FloatLabel>
|
||||||
|
<InputText class="w-full" v-model="headline"/>
|
||||||
|
<label>{{ $t("عنوان ویدیو") }}</label>
|
||||||
|
</FloatLabel>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-1 w-96">
|
||||||
|
<FloatLabel>
|
||||||
|
<Textarea v-model="description" rows="3" class="w-full" />
|
||||||
|
<label>{{ $t("توضیحات متا") }}</label>
|
||||||
|
</FloatLabel>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-1 w-96">
|
||||||
|
<FloatLabel>
|
||||||
|
<Dropdown
|
||||||
|
v-model="type"
|
||||||
|
@change="setType"
|
||||||
|
:options="['تکمیل شده', 'غیرفعال', 'درحال ضبط', 'به زودی...']"
|
||||||
|
:optionLabel="levels"
|
||||||
|
:optionValue="levels"
|
||||||
|
class="w-full"
|
||||||
|
/>
|
||||||
|
<label>{{ $t("وضعیت ویدیو") }}</label>
|
||||||
|
</FloatLabel>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-7 items-center">
|
||||||
|
<div>
|
||||||
|
<div class="card w-[400px]">
|
||||||
|
<Toast />
|
||||||
|
<FileUpload
|
||||||
|
name="demo[]"
|
||||||
|
url="/api/upload"
|
||||||
|
@upload="onTemplatedUpload($event)"
|
||||||
|
:multiple="true"
|
||||||
|
accept="image/*"
|
||||||
|
:maxFileSize="1000000"
|
||||||
|
@select="onSelectedFiles"
|
||||||
|
>
|
||||||
|
<template
|
||||||
|
#header="{
|
||||||
|
chooseCallback,
|
||||||
|
uploadCallback,
|
||||||
|
clearCallback,
|
||||||
|
files,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex flex-wrap justify-between items-center flex-1 gap-4"
|
||||||
|
>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<Button
|
||||||
|
@click="chooseCallback()"
|
||||||
|
icon="pi pi-images"
|
||||||
|
rounded
|
||||||
|
outlined
|
||||||
|
severity="secondary"
|
||||||
|
></Button>
|
||||||
|
<Button
|
||||||
|
@click="uploadEvent(uploadCallback)"
|
||||||
|
icon="pi pi-cloud-upload"
|
||||||
|
rounded
|
||||||
|
outlined
|
||||||
|
severity="success"
|
||||||
|
:disabled="!files || files.length === 0"
|
||||||
|
></Button>
|
||||||
|
<Button
|
||||||
|
@click="clearCallback()"
|
||||||
|
icon="pi pi-times"
|
||||||
|
rounded
|
||||||
|
outlined
|
||||||
|
severity="danger"
|
||||||
|
:disabled="!files || files.length === 0"
|
||||||
|
></Button>
|
||||||
|
</div>
|
||||||
|
<ProgressBar
|
||||||
|
:value="totalSizePercent"
|
||||||
|
:showValue="false"
|
||||||
|
class="md:w-20rem h-1 w-full md:ml-auto"
|
||||||
|
>
|
||||||
|
<span class="whitespace-nowrap"
|
||||||
|
>{{ totalSize }}B / 1Mb</span
|
||||||
|
>
|
||||||
|
</ProgressBar>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template
|
||||||
|
#content="{
|
||||||
|
files,
|
||||||
|
uploadedFiles,
|
||||||
|
removeUploadedFileCallback,
|
||||||
|
removeFileCallback,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div class="flex flex-col gap-8 pt-4">
|
||||||
|
<div v-if="files.length > 0">
|
||||||
|
<h5>Pending</h5>
|
||||||
|
<div class="flex flex-wrap gap-4">
|
||||||
|
<div
|
||||||
|
v-for="(file, index) of files"
|
||||||
|
:key="file.name + file.type + file.size"
|
||||||
|
class="p-8 rounded-border flex flex-col border border-surface items-center gap-4"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<img
|
||||||
|
role="presentation"
|
||||||
|
:alt="file.name"
|
||||||
|
:src="file.objectURL"
|
||||||
|
width="100"
|
||||||
|
height="50"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
class="font-semibold text-ellipsis max-w-60 whitespace-nowrap overflow-hidden"
|
||||||
|
>{{ file.name }}</span
|
||||||
|
>
|
||||||
|
<div>{{ formatSize(file.size) }}</div>
|
||||||
|
<Badge value="Pending" severity="warn" />
|
||||||
|
<Button
|
||||||
|
icon="pi pi-times"
|
||||||
|
@click="
|
||||||
|
onRemoveTemplatingFile(
|
||||||
|
file,
|
||||||
|
removeFileCallback,
|
||||||
|
index
|
||||||
|
)
|
||||||
|
"
|
||||||
|
outlined
|
||||||
|
rounded
|
||||||
|
severity="danger"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="uploadedFiles.length > 0">
|
||||||
|
<h5>Completed</h5>
|
||||||
|
<div class="flex flex-wrap gap-4">
|
||||||
|
<div
|
||||||
|
v-for="(file, index) of uploadedFiles"
|
||||||
|
:key="file.name + file.type + file.size"
|
||||||
|
class="p-8 rounded-border flex flex-col border border-surface items-center gap-4"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<img
|
||||||
|
role="presentation"
|
||||||
|
:alt="file.name"
|
||||||
|
:src="file.objectURL"
|
||||||
|
width="100"
|
||||||
|
height="50"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
class="font-semibold text-ellipsis max-w-60 whitespace-nowrap overflow-hidden"
|
||||||
|
>{{ file.name }}</span
|
||||||
|
>
|
||||||
|
<div>{{ formatSize(file.size) }}</div>
|
||||||
|
<Badge
|
||||||
|
value="Completed"
|
||||||
|
class="mt-4"
|
||||||
|
severity="success"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
icon="pi pi-times"
|
||||||
|
@click="removeUploadedFileCallback(index)"
|
||||||
|
outlined
|
||||||
|
rounded
|
||||||
|
severity="danger"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #empty>
|
||||||
|
<div class="flex items-center justify-center flex-col">
|
||||||
|
<i
|
||||||
|
class="pi pi-cloud-upload border-2 rounded-full p-8 text-4xl text-muted-color"
|
||||||
|
/>
|
||||||
|
<p class="mt-6 mb-0">ویدیو را اینجا رها کنید</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</FileUpload>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w-full flex gap-2 mt-4">
|
||||||
|
<Button
|
||||||
|
:label="$t('back')"
|
||||||
|
outlined
|
||||||
|
severity="secondary"
|
||||||
|
class="ml-auto"
|
||||||
|
@click="dialog.close()"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
:label="$t('save')"
|
||||||
|
icon="pi pi-save"
|
||||||
|
severity="success"
|
||||||
|
@click="save()"
|
||||||
|
:loading="saving"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { inject, reactive, ref } from "vue";
|
||||||
|
import { usePrimeVue } from "primevue/config";
|
||||||
|
import { useToast } from "primevue/usetoast";
|
||||||
|
import { useHeadlinesStore } from "@/stores/Headlines"
|
||||||
|
const store = useHeadlinesStore()
|
||||||
|
const dialog = inject("dialogRef");
|
||||||
|
const type = ref();
|
||||||
|
const produc = reactive(Object.assign({}, dialog.value.data));
|
||||||
|
const sabt = () => {
|
||||||
|
console.log(produc);
|
||||||
|
};
|
||||||
|
const videoStatus = ref(null);
|
||||||
|
const setType = () => {
|
||||||
|
if (type.value === "غیرفعال") {
|
||||||
|
videoStatus.value = "DeActivate";
|
||||||
|
}
|
||||||
|
if (type.value === "تکمیل شده") {
|
||||||
|
videoStatus.value = "Completed";
|
||||||
|
}
|
||||||
|
if (type.value === "درحال ضبط") {
|
||||||
|
videoStatus.value = "Recording";
|
||||||
|
}
|
||||||
|
if (type.value === "به زودی...") {
|
||||||
|
videoStatus.value = "Soon";
|
||||||
|
}
|
||||||
|
console.log("type:", videoStatus.value, produc.produc);
|
||||||
|
console.log(type.value);
|
||||||
|
};
|
||||||
|
const headline = ref('');
|
||||||
|
const description = ref('');
|
||||||
|
const videoUrl = ref('');
|
||||||
|
const $primevue = usePrimeVue();
|
||||||
|
const toast = useToast();
|
||||||
|
|
||||||
|
const totalSize = ref(0);
|
||||||
|
const totalSizePercent = ref(0);
|
||||||
|
const files = ref([]);
|
||||||
|
const course = ref(produc.produc)
|
||||||
|
|
||||||
|
const save = async() =>{
|
||||||
|
const send = await store.create({
|
||||||
|
headline: headline.value,
|
||||||
|
description: description.value,
|
||||||
|
course: produc.produc,
|
||||||
|
videoUrl: 'https://dlearn.storage.iran.liara.space/test/1cb985c8-26a0-4120-824c-f496349e45bfmatt_devir--one_minute_drive_preview.webm',
|
||||||
|
status: videoStatus.value
|
||||||
|
})
|
||||||
|
console.log('send', send);
|
||||||
|
}
|
||||||
|
|
||||||
|
const onRemoveTemplatingFile = (file, removeFileCallback, index) => {
|
||||||
|
removeFileCallback(index);
|
||||||
|
totalSize.value -= parseInt(formatSize(file.size));
|
||||||
|
totalSizePercent.value = totalSize.value / 10;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onClearTemplatingUpload = (clear) => {
|
||||||
|
clear();
|
||||||
|
totalSize.value = 0;
|
||||||
|
totalSizePercent.value = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSelectedFiles = (event) => {
|
||||||
|
files.value = event.files;
|
||||||
|
files.value.forEach((file) => {
|
||||||
|
totalSize.value += parseInt(formatSize(file.size));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const uploadEvent = (callback) => {
|
||||||
|
totalSizePercent.value = totalSize.value / 10;
|
||||||
|
callback();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onTemplatedUpload = () => {
|
||||||
|
toast.add({
|
||||||
|
severity: "info",
|
||||||
|
summary: "Success",
|
||||||
|
detail: "File Uploaded",
|
||||||
|
life: 3000,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatSize = (bytes) => {
|
||||||
|
const k = 1024;
|
||||||
|
const dm = 3;
|
||||||
|
const sizes = $primevue.config.locale.fileSizeTypes;
|
||||||
|
|
||||||
|
if (bytes === 0) {
|
||||||
|
return `0 ${sizes[0]}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||||
|
const formattedSize = parseFloat((bytes / Math.pow(k, i)).toFixed(dm));
|
||||||
|
|
||||||
|
return `${formattedSize} ${sizes[i]}`;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
<template>
|
||||||
|
<section class="flex flex-col gap-6 w-96">
|
||||||
|
<ul class="flex flex-col gap-5">
|
||||||
|
|
||||||
|
<li class="flex items-center justify-between">
|
||||||
|
<video :src="head.product.videoUrl" autoplay></video>
|
||||||
|
</li>
|
||||||
|
<li class="flex items-center justify-between">
|
||||||
|
<strong>{{ $t('عنوان') }}</strong>
|
||||||
|
<div class="flex items-center gap-2 w-max">
|
||||||
|
<!-- <i v-if="user.confirmEmail" class="pi pi-verified text-green-600"></i> -->
|
||||||
|
<span>{{ head.product.headline }}</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="flex items-center justify-between">
|
||||||
|
<strong>{{ $t('توضیحات') }}</strong>
|
||||||
|
<span>{{ head.product.description }}</span>
|
||||||
|
</li>
|
||||||
|
<li class="flex items-center justify-between">
|
||||||
|
<strong>{{ $t('تعداد نظرات') }}</strong>
|
||||||
|
<span>{{ head.product.Comment.length }}</span>
|
||||||
|
</li>
|
||||||
|
<!--
|
||||||
|
<li class="flex items-center justify-between">
|
||||||
|
<strong>{{ $t('createdAt') }}</strong>
|
||||||
|
<span>{{ jDate(user.product.createdAt) }}</span>
|
||||||
|
</li>
|
||||||
|
<li class="flex items-center justify-between">
|
||||||
|
<strong>{{ $t('updatedAt') }}</strong>
|
||||||
|
<span>{{ jDate(user.product.updatedAt) }}</span>
|
||||||
|
</li>
|
||||||
|
<li class="flex items-center justify-between">
|
||||||
|
<strong>{{ $t('زمان دوره') }}</strong>
|
||||||
|
<span>{{ user.product.duration }} ساعت</span>
|
||||||
|
</li>
|
||||||
|
<li class="flex items-center justify-between">
|
||||||
|
<strong>{{ $t('زبان') }}</strong>
|
||||||
|
<span>{{ user.product.language }}</span>
|
||||||
|
</li>
|
||||||
|
<li class="flex items-center justify-between">
|
||||||
|
<strong>{{ $t('price') }}</strong>
|
||||||
|
<span>{{ numberFormat(user.product.price) }} تومان</span>
|
||||||
|
</li>
|
||||||
|
<li class="flex items-center justify-between">
|
||||||
|
<strong>{{ $t('تعداد دانشجو ها') }}</strong>
|
||||||
|
<span>{{ user.product.studentsCount }}</span>
|
||||||
|
</li>
|
||||||
|
<li class="flex items-center justify-between">
|
||||||
|
<strong>{{ $t('مدرس دوره') }}</strong>
|
||||||
|
<span>{{ user.product.teacher.name }}</span>
|
||||||
|
</li>
|
||||||
|
<li class="flex items-center justify-between">
|
||||||
|
<strong>{{ $t('حجم دوره') }}</strong>
|
||||||
|
<span>{{ user.product.totalFileSize }} گیگابایت</span>
|
||||||
|
</li>
|
||||||
|
<li class="flex items-center justify-between">
|
||||||
|
<strong>{{ $t('امتیاز دانشجویان') }}</strong>
|
||||||
|
<span>{{ user.product.averageRating }}</span>
|
||||||
|
</li> -->
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { inject, reactive } from 'vue';
|
||||||
|
import { jDate } from '@/utils/jDate';
|
||||||
|
import { numberFormat } from '@/utils/numberFormat';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
const tabs = ref([
|
||||||
|
{ title: 'Tab 1', content: 'Tab 1 Content', value: '0' },
|
||||||
|
{ title: 'Tab 2', content: 'Tab 2 Content', value: '1' },
|
||||||
|
{ title: 'Tab 3', content: 'Tab 3 Content', value: '2' }
|
||||||
|
]);
|
||||||
|
const dialog = inject('dialogRef')
|
||||||
|
|
||||||
|
const head = reactive(Object.assign({}, dialog.value.data))
|
||||||
|
console.log('der', head);
|
||||||
|
// const confirmToSales = (value) => {
|
||||||
|
// dialog.value.data.confirm(user, value)
|
||||||
|
// }
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
@@ -104,8 +104,8 @@ const items = ref([
|
|||||||
command: () => router.push('/create')
|
command: () => router.push('/create')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('addVideo'),
|
label: t('مدیریت ویدیو ها'),
|
||||||
icon: 'pi pi-file-edit',
|
icon: 'pi pi-video',
|
||||||
command: () => router.push('/videos')
|
command: () => router.push('/videos')
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -108,6 +108,11 @@ const router = createRouter({
|
|||||||
name: 'AddVideos',
|
name: 'AddVideos',
|
||||||
component: () => import('@/views/AddVideos.vue'),
|
component: () => import('@/views/AddVideos.vue'),
|
||||||
},
|
},
|
||||||
|
// {
|
||||||
|
// path: '/videos/create',
|
||||||
|
// name: 'createVideo',
|
||||||
|
// component: () => import('@/views/CreateVideo.vue'),
|
||||||
|
// },
|
||||||
{
|
{
|
||||||
path: '/pages',
|
path: '/pages',
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
+14
-13
@@ -12,32 +12,33 @@ export const useHeadlinesStore = defineStore('headlines', {
|
|||||||
actions: {
|
actions: {
|
||||||
async index(courseId) {
|
async index(courseId) {
|
||||||
this.items = [];
|
this.items = [];
|
||||||
|
const params = { courseId }
|
||||||
|
|
||||||
this.fetching = true
|
this.fetching = true
|
||||||
const { status, data } = await axios.get('/courseHeadline', courseId)
|
const { status, data } = await axios.get('/courseHeadline', { params })
|
||||||
this.fetching = false
|
this.fetching = false
|
||||||
return data
|
return this.items = data
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
async create(newCourse) {
|
|
||||||
const { status, data } = await axios.post('/course', newCourse)
|
|
||||||
|
|
||||||
return data
|
|
||||||
|
|
||||||
},
|
},
|
||||||
async delete(id) {
|
async delete(id) {
|
||||||
const { status, data } = await axios.delete(`/course/${id}`, id)
|
const { status, data } = await axios.delete(`/courseHeadline/${id}`, id)
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
},
|
},
|
||||||
|
// async create(newCourse) {
|
||||||
|
// const { status, data } = await axios.post('/course', newCourse)
|
||||||
|
// return data
|
||||||
|
// },
|
||||||
|
|
||||||
|
|
||||||
async edit(id) {
|
async edit(id) {
|
||||||
const { status, data } = await axios.get(`/course/${id}`)
|
const { status, data } = await axios.get(`/course/${id}`)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
},
|
},
|
||||||
|
async create(form){
|
||||||
|
const {status, data} = await axios.post('/courseHeadline', form)
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// async store(form) {
|
// async store(form) {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export const useUploaderStore = defineStore('uploader', {
|
|||||||
const form = new FormData()
|
const form = new FormData()
|
||||||
|
|
||||||
form.append('directoryName', 'directoryName')
|
form.append('directoryName', 'directoryName')
|
||||||
form.append('file', new Blob([file]))
|
form.append('file', file)
|
||||||
// for (var pair of form.entries()) {
|
// for (var pair of form.entries()) {
|
||||||
// console.log('pairs :',pair[0]+ ', ' + pair[1]);
|
// console.log('pairs :',pair[0]+ ', ' + pair[1]);
|
||||||
// }
|
// }
|
||||||
@@ -21,6 +21,7 @@ export const useUploaderStore = defineStore('uploader', {
|
|||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "multipart/form-data",
|
"Content-Type": "multipart/form-data",
|
||||||
},
|
},
|
||||||
|
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
const result = await axios.post('/uploader',
|
const result = await axios.post('/uploader',
|
||||||
|
|||||||
+142
-12
@@ -1,24 +1,154 @@
|
|||||||
<template>
|
<template>
|
||||||
<h2>add</h2>
|
|
||||||
{{ videos }}
|
<Panel :header="$t('لیست ویدیو های دوره')">
|
||||||
|
<template #icons>
|
||||||
</template>
|
<Button
|
||||||
|
icon="pi pi-plus"
|
||||||
|
:label="$t('افزودن ویدیو')"
|
||||||
|
severity="success"
|
||||||
|
@click="create()"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<DataTable :value="store.items">
|
||||||
|
|
||||||
|
<Column class="w-64" field="headline" :header="$t('عنوان ویدیو')" />
|
||||||
|
<Column field="description" :header="$t('description')" />
|
||||||
|
<Column :header="$t('options')" headerClass="w-32">
|
||||||
|
<template #body="{ data }">
|
||||||
|
<div class="flex justify-end">
|
||||||
|
<Button icon="pi pi-eye" rounded text severity="secondary"
|
||||||
|
@click="show(data)" />
|
||||||
|
<Button
|
||||||
|
|
||||||
|
icon="pi pi-pencil"
|
||||||
|
rounded
|
||||||
|
text
|
||||||
|
severity="secondary"
|
||||||
|
@click="edit(data)"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
@click="remove(data)"
|
||||||
|
icon="pi pi-trash"
|
||||||
|
rounded
|
||||||
|
text
|
||||||
|
severity="danger"
|
||||||
|
:loading="data.removing"
|
||||||
|
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</Column>
|
||||||
|
<!-- <Column :field="({ price }) => numberFormat(price)" :header="$t('price')" />
|
||||||
|
<Column :header="$t('category')" class="whitespace-nowrap">
|
||||||
|
<template #body="{ data: { category } }">
|
||||||
|
<span v-if="category.length > 0">
|
||||||
|
{{ category.slice(-1)[0].name }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</Column>
|
||||||
|
<Column field="name" :header="$t('reviews')">
|
||||||
|
<template #body="{ data: { name } }">
|
||||||
|
<Rating :modelValue="name" readonly :cancel="false" class="[&_svg]:text-yellow-400" />
|
||||||
|
</template>
|
||||||
|
</Column>
|
||||||
|
<Column :header="$t('status')">
|
||||||
|
<template #body="{ data: { confirmToShow, _id } }">
|
||||||
|
<Tag v-if="!confirmToShow" value="غیر فعال" severity="danger" @click="accepter(_id,true)"/>
|
||||||
|
<Tag v-if="confirmToShow" value="فعال" severity="success" @click="accepter(_id,false)"/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</Column>
|
||||||
|
<Column :field="({ createdAt }) => jDate(createdAt)" :header="$t('createdAt')" class="w-28" />
|
||||||
|
<Column :field="({ updatedAt }) => jDate(updatedAt)" :header="$t('updatedAt')" class="w-32 text-center" />
|
||||||
|
<Column headerClass="w-32">
|
||||||
|
<template #body="{ data }">
|
||||||
|
<div class="flex justify-end">
|
||||||
|
<Button icon="pi pi-eye" rounded text severity="secondary" @click="show(data)" />
|
||||||
|
<Button icon="pi pi-pencil" rounded text severity="secondary" @click="edit(data)" />
|
||||||
|
<Button icon="pi pi-trash" rounded text severity="danger" :loading="data.removing"
|
||||||
|
@click="remove(data)" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</Column> -->
|
||||||
|
<template #empty>
|
||||||
|
<p>{{ store.fetching ? $t("loading") : $t("emptyTable") }}</p>
|
||||||
|
</template>
|
||||||
|
<template #footer>
|
||||||
|
<Pagination :total="store.total" />
|
||||||
|
</template>
|
||||||
|
</DataTable>
|
||||||
|
<!-- <Galleria
|
||||||
|
v-model:visible="galleryVes"
|
||||||
|
:value="gallery"
|
||||||
|
:numVisible="5"
|
||||||
|
containerClass="w-1/2"
|
||||||
|
circular
|
||||||
|
fullScreen
|
||||||
|
showItemNavigators
|
||||||
|
:showThumbnailNavigators="false"
|
||||||
|
> -->
|
||||||
|
|
||||||
|
</Panel>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
const { toast, dialog, confirm, t } = inject('service')
|
||||||
|
|
||||||
import { ref, watchEffect } from "vue";
|
import { ref, watchEffect, reactive, defineAsyncComponent, inject } from "vue";
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute, useRouter } from "vue-router";
|
||||||
import { useHeadlinesStore } from "@/stores/Headlines"
|
import { useHeadlinesStore } from "@/stores/Headlines"
|
||||||
const store = useHeadlinesStore()
|
const store = useHeadlinesStore()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const videos = ref([])
|
const videos = reactive({})
|
||||||
|
const HeadlineDetail = defineAsyncComponent(() => import('../components/HeadlineDetail.vue'));
|
||||||
|
const AddVideo = defineAsyncComponent(() => import('../components/AddVideo.vue'));
|
||||||
watchEffect(async() => {
|
watchEffect(async() => {
|
||||||
videos.value = await store.index({
|
await store.index(route.params.id)
|
||||||
courseId: route.params.id
|
|
||||||
})
|
|
||||||
console.log(videos);
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const show = (product) => {
|
||||||
|
dialog.open(HeadlineDetail, {
|
||||||
|
props: { modal: true, closable: true, header: t('پیش نمایش ویدیو') },
|
||||||
|
data: {
|
||||||
|
product
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const router = useRouter()
|
||||||
|
const create = () =>{
|
||||||
|
// router.push('/videos/create')
|
||||||
|
dialog.open(AddVideo, {
|
||||||
|
props: { modal: true, closable: true, header: t('افزودن ویدیو') },
|
||||||
|
data: {
|
||||||
|
produc : route.params.id
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const remove = async(data) => {
|
||||||
|
confirm.require({
|
||||||
|
message: t('Are you sure you want to proceed?'),
|
||||||
|
header: t('Danger Zone'),
|
||||||
|
icon: 'pi pi-info-circle',
|
||||||
|
acceptClass: 'p-button-danger p-button-sm',
|
||||||
|
rejectClass: 'p-button-secondary p-button-outlined p-button-sm',
|
||||||
|
rejectLabel: t('cancel'),
|
||||||
|
acceptLabel: t('beOmitted'),
|
||||||
|
defaultFocus: 'reject',
|
||||||
|
accept: async () => {
|
||||||
|
await store.delete(data.id)
|
||||||
|
await store.index(route.params.id)
|
||||||
|
// if (status === 200)
|
||||||
|
// toast.add({
|
||||||
|
// severity: 'success', summary: t('successful'), detail: t('destroySuccessfully'), life: 3000
|
||||||
|
// });
|
||||||
|
// else
|
||||||
|
// toast.add({
|
||||||
|
// severity: 'error', summary: t('error'), detail: data.msg, life: 3000
|
||||||
|
// });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@@ -27,6 +27,8 @@
|
|||||||
<Dropdown
|
<Dropdown
|
||||||
v-model="level"
|
v-model="level"
|
||||||
:options="['مبتدی', 'متوسط', 'پیشرفته']"
|
:options="['مبتدی', 'متوسط', 'پیشرفته']"
|
||||||
|
|
||||||
|
|
||||||
class="w-full"
|
class="w-full"
|
||||||
/>
|
/>
|
||||||
<label>{{ $t("سطح دوره") }}</label>
|
<label>{{ $t("سطح دوره") }}</label>
|
||||||
@@ -80,9 +82,10 @@
|
|||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
class="opacity-0 absolute inset-0 cursor-pointer"
|
class="opacity-0 absolute inset-0 cursor-pointer"
|
||||||
accept="image/*"
|
|
||||||
@input="chooseImage"
|
@input="chooseImage"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</Button>
|
</Button>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
<label>{{ $t("image") }}</label>
|
<label>{{ $t("image") }}</label>
|
||||||
@@ -198,10 +201,11 @@ const newCourse = reactive({
|
|||||||
countOfVideos: 0,
|
countOfVideos: 0,
|
||||||
totalFileSize: "",
|
totalFileSize: "",
|
||||||
});
|
});
|
||||||
const chooseImage = async (el) => {
|
const chooseImage = async (val) => {
|
||||||
const uploader = await uploadStore.uploader(el.target.value);
|
console.log(val.target.files[0]);
|
||||||
//console.log('uploader', uploader.data.url);
|
const uploader = await uploadStore.uploader(val.target.files[0]);
|
||||||
newCourse.image = uploader.data.url;
|
console.log('uploader', uploader.data.url);
|
||||||
|
newCourse.image = uploader.data.url;
|
||||||
console.log("تصویر آپلود شد");
|
console.log("تصویر آپلود شد");
|
||||||
console.log("upldr", uploader);
|
console.log("upldr", uploader);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -34,9 +34,10 @@
|
|||||||
<Column :header="$t('options')" headerClass="w-32">
|
<Column :header="$t('options')" headerClass="w-32">
|
||||||
<template #body="{ data }">
|
<template #body="{ data }">
|
||||||
<div class="flex justify-end">
|
<div class="flex justify-end">
|
||||||
<Button icon="pi pi-eye" rounded text severity="secondary" @click="show(data)" />
|
<Button icon="pi pi-eye" rounded text severity="secondary"
|
||||||
|
@click="show(data)" />
|
||||||
<Button
|
<Button
|
||||||
icon="pi pi-pencil"
|
icon="pi pi-video"
|
||||||
rounded
|
rounded
|
||||||
text
|
text
|
||||||
severity="secondary"
|
severity="secondary"
|
||||||
|
|||||||
Reference in New Issue
Block a user