create ticket section
This commit is contained in:
Vendored
+1
@@ -16,6 +16,7 @@ declare module 'vue' {
|
|||||||
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']
|
||||||
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']
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ const items = ref([
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('سوالات متداول'),
|
label: t('سوالات متداول'),
|
||||||
icon: 'pi pi-exclamation-circle',
|
icon: 'pi pi-question-circle',
|
||||||
command: () => router.push('/pages/Faq')
|
command: () => router.push('/pages/Faq')
|
||||||
},
|
},
|
||||||
// {
|
// {
|
||||||
|
|||||||
@@ -83,6 +83,11 @@ const router = createRouter({
|
|||||||
name: 'EditCoupon',
|
name: 'EditCoupon',
|
||||||
component: () => import('@/views/EditCoupon.vue'),
|
component: () => import('@/views/EditCoupon.vue'),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/tickets/:id',
|
||||||
|
name: 'ShowTickets',
|
||||||
|
component: () => import('@/views/ShowTickets.vue'),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/tickets',
|
path: '/tickets',
|
||||||
name: 'Tickets',
|
name: 'Tickets',
|
||||||
|
|||||||
@@ -48,13 +48,10 @@ export const useCategoriesStore = defineStore('categories', {
|
|||||||
actions: {
|
actions: {
|
||||||
async index(page, rows) {
|
async index(page, rows) {
|
||||||
this.fetching = true
|
this.fetching = true
|
||||||
|
|
||||||
const params = { page, rows }
|
const params = { page, rows }
|
||||||
|
|
||||||
const { status, data } = await axios.get('/courseCategory', { params })
|
const { status, data } = await axios.get('/courseCategory', { params })
|
||||||
|
|
||||||
this.fetching = false
|
this.fetching = false
|
||||||
|
return data
|
||||||
if (status === 200) {
|
if (status === 200) {
|
||||||
const map = (items, parent = null) => {
|
const map = (items, parent = null) => {
|
||||||
return items.map((item) => {
|
return items.map((item) => {
|
||||||
@@ -84,7 +81,7 @@ export const useCategoriesStore = defineStore('categories', {
|
|||||||
name: id.value
|
name: id.value
|
||||||
})
|
})
|
||||||
|
|
||||||
//console.log('result', result);
|
//console.log('result', result);
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,207 @@
|
|||||||
|
|
||||||
|
import axios from '../plugins/axios'
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
|
export const useTicketsStore = defineStore('tickets', {
|
||||||
|
state: () => ({
|
||||||
|
items: [],
|
||||||
|
fetching: true,
|
||||||
|
total: 0
|
||||||
|
}),
|
||||||
|
getters: {
|
||||||
|
// treeSelect: (state) => (id = null) => {
|
||||||
|
// if (id) {
|
||||||
|
// const foreach = (items) => {
|
||||||
|
// return items.filter((item) => {
|
||||||
|
// if (item.key != id) {
|
||||||
|
// if (item.children)
|
||||||
|
// item.children = foreach(item.children)
|
||||||
|
// return true
|
||||||
|
// } else return false
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// return foreach(state.items)
|
||||||
|
// }
|
||||||
|
// return state.items
|
||||||
|
// },
|
||||||
|
find: (state) => (id) => {
|
||||||
|
if (id) {
|
||||||
|
const foreach = (items) => {
|
||||||
|
const item = items.find(({ key }) => key == id)
|
||||||
|
if (item) return item
|
||||||
|
|
||||||
|
for (let i = 0; i < items.length; i++) {
|
||||||
|
const item = items[i];
|
||||||
|
|
||||||
|
if (item.children) {
|
||||||
|
const temp = foreach(item.children)
|
||||||
|
if (temp) return temp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return foreach(state.items)
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
async index(page, rows) {
|
||||||
|
this.fetching = true
|
||||||
|
|
||||||
|
const params = { page, rows }
|
||||||
|
|
||||||
|
const { status, data } = await axios.get('/ticket', { params })
|
||||||
|
|
||||||
|
this.fetching = false
|
||||||
|
return data
|
||||||
|
if (status === 200) {
|
||||||
|
const map = (items, parent = null) => {
|
||||||
|
return items.map((item) => {
|
||||||
|
const temp = {
|
||||||
|
key: item._id,
|
||||||
|
label: item.name,
|
||||||
|
data: item
|
||||||
|
}
|
||||||
|
if (parent)
|
||||||
|
temp.data.parentCategoryID = { [parent]: true }
|
||||||
|
if (item.sub) {
|
||||||
|
temp.children = map(item.sub, temp.key)
|
||||||
|
delete temp.data.sub
|
||||||
|
}
|
||||||
|
return temp;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.items = map(data)
|
||||||
|
|
||||||
|
// this.items = data.items
|
||||||
|
// this.total = data.total
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async ticket(id) {
|
||||||
|
this.fetching = true
|
||||||
|
const { status, data } = await axios.get(`/ticket/${id}`)
|
||||||
|
this.fetching = false
|
||||||
|
return data
|
||||||
|
if (status === 200) {
|
||||||
|
const map = (items, parent = null) => {
|
||||||
|
return items.map((item) => {
|
||||||
|
const temp = {
|
||||||
|
key: item._id,
|
||||||
|
label: item.name,
|
||||||
|
data: item
|
||||||
|
}
|
||||||
|
if (parent)
|
||||||
|
temp.data.parentCategoryID = { [parent]: true }
|
||||||
|
if (item.sub) {
|
||||||
|
temp.children = map(item.sub, temp.key)
|
||||||
|
delete temp.data.sub
|
||||||
|
}
|
||||||
|
return temp;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.items = map(data)
|
||||||
|
|
||||||
|
// this.items = data.items
|
||||||
|
// this.total = data.total
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async close(id){
|
||||||
|
this.fetching = true
|
||||||
|
const { status, data } = await axios.patch(`/ticket/close/${id}`, id)
|
||||||
|
this.fetching = false
|
||||||
|
return data
|
||||||
|
if (status === 200) {
|
||||||
|
const map = (items, parent = null) => {
|
||||||
|
return items.map((item) => {
|
||||||
|
const temp = {
|
||||||
|
key: item._id,
|
||||||
|
label: item.name,
|
||||||
|
data: item
|
||||||
|
}
|
||||||
|
if (parent)
|
||||||
|
temp.data.parentCategoryID = { [parent]: true }
|
||||||
|
if (item.sub) {
|
||||||
|
temp.children = map(item.sub, temp.key)
|
||||||
|
delete temp.data.sub
|
||||||
|
}
|
||||||
|
return temp;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.items = map(data)
|
||||||
|
|
||||||
|
// this.items = data.items
|
||||||
|
// this.total = data.total
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async reply(form){
|
||||||
|
this.fetching = true
|
||||||
|
const { status, data } = await axios.post('/ticket/message', form)
|
||||||
|
this.fetching = false
|
||||||
|
return data
|
||||||
|
if (status === 200) {
|
||||||
|
const map = (items, parent = null) => {
|
||||||
|
return items.map((item) => {
|
||||||
|
const temp = {
|
||||||
|
key: item._id,
|
||||||
|
label: item.name,
|
||||||
|
data: item
|
||||||
|
}
|
||||||
|
if (parent)
|
||||||
|
temp.data.parentCategoryID = { [parent]: true }
|
||||||
|
if (item.sub) {
|
||||||
|
temp.children = map(item.sub, temp.key)
|
||||||
|
delete temp.data.sub
|
||||||
|
}
|
||||||
|
return temp;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.items = map(data)
|
||||||
|
|
||||||
|
// this.items = data.items
|
||||||
|
// this.total = data.total
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async create(id) {
|
||||||
|
const result = await axios.post('/courseCategory', {
|
||||||
|
name: id.value
|
||||||
|
})
|
||||||
|
|
||||||
|
//console.log('result', result);
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
|
||||||
|
async store(form) {
|
||||||
|
const result = await axios.post('/admin/categories', form)
|
||||||
|
|
||||||
|
if (result.status === 201)
|
||||||
|
this.items.unshift(result.data)
|
||||||
|
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
async update(id, form) {
|
||||||
|
const result = await axios.put(`/admin/categories/${id}`, form)
|
||||||
|
|
||||||
|
if (result.status === 200) {
|
||||||
|
const index = this.items.findIndex(({ _id }) => _id == id)
|
||||||
|
this.items[index] = result.data
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
async remove(id) {
|
||||||
|
const result = await axios.delete(`/courseCategory/${id}`)
|
||||||
|
|
||||||
|
if (result.status === 200) {
|
||||||
|
const index = this.items.findIndex(({ _id }) => _id == id)
|
||||||
|
this.items.splice(index, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
+45
-35
@@ -25,10 +25,8 @@
|
|||||||
<div class="flex flex-col gap-1">
|
<div class="flex flex-col gap-1">
|
||||||
<FloatLabel>
|
<FloatLabel>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
:options="levels"
|
v-model="level"
|
||||||
:optionLabel="levels"
|
:options="['مبتدی', 'متوسط', 'پیشرفته']"
|
||||||
:optionValue="levels"
|
|
||||||
v-model="newCourse.level"
|
|
||||||
class="w-full"
|
class="w-full"
|
||||||
/>
|
/>
|
||||||
<label>{{ $t("سطح دوره") }}</label>
|
<label>{{ $t("سطح دوره") }}</label>
|
||||||
@@ -41,12 +39,12 @@
|
|||||||
</FloatLabel>
|
</FloatLabel>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col gap-1">
|
<!-- <div class="flex flex-col gap-1">
|
||||||
<FloatLabel>
|
<FloatLabel>
|
||||||
<InputText class="w-full" v-model="newCourse.categories" />
|
<InputText class="w-full" v-model="newCourse.categories" />
|
||||||
<label>{{ $t("دسته بندی") }}</label>
|
<label>{{ $t("دسته بندی") }}</label>
|
||||||
</FloatLabel>
|
</FloatLabel>
|
||||||
</div>
|
</div> -->
|
||||||
|
|
||||||
<div class="flex flex-col gap-1">
|
<div class="flex flex-col gap-1">
|
||||||
<FloatLabel>
|
<FloatLabel>
|
||||||
@@ -71,6 +69,25 @@
|
|||||||
<label>{{ $t("حجم کل دوره") }}</label>
|
<label>{{ $t("حجم کل دوره") }}</label>
|
||||||
</FloatLabel>
|
</FloatLabel>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-1">
|
||||||
|
<FloatLabel>
|
||||||
|
<InputGroup>
|
||||||
|
<InputText class="pointer-events-none truncate" dir="ltr" />
|
||||||
|
<Button severity="secondary">
|
||||||
|
<i class="pi pi-image ml-2"></i>
|
||||||
|
<span>{{ $t("chooseImage") }}</span>
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
class="opacity-0 absolute inset-0 cursor-pointer"
|
||||||
|
accept="image/*"
|
||||||
|
@input="chooseImage"
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</InputGroup>
|
||||||
|
<label>{{ $t("image") }}</label>
|
||||||
|
</FloatLabel>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex w-full mt-7">
|
<div class="flex w-full mt-7">
|
||||||
@@ -84,27 +101,8 @@
|
|||||||
</FloatLabel>
|
</FloatLabel>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="basis-2/6 ms-10">
|
<div class="basis-2/6 ms-8">
|
||||||
<div class="flex flex-col gap-1">
|
<div class="card flex flex-col gap-2 justify-center">
|
||||||
<FloatLabel>
|
|
||||||
<InputGroup>
|
|
||||||
<InputText class="pointer-events-none truncate" dir="ltr" />
|
|
||||||
<Button severity="secondary">
|
|
||||||
<i class="pi pi-image ml-2"></i>
|
|
||||||
<span>{{ $t("chooseImage") }}</span>
|
|
||||||
<input
|
|
||||||
type="file"
|
|
||||||
class="opacity-0 absolute inset-0 cursor-pointer"
|
|
||||||
accept="image/*"
|
|
||||||
@input="chooseImage"
|
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
</InputGroup>
|
|
||||||
<label>{{ $t("image") }}</label>
|
|
||||||
</FloatLabel>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card flex flex-col gap-2 justify-center mt-7">
|
|
||||||
<Listbox
|
<Listbox
|
||||||
listStyle="height:240px"
|
listStyle="height:240px"
|
||||||
emptyMessage="دسته بندی وجود ندارد"
|
emptyMessage="دسته بندی وجود ندارد"
|
||||||
@@ -152,6 +150,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import Listbox from "primevue/listbox";
|
||||||
import { jDate } from "@/utils/jDate";
|
import { jDate } from "@/utils/jDate";
|
||||||
import { treeTogglerRTL } from "@/utils/tree-toggler-rtl";
|
import { treeTogglerRTL } from "@/utils/tree-toggler-rtl";
|
||||||
|
|
||||||
@@ -168,10 +167,21 @@ import {
|
|||||||
import { useStaticsStore } from "@/stores/statics";
|
import { useStaticsStore } from "@/stores/statics";
|
||||||
import { useUploaderStore } from "@/stores/uploader";
|
import { useUploaderStore } from "@/stores/uploader";
|
||||||
import { useProductsStore } from "@/stores/products";
|
import { useProductsStore } from "@/stores/products";
|
||||||
const courseStore = useProductsStore()
|
import { useCategoriesStore } from "@/stores/categoreis";
|
||||||
|
const categoriesStore = useCategoriesStore();
|
||||||
|
const courseStore = useProductsStore();
|
||||||
const uploadStore = useUploaderStore();
|
const uploadStore = useUploaderStore();
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
|
const route = useRoute();
|
||||||
|
const level = ref(null)
|
||||||
|
watchEffect(async () => {
|
||||||
|
const { page = 1, rows = 10 } = route.query;
|
||||||
|
const categoriess = await categoriesStore.index(page, rows);
|
||||||
|
console.log("cat", categoriess);
|
||||||
|
cities.value = categoriess;
|
||||||
|
});
|
||||||
const selectedCity = ref();
|
const selectedCity = ref();
|
||||||
|
const cities = ref();
|
||||||
const levels = reactive(["آسان", "متوسط", "سخت"]);
|
const levels = reactive(["آسان", "متوسط", "سخت"]);
|
||||||
const newCourse = reactive({
|
const newCourse = reactive({
|
||||||
name: "",
|
name: "",
|
||||||
@@ -193,7 +203,7 @@ const chooseImage = async (el) => {
|
|||||||
//console.log('uploader', uploader.data.url);
|
//console.log('uploader', uploader.data.url);
|
||||||
newCourse.image = uploader.data.url;
|
newCourse.image = uploader.data.url;
|
||||||
console.log("تصویر آپلود شد");
|
console.log("تصویر آپلود شد");
|
||||||
console.log('upldr',uploader);
|
console.log("upldr", uploader);
|
||||||
};
|
};
|
||||||
const create = async (data) => {
|
const create = async (data) => {
|
||||||
if (newCourse.image === "") {
|
if (newCourse.image === "") {
|
||||||
@@ -219,20 +229,20 @@ const create = async (data) => {
|
|||||||
newCourse.slug = data.name;
|
newCourse.slug = data.name;
|
||||||
newCourse.duration = data.duration;
|
newCourse.duration = data.duration;
|
||||||
// newCourse.categories = data.categories;
|
// newCourse.categories = data.categories;
|
||||||
newCourse.categories = "66587ae698d0a0db14693a5e"
|
newCourse.categories = "66587ae698d0a0db14693a5e";
|
||||||
// newCourse.teacher = data.teacher;
|
// newCourse.teacher = data.teacher;
|
||||||
newCourse.teacher = "66530b0480ef484e2bd19220"
|
newCourse.teacher = "66530b0480ef484e2bd19220";
|
||||||
// newCourse.completionPercentage = data.completionPercentage;
|
// newCourse.completionPercentage = data.completionPercentage;
|
||||||
newCourse.completionPercentage = 20;
|
newCourse.completionPercentage = 20;
|
||||||
// newCourse.level = data.level;
|
// newCourse.level = data.level;
|
||||||
newCourse.level = "متوسط"
|
newCourse.level = "متوسط";
|
||||||
// newCourse.language = data.language;
|
// newCourse.language = data.language;
|
||||||
newCourse.language = "فارسی"
|
newCourse.language = "فارسی";
|
||||||
newCourse.countOfVideos = data.countOfVideos;
|
newCourse.countOfVideos = data.countOfVideos;
|
||||||
newCourse.totalFileSize = data.totalFileSize;
|
newCourse.totalFileSize = data.totalFileSize;
|
||||||
// console.log("newCourse: ", newCourse);
|
// console.log("newCourse: ", newCourse);
|
||||||
const creat = await courseStore.create(newCourse)
|
const creat = await courseStore.create(newCourse);
|
||||||
console.log('created', creat);
|
console.log("created", creat);
|
||||||
};
|
};
|
||||||
// console.log("form", data);
|
// console.log("form", data);
|
||||||
// console.log("json", JSON.stringify(data));
|
// console.log("json", JSON.stringify(data));
|
||||||
|
|||||||
+144
-145
@@ -1,127 +1,117 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<section class="flex flex-col gap-4">
|
||||||
<section class="flex flex-col gap-4">
|
<Panel :header="$t('ویرایش دوره')">
|
||||||
<Panel :header="$t('ویرایش دوره')">
|
<div class="grid grid-cols-3 gap-7">
|
||||||
<div class="grid grid-cols-3 gap-7">
|
<div class="flex flex-col gap-1">
|
||||||
<div class="flex flex-col gap-1">
|
<FloatLabel>
|
||||||
<FloatLabel>
|
<InputText class="w-full" v-model="course.name" />
|
||||||
<InputText class="w-full" v-model="course.name" />
|
<label>{{ $t("title") }}</label>
|
||||||
<label>{{ $t("title") }}</label>
|
</FloatLabel>
|
||||||
</FloatLabel>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex flex-col gap-1">
|
|
||||||
<FloatLabel>
|
|
||||||
<InputText class="w-full" v-model="course.language" />
|
|
||||||
<label>{{ $t("زبان آموزش") }}</label>
|
|
||||||
</FloatLabel>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col gap-1">
|
|
||||||
<FloatLabel>
|
|
||||||
<InputText class="w-full" v-model="course.duration" />
|
|
||||||
<label>{{ $t("مدت زمان دوره") }}</label>
|
|
||||||
</FloatLabel>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex flex-col gap-1">
|
|
||||||
<FloatLabel>
|
|
||||||
<Dropdown
|
|
||||||
:options="levels"
|
|
||||||
:optionLabel="levels"
|
|
||||||
:optionValue="levels"
|
|
||||||
|
|
||||||
class="w-full"
|
|
||||||
/>
|
|
||||||
<label>{{ $t("سطح دوره") }}</label>
|
|
||||||
</FloatLabel>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col gap-1">
|
|
||||||
<FloatLabel>
|
|
||||||
<InputText class="w-full" />
|
|
||||||
<label>{{ $t("مدرس دوره") }}</label>
|
|
||||||
</FloatLabel>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex flex-col gap-1">
|
|
||||||
<FloatLabel>
|
|
||||||
<InputText class="w-full" />
|
|
||||||
<label>{{ $t("دسته بندی") }}</label>
|
|
||||||
</FloatLabel>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex flex-col gap-1">
|
|
||||||
<FloatLabel>
|
|
||||||
<InputText
|
|
||||||
class="w-full"
|
|
||||||
|
|
||||||
/>
|
<div class="flex flex-col gap-1">
|
||||||
<label>{{ $t("درصد تکمیل دوره") }}</label>
|
<FloatLabel>
|
||||||
</FloatLabel>
|
<InputText class="w-full" v-model="course.language" />
|
||||||
</div>
|
<label>{{ $t("زبان آموزش") }}</label>
|
||||||
|
</FloatLabel>
|
||||||
<div class="flex flex-col gap-1">
|
</div>
|
||||||
<FloatLabel>
|
<div class="flex flex-col gap-1">
|
||||||
<InputText class="w-full" />
|
<FloatLabel>
|
||||||
<label>{{ $t("تعداد ویدیو ها") }}</label>
|
<InputText class="w-full" v-model="course.duration" />
|
||||||
</FloatLabel>
|
<label>{{ $t("مدت زمان دوره") }}</label>
|
||||||
</div>
|
</FloatLabel>
|
||||||
|
</div>
|
||||||
<div class="flex flex-col gap-1">
|
|
||||||
<FloatLabel>
|
<div class="flex flex-col gap-1">
|
||||||
<InputText class="w-full" />
|
<FloatLabel>
|
||||||
<label>{{ $t("حجم کل دوره") }}</label>
|
<Dropdown
|
||||||
</FloatLabel>
|
:options="levels"
|
||||||
</div>
|
:optionLabel="levels"
|
||||||
</div>
|
:optionValue="levels"
|
||||||
|
v-model="course.level"
|
||||||
<div class="flex w-full mt-7">
|
class="w-full"
|
||||||
<div class="basis-4/6">
|
/>
|
||||||
<FloatLabel>
|
<label>{{ $t("سطح دوره") }}</label>
|
||||||
<Editor
|
</FloatLabel>
|
||||||
|
</div>
|
||||||
placeholder="توضیحات"
|
<div class="flex flex-col gap-1">
|
||||||
editorStyle="height: 320px"
|
<FloatLabel>
|
||||||
/>
|
<InputText class="w-full" v-model="course.teacher.name" />
|
||||||
</FloatLabel>
|
<label>{{ $t("مدرس دوره") }}</label>
|
||||||
</div>
|
</FloatLabel>
|
||||||
|
</div>
|
||||||
<div class="basis-2/6 ms-10">
|
|
||||||
<div class="flex flex-col gap-1">
|
<div class="flex flex-col gap-1">
|
||||||
<FloatLabel>
|
<FloatLabel>
|
||||||
<InputGroup>
|
<InputText class="w-full" v-model="course.completionPercentage" />
|
||||||
<InputText class="pointer-events-none truncate" dir="ltr" />
|
<label>{{ $t("درصد تکمیل دوره") }}</label>
|
||||||
<Button severity="secondary">
|
</FloatLabel>
|
||||||
<i class="pi pi-image ml-2"></i>
|
</div>
|
||||||
<span>{{ $t("chooseImage") }}</span>
|
|
||||||
<input
|
<div class="flex flex-col gap-1">
|
||||||
type="file"
|
<FloatLabel>
|
||||||
class="opacity-0 absolute inset-0 cursor-pointer"
|
<InputText class="w-full" v-model="course.videosCount" />
|
||||||
accept="image/*"
|
<label>{{ $t("تعداد ویدیو ها") }}</label>
|
||||||
|
</FloatLabel>
|
||||||
/>
|
</div>
|
||||||
</Button>
|
|
||||||
</InputGroup>
|
<div class="flex flex-col gap-1">
|
||||||
<label>{{ $t("image") }}</label>
|
<FloatLabel>
|
||||||
</FloatLabel>
|
<InputText class="w-full" v-model="course.totalFileSize" />
|
||||||
</div>
|
<label>{{ $t("حجم کل دوره") }}</label>
|
||||||
|
</FloatLabel>
|
||||||
<div class="card flex flex-col gap-2 justify-center mt-7">
|
</div>
|
||||||
<Listbox
|
|
||||||
listStyle="height:240px"
|
|
||||||
emptyMessage="دسته بندی وجود ندارد"
|
<div class="flex flex-col gap-1">
|
||||||
emptyFilterMessage="دسته بندی وجود ندارد"
|
<FloatLabel>
|
||||||
filterPlaceholder=" دسته بندی"
|
<InputGroup>
|
||||||
:options="cities"
|
<InputText class="pointer-events-none truncate" dir="ltr" />
|
||||||
filter
|
<Button severity="secondary">
|
||||||
optionLabel="name"
|
<i class="pi pi-image ml-2"></i>
|
||||||
class="w-full"
|
<span>{{ $t("chooseImage") }}</span>
|
||||||
/>
|
<input
|
||||||
</div>
|
:value="course.image"
|
||||||
<div></div>
|
type="file"
|
||||||
</div>
|
class="opacity-0 absolute inset-0 cursor-pointer"
|
||||||
</div>
|
accept="image/*"
|
||||||
|
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</InputGroup>
|
||||||
|
<label>{{ $t("image") }}</label>
|
||||||
|
</FloatLabel>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex w-full mt-7">
|
||||||
|
<div class="basis-4/6">
|
||||||
|
<FloatLabel>
|
||||||
|
<Editor
|
||||||
|
v-model="course.description"
|
||||||
|
placeholder="توضیحات"
|
||||||
|
editorStyle="height: 320px"
|
||||||
|
/>
|
||||||
|
</FloatLabel>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="basis-2/6 ms-8">
|
||||||
|
<div class="card flex flex-col gap-2 justify-center ">
|
||||||
|
<Listbox
|
||||||
|
listStyle="height:240px"
|
||||||
|
emptyMessage="دسته بندی وجود ندارد"
|
||||||
|
emptyFilterMessage="دسته بندی وجود ندارد"
|
||||||
|
filterPlaceholder=" دسته بندی"
|
||||||
|
:options="cities"
|
||||||
|
filter
|
||||||
|
optionLabel="name"
|
||||||
|
class="w-full"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="flex pt-4 justify-end">
|
<div class="flex pt-4 justify-end">
|
||||||
<Button
|
<Button
|
||||||
:label="$t('edit')"
|
:label="$t('edit')"
|
||||||
@@ -131,16 +121,17 @@
|
|||||||
@click="create(course)"
|
@click="create(course)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Panel>
|
</Panel>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useProductsStore } from '@/stores/products';
|
import { useProductsStore } from "@/stores/products";
|
||||||
import { ref, watchEffect, reactive } from 'vue';
|
import { ref, watchEffect, reactive } from "vue";
|
||||||
|
|
||||||
const store = useProductsStore()
|
const store = useProductsStore();
|
||||||
const data = ref(null)
|
const data = ref(null);
|
||||||
const course = reactive({
|
const course = reactive({
|
||||||
|
id: "",
|
||||||
name: "",
|
name: "",
|
||||||
description: "",
|
description: "",
|
||||||
slug: "",
|
slug: "",
|
||||||
@@ -155,30 +146,38 @@ const course = reactive({
|
|||||||
countOfVideos: 0,
|
countOfVideos: 0,
|
||||||
totalFileSize: "",
|
totalFileSize: "",
|
||||||
});
|
});
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from "vue-router";
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute();
|
||||||
|
|
||||||
watchEffect(async()=>{
|
watchEffect(async () => {
|
||||||
data.value = await store.edit(route.params.id)
|
data.value = await store.edit(route.params.id);
|
||||||
console.log('store7',data.value.course);
|
|
||||||
course.name = data.value.course.name
|
course.id = data.value.course.id;
|
||||||
course.language = data.value.course.language
|
course.name = data.value.course.name;
|
||||||
course.duration = data.value.course.duration
|
course.description = data.value.course.description;
|
||||||
})
|
course.slug = data.value.course.slug;
|
||||||
|
course.duration = data.value.course.duration;
|
||||||
|
course.image = data.value.course.image;
|
||||||
|
course.categories = data.value.course.categories;
|
||||||
|
course.price = data.value.course.price;
|
||||||
|
course.teacher = data.value.course.teacher;
|
||||||
|
course.completionPercentage = data.value.course.completionPercentage;
|
||||||
|
course.level = data.value.course.level;
|
||||||
|
course.language = data.value.course.language;
|
||||||
|
course.countOfVideos = data.value.course.countOfVideos;
|
||||||
|
course.totalFileSize = data.value.course.totalFileSize;
|
||||||
|
});
|
||||||
|
|
||||||
// const levels = reactive(["آسان", "متوسط", "سخت"]);
|
// const levels = reactive(["آسان", "متوسط", "سخت"]);
|
||||||
|
|
||||||
|
|
||||||
const chooseImage = async (el) => {
|
const chooseImage = async (el) => {
|
||||||
// const uploader = await uploadStore.uploader(el.target.value);
|
// const uploader = await uploadStore.uploader(el.target.value);
|
||||||
// //console.log('uploader', uploader.data.url);
|
// //console.log('uploader', uploader.data.url);
|
||||||
// newCourse.image = uploader.data.url;
|
// newCourse.image = uploader.data.url;
|
||||||
// console.log("تصویر آپلود شد");
|
// console.log("تصویر آپلود شد");
|
||||||
// console.log('upldr',uploader);
|
// console.log('upldr',uploader);
|
||||||
};
|
};
|
||||||
|
|
||||||
const create = async (data) => {
|
const create = async (data) => {};
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
<template>
|
||||||
|
<Panel :header="$t('گفتگو')">
|
||||||
|
<!-- <DataTable :value="messages.ticketMessages">
|
||||||
|
<Column field="content" :header="$t('متن تیکت')" />
|
||||||
|
<Column field="id" :header="$t('id')" />
|
||||||
|
<Column :field="({createdAt}) => jDate(createdAt)" :header="$t('createdAt')" />
|
||||||
|
<Column :header="$t('options')" headerClass="w-32">
|
||||||
|
<template #body="{ data }">
|
||||||
|
<div class="flex justify-end">
|
||||||
|
<Button
|
||||||
|
icon="pi pi-reply"
|
||||||
|
rounded
|
||||||
|
text
|
||||||
|
severity="secondary"
|
||||||
|
@click="edit(data)"
|
||||||
|
/>
|
||||||
|
</div></template></Column>
|
||||||
|
<template #empty>
|
||||||
|
<p>{{ store.fetching ? $t("loading") : $t("emptyTable") }}</p>
|
||||||
|
</template>
|
||||||
|
</DataTable> -->
|
||||||
|
|
||||||
|
<div v-for="item in messages.ticketMessages" :key="item.id">
|
||||||
|
<!-- <Textarea :value="item.content" cols="30" disabled /> -->
|
||||||
|
<Fieldset legend="متن تیکت" class="mb-8" :class="{'bg-gray-100' : item.createdBy.roles[0] === 'Admin'}">
|
||||||
|
<p class="m-0">
|
||||||
|
{{ item.content }}
|
||||||
|
</p>
|
||||||
|
</Fieldset>
|
||||||
|
</div>
|
||||||
|
<Editor v-model="value" editorStyle="height: 320px" />
|
||||||
|
|
||||||
|
<div class="flex pt-4 justify-end">
|
||||||
|
<Button
|
||||||
|
:label="$t('send')"
|
||||||
|
icon="pi pi-send"
|
||||||
|
severity="success"
|
||||||
|
:loading="saving"
|
||||||
|
@click="send(value)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Panel>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, watchEffect } from "vue";
|
||||||
|
import { useRoute } from "vue-router";
|
||||||
|
const value = ref("");
|
||||||
|
import { useTicketsStore } from "@/stores/tickets";
|
||||||
|
import { jDate } from "@/utils/jDate";
|
||||||
|
const store = useTicketsStore();
|
||||||
|
const messages = ref([]);
|
||||||
|
const route = useRoute();
|
||||||
|
console.log(route.params.id);
|
||||||
|
const send = async (value) => {
|
||||||
|
console.log(value);
|
||||||
|
const sended = await store.reply({
|
||||||
|
content: value,
|
||||||
|
ticketId: route.params.id,
|
||||||
|
});
|
||||||
|
console.log('sended', sended);
|
||||||
|
};
|
||||||
|
watchEffect(async () => {
|
||||||
|
messages.value = await store.ticket(route.params.id);
|
||||||
|
console.log("mess", messages.value.ticketMessages);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
+62
-2
@@ -1,3 +1,63 @@
|
|||||||
<template>
|
<template>
|
||||||
<h1>tickets</h1>
|
<Panel :header="$t('تیکت ها')">
|
||||||
</template>
|
<DataTable :value="data">
|
||||||
|
|
||||||
|
<Column field="subject" :header="$t('موضوع')" />
|
||||||
|
<Column field="id" :header="$t('id')" />
|
||||||
|
<Column :field="({ createdBy }) => createdBy.name" :header="$t('کاربر')" />
|
||||||
|
<Column field="status" :header="$t('status')" />
|
||||||
|
<Column :field="({ createdAt }) => jDate(createdAt)" :header="$t('createdAt')" />
|
||||||
|
<Column :header="$t('options')" headerClass="w-32">
|
||||||
|
<template #body="{ data }">
|
||||||
|
<div class="flex">
|
||||||
|
<Button
|
||||||
|
icon="pi pi-comments"
|
||||||
|
rounded
|
||||||
|
text
|
||||||
|
severity="secondary"
|
||||||
|
@click="chat(data)"
|
||||||
|
/>
|
||||||
|
<Button icon="pi pi-times-circle" style="color: red" rounded text severity="secondary" @click="closeTicket(data)" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</Column>
|
||||||
|
<template #empty>
|
||||||
|
<p>{{ store.fetching ? $t("loading") : $t("emptyTable") }}</p>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<!--
|
||||||
|
<Paginator :rows="store.total" :totalRecords="store.total" :rowsPerPageOptions="[5, 20, 30]"></Paginator>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<Pagination :total="store.total" />
|
||||||
|
</template>
|
||||||
|
</DataTable>
|
||||||
|
</Panel>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, watchEffect } from "vue";
|
||||||
|
import {useTicketsStore} from "@/stores/tickets"
|
||||||
|
import { useRoute, useRouter } from "vue-router";
|
||||||
|
import {jDate} from "@/utils/jDate"
|
||||||
|
const store = useTicketsStore()
|
||||||
|
const router = useRouter()
|
||||||
|
const data = ref([])
|
||||||
|
const route = useRoute()
|
||||||
|
const chat = (data) =>{
|
||||||
|
router.push(`/tickets/${data.id}`)
|
||||||
|
console.log(data.id);
|
||||||
|
}
|
||||||
|
const closeTicket = async(data) =>{
|
||||||
|
// console.log(data.id);
|
||||||
|
const closess = await store.close(data.id)
|
||||||
|
console.log('close',closess);
|
||||||
|
await store.index()
|
||||||
|
}
|
||||||
|
watchEffect(async() =>{
|
||||||
|
const { page = 1, pageSize = 10 } = route.query;
|
||||||
|
data.value = await store.index(page, pageSize)
|
||||||
|
console.log(data.value[1]);
|
||||||
|
})
|
||||||
|
</script>
|
||||||
Reference in New Issue
Block a user