| @@ -36,7 +36,6 @@ export default { | |||||
| event.preventDefault(); | event.preventDefault(); | ||||
| }, | }, | ||||
| handleKeyDown(event) { | handleKeyDown(event) { | ||||
| console.log('handleKeyDown called', event.key, event.ctrlKey); | |||||
| // Check if Ctrl+K is pressed | // Check if Ctrl+K is pressed | ||||
| if (event.ctrlKey && event.key === 'k') { | if (event.ctrlKey && event.key === 'k') { | ||||
| // Prevent the default action (e.g., browser search) | // Prevent the default action (e.g., browser search) | ||||
| @@ -47,6 +47,7 @@ | |||||
| <label class="form-label">تصویر دسته</label> | <label class="form-label">تصویر دسته</label> | ||||
| <input | <input | ||||
| ref="imageFileRef" | |||||
| type="file" | type="file" | ||||
| accept="image/*" | accept="image/*" | ||||
| @change="handleImageChange" | @change="handleImageChange" | ||||
| @@ -206,6 +207,7 @@ export default { | |||||
| const title = ref(); | const title = ref(); | ||||
| const errors = ref({}); | const errors = ref({}); | ||||
| const loading = ref(false); | const loading = ref(false); | ||||
| const imageFileRef = ref(null); | |||||
| watch( | watch( | ||||
| () => props.parents, | () => props.parents, | ||||
| @@ -310,6 +312,7 @@ export default { | |||||
| description.value = ""; | description.value = ""; | ||||
| selectedPaernt.value = "" | selectedPaernt.value = "" | ||||
| selectedIcon.value = ""; | selectedIcon.value = ""; | ||||
| imageFileRef.value.value = null | |||||
| }, 500); | }, 500); | ||||
| }) | }) | ||||
| .catch((error) => { | .catch((error) => { | ||||
| @@ -340,6 +343,7 @@ export default { | |||||
| setSelectedIcon, | setSelectedIcon, | ||||
| iconData, | iconData, | ||||
| selectedIcon, | selectedIcon, | ||||
| imageFileRef, | |||||
| }; | }; | ||||
| }, | }, | ||||
| }; | }; | ||||
| @@ -46,6 +46,7 @@ | |||||
| <label class="form-label">تصویر دسته</label> | <label class="form-label">تصویر دسته</label> | ||||
| <input | <input | ||||
| ref="imageFileRef" | |||||
| type="file" | type="file" | ||||
| @input="clearError('localImage')" | @input="clearError('localImage')" | ||||
| accept="image/*" | accept="image/*" | ||||
| @@ -232,6 +233,7 @@ export default { | |||||
| const image = ref(null); | const image = ref(null); | ||||
| const localId = toRef(props.id); | const localId = toRef(props.id); | ||||
| const errors = ref({}); | const errors = ref({}); | ||||
| const imageFileRef = ref(null); | |||||
| const loading = ref(false); | const loading = ref(false); | ||||
| @@ -382,7 +384,7 @@ export default { | |||||
| localParent, | localParent, | ||||
| allLocalParents, | allLocalParents, | ||||
| setSelectedIcon, | setSelectedIcon, | ||||
| imageFileRef, | |||||
| localIcon, | localIcon, | ||||
| }; | }; | ||||
| }, | }, | ||||
| @@ -24,7 +24,7 @@ | |||||
| <form @submit.prevent="addIdentity"> | <form @submit.prevent="addIdentity"> | ||||
| <BRow class="g-3"> | <BRow class="g-3"> | ||||
| <!-- Brand Title --> | <!-- Brand Title --> | ||||
| <BCol lg="6"> | |||||
| <BCol lg="12"> | |||||
| <div class="form-group"> | <div class="form-group"> | ||||
| <label class="form-label">عنوان مشخصه</label> | <label class="form-label">عنوان مشخصه</label> | ||||
| @@ -42,25 +42,25 @@ | |||||
| </div> | </div> | ||||
| </BCol> | </BCol> | ||||
| <BCol lg="6"> | |||||
| <div class="form-group"> | |||||
| <label class="form-label">انتخاب دسته</label> | |||||
| <div class="color-picker-wrapper"> | |||||
| <VueSelect | |||||
| style="--vs-min-height: 48px; --vs-border-radius: 8px" | |||||
| :isLoading="categorySelectorLoader" | |||||
| v-model="selectedCat" | |||||
| :options="formattedCategories" | |||||
| placeholder="دسته ای را انتخاب کنید" | |||||
| @search="handleSearch" | |||||
| /> | |||||
| </div> | |||||
| <small v-if="errors.selectedCat" class="text-danger"> | |||||
| {{ errors.selectedCat }} | |||||
| </small> | |||||
| </div> | |||||
| </BCol> | |||||
| <!-- <BCol lg="6">--> | |||||
| <!-- <div class="form-group">--> | |||||
| <!-- <label class="form-label">انتخاب دسته</label>--> | |||||
| <!-- <div class="color-picker-wrapper">--> | |||||
| <!-- <VueSelect--> | |||||
| <!-- style="--vs-min-height: 48px; --vs-border-radius: 8px"--> | |||||
| <!-- :isLoading="categorySelectorLoader"--> | |||||
| <!-- v-model="selectedCat"--> | |||||
| <!-- :options="formattedCategories"--> | |||||
| <!-- placeholder="دسته ای را انتخاب کنید"--> | |||||
| <!-- @search="handleSearch"--> | |||||
| <!-- />--> | |||||
| <!-- </div>--> | |||||
| <!-- <small v-if="errors.selectedCat" class="text-danger">--> | |||||
| <!-- {{ errors.selectedCat }}--> | |||||
| <!-- </small>--> | |||||
| <!-- </div>--> | |||||
| <!-- </BCol>--> | |||||
| </BRow> | </BRow> | ||||
| <!-- Submit Buttons --> | <!-- Submit Buttons --> | ||||
| @@ -95,16 +95,21 @@ | |||||
| <script> | <script> | ||||
| import { ref, computed } from "vue"; | import { ref, computed } from "vue"; | ||||
| import VueSelect from "vue3-select-component"; | |||||
| import { toast } from "vue3-toastify"; | import { toast } from "vue3-toastify"; | ||||
| import "vue3-toastify/dist/index.css"; | import "vue3-toastify/dist/index.css"; | ||||
| import ApiServiece from "@/services/ApiService"; | import ApiServiece from "@/services/ApiService"; | ||||
| export default { | export default { | ||||
| components: { | |||||
| VueSelect, | |||||
| props: { | |||||
| categoryId: { | |||||
| type: Number, | |||||
| required: true, | |||||
| } | |||||
| }, | }, | ||||
| setup(props, { emit }) { | setup(props, { emit }) { | ||||
| const selectedCat = ref(); | const selectedCat = ref(); | ||||
| const title = ref(); | const title = ref(); | ||||
| const errors = ref({}); | const errors = ref({}); | ||||
| @@ -159,8 +164,8 @@ export default { | |||||
| loading.value = true; | loading.value = true; | ||||
| const formData = new FormData(); | const formData = new FormData(); | ||||
| if (selectedCat.value) { | |||||
| formData.append("category_id", selectedCat.value); | |||||
| if (props.categoryId) { | |||||
| formData.append("category_id", props.categoryId); | |||||
| } | } | ||||
| formData.append("title", title.value); | formData.append("title", title.value); | ||||
| @@ -28,7 +28,6 @@ export default { | |||||
| event.preventDefault(); | event.preventDefault(); | ||||
| }, | }, | ||||
| handleKeyDown(event) { | handleKeyDown(event) { | ||||
| console.log('handleKeyDown called', event.key, event.ctrlKey); | |||||
| // Check if Ctrl+K is pressed | // Check if Ctrl+K is pressed | ||||
| if (event.ctrlKey && event.key === 'k') { | if (event.ctrlKey && event.key === 'k') { | ||||
| // Prevent the default action (e.g., browser search) | // Prevent the default action (e.g., browser search) | ||||
| @@ -31,7 +31,6 @@ export default { | |||||
| event.preventDefault(); | event.preventDefault(); | ||||
| }, | }, | ||||
| handleKeyDown(event) { | handleKeyDown(event) { | ||||
| console.log("handleKeyDown called", event.key, event.ctrlKey); | |||||
| // Check if Ctrl+K is pressed | // Check if Ctrl+K is pressed | ||||
| if (event.ctrlKey && event.key === "k") { | if (event.ctrlKey && event.key === "k") { | ||||
| // Prevent the default action (e.g., browser search) | // Prevent the default action (e.g., browser search) | ||||
| @@ -17,7 +17,6 @@ export default { | |||||
| const dir = localStorage.getItem("dir"); | const dir = localStorage.getItem("dir"); | ||||
| const validDir = dir === "ltr" || dir === "rtl" ? dir : "rtl"; | const validDir = dir === "ltr" || dir === "rtl" ? dir : "rtl"; | ||||
| document.body.setAttribute("data-pc-direction", validDir); | document.body.setAttribute("data-pc-direction", validDir); | ||||
| console.log(validDir); | |||||
| }, | }, | ||||
| }; | }; | ||||
| </script> | </script> | ||||
| @@ -1,7 +1,7 @@ | |||||
| import { createWebHistory, createRouter } from "vue-router"; | import { createWebHistory, createRouter } from "vue-router"; | ||||
| import routes from "./routes"; | import routes from "./routes"; | ||||
| import appConfig from "../../app.config"; | import appConfig from "../../app.config"; | ||||
| import store from "../state/store"; | |||||
| //import store from "../state/store"; | |||||
| const router = createRouter({ | const router = createRouter({ | ||||
| history: createWebHistory("/"), | history: createWebHistory("/"), | ||||
| @@ -11,11 +11,11 @@ const router = createRouter({ | |||||
| router.beforeResolve(async (routeTo, routeFrom, next) => { | router.beforeResolve(async (routeTo, routeFrom, next) => { | ||||
| try { | try { | ||||
| if (routeTo.matched.some((record) => record.meta.requiresAuth)) { | if (routeTo.matched.some((record) => record.meta.requiresAuth)) { | ||||
| await store.dispatch("user/verifyLogin"); | |||||
| //await store.dispatch("user/verifyLogin"); | |||||
| if (!store.getters["user/isAuthenticated"]) { | |||||
| return next({ name: "otpLogin" }); | |||||
| } | |||||
| // if (!store.getters["user/isAuthenticated"]) { | |||||
| // return next({ name: "otpLogin" }); | |||||
| // } | |||||
| } | } | ||||
| // For each matched route... | // For each matched route... | ||||
| @@ -14,16 +14,6 @@ export default [ | |||||
| component: () => | component: () => | ||||
| import("../views/live-preview/pages/auth1/forgot-password.vue"), | import("../views/live-preview/pages/auth1/forgot-password.vue"), | ||||
| }, | }, | ||||
| { | |||||
| path: "/dashPage", | |||||
| name: "dashPage", | |||||
| meta: { | |||||
| requiresAuth: true, | |||||
| title: "داشبورد", | |||||
| }, | |||||
| component: () => | |||||
| import("../views/live-preview/pages/dashboard/dashPage.vue"), | |||||
| }, | |||||
| { | { | ||||
| path: "/users", | path: "/users", | ||||
| name: "users", | name: "users", | ||||
| @@ -1,6 +1,8 @@ | |||||
| import axios from "axios"; | import axios from "axios"; | ||||
| import router from "@/router/index"; | |||||
| const url = process.env.VUE_APP_ROOT_URL; | const url = process.env.VUE_APP_ROOT_URL; | ||||
| const ApiServiece = axios.create({ | const ApiServiece = axios.create({ | ||||
| baseURL: url, | baseURL: url, | ||||
| headers: { | headers: { | ||||
| @@ -27,7 +29,9 @@ ApiServiece.interceptors.response.use( | |||||
| return response; | return response; | ||||
| }, | }, | ||||
| (error) => { | (error) => { | ||||
| console.error("API Error:", error); | |||||
| if (error?.status === 401) { | |||||
| router.push({ name: "otpLogin" }); | |||||
| } | |||||
| return Promise.reject(error); | return Promise.reject(error); | ||||
| } | } | ||||
| ); | ); | ||||
| @@ -619,7 +619,7 @@ export default { | |||||
| } | } | ||||
| formData.append("panel", pannel.value); | formData.append("panel", pannel.value); | ||||
| if (pannel.value == "wholesale") { | if (pannel.value == "wholesale") { | ||||
| formData.append("page_type", null); | |||||
| formData.append("page_type", "main_page"); | |||||
| } | } | ||||
| if (pannel.value !== "wholesale") { | if (pannel.value !== "wholesale") { | ||||
| @@ -198,6 +198,31 @@ export default { | |||||
| }); | }); | ||||
| }; | }; | ||||
| const setPageType = (banner)=> { | |||||
| switch (banner.page_type) { | |||||
| case 'category': | |||||
| return 'دسته ' + banner?.category_page?.title; | |||||
| case 'brand': | |||||
| return 'برند ' + banner?.brand_page?.title | |||||
| case 'main_page': | |||||
| return 'صفحه اصلی' | |||||
| case 'special_page': | |||||
| return 'شگفت انگیزها' | |||||
| case 'blog_page': | |||||
| return 'مقالات' | |||||
| } | |||||
| } | |||||
| const setProductOrCategory = (banner) => { | |||||
| if (banner?.category_id) { | |||||
| return `دسته<br>${banner?.category?.title}`; | |||||
| } | |||||
| if (banner?.product_id) { | |||||
| return `محصول<br>${banner?.product?.title}`; | |||||
| } | |||||
| return ""; | |||||
| }; | |||||
| onMounted(() => { | onMounted(() => { | ||||
| getBanners(); | getBanners(); | ||||
| }); | }); | ||||
| @@ -224,6 +249,8 @@ export default { | |||||
| searchPage, | searchPage, | ||||
| visiblePages, | visiblePages, | ||||
| selectedPageType, | selectedPageType, | ||||
| setPageType, | |||||
| setProductOrCategory, | |||||
| }; | }; | ||||
| }, | }, | ||||
| }; | }; | ||||
| @@ -282,6 +309,9 @@ export default { | |||||
| <th>موقعیت</th> | <th>موقعیت</th> | ||||
| <th>نوع</th> | <th>نوع</th> | ||||
| <th>تاریخ ایجاد</th> | <th>تاریخ ایجاد</th> | ||||
| <th>پنل</th> | |||||
| <th>نمایش در</th> | |||||
| <th>صفحه فرود</th> | |||||
| <th>عملیات</th> | <th>عملیات</th> | ||||
| </tr> | </tr> | ||||
| </thead> | </thead> | ||||
| @@ -328,6 +358,11 @@ export default { | |||||
| <td v-if="banner.type === 'slider'">اسلایدر</td> | <td v-if="banner.type === 'slider'">اسلایدر</td> | ||||
| <td v-if="banner.type === 'banner'">بنر</td> | <td v-if="banner.type === 'banner'">بنر</td> | ||||
| <td>{{ convertToJalali(banner.created_at) }}</td> | <td>{{ convertToJalali(banner.created_at) }}</td> | ||||
| <td>{{ banner?.panel === 'wholesale' ? 'عمده': 'وب و اپلیکیشن' }}</td> | |||||
| <td>{{ setPageType(banner) }}</td> | |||||
| <td> | |||||
| <div v-html="setProductOrCategory(banner)"></div> | |||||
| </td> | |||||
| <td> | <td> | ||||
| <router-link | <router-link | ||||
| :to="`/editBanner/${banner?.id}`" | :to="`/editBanner/${banner?.id}`" | ||||
| @@ -69,13 +69,8 @@ | |||||
| class="form-control" | class="form-control" | ||||
| type="number" | type="number" | ||||
| placeholder="میزان سفارش" | placeholder="میزان سفارش" | ||||
| :class="{ 'is-invalid': errors.minOrder }" | |||||
| @input="clearError('minOrder')" | |||||
| /> | /> | ||||
| </div> | </div> | ||||
| <small v-if="errors.minOrder" class="text-danger"> | |||||
| {{ errors.minOrder }} | |||||
| </small> | |||||
| </BCol> | </BCol> | ||||
| <BCol md="6"> | <BCol md="6"> | ||||
| @@ -86,13 +81,8 @@ | |||||
| type="number" | type="number" | ||||
| class="form-control" | class="form-control" | ||||
| placeholder="حداکثر میزان استفاده" | placeholder="حداکثر میزان استفاده" | ||||
| :class="{ 'is-invalid': errors.maxUsage }" | |||||
| @input="clearError('maxUsage')" | |||||
| /> | /> | ||||
| </div> | </div> | ||||
| <small v-if="errors.maxUsage" class="text-danger"> | |||||
| {{ errors.maxUsage }} | |||||
| </small> | |||||
| </BCol> | </BCol> | ||||
| <BCol md="6"> | <BCol md="6"> | ||||
| @@ -101,8 +91,6 @@ | |||||
| <select | <select | ||||
| v-model="whichPart" | v-model="whichPart" | ||||
| class="form-control" | class="form-control" | ||||
| :class="{ 'is-invalid': errors.whichPart }" | |||||
| @change="clearError('whichPart')" | |||||
| placeholder="انتخاب محل اعمال تخفبف" | placeholder="انتخاب محل اعمال تخفبف" | ||||
| > | > | ||||
| <option value="cat">دسته</option> | <option value="cat">دسته</option> | ||||
| @@ -110,9 +98,6 @@ | |||||
| <option value="all">همه</option> | <option value="all">همه</option> | ||||
| </select> | </select> | ||||
| </div> | </div> | ||||
| <small v-if="errors.whichPart" class="text-danger"> | |||||
| {{ errors.whichPart }} | |||||
| </small> | |||||
| </BCol> | </BCol> | ||||
| <BCol v-if="whichPart === 'cat'" md="6"> | <BCol v-if="whichPart === 'cat'" md="6"> | ||||
| @@ -161,31 +146,25 @@ | |||||
| <BCol md="6"> | <BCol md="6"> | ||||
| <div class="form-group"> | <div class="form-group"> | ||||
| <label class="form-label"> تاریخ اعمال تخفیف </label> | <label class="form-label"> تاریخ اعمال تخفیف </label> | ||||
| <DatePicker | <DatePicker | ||||
| :format="'jYYYY/jMM/jDD HH:mm:ss'" | :format="'jYYYY/jMM/jDD HH:mm:ss'" | ||||
| type="datetime" | type="datetime" | ||||
| v-model="startDate" | v-model="startDate" | ||||
| clearable | |||||
| ></DatePicker> | ></DatePicker> | ||||
| </div> | </div> | ||||
| <small v-if="errors.startDate" class="text-danger"> | |||||
| {{ errors.startDate }} | |||||
| </small> | |||||
| </BCol> | </BCol> | ||||
| <BCol md="6"> | <BCol md="6"> | ||||
| <div class="form-group"> | <div class="form-group"> | ||||
| <label class="form-label"> تاریخ انقضای تخفیف </label> | <label class="form-label"> تاریخ انقضای تخفیف </label> | ||||
| <DatePicker | <DatePicker | ||||
| :format="'jYYYY/jMM/jDD HH:mm:ss'" | :format="'jYYYY/jMM/jDD HH:mm:ss'" | ||||
| type="datetime" | type="datetime" | ||||
| v-model="expire" | v-model="expire" | ||||
| clearable | |||||
| ></DatePicker> | ></DatePicker> | ||||
| </div> | </div> | ||||
| <small v-if="errors.expire" class="text-danger"> | |||||
| {{ errors.expire }} | |||||
| </small> | |||||
| </BCol> | </BCol> | ||||
| </BRow> | </BRow> | ||||
| </BCardBody> | </BCardBody> | ||||
| @@ -235,12 +214,12 @@ export default { | |||||
| const title = ref(); | const title = ref(); | ||||
| const discountType = ref(); | const discountType = ref(); | ||||
| const amount = ref(); | const amount = ref(); | ||||
| const minOrder = ref(); | |||||
| const minOrder = ref(null); | |||||
| const selectedCat = ref(); | const selectedCat = ref(); | ||||
| const selectedProduct = ref(); | const selectedProduct = ref(); | ||||
| const startDate = ref(); | const startDate = ref(); | ||||
| const expire = ref(); | const expire = ref(); | ||||
| const maxUsage = ref(); | |||||
| const maxUsage = ref(null); | |||||
| const whichPart = ref(); | const whichPart = ref(); | ||||
| const loading = ref(false); | const loading = ref(false); | ||||
| const categories = ref([]); | const categories = ref([]); | ||||
| @@ -304,14 +283,14 @@ export default { | |||||
| if (!amount.value) | if (!amount.value) | ||||
| errors.value.amount = "وارد کردن مقدار تخفیف الزامی می باشد"; | errors.value.amount = "وارد کردن مقدار تخفیف الزامی می باشد"; | ||||
| if (!selectedCat.value && whichPart.value === "cat") | |||||
| errors.value.selectedCat = "انتخاب دسته برای تخفیف الزامی می باشد"; | |||||
| if (!selectedProduct.value && whichPart.value === "product") | |||||
| errors.value.selectedProduct = "انتخاب محصول برای تخفیف الزامی می باشد"; | |||||
| if (!whichPart.value) | |||||
| errors.value.whichPart = "مشخص کنید تخفیف بر چه بخشی اعمال شود"; | |||||
| // if (!selectedCat.value && whichPart.value === "cat") | |||||
| // errors.value.selectedCat = "انتخاب دسته برای تخفیف الزامی می باشد"; | |||||
| // if (!selectedProduct.value && whichPart.value === "product") | |||||
| // errors.value.selectedProduct = "انتخاب محصول برای تخفیف الزامی می باشد"; | |||||
| // | |||||
| // | |||||
| // if (!whichPart.value) | |||||
| // errors.value.whichPart = "مشخص کنید تخفیف بر چه بخشی اعمال شود"; | |||||
| return Object.keys(errors.value).length === 0; | return Object.keys(errors.value).length === 0; | ||||
| }; | }; | ||||
| @@ -333,7 +312,8 @@ export default { | |||||
| formData.append("title", title.value); | formData.append("title", title.value); | ||||
| formData.append("type", discountType.value); | formData.append("type", discountType.value); | ||||
| formData.append("amount", amount.value); | formData.append("amount", amount.value); | ||||
| formData.append("min_order", minOrder.value); | |||||
| if(minOrder.value) | |||||
| formData.append("min_order", minOrder.value); | |||||
| if (whichPart.value === "cat") { | if (whichPart.value === "cat") { | ||||
| formData.append("category_id", selectedCat.value); | formData.append("category_id", selectedCat.value); | ||||
| @@ -359,16 +339,16 @@ export default { | |||||
| formData.append("expires_at", georgianDate); | formData.append("expires_at", georgianDate); | ||||
| } | } | ||||
| formData.append("max_usage", maxUsage.value); | |||||
| if (maxUsage.value) | |||||
| formData.append("max_usage", maxUsage.value); | |||||
| ApiServiece.post(`/admin/discounts`, formData) | ApiServiece.post(`/admin/discounts`, formData) | ||||
| .then((resp) => { | |||||
| .then(() => { | |||||
| loading.value = false; | loading.value = false; | ||||
| toast.success("!تخفیف با موفقیت اضافه شد", { | toast.success("!تخفیف با موفقیت اضافه شد", { | ||||
| position: "top-right", | position: "top-right", | ||||
| autoClose: 1000, | autoClose: 1000, | ||||
| }); | }); | ||||
| console.log(resp); | |||||
| // Clear form fields after successful submission | // Clear form fields after successful submission | ||||
| title.value = ""; | title.value = ""; | ||||
| @@ -36,9 +36,11 @@ export default { | |||||
| const discounts = ref(); | const discounts = ref(); | ||||
| const convertToJalali = (date) => { | const convertToJalali = (date) => { | ||||
| if (!date) return | |||||
| return moment(date, "YYYY-MM-DD HH:mm:ss") | return moment(date, "YYYY-MM-DD HH:mm:ss") | ||||
| .locale("fa") | |||||
| .format("YYYY/MM/DD"); | |||||
| .locale("fa") | |||||
| .format("YYYY/MM/DD"); | |||||
| }; | }; | ||||
| const handleSearchChange = () => { | const handleSearchChange = () => { | ||||
| @@ -67,7 +69,6 @@ export default { | |||||
| .then((resp) => { | .then((resp) => { | ||||
| filterLoading.value = false; | filterLoading.value = false; | ||||
| discounts.value = resp.data.data.data; | discounts.value = resp.data.data.data; | ||||
| console.log(resp.data.data); | |||||
| currentPage.value = resp.data.data.current_page; | currentPage.value = resp.data.data.current_page; | ||||
| totalPages.value = resp.data.data.last_page; | totalPages.value = resp.data.data.last_page; | ||||
| }) | }) | ||||
| @@ -70,13 +70,8 @@ | |||||
| class="form-control" | class="form-control" | ||||
| type="number" | type="number" | ||||
| placeholder="میزان سفارش" | placeholder="میزان سفارش" | ||||
| :class="{ 'is-invalid': errors.minOrder }" | |||||
| @input="clearError('minOrder')" | |||||
| /> | /> | ||||
| </div> | </div> | ||||
| <small v-if="errors.minOrder" class="text-danger"> | |||||
| {{ errors.minOrder }} | |||||
| </small> | |||||
| </BCol> | </BCol> | ||||
| <BCol md="6"> | <BCol md="6"> | ||||
| @@ -87,13 +82,8 @@ | |||||
| type="number" | type="number" | ||||
| class="form-control" | class="form-control" | ||||
| placeholder="حداکثر میزان استفاده" | placeholder="حداکثر میزان استفاده" | ||||
| :class="{ 'is-invalid': errors.maxUsage }" | |||||
| @input="clearError('maxUsage')" | |||||
| /> | /> | ||||
| </div> | </div> | ||||
| <small v-if="errors.maxUsage" class="text-danger"> | |||||
| {{ errors.maxUsage }} | |||||
| </small> | |||||
| </BCol> | </BCol> | ||||
| <BCol md="6"> | <BCol md="6"> | ||||
| @@ -102,8 +92,6 @@ | |||||
| <select | <select | ||||
| v-model="whichPart" | v-model="whichPart" | ||||
| class="form-control" | class="form-control" | ||||
| :class="{ 'is-invalid': errors.whichPart }" | |||||
| @change="clearError('whichPart')" | |||||
| placeholder="انتخاب محل اعمل تخفیف" | placeholder="انتخاب محل اعمل تخفیف" | ||||
| > | > | ||||
| <option value="cat">دسته</option> | <option value="cat">دسته</option> | ||||
| @@ -111,9 +99,6 @@ | |||||
| <option value="all">همه</option> | <option value="all">همه</option> | ||||
| </select> | </select> | ||||
| </div> | </div> | ||||
| <small v-if="errors.discountType" class="text-danger"> | |||||
| {{ errors.discountType }} | |||||
| </small> | |||||
| </BCol> | </BCol> | ||||
| <BCol v-if="whichPart === 'cat'" md="6"> | <BCol v-if="whichPart === 'cat'" md="6"> | ||||
| @@ -125,14 +110,10 @@ | |||||
| :options="formattedCategories" | :options="formattedCategories" | ||||
| label="label" | label="label" | ||||
| :reduce="(option) => option.value" | :reduce="(option) => option.value" | ||||
| @change="clearError('selectedCat')" | |||||
| placeholder="دسته ای را انتخاب کنید" | placeholder="دسته ای را انتخاب کنید" | ||||
| @search="handleSearch" | @search="handleSearch" | ||||
| /> | /> | ||||
| </div> | </div> | ||||
| <small v-if="errors.selectedCat" class="text-danger"> | |||||
| {{ errors.selectedCat }} | |||||
| </small> | |||||
| </BCol> | </BCol> | ||||
| <BCol v-if="whichPart === 'product'" md="6"> | <BCol v-if="whichPart === 'product'" md="6"> | ||||
| @@ -144,13 +125,9 @@ | |||||
| v-model="selectedProduct" | v-model="selectedProduct" | ||||
| :options="formattedProducts" | :options="formattedProducts" | ||||
| @search="handleProductSearch" | @search="handleProductSearch" | ||||
| @change="clearError('selectedProduct')" | |||||
| placeholder="محصولی را انتخاب کنید " | placeholder="محصولی را انتخاب کنید " | ||||
| /> | /> | ||||
| </div> | </div> | ||||
| <small v-if="errors.selectedProduct" class="text-danger"> | |||||
| {{ errors.selectedProduct }} | |||||
| </small> | |||||
| </BCol> | </BCol> | ||||
| <BCol md="6"> | <BCol md="6"> | ||||
| @@ -160,13 +137,11 @@ | |||||
| <DatePicker | <DatePicker | ||||
| :format="'jYYYY/jMM/jDD HH:mm:ss'" | :format="'jYYYY/jMM/jDD HH:mm:ss'" | ||||
| type="datetime" | type="datetime" | ||||
| clearable | |||||
| v-model="startDate" | v-model="startDate" | ||||
| @input="handleStartDateInput" | @input="handleStartDateInput" | ||||
| ></DatePicker> | ></DatePicker> | ||||
| </div> | </div> | ||||
| <small v-if="errors.startDate" class="text-danger"> | |||||
| {{ errors.startDate }} | |||||
| </small> | |||||
| </BCol> | </BCol> | ||||
| <BCol md="6"> | <BCol md="6"> | ||||
| @@ -176,13 +151,11 @@ | |||||
| <DatePicker | <DatePicker | ||||
| :format="'jYYYY/jMM/jDD HH:mm:ss'" | :format="'jYYYY/jMM/jDD HH:mm:ss'" | ||||
| type="datetime" | type="datetime" | ||||
| clearable | |||||
| v-model="expire" | v-model="expire" | ||||
| @input="handleExpireDateInput" | @input="handleExpireDateInput" | ||||
| ></DatePicker> | ></DatePicker> | ||||
| </div> | </div> | ||||
| <small v-if="errors.expire" class="text-danger"> | |||||
| {{ errors.expire }} | |||||
| </small> | |||||
| </BCol> | </BCol> | ||||
| </BRow> | </BRow> | ||||
| </BCardBody> | </BCardBody> | ||||
| @@ -373,15 +346,15 @@ export default { | |||||
| if (!amount.value) | if (!amount.value) | ||||
| errors.value.amount = "وارد کردن مقدار تخفیف الزامی می باشد"; | errors.value.amount = "وارد کردن مقدار تخفیف الزامی می باشد"; | ||||
| if (!selectedCat.value && whichPart.value === "cat") | |||||
| errors.value.selectedCat = "انتخاب دسته برای تخفیف الزامی می باشد"; | |||||
| if (!selectedProduct.value && whichPart.value === "product") | |||||
| errors.value.selectedProduct = "انتخاب محصول برای تخفیف الزامی می باشد"; | |||||
| if (!startDate.value) | |||||
| errors.value.startDate = "انتخاب تاریخ اعمال تخفیف الزامی می باشد "; | |||||
| if (!whichPart.value) | |||||
| errors.value.whichPart = "مشخص کنید تخفیف بر چه بخشی اعمال شود"; | |||||
| // if (!selectedCat.value && whichPart.value === "cat") | |||||
| // errors.value.selectedCat = "انتخاب دسته برای تخفیف الزامی می باشد"; | |||||
| // if (!selectedProduct.value && whichPart.value === "product") | |||||
| // errors.value.selectedProduct = "انتخاب محصول برای تخفیف الزامی می باشد"; | |||||
| // if (!startDate.value) | |||||
| // errors.value.startDate = "انتخاب تاریخ اعمال تخفیف الزامی می باشد "; | |||||
| // | |||||
| // if (!whichPart.value) | |||||
| // errors.value.whichPart = "مشخص کنید تخفیف بر چه بخشی اعمال شود"; | |||||
| return Object.keys(errors.value).length === 0; | return Object.keys(errors.value).length === 0; | ||||
| }; | }; | ||||
| @@ -406,7 +379,9 @@ export default { | |||||
| formData.append("title", title.value); | formData.append("title", title.value); | ||||
| formData.append("type", discountType.value); | formData.append("type", discountType.value); | ||||
| formData.append("amount", amount.value); | formData.append("amount", amount.value); | ||||
| formData.append("min_order", minOrder.value); | |||||
| if (minOrder.value) { | |||||
| formData.append("min_order", minOrder.value); | |||||
| } | |||||
| if (whichPart.value === "cat") { | if (whichPart.value === "cat") { | ||||
| formData.append("category_id", selectedCat.value); | formData.append("category_id", selectedCat.value); | ||||
| } | } | ||||
| @@ -431,7 +406,8 @@ export default { | |||||
| formData.append("expires_at", georgianDate); | formData.append("expires_at", georgianDate); | ||||
| } | } | ||||
| formData.append("max_usage", maxUsage.value); | |||||
| if (maxUsage.value) | |||||
| formData.append("max_usage", maxUsage.value); | |||||
| ApiServiece.post(`/admin/discounts`, formData) | ApiServiece.post(`/admin/discounts`, formData) | ||||
| .then((resp) => { | .then((resp) => { | ||||
| @@ -357,15 +357,13 @@ export default { | |||||
| <thead class="table-light"> | <thead class="table-light"> | ||||
| <tr> | <tr> | ||||
| <th class="text-start">جزییات محصول</th> | <th class="text-start">جزییات محصول</th> | ||||
| <th>توضیحات</th> | |||||
| <th>رنگ محصول</th> | |||||
| <th>وضعیت</th> | <th>وضعیت</th> | ||||
| <th>تاریخ ایجاد</th> | <th>تاریخ ایجاد</th> | ||||
| <th>قیمت عمده</th> | <th>قیمت عمده</th> | ||||
| <th>قیمت تک</th> | <th>قیمت تک</th> | ||||
| <th>تعداد سفارش</th> | <th>تعداد سفارش</th> | ||||
| <th>تعداد ارسال شده</th> | <th>تعداد ارسال شده</th> | ||||
| <th>عنوان برند</th> | |||||
| <th>تصویر برند</th> | |||||
| <th>عملیات</th> | <th>عملیات</th> | ||||
| </tr> | </tr> | ||||
| </thead> | </thead> | ||||
| @@ -394,21 +392,9 @@ export default { | |||||
| </div> | </div> | ||||
| </td> | </td> | ||||
| <!-- Description --> | |||||
| <!-- Product color --> | |||||
| <td> | <td> | ||||
| <div | |||||
| type="button" | |||||
| data-bs-target="#showDescription" | |||||
| data-bs-toggle="modal" | |||||
| @click="descriptionModal(order?.description)" | |||||
| class="subject-box" | |||||
| > | |||||
| <i class="fas fa-comments subject-icon"></i> | |||||
| <span class="subject-text"> | |||||
| {{ order?.description?.slice(0, 20) | |||||
| }}{{ order?.description?.length > 20 ? "..." : "" }} | |||||
| </span> | |||||
| </div> | |||||
| {{ order?.attribute_value_product?.attribute_value?.title }} | |||||
| </td> | </td> | ||||
| <!-- Status --> | <!-- Status --> | ||||
| @@ -452,19 +438,6 @@ export default { | |||||
| <!-- Sent Count --> | <!-- Sent Count --> | ||||
| <td>{{ order.send_count }}</td> | <td>{{ order.send_count }}</td> | ||||
| <!-- Brand Title --> | |||||
| <td>{{ order.product?.brand?.title }}</td> | |||||
| <!-- Brand Image --> | |||||
| <td> | |||||
| <img | |||||
| :src="order.product?.brand?.image" | |||||
| alt="brand" | |||||
| class="rounded" | |||||
| style="width: 40px; height: 40px; object-fit: cover" | |||||
| /> | |||||
| </td> | |||||
| <!-- Operations --> | <!-- Operations --> | ||||
| <td> | <td> | ||||
| <router-link | <router-link | ||||
| @@ -490,33 +463,9 @@ export default { | |||||
| <li> | <li> | ||||
| <a | <a | ||||
| class="dropdown-item d-flex justify-content-center align-items-center" | class="dropdown-item d-flex justify-content-center align-items-center" | ||||
| @click="changeStatus(order?.id, 'waiting')" | |||||
| > | |||||
| <span class="badge badge-waiting">در انتظار</span> | |||||
| </a> | |||||
| </li> | |||||
| <li> | |||||
| <a | |||||
| class="dropdown-item d-flex justify-content-center align-items-center" | |||||
| @click="changeStatus(order?.id, 'paid')" | |||||
| > | |||||
| <span class="badge badge-paid">پرداختشده</span> | |||||
| </a> | |||||
| </li> | |||||
| <li> | |||||
| <a | |||||
| class="dropdown-item d-flex justify-content-center align-items-center" | |||||
| @click="changeStatus(order?.id, 'un_paid')" | |||||
| > | |||||
| <span class="badge badge-un_paid">پرداختنشده</span> | |||||
| </a> | |||||
| </li> | |||||
| <li> | |||||
| <a | |||||
| class="dropdown-item d-flex justify-content-center align-items-center" | |||||
| @click="changeStatus(order?.id, 'approved')" | |||||
| @click="changeStatus(order?.id, 'done')" | |||||
| > | > | ||||
| <span class="badge badge-approved">تأییدشده</span> | |||||
| <span class="badge badge-in-done">کامل شده</span> | |||||
| </a> | </a> | ||||
| </li> | </li> | ||||
| <li> | <li> | ||||
| @@ -529,32 +478,6 @@ export default { | |||||
| > | > | ||||
| </a> | </a> | ||||
| </li> | </li> | ||||
| <li> | |||||
| <a | |||||
| class="dropdown-item d-flex justify-content-center align-items-center" | |||||
| @click="changeStatus(order?.id, 'shipping')" | |||||
| > | |||||
| <span class="badge badge-shipping" | |||||
| >در حال ارسال</span | |||||
| > | |||||
| </a> | |||||
| </li> | |||||
| <li> | |||||
| <a | |||||
| class="dropdown-item d-flex justify-content-center align-items-center" | |||||
| @click="changeStatus(order?.id, 'delivered')" | |||||
| > | |||||
| <span class="badge badge-delivered">تحویلشده</span> | |||||
| </a> | |||||
| </li> | |||||
| <li> | |||||
| <a | |||||
| class="dropdown-item d-flex justify-content-center align-items-center" | |||||
| @click="changeStatus(order?.id, 'canceled')" | |||||
| > | |||||
| <span class="badge badge-canceled">لغوشده</span> | |||||
| </a> | |||||
| </li> | |||||
| </ul> | </ul> | ||||
| </td> | </td> | ||||
| </tr> | </tr> | ||||
| @@ -24,9 +24,11 @@ export default { | |||||
| const orders = ref(); | const orders = ref(); | ||||
| const convertToJalali = (date) => { | const convertToJalali = (date) => { | ||||
| if (!date) return | |||||
| return moment(date, "YYYY-MM-DD HH:mm:ss") | return moment(date, "YYYY-MM-DD HH:mm:ss") | ||||
| .locale("fa") | .locale("fa") | ||||
| .format("YYYY/MM/DD"); | |||||
| .format("HH:mm:ss YYYY/MM/DD "); | |||||
| }; | }; | ||||
| const loadingId = ref(null); | const loadingId = ref(null); | ||||
| @@ -34,8 +36,12 @@ export default { | |||||
| const getExport = (id) => { | const getExport = (id) => { | ||||
| loadingId.value = id; | loadingId.value = id; | ||||
| ApiServiece.post(`admin/orders/${id}/export`, { responseType: "blob" }) | |||||
| .then((resp) => { | |||||
| //ApiServiece.post(`admin/orders/${id}/export`, {}, { responseType: "blob" }) | |||||
| ApiServiece({ | |||||
| method: 'POST', | |||||
| url: `admin/orders/${id}/export`, | |||||
| config: { responseType: "blob" } | |||||
| }).then((resp) => { | |||||
| const excelBlob = resp.data; | const excelBlob = resp.data; | ||||
| const url = window.URL.createObjectURL(excelBlob); | const url = window.URL.createObjectURL(excelBlob); | ||||
| @@ -70,7 +76,6 @@ export default { | |||||
| .then((resp) => { | .then((resp) => { | ||||
| filterLoading.value = false; | filterLoading.value = false; | ||||
| orders.value = resp.data.data.data; | orders.value = resp.data.data.data; | ||||
| console.log(orders.value); | |||||
| currentPage.value = resp.data.data.current_page; | currentPage.value = resp.data.data.current_page; | ||||
| totalPages.value = resp.data.data.last_page; | totalPages.value = resp.data.data.last_page; | ||||
| }) | }) | ||||
| @@ -104,7 +104,9 @@ export default { | |||||
| }; | }; | ||||
| const formatPrice = (price) => { | const formatPrice = (price) => { | ||||
| return numeral(price).format("0,0"); | |||||
| if (!price) return 0 | |||||
| return numeral(price).format("0,0") | |||||
| }; | }; | ||||
| onMounted(() => { | onMounted(() => { | ||||
| @@ -142,6 +144,11 @@ export default { | |||||
| <strong class="me-2">نام مشتری:</strong> | <strong class="me-2">نام مشتری:</strong> | ||||
| <span>{{ order?.user?.name || "بدون نام" }}</span> | <span>{{ order?.user?.name || "بدون نام" }}</span> | ||||
| </BCol> | </BCol> | ||||
| <BCol md="6"> | |||||
| <strong class="me-2">موبایل:</strong> | |||||
| <span>{{ order?.user?.mobile }}</span> | |||||
| </BCol> | |||||
| </BRow> | </BRow> | ||||
| <BRow class="mb-3"> | <BRow class="mb-3"> | ||||
| @@ -161,27 +168,37 @@ export default { | |||||
| <span> | <span> | ||||
| {{ | {{ | ||||
| order?.shipping_price != null | order?.shipping_price != null | ||||
| ? formatPrice(order.shipping_price) + " تومان" | |||||
| ? formatPrice(order?.shipping_price) + ' تومان' | |||||
| : "بدون قیمت" | : "بدون قیمت" | ||||
| }} | }} | ||||
| </span> | </span> | ||||
| </BCol> | </BCol> | ||||
| <BCol md="6"> | <BCol md="6"> | ||||
| <strong class="me-2">تخفیف:</strong> | <strong class="me-2">تخفیف:</strong> | ||||
| <span>{{ | |||||
| order?.discount | |||||
| ? formatPrice(order.discount) + " تومان" | |||||
| : "بدون تخفیف" | |||||
| }}</span> | |||||
| <span>{{ formatPrice(order?.discount?.amount) + (order?.discount?.type === 'percentage' ? ' درصد' : 'تومان') }}</span> | |||||
| </BCol> | </BCol> | ||||
| </BRow> | </BRow> | ||||
| <BRow> | |||||
| <BRow class="mb-3"> | |||||
| <BCol md="6"> | |||||
| <strong class="me-2">کد تخفیف:</strong> | |||||
| <span>{{ order?.discount?.title ?? '-' }}</span> | |||||
| </BCol> | |||||
| <BCol md="6"> | <BCol md="6"> | ||||
| <strong class="me-2">رنگ سفارش:</strong> | <strong class="me-2">رنگ سفارش:</strong> | ||||
| <span>{{ order.color || "---" }}</span> | |||||
| <span>{{ order?.status || "-" }}</span> | |||||
| </BCol> | </BCol> | ||||
| </BRow> | </BRow> | ||||
| <BRow class="mb-3"> | |||||
| <BCol md="6"> | |||||
| <strong class="me-2">قیمت کل:</strong> | |||||
| <span>{{ order?.total_price ? order?.total_price + 'تومان' : '0' }}</span> | |||||
| </BCol> | |||||
| </BRow> | |||||
| </div> | </div> | ||||
| <!-- Order Details and Items Here --> | <!-- Order Details and Items Here --> | ||||
| @@ -195,6 +212,7 @@ export default { | |||||
| :items="order.order_items" | :items="order.order_items" | ||||
| :fields="[ | :fields="[ | ||||
| { key: 'title', label: 'عنوان محصول' }, | { key: 'title', label: 'عنوان محصول' }, | ||||
| { key: 'color', label: 'رنگ محصول' }, | |||||
| { key: 'count', label: 'تعداد در خواستی ' }, | { key: 'count', label: 'تعداد در خواستی ' }, | ||||
| { key: 'price', label: 'قیمت' }, | { key: 'price', label: 'قیمت' }, | ||||
| { key: 'created_at', label: 'تاریخ ثبت' }, | { key: 'created_at', label: 'تاریخ ثبت' }, | ||||
| @@ -222,6 +240,10 @@ export default { | |||||
| {{ data.item.count }} | {{ data.item.count }} | ||||
| </template> | </template> | ||||
| <template #cell(color)="data"> | |||||
| {{ data?.item?.attribute_value_product?.attribute_value?.title }} | |||||
| </template> | |||||
| <!-- Editable shipped quantity with API call --> | <!-- Editable shipped quantity with API call --> | ||||
| <template #cell(edit_count)="data"> | <template #cell(edit_count)="data"> | ||||
| <input | <input | ||||
| @@ -61,14 +61,16 @@ | |||||
| <BCol md="6"> | <BCol md="6"> | ||||
| <div class="form-group"> | <div class="form-group"> | ||||
| <label class="form-label">توضیحات محصول</label> | <label class="form-label">توضیحات محصول</label> | ||||
| <div | |||||
| @input="clearError('editorContent')" | |||||
| ref="editor" | |||||
| class="quill-editor" | |||||
| ></div> | |||||
| <textarea | |||||
| v-model="description" | |||||
| class="form-control" | |||||
| placeholder="توضیحات محصول" | |||||
| :class="{ 'is-invalid': errors.description }" | |||||
| @input="clearError('description')" | |||||
| /> | |||||
| </div> | </div> | ||||
| <small v-if="errors.editorContent" class="text-danger"> | |||||
| {{ errors.editorContent }} | |||||
| <small v-if="errors.description" class="text-danger"> | |||||
| {{ errors.description }} | |||||
| </small> | </small> | ||||
| </BCol> | </BCol> | ||||
| @@ -77,6 +79,7 @@ | |||||
| <label class="form-label">تصویر محصول</label> | <label class="form-label">تصویر محصول</label> | ||||
| <input | <input | ||||
| ref="productImageRef" | |||||
| type="file" | type="file" | ||||
| accept="image/*" | accept="image/*" | ||||
| @change="handleImageUpload" | @change="handleImageUpload" | ||||
| @@ -395,8 +398,18 @@ | |||||
| </BCard> | </BCard> | ||||
| <BCard> | <BCard> | ||||
| <div class="card-header"> | |||||
| <div class="card-header d-flex justify-content-between"> | |||||
| <h5 class="mb-0">اضافه کردن مشخصه ها</h5> | <h5 class="mb-0">اضافه کردن مشخصه ها</h5> | ||||
| <BButton | |||||
| v-if="relatedAttrebutes?.length" | |||||
| variant="success" | |||||
| size="lg" | |||||
| class="mt-1 px-4 py-2 shadow-lg rounded-pill" | |||||
| @click="handleAddIdentityClick" | |||||
| > | |||||
| <i class="fas fa-plus me-2"></i> کلیک کنید | |||||
| </BButton> | |||||
| </div> | </div> | ||||
| <BRow class="g-3 mt-2"> | <BRow class="g-3 mt-2"> | ||||
| @@ -409,8 +422,7 @@ | |||||
| variant="success" | variant="success" | ||||
| size="lg" | size="lg" | ||||
| class="mt-1 px-4 py-2 shadow-lg rounded-pill" | class="mt-1 px-4 py-2 shadow-lg rounded-pill" | ||||
| data-bs-toggle="modal" | |||||
| data-bs-target="#addIdentity" | |||||
| @click="handleAddIdentityClick" | |||||
| > | > | ||||
| <i class="fas fa-plus me-2"></i> کلیک کنید | <i class="fas fa-plus me-2"></i> کلیک کنید | ||||
| </BButton> | </BButton> | ||||
| @@ -554,7 +566,7 @@ | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </BCardFooter> | </BCardFooter> | ||||
| <addIdentity @identity-updated="handleIdentityUpdate" /> | |||||
| <addIdentity @identity-updated="handleIdentityUpdate" :categoryId="selectedCat" /> | |||||
| <addAttribute | <addAttribute | ||||
| :attributeValues="attributeValues" | :attributeValues="attributeValues" | ||||
| @attribute-updated="handleAttributeUpdated()" | @attribute-updated="handleAttributeUpdated()" | ||||
| @@ -572,12 +584,12 @@ import moment from "jalali-moment"; | |||||
| import { toast } from "vue3-toastify"; | import { toast } from "vue3-toastify"; | ||||
| import "vue3-toastify/dist/index.css"; | import "vue3-toastify/dist/index.css"; | ||||
| import ApiServiece from "@/services/ApiService"; | import ApiServiece from "@/services/ApiService"; | ||||
| import { ref, onMounted, watch, computed, nextTick } from "vue"; | |||||
| import { ref, onMounted, watch, computed } from "vue"; | |||||
| import Layout from "@/layout/custom.vue"; | import Layout from "@/layout/custom.vue"; | ||||
| import DatePicker from "vue3-persian-datetime-picker"; | import DatePicker from "vue3-persian-datetime-picker"; | ||||
| import addIdentity from "@/components/modals/identity/addIdentity.vue"; | import addIdentity from "@/components/modals/identity/addIdentity.vue"; | ||||
| import Quill from "quill"; | |||||
| import "quill/dist/quill.snow.css"; | |||||
| import { Modal } from "bootstrap" | |||||
| export default { | export default { | ||||
| name: "SAMPLE-PAGE", | name: "SAMPLE-PAGE", | ||||
| @@ -625,6 +637,10 @@ export default { | |||||
| const editor = ref(null); | const editor = ref(null); | ||||
| const editorContent = ref(""); | const editorContent = ref(""); | ||||
| // ALIREZA | |||||
| const productImageRef = ref(null) | |||||
| const description = ref(null) | |||||
| const getAttributeValues = () => { | const getAttributeValues = () => { | ||||
| ApiServiece.get(`admin/attributes`).then((resp) => { | ApiServiece.get(`admin/attributes`).then((resp) => { | ||||
| console.log(resp); | console.log(resp); | ||||
| @@ -636,21 +652,22 @@ export default { | |||||
| getAttrebuteValues(); | getAttrebuteValues(); | ||||
| }; | }; | ||||
| watch(selectedCat, () => { | |||||
| ApiServiece.get(`admin/attributes?category_id=${selectedCat.value}`) | |||||
| .then((resp) => { | |||||
| relatedAttrebutes.value.push(...resp.data.data); | |||||
| }) | |||||
| .catch((err) => { | |||||
| console.log(err); | |||||
| }); | |||||
| watch(selectedCat, (value) => { | |||||
| if (value){ | |||||
| ApiServiece.get(`admin/attributes?category_id=${selectedCat.value}`) | |||||
| .then((resp) => { | |||||
| relatedAttrebutes.value = resp?.data?.data | |||||
| }) | |||||
| .catch((err) => { | |||||
| console.log(err); | |||||
| }); | |||||
| } | |||||
| }); | }); | ||||
| const handleIdentityUpdate = () => { | const handleIdentityUpdate = () => { | ||||
| ApiServiece.get(`admin/attributes?category_id=${selectedCat.value}`) | ApiServiece.get(`admin/attributes?category_id=${selectedCat.value}`) | ||||
| .then((resp) => { | .then((resp) => { | ||||
| relatedAttrebutes.value = resp.data.data; | relatedAttrebutes.value = resp.data.data; | ||||
| console.log("sadsadsaasdasddsad"); | |||||
| }) | }) | ||||
| .catch((err) => { | .catch((err) => { | ||||
| console.log(err); | console.log(err); | ||||
| @@ -779,8 +796,8 @@ export default { | |||||
| if (!image.value) | if (!image.value) | ||||
| errors.value.image = "وارد کردن عکس محصول ضروری می باشد"; | errors.value.image = "وارد کردن عکس محصول ضروری می باشد"; | ||||
| if (!editorContent.value) | |||||
| errors.value.editorContent = "وارد کردن توضیحات محصول ضروری می باشد"; | |||||
| if (!description.value) | |||||
| errors.value.description = "وارد کردن توضیحات محصول ضروری می باشد"; | |||||
| if (!productType.value) | if (!productType.value) | ||||
| errors.value.productType = "انتخاب حالت محصول ضروری می باشد"; | errors.value.productType = "انتخاب حالت محصول ضروری می باشد"; | ||||
| @@ -844,37 +861,51 @@ export default { | |||||
| errors.value[field] = ""; | errors.value[field] = ""; | ||||
| }; | }; | ||||
| onMounted(() => { | |||||
| const quill = new Quill(editor.value, { | |||||
| theme: "snow", | |||||
| modules: { | |||||
| toolbar: [ | |||||
| [{ header: "1" }, { header: "2" }, { font: [] }], | |||||
| [{ list: "ordered" }, { list: "bullet" }], | |||||
| [{ align: [] }], | |||||
| ["bold", "italic", "underline"], | |||||
| ["link", "image"], | |||||
| [{ script: "sub" }, { script: "super" }], | |||||
| [{ direction: "rtl" }], | |||||
| ], | |||||
| }, | |||||
| }); | |||||
| const handleAddIdentityClick = () => { | |||||
| if (!selectedCat.value) { | |||||
| toast.error("لطفا ابتدا یک دستهبندی انتخاب کنید", { | |||||
| position: "top-right", | |||||
| autoClose: 3000 | |||||
| }); | |||||
| return; | |||||
| } | |||||
| quill.root.setAttribute("dir", "rtl"); | |||||
| quill.format("direction", "rtl"); | |||||
| const modal = new Modal(document.getElementById('addIdentity')); | |||||
| nextTick(() => { | |||||
| const rtlButton = quill.container.querySelector( | |||||
| ".ql-direction[data-value='rtl']" | |||||
| ); | |||||
| if (rtlButton) { | |||||
| rtlButton.click(); | |||||
| } | |||||
| }); | |||||
| modal?.show(); | |||||
| }; | |||||
| quill.on("text-change", () => { | |||||
| editorContent.value = quill.root.innerHTML; | |||||
| }); | |||||
| onMounted(() => { | |||||
| // const quill = new Quill(editor.value, { | |||||
| // theme: "snow", | |||||
| // modules: { | |||||
| // toolbar: [ | |||||
| // [{ header: "1" }, { header: "2" }, { font: [] }], | |||||
| // [{ list: "ordered" }, { list: "bullet" }], | |||||
| // [{ align: [] }], | |||||
| // ["bold", "italic", "underline"], | |||||
| // ["link", "image"], | |||||
| // [{ script: "sub" }, { script: "super" }], | |||||
| // [{ direction: "rtl" }], | |||||
| // ], | |||||
| // }, | |||||
| // }); | |||||
| // | |||||
| // quill.root.setAttribute("dir", "rtl"); | |||||
| // quill.format("direction", "rtl"); | |||||
| // | |||||
| // nextTick(() => { | |||||
| // const rtlButton = quill.container.querySelector( | |||||
| // ".ql-direction[data-value='rtl']" | |||||
| // ); | |||||
| // if (rtlButton) { | |||||
| // rtlButton.click(); | |||||
| // } | |||||
| // }); | |||||
| // | |||||
| // quill.on("text-change", () => { | |||||
| // editorContent.value = quill.root.innerHTML; | |||||
| // }); | |||||
| getAttrebuteValues(); | getAttrebuteValues(); | ||||
| getAttributeValues(); | getAttributeValues(); | ||||
| }); | }); | ||||
| @@ -894,7 +925,7 @@ export default { | |||||
| formData.append("title", title.value); | formData.append("title", title.value); | ||||
| formData.append("slug", slug.value); | formData.append("slug", slug.value); | ||||
| formData.append("summary", summary.value); | formData.append("summary", summary.value); | ||||
| formData.append("description", editorContent.value); | |||||
| formData.append("description", description.value); | |||||
| if (isChosen.value == 1) { | if (isChosen.value == 1) { | ||||
| formData.append("is_chosen", isChosen.value); | formData.append("is_chosen", isChosen.value); | ||||
| @@ -994,7 +1025,6 @@ export default { | |||||
| // 🔸 Upload images if any | // 🔸 Upload images if any | ||||
| const validImages = images.value.filter((image) => image.file); | const validImages = images.value.filter((image) => image.file); | ||||
| if (validImages.length > 0) { | if (validImages.length > 0) { | ||||
| console.log(validImages, "valid images"); | |||||
| validImages.forEach((image) => { | validImages.forEach((image) => { | ||||
| const formData = new FormData(); | const formData = new FormData(); | ||||
| formData.append("image", image.file); | formData.append("image", image.file); | ||||
| @@ -1030,6 +1060,10 @@ export default { | |||||
| countInCarton.value = ""; | countInCarton.value = ""; | ||||
| image.value = null; | image.value = null; | ||||
| images.value = []; | images.value = []; | ||||
| description.value = null; | |||||
| if (productImageRef.value) { | |||||
| productImageRef.value.value = null | |||||
| } | |||||
| attrebutes.value.forEach((attribute) => { | attrebutes.value.forEach((attribute) => { | ||||
| attribute.isChecked = false; | attribute.isChecked = false; | ||||
| attribute.value = ""; | attribute.value = ""; | ||||
| @@ -1097,6 +1131,9 @@ export default { | |||||
| handleSearch, | handleSearch, | ||||
| formattedCategories, | formattedCategories, | ||||
| categorySelectorLoader, | categorySelectorLoader, | ||||
| productImageRef, | |||||
| description, | |||||
| handleAddIdentityClick | |||||
| }; | }; | ||||
| }, | }, | ||||
| }; | }; | ||||
| @@ -61,20 +61,19 @@ | |||||
| </small> | </small> | ||||
| </BCol> | </BCol> | ||||
| <BCol md="6"> | <BCol md="6"> | ||||
| <div class="form-group"> | <div class="form-group"> | ||||
| <label class="form-label">توضیحات محصول</label> | <label class="form-label">توضیحات محصول</label> | ||||
| <div | |||||
| @input="clearError('editorContent')" | |||||
| ref="editor" | |||||
| class="quill-editor" | |||||
| ></div> | |||||
| <textarea | |||||
| v-model="description" | |||||
| class="form-control" | |||||
| placeholder="توضیحات محصول" | |||||
| :class="{ 'is-invalid': errors.description }" | |||||
| @input="clearError('description')" | |||||
| /> | |||||
| </div> | </div> | ||||
| <small v-if="errors.editorContent" class="text-danger"> | |||||
| {{ errors.editorContent }} | |||||
| <small v-if="errors.description" class="text-danger"> | |||||
| {{ errors.description }} | |||||
| </small> | </small> | ||||
| </BCol> | </BCol> | ||||
| @@ -866,7 +865,6 @@ export default { | |||||
| const spescialPrice = ref(); | const spescialPrice = ref(); | ||||
| const wholesalePrice = ref(); | const wholesalePrice = ref(); | ||||
| const retailePrice = ref(); | const retailePrice = ref(); | ||||
| const description = ref(); | |||||
| const productAttributes = ref([]); | const productAttributes = ref([]); | ||||
| const images = ref([{ file: null, preview: null }]); | const images = ref([{ file: null, preview: null }]); | ||||
| const localImages = ref([{ preview: null }]); | const localImages = ref([{ preview: null }]); | ||||
| @@ -895,6 +893,11 @@ export default { | |||||
| const editorContent = ref(""); | const editorContent = ref(""); | ||||
| const categorySelectorLoader = ref(false); | const categorySelectorLoader = ref(false); | ||||
| const brandSelectorLoader = ref(false); | const brandSelectorLoader = ref(false); | ||||
| // ALIREZA | |||||
| const productImageRef = ref(null) | |||||
| const description = ref(null) | |||||
| const formattedCategories = computed(() => | const formattedCategories = computed(() => | ||||
| Array.isArray(categories.value) | Array.isArray(categories.value) | ||||
| @@ -1179,8 +1182,8 @@ export default { | |||||
| if (!imagePreview.value) | if (!imagePreview.value) | ||||
| errors.value.image = "وارد کردن عکس محصول ضروری می باشد"; | errors.value.image = "وارد کردن عکس محصول ضروری می باشد"; | ||||
| if (!editorContent.value) | |||||
| errors.value.editorContent = "وارد کردن توضیحات محصول ضروری می باشد"; | |||||
| if (!description.value) | |||||
| errors.value.description = "وارد کردن توضیحات محصول ضروری می باشد"; | |||||
| if (!productType.value) | if (!productType.value) | ||||
| errors.value.productType = "انتخاب حالت محصول ضروری می باشد"; | errors.value.productType = "انتخاب حالت محصول ضروری می باشد"; | ||||
| @@ -1270,6 +1273,7 @@ export default { | |||||
| spescialPrice.value = product.value?.special_price; | spescialPrice.value = product.value?.special_price; | ||||
| selectedCat.value = resp?.data?.data?.category.id; | selectedCat.value = resp?.data?.data?.category.id; | ||||
| selectedBrand.value = resp?.data?.data?.brand.id; | selectedBrand.value = resp?.data?.data?.brand.id; | ||||
| description.value = product.value?.description; | |||||
| if (product.value?.special_expires_at) { | if (product.value?.special_expires_at) { | ||||
| expire.value = moment( | expire.value = moment( | ||||
| @@ -1278,30 +1282,30 @@ export default { | |||||
| ).format("jYYYY/jMM/jDD HH:mm:ss"); | ).format("jYYYY/jMM/jDD HH:mm:ss"); | ||||
| } | } | ||||
| if (editor.value) { | |||||
| quillInstance.value = new Quill(editor.value, { | |||||
| theme: "snow", | |||||
| modules: { | |||||
| toolbar: [ | |||||
| [{ header: "1" }, { header: "2" }, { font: [] }], | |||||
| [{ list: "ordered" }, { list: "bullet" }], | |||||
| [{ align: [] }], | |||||
| ["bold", "italic", "underline"], | |||||
| ["link", "image"], | |||||
| [{ script: "sub" }, { script: "super" }], | |||||
| [{ direction: "rtl" }], | |||||
| ], | |||||
| }, | |||||
| }); | |||||
| quillInstance.value.root.innerHTML = product.value.description; | |||||
| editorContent.value = product.value.description; | |||||
| quillInstance.value.on("text-change", () => { | |||||
| editorContent.value = quillInstance.value.root.innerHTML; | |||||
| }); | |||||
| } | |||||
| // if (editor.value) { | |||||
| // quillInstance.value = new Quill(editor.value, { | |||||
| // theme: "snow", | |||||
| // modules: { | |||||
| // toolbar: [ | |||||
| // [{ header: "1" }, { header: "2" }, { font: [] }], | |||||
| // [{ list: "ordered" }, { list: "bullet" }], | |||||
| // [{ align: [] }], | |||||
| // ["bold", "italic", "underline"], | |||||
| // ["link", "image"], | |||||
| // [{ script: "sub" }, { script: "super" }], | |||||
| // [{ direction: "rtl" }], | |||||
| // ], | |||||
| // }, | |||||
| // }); | |||||
| // | |||||
| // quillInstance.value.root.innerHTML = product.value.description; | |||||
| // | |||||
| // | |||||
| // | |||||
| // quillInstance.value.on("text-change", () => { | |||||
| // description.value = quillInstance.value.root.innerHTML; | |||||
| // }); | |||||
| // } | |||||
| selectedBrand.value = product.value?.brand_id; | selectedBrand.value = product.value?.brand_id; | ||||
| selectedCat.value = product.value?.category_id; | selectedCat.value = product.value?.category_id; | ||||
| @@ -1456,7 +1460,7 @@ export default { | |||||
| formData.append("title", title.value); | formData.append("title", title.value); | ||||
| formData.append("slug", slug.value); | formData.append("slug", slug.value); | ||||
| formData.append("summary", summary.value); | formData.append("summary", summary.value); | ||||
| formData.append("description", editorContent.value); | |||||
| formData.append("description", description.value); | |||||
| if (productType.value == 2 || productType.value == 3) { | if (productType.value == 2 || productType.value == 3) { | ||||
| formData.append("count_in_carton", countInCarton.value); | formData.append("count_in_carton", countInCarton.value); | ||||
| @@ -1682,6 +1686,7 @@ export default { | |||||
| brandSelectorLoader, | brandSelectorLoader, | ||||
| handleSearch, | handleSearch, | ||||
| handleBrandSearch, | handleBrandSearch, | ||||
| productImageRef | |||||
| }; | }; | ||||
| }, | }, | ||||
| }; | }; | ||||
| @@ -363,6 +363,8 @@ export default { | |||||
| <th>عکس</th> | <th>عکس</th> | ||||
| <th>عنوان</th> | <th>عنوان</th> | ||||
| <th>مدل</th> | <th>مدل</th> | ||||
| <th>دسته بندی</th> | |||||
| <th>برند</th> | |||||
| <th>تعداد فروش</th> | <th>تعداد فروش</th> | ||||
| <th>برگزیده</th> | <th>برگزیده</th> | ||||
| <th>تخفیف برگزیده</th> | <th>تخفیف برگزیده</th> | ||||
| @@ -389,6 +391,11 @@ export default { | |||||
| <td v-if="product.type == 1">تکی</td> | <td v-if="product.type == 1">تکی</td> | ||||
| <td v-if="product.type == 2">عمده</td> | <td v-if="product.type == 2">عمده</td> | ||||
| <td v-if="product.type == 3">تکی و عمده</td> | <td v-if="product.type == 3">تکی و عمده</td> | ||||
| <td>{{ product?.category?.title }}</td> | |||||
| <td>{{ product?.brand?.title }}</td> | |||||
| <td>{{ product.sold_count }}</td> | <td>{{ product.sold_count }}</td> | ||||
| <td> | <td> | ||||
| <span v-if="product.is_chosen == 0"> | <span v-if="product.is_chosen == 0"> | ||||