Procházet zdrojové kódy

fixed bugs mizito

master
alireza před 9 měsíci
rodič
revize
2a8363874d
22 změnil soubory, kde provedl 4364 přidání a 9213 odebrání
  1. +4057
    -8898
      package-lock.json
  2. +0
    -1
      src/components/c-menu.vue
  3. +4
    -0
      src/components/modals/categories/addCat.vue
  4. +3
    -1
      src/components/modals/categories/editCat.vue
  5. +30
    -25
      src/components/modals/identity/addIdentity.vue
  6. +0
    -1
      src/components/navbar-advanced.vue
  7. +0
    -1
      src/components/navbar.vue
  8. +0
    -1
      src/layout/custom.vue
  9. +5
    -5
      src/router/index.js
  10. +0
    -10
      src/router/routes.js
  11. +5
    -1
      src/services/ApiService.js
  12. +1
    -1
      src/views/live-preview/pages/banners/addBanner.vue
  13. +35
    -0
      src/views/live-preview/pages/banners/banners.vue
  14. +17
    -37
      src/views/live-preview/pages/discounts/addDiscount.vue
  15. +4
    -3
      src/views/live-preview/pages/discounts/discounts.vue
  16. +16
    -40
      src/views/live-preview/pages/discounts/editDiscount.vue
  17. +5
    -82
      src/views/live-preview/pages/orders/approvedOrders.vue
  18. +9
    -4
      src/views/live-preview/pages/orders/orders.vue
  19. +31
    -9
      src/views/live-preview/pages/orders/singleOrder.vue
  20. +92
    -55
      src/views/live-preview/pages/products/addProduct.vue
  21. +43
    -38
      src/views/live-preview/pages/products/editProduct.vue
  22. +7
    -0
      src/views/live-preview/pages/products/products.vue

+ 4057
- 8898
package-lock.json
Diff nebyl zobrazen, protože je příliš veliký
Zobrazit soubor


+ 0
- 1
src/components/c-menu.vue Zobrazit soubor

@@ -36,7 +36,6 @@ export default {
event.preventDefault();
},
handleKeyDown(event) {
console.log('handleKeyDown called', event.key, event.ctrlKey);
// Check if Ctrl+K is pressed
if (event.ctrlKey && event.key === 'k') {
// Prevent the default action (e.g., browser search)


+ 4
- 0
src/components/modals/categories/addCat.vue Zobrazit soubor

@@ -47,6 +47,7 @@
<label class="form-label">تصویر دسته</label>

<input
ref="imageFileRef"
type="file"
accept="image/*"
@change="handleImageChange"
@@ -206,6 +207,7 @@ export default {
const title = ref();
const errors = ref({});
const loading = ref(false);
const imageFileRef = ref(null);

watch(
() => props.parents,
@@ -310,6 +312,7 @@ export default {
description.value = "";
selectedPaernt.value = ""
selectedIcon.value = "";
imageFileRef.value.value = null
}, 500);
})
.catch((error) => {
@@ -340,6 +343,7 @@ export default {
setSelectedIcon,
iconData,
selectedIcon,
imageFileRef,
};
},
};


+ 3
- 1
src/components/modals/categories/editCat.vue Zobrazit soubor

@@ -46,6 +46,7 @@
<label class="form-label">تصویر دسته</label>

<input
ref="imageFileRef"
type="file"
@input="clearError('localImage')"
accept="image/*"
@@ -232,6 +233,7 @@ export default {
const image = ref(null);
const localId = toRef(props.id);
const errors = ref({});
const imageFileRef = ref(null);

const loading = ref(false);

@@ -382,7 +384,7 @@ export default {
localParent,
allLocalParents,
setSelectedIcon,
imageFileRef,
localIcon,
};
},


+ 30
- 25
src/components/modals/identity/addIdentity.vue Zobrazit soubor

@@ -24,7 +24,7 @@
<form @submit.prevent="addIdentity">
<BRow class="g-3">
<!-- Brand Title -->
<BCol lg="6">
<BCol lg="12">
<div class="form-group">
<label class="form-label">عنوان مشخصه</label>

@@ -42,25 +42,25 @@
</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>
<!-- <BCol lg="6">-->
<!-- <div class="form-group">-->
<!-- <label class="form-label">انتخاب دسته</label>-->
<!-- <div class="color-picker-wrapper">-->
<!-- <VueSelect-->
<!-- style="&#45;&#45;vs-min-height: 48px; &#45;&#45;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>

<!-- Submit Buttons -->
@@ -95,16 +95,21 @@

<script>
import { ref, computed } from "vue";
import VueSelect from "vue3-select-component";
import { toast } from "vue3-toastify";
import "vue3-toastify/dist/index.css";
import ApiServiece from "@/services/ApiService";

export default {
components: {
VueSelect,

props: {
categoryId: {
type: Number,
required: true,
}
},

setup(props, { emit }) {

const selectedCat = ref();
const title = ref();
const errors = ref({});
@@ -159,8 +164,8 @@ export default {
loading.value = true;

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);



+ 0
- 1
src/components/navbar-advanced.vue Zobrazit soubor

@@ -28,7 +28,6 @@ export default {
event.preventDefault();
},
handleKeyDown(event) {
console.log('handleKeyDown called', event.key, event.ctrlKey);
// Check if Ctrl+K is pressed
if (event.ctrlKey && event.key === 'k') {
// Prevent the default action (e.g., browser search)


+ 0
- 1
src/components/navbar.vue Zobrazit soubor

@@ -31,7 +31,6 @@ export default {
event.preventDefault();
},
handleKeyDown(event) {
console.log("handleKeyDown called", event.key, event.ctrlKey);
// Check if Ctrl+K is pressed
if (event.ctrlKey && event.key === "k") {
// Prevent the default action (e.g., browser search)


+ 0
- 1
src/layout/custom.vue Zobrazit soubor

@@ -17,7 +17,6 @@ export default {
const dir = localStorage.getItem("dir");
const validDir = dir === "ltr" || dir === "rtl" ? dir : "rtl";
document.body.setAttribute("data-pc-direction", validDir);
console.log(validDir);
},
};
</script>


+ 5
- 5
src/router/index.js Zobrazit soubor

@@ -1,7 +1,7 @@
import { createWebHistory, createRouter } from "vue-router";
import routes from "./routes";
import appConfig from "../../app.config";
import store from "../state/store";
//import store from "../state/store";

const router = createRouter({
history: createWebHistory("/"),
@@ -11,11 +11,11 @@ const router = createRouter({
router.beforeResolve(async (routeTo, routeFrom, next) => {
try {
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...


+ 0
- 10
src/router/routes.js Zobrazit soubor

@@ -14,16 +14,6 @@ export default [
component: () =>
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",
name: "users",


+ 5
- 1
src/services/ApiService.js Zobrazit soubor

@@ -1,6 +1,8 @@
import axios from "axios";
import router from "@/router/index";
const url = process.env.VUE_APP_ROOT_URL;


const ApiServiece = axios.create({
baseURL: url,
headers: {
@@ -27,7 +29,9 @@ ApiServiece.interceptors.response.use(
return response;
},
(error) => {
console.error("API Error:", error);
if (error?.status === 401) {
router.push({ name: "otpLogin" });
}
return Promise.reject(error);
}
);


+ 1
- 1
src/views/live-preview/pages/banners/addBanner.vue Zobrazit soubor

@@ -619,7 +619,7 @@ export default {
}
formData.append("panel", pannel.value);
if (pannel.value == "wholesale") {
formData.append("page_type", null);
formData.append("page_type", "main_page");
}

if (pannel.value !== "wholesale") {


+ 35
- 0
src/views/live-preview/pages/banners/banners.vue Zobrazit soubor

@@ -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(() => {
getBanners();
});
@@ -224,6 +249,8 @@ export default {
searchPage,
visiblePages,
selectedPageType,
setPageType,
setProductOrCategory,
};
},
};
@@ -282,6 +309,9 @@ export default {
<th>موقعیت</th>
<th>نوع</th>
<th>تاریخ ایجاد</th>
<th>پنل</th>
<th>نمایش در</th>
<th>صفحه فرود</th>
<th>عملیات</th>
</tr>
</thead>
@@ -328,6 +358,11 @@ export default {
<td v-if="banner.type === 'slider'">اسلایدر</td>
<td v-if="banner.type === 'banner'">بنر</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>
<router-link
:to="`/editBanner/${banner?.id}`"


+ 17
- 37
src/views/live-preview/pages/discounts/addDiscount.vue Zobrazit soubor

@@ -69,13 +69,8 @@
class="form-control"
type="number"
placeholder="میزان سفارش"
:class="{ 'is-invalid': errors.minOrder }"
@input="clearError('minOrder')"
/>
</div>
<small v-if="errors.minOrder" class="text-danger">
{{ errors.minOrder }}
</small>
</BCol>

<BCol md="6">
@@ -86,13 +81,8 @@
type="number"
class="form-control"
placeholder="حداکثر میزان استفاده"
:class="{ 'is-invalid': errors.maxUsage }"
@input="clearError('maxUsage')"
/>
</div>
<small v-if="errors.maxUsage" class="text-danger">
{{ errors.maxUsage }}
</small>
</BCol>

<BCol md="6">
@@ -101,8 +91,6 @@
<select
v-model="whichPart"
class="form-control"
:class="{ 'is-invalid': errors.whichPart }"
@change="clearError('whichPart')"
placeholder="انتخاب محل اعمال تخفبف"
>
<option value="cat">دسته</option>
@@ -110,9 +98,6 @@
<option value="all">همه</option>
</select>
</div>
<small v-if="errors.whichPart" class="text-danger">
{{ errors.whichPart }}
</small>
</BCol>

<BCol v-if="whichPart === 'cat'" md="6">
@@ -161,31 +146,25 @@
<BCol md="6">
<div class="form-group">
<label class="form-label"> تاریخ اعمال تخفیف </label>

<DatePicker
:format="'jYYYY/jMM/jDD HH:mm:ss'"
type="datetime"
v-model="startDate"
clearable
></DatePicker>
</div>
<small v-if="errors.startDate" class="text-danger">
{{ errors.startDate }}
</small>
</BCol>

<BCol md="6">
<div class="form-group">
<label class="form-label"> تاریخ انقضای تخفیف </label>

<DatePicker
:format="'jYYYY/jMM/jDD HH:mm:ss'"
type="datetime"
v-model="expire"
clearable
></DatePicker>
</div>
<small v-if="errors.expire" class="text-danger">
{{ errors.expire }}
</small>
</BCol>
</BRow>
</BCardBody>
@@ -235,12 +214,12 @@ export default {
const title = ref();
const discountType = ref();
const amount = ref();
const minOrder = ref();
const minOrder = ref(null);
const selectedCat = ref();
const selectedProduct = ref();
const startDate = ref();
const expire = ref();
const maxUsage = ref();
const maxUsage = ref(null);
const whichPart = ref();
const loading = ref(false);
const categories = ref([]);
@@ -304,14 +283,14 @@ export default {
if (!amount.value)
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;
};

@@ -333,7 +312,8 @@ export default {
formData.append("title", title.value);
formData.append("type", discountType.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") {
formData.append("category_id", selectedCat.value);
@@ -359,16 +339,16 @@ export default {
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)
.then((resp) => {
.then(() => {
loading.value = false;
toast.success("!تخفیف با موفقیت اضافه شد", {
position: "top-right",
autoClose: 1000,
});
console.log(resp);

// Clear form fields after successful submission
title.value = "";


+ 4
- 3
src/views/live-preview/pages/discounts/discounts.vue Zobrazit soubor

@@ -36,9 +36,11 @@ export default {
const discounts = ref();

const convertToJalali = (date) => {
if (!date) return

return moment(date, "YYYY-MM-DD HH:mm:ss")
.locale("fa")
.format("YYYY/MM/DD");
.locale("fa")
.format("YYYY/MM/DD");
};

const handleSearchChange = () => {
@@ -67,7 +69,6 @@ export default {
.then((resp) => {
filterLoading.value = false;
discounts.value = resp.data.data.data;
console.log(resp.data.data);
currentPage.value = resp.data.data.current_page;
totalPages.value = resp.data.data.last_page;
})


+ 16
- 40
src/views/live-preview/pages/discounts/editDiscount.vue Zobrazit soubor

@@ -70,13 +70,8 @@
class="form-control"
type="number"
placeholder="میزان سفارش"
:class="{ 'is-invalid': errors.minOrder }"
@input="clearError('minOrder')"
/>
</div>
<small v-if="errors.minOrder" class="text-danger">
{{ errors.minOrder }}
</small>
</BCol>

<BCol md="6">
@@ -87,13 +82,8 @@
type="number"
class="form-control"
placeholder="حداکثر میزان استفاده"
:class="{ 'is-invalid': errors.maxUsage }"
@input="clearError('maxUsage')"
/>
</div>
<small v-if="errors.maxUsage" class="text-danger">
{{ errors.maxUsage }}
</small>
</BCol>

<BCol md="6">
@@ -102,8 +92,6 @@
<select
v-model="whichPart"
class="form-control"
:class="{ 'is-invalid': errors.whichPart }"
@change="clearError('whichPart')"
placeholder="انتخاب محل اعمل تخفیف"
>
<option value="cat">دسته</option>
@@ -111,9 +99,6 @@
<option value="all">همه</option>
</select>
</div>
<small v-if="errors.discountType" class="text-danger">
{{ errors.discountType }}
</small>
</BCol>

<BCol v-if="whichPart === 'cat'" md="6">
@@ -125,14 +110,10 @@
:options="formattedCategories"
label="label"
:reduce="(option) => option.value"
@change="clearError('selectedCat')"
placeholder="دسته ای را انتخاب کنید"
@search="handleSearch"
/>
</div>
<small v-if="errors.selectedCat" class="text-danger">
{{ errors.selectedCat }}
</small>
</BCol>

<BCol v-if="whichPart === 'product'" md="6">
@@ -144,13 +125,9 @@
v-model="selectedProduct"
:options="formattedProducts"
@search="handleProductSearch"
@change="clearError('selectedProduct')"
placeholder="محصولی را انتخاب کنید "
/>
</div>
<small v-if="errors.selectedProduct" class="text-danger">
{{ errors.selectedProduct }}
</small>
</BCol>

<BCol md="6">
@@ -160,13 +137,11 @@
<DatePicker
:format="'jYYYY/jMM/jDD HH:mm:ss'"
type="datetime"
clearable
v-model="startDate"
@input="handleStartDateInput"
></DatePicker>
</div>
<small v-if="errors.startDate" class="text-danger">
{{ errors.startDate }}
</small>
</BCol>

<BCol md="6">
@@ -176,13 +151,11 @@
<DatePicker
:format="'jYYYY/jMM/jDD HH:mm:ss'"
type="datetime"
clearable
v-model="expire"
@input="handleExpireDateInput"
></DatePicker>
</div>
<small v-if="errors.expire" class="text-danger">
{{ errors.expire }}
</small>
</BCol>
</BRow>
</BCardBody>
@@ -373,15 +346,15 @@ export default {
if (!amount.value)
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;
};

@@ -406,7 +379,9 @@ export default {
formData.append("title", title.value);
formData.append("type", discountType.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") {
formData.append("category_id", selectedCat.value);
}
@@ -431,7 +406,8 @@ export default {
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)
.then((resp) => {


+ 5
- 82
src/views/live-preview/pages/orders/approvedOrders.vue Zobrazit soubor

@@ -357,15 +357,13 @@ export default {
<thead class="table-light">
<tr>
<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>
</tr>
</thead>
@@ -394,21 +392,9 @@ export default {
</div>
</td>

<!-- Description -->
<!-- Product color -->
<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>

<!-- Status -->
@@ -452,19 +438,6 @@ export default {
<!-- Sent Count -->
<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 -->
<td>
<router-link
@@ -490,33 +463,9 @@ export default {
<li>
<a
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>
</li>
<li>
@@ -529,32 +478,6 @@ export default {
>
</a>
</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>
</td>
</tr>


+ 9
- 4
src/views/live-preview/pages/orders/orders.vue Zobrazit soubor

@@ -24,9 +24,11 @@ export default {
const orders = ref();

const convertToJalali = (date) => {
if (!date) return

return moment(date, "YYYY-MM-DD HH:mm:ss")
.locale("fa")
.format("YYYY/MM/DD");
.format("HH:mm:ss YYYY/MM/DD ");
};

const loadingId = ref(null);
@@ -34,8 +36,12 @@ export default {
const getExport = (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 url = window.URL.createObjectURL(excelBlob);

@@ -70,7 +76,6 @@ export default {
.then((resp) => {
filterLoading.value = false;
orders.value = resp.data.data.data;
console.log(orders.value);
currentPage.value = resp.data.data.current_page;
totalPages.value = resp.data.data.last_page;
})


+ 31
- 9
src/views/live-preview/pages/orders/singleOrder.vue Zobrazit soubor

@@ -104,7 +104,9 @@ export default {
};

const formatPrice = (price) => {
return numeral(price).format("0,0");
if (!price) return 0

return numeral(price).format("0,0")
};

onMounted(() => {
@@ -142,6 +144,11 @@ export default {
<strong class="me-2">نام مشتری:</strong>
<span>{{ order?.user?.name || "بدون نام" }}</span>
</BCol>

<BCol md="6">
<strong class="me-2">موبایل:</strong>
<span>{{ order?.user?.mobile }}</span>
</BCol>
</BRow>

<BRow class="mb-3">
@@ -161,27 +168,37 @@ export default {
<span>
{{
order?.shipping_price != null
? formatPrice(order.shipping_price) + " تومان"
? formatPrice(order?.shipping_price) + ' تومان'
: "بدون قیمت"
}}
</span>
</BCol>
<BCol md="6">
<strong class="me-2">تخفیف:</strong>
<span>{{
order?.discount
? formatPrice(order.discount) + " تومان"
: "بدون تخفیف"
}}</span>
<span>{{ formatPrice(order?.discount?.amount) + (order?.discount?.type === 'percentage' ? ' درصد' : 'تومان') }}</span>
</BCol>
</BRow>

<BRow>

<BRow class="mb-3">
<BCol md="6">
<strong class="me-2">کد تخفیف:</strong>
<span>{{ order?.discount?.title ?? '-' }}</span>
</BCol>

<BCol md="6">
<strong class="me-2">رنگ سفارش:</strong>
<span>{{ order.color || "---" }}</span>
<span>{{ order?.status || "-" }}</span>
</BCol>
</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>

<!-- Order Details and Items Here -->
@@ -195,6 +212,7 @@ export default {
:items="order.order_items"
:fields="[
{ key: 'title', label: 'عنوان محصول' },
{ key: 'color', label: 'رنگ محصول' },
{ key: 'count', label: 'تعداد در خواستی ' },
{ key: 'price', label: 'قیمت' },
{ key: 'created_at', label: 'تاریخ ثبت' },
@@ -222,6 +240,10 @@ export default {
{{ data.item.count }}
</template>

<template #cell(color)="data">
{{ data?.item?.attribute_value_product?.attribute_value?.title }}
</template>

<!-- Editable shipped quantity with API call -->
<template #cell(edit_count)="data">
<input


+ 92
- 55
src/views/live-preview/pages/products/addProduct.vue Zobrazit soubor

@@ -61,14 +61,16 @@
<BCol md="6">
<div class="form-group">
<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>
<small v-if="errors.editorContent" class="text-danger">
{{ errors.editorContent }}
<small v-if="errors.description" class="text-danger">
{{ errors.description }}
</small>
</BCol>

@@ -77,6 +79,7 @@
<label class="form-label">تصویر محصول</label>

<input
ref="productImageRef"
type="file"
accept="image/*"
@change="handleImageUpload"
@@ -395,8 +398,18 @@
</BCard>

<BCard>
<div class="card-header">
<div class="card-header d-flex justify-content-between">
<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>

<BRow class="g-3 mt-2">
@@ -409,8 +422,7 @@
variant="success"
size="lg"
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> کلیک کنید
</BButton>
@@ -554,7 +566,7 @@
</div>
</div>
</BCardFooter>
<addIdentity @identity-updated="handleIdentityUpdate" />
<addIdentity @identity-updated="handleIdentityUpdate" :categoryId="selectedCat" />
<addAttribute
:attributeValues="attributeValues"
@attribute-updated="handleAttributeUpdated()"
@@ -572,12 +584,12 @@ import moment from "jalali-moment";
import { toast } from "vue3-toastify";
import "vue3-toastify/dist/index.css";
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 DatePicker from "vue3-persian-datetime-picker";
import addIdentity from "@/components/modals/identity/addIdentity.vue";
import Quill from "quill";
import "quill/dist/quill.snow.css";
import { Modal } from "bootstrap"

export default {
name: "SAMPLE-PAGE",
@@ -625,6 +637,10 @@ export default {
const editor = ref(null);
const editorContent = ref("");

// ALIREZA
const productImageRef = ref(null)
const description = ref(null)

const getAttributeValues = () => {
ApiServiece.get(`admin/attributes`).then((resp) => {
console.log(resp);
@@ -636,21 +652,22 @@ export default {
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 = () => {
ApiServiece.get(`admin/attributes?category_id=${selectedCat.value}`)
.then((resp) => {
relatedAttrebutes.value = resp.data.data;
console.log("sadsadsaasdasddsad");
})
.catch((err) => {
console.log(err);
@@ -779,8 +796,8 @@ export default {

if (!image.value)
errors.value.image = "وارد کردن عکس محصول ضروری می باشد";
if (!editorContent.value)
errors.value.editorContent = "وارد کردن توضیحات محصول ضروری می باشد";
if (!description.value)
errors.value.description = "وارد کردن توضیحات محصول ضروری می باشد";
if (!productType.value)
errors.value.productType = "انتخاب حالت محصول ضروری می باشد";

@@ -844,37 +861,51 @@ export default {
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();
getAttributeValues();
});
@@ -894,7 +925,7 @@ export default {
formData.append("title", title.value);
formData.append("slug", slug.value);
formData.append("summary", summary.value);
formData.append("description", editorContent.value);
formData.append("description", description.value);

if (isChosen.value == 1) {
formData.append("is_chosen", isChosen.value);
@@ -994,7 +1025,6 @@ export default {
// 🔸 Upload images if any
const validImages = images.value.filter((image) => image.file);
if (validImages.length > 0) {
console.log(validImages, "valid images");
validImages.forEach((image) => {
const formData = new FormData();
formData.append("image", image.file);
@@ -1030,6 +1060,10 @@ export default {
countInCarton.value = "";
image.value = null;
images.value = [];
description.value = null;
if (productImageRef.value) {
productImageRef.value.value = null
}
attrebutes.value.forEach((attribute) => {
attribute.isChecked = false;
attribute.value = "";
@@ -1097,6 +1131,9 @@ export default {
handleSearch,
formattedCategories,
categorySelectorLoader,
productImageRef,
description,
handleAddIdentityClick
};
},
};


+ 43
- 38
src/views/live-preview/pages/products/editProduct.vue Zobrazit soubor

@@ -61,20 +61,19 @@
</small>
</BCol>



<BCol md="6">
<div class="form-group">
<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>
<small v-if="errors.editorContent" class="text-danger">
{{ errors.editorContent }}
<small v-if="errors.description" class="text-danger">
{{ errors.description }}
</small>
</BCol>

@@ -866,7 +865,6 @@ export default {
const spescialPrice = ref();
const wholesalePrice = ref();
const retailePrice = ref();
const description = ref();
const productAttributes = ref([]);
const images = ref([{ file: null, preview: null }]);
const localImages = ref([{ preview: null }]);
@@ -895,6 +893,11 @@ export default {
const editorContent = ref("");
const categorySelectorLoader = ref(false);
const brandSelectorLoader = ref(false);
// ALIREZA
const productImageRef = ref(null)
const description = ref(null)



const formattedCategories = computed(() =>
Array.isArray(categories.value)
@@ -1179,8 +1182,8 @@ export default {

if (!imagePreview.value)
errors.value.image = "وارد کردن عکس محصول ضروری می باشد";
if (!editorContent.value)
errors.value.editorContent = "وارد کردن توضیحات محصول ضروری می باشد";
if (!description.value)
errors.value.description = "وارد کردن توضیحات محصول ضروری می باشد";
if (!productType.value)
errors.value.productType = "انتخاب حالت محصول ضروری می باشد";

@@ -1270,6 +1273,7 @@ export default {
spescialPrice.value = product.value?.special_price;
selectedCat.value = resp?.data?.data?.category.id;
selectedBrand.value = resp?.data?.data?.brand.id;
description.value = product.value?.description;

if (product.value?.special_expires_at) {
expire.value = moment(
@@ -1278,30 +1282,30 @@ export default {
).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;
selectedCat.value = product.value?.category_id;

@@ -1456,7 +1460,7 @@ export default {
formData.append("title", title.value);
formData.append("slug", slug.value);
formData.append("summary", summary.value);
formData.append("description", editorContent.value);
formData.append("description", description.value);

if (productType.value == 2 || productType.value == 3) {
formData.append("count_in_carton", countInCarton.value);
@@ -1682,6 +1686,7 @@ export default {
brandSelectorLoader,
handleSearch,
handleBrandSearch,
productImageRef
};
},
};


+ 7
- 0
src/views/live-preview/pages/products/products.vue Zobrazit soubor

@@ -363,6 +363,8 @@ export default {
<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 == 2">عمده</td>
<td v-if="product.type == 3">تکی و عمده</td>

<td>{{ product?.category?.title }}</td>

<td>{{ product?.brand?.title }}</td>

<td>{{ product.sold_count }}</td>
<td>
<span v-if="product.is_chosen == 0">


Načítá se…
Zrušit
Uložit