3 Ревизии

Автор SHA1 Съобщение Дата
  alireza 4969e578de completed panel преди 2 месеца
  alireza 5e8c5099f3 completed truck admin преди 2 месеца
  alireza 6301146eaa completed admin panel truck преди 2 месеца
променени са 84 файла, в които са добавени 317 реда и са изтрити 275 реда
  1. +15
    -2
      .gitignore
  2. +3
    -3
      app.config.json
  3. +0
    -1
      dist/css/1203.1fa6b175.css
  4. +0
    -1
      dist/css/1353.0f1e0cc5.css
  5. +0
    -1
      dist/css/1521.9e99b6a1.css
  6. +0
    -1
      dist/css/1756.a8f32166.css
  7. +0
    -1
      dist/css/1919.1ef8e781.css
  8. +0
    -1
      dist/css/2348.bdb4a037.css
  9. +0
    -1
      dist/css/2482.7ca1fb1d.css
  10. +0
    -1
      dist/css/2983.16754f31.css
  11. +0
    -1
      dist/css/5053.6317593b.css
  12. +0
    -1
      dist/css/5768.30642346.css
  13. +0
    -1
      dist/css/7282.946dace5.css
  14. +0
    -1
      dist/css/7285.b299370e.css
  15. +0
    -1
      dist/css/7353.6ad37414.css
  16. +0
    -1
      dist/css/8880.dae9879e.css
  17. +1
    -1
      dist/index.html
  18. +0
    -2
      dist/js/1203.412136f8.js
  19. +0
    -1
      dist/js/1203.412136f8.js.map
  20. +0
    -2
      dist/js/1353.7187d530.js
  21. +0
    -1
      dist/js/1353.7187d530.js.map
  22. +0
    -2
      dist/js/1521.26aa8887.js
  23. +0
    -1
      dist/js/1521.26aa8887.js.map
  24. +0
    -2
      dist/js/1756.9856eeee.js
  25. +0
    -1
      dist/js/1756.9856eeee.js.map
  26. +0
    -2
      dist/js/1919.df6414e8.js
  27. +0
    -1
      dist/js/1919.df6414e8.js.map
  28. +0
    -2
      dist/js/2348.c4bf36ce.js
  29. +0
    -1
      dist/js/2348.c4bf36ce.js.map
  30. +0
    -2
      dist/js/2482.bccd2223.js
  31. +0
    -1
      dist/js/2482.bccd2223.js.map
  32. +0
    -2
      dist/js/2983.f00900c5.js
  33. +0
    -1
      dist/js/2983.f00900c5.js.map
  34. +0
    -2
      dist/js/5053.95704f9e.js
  35. +0
    -1
      dist/js/5053.95704f9e.js.map
  36. +0
    -2
      dist/js/518.e2b86785.js
  37. +0
    -1
      dist/js/518.e2b86785.js.map
  38. +0
    -2
      dist/js/5768.f1b2dd7b.js
  39. +0
    -1
      dist/js/5768.f1b2dd7b.js.map
  40. +0
    -2
      dist/js/6215.838ca982.js
  41. +0
    -1
      dist/js/6215.838ca982.js.map
  42. +0
    -2
      dist/js/7282.7b0e4d35.js
  43. +0
    -1
      dist/js/7282.7b0e4d35.js.map
  44. +0
    -2
      dist/js/7285.1636212e.js
  45. +0
    -1
      dist/js/7285.1636212e.js.map
  46. +0
    -2
      dist/js/7353.9f915fe2.js
  47. +0
    -1
      dist/js/7353.9f915fe2.js.map
  48. +0
    -2
      dist/js/7571.9af754dc.js
  49. +0
    -1
      dist/js/7571.9af754dc.js.map
  50. +0
    -2
      dist/js/8880.a1679da2.js
  51. +0
    -1
      dist/js/8880.a1679da2.js.map
  52. +0
    -2
      dist/js/app.67eaa993.js
  53. +0
    -1
      dist/js/app.67eaa993.js.map
  54. +2
    -2
      package-lock.json
  55. +1
    -1
      package.json
  56. +0
    -1
      public/index.html
  57. +12
    -12
      src/components/AtrributesProduct.vue
  58. +75
    -3
      src/components/ProductInfo.vue
  59. +1
    -1
      src/components/customSidebar.vue
  60. +2
    -1
      src/components/modals/Brands/addBrand.vue
  61. +22
    -12
      src/components/modals/Brands/editBrand.vue
  62. +10
    -7
      src/components/modals/attribute-value/addAttributeValue.vue
  63. +4
    -22
      src/components/modals/attribute-value/editAttributeValue.vue
  64. +13
    -6
      src/components/modals/attribute/addAttribute.vue
  65. +39
    -14
      src/components/modals/attribute/editAttribute.vue
  66. +4
    -1
      src/components/modals/blogCat/addBlogCat.vue
  67. +13
    -7
      src/components/modals/blogCat/editBlogCat.vue
  68. +8
    -9
      src/components/modals/categories/addCat.vue
  69. +4
    -1
      src/components/modals/categories/editCat.vue
  70. +1
    -1
      src/router/index.js
  71. +2
    -2
      src/services/ApiService.js
  72. +3
    -3
      src/views/live-preview/pages/attributes-value/attributes-value.vue
  73. +0
    -8
      src/views/live-preview/pages/auth2/login.vue
  74. +15
    -9
      src/views/live-preview/pages/banners/editBanner.vue
  75. +3
    -3
      src/views/live-preview/pages/blogCats/blogCat.vue
  76. +18
    -8
      src/views/live-preview/pages/blogs/addBlog.vue
  77. +14
    -1
      src/views/live-preview/pages/blogs/editBlog.vue
  78. +1
    -25
      src/views/live-preview/pages/countries/countries.vue
  79. +4
    -5
      src/views/live-preview/pages/discounts/discounts.vue
  80. +11
    -19
      src/views/live-preview/pages/products/addProduct.vue
  81. +8
    -7
      src/views/live-preview/pages/products/editProduct.vue
  82. +7
    -8
      src/views/live-preview/pages/products/products.vue
  83. +0
    -1
      src/views/live-preview/pages/users/users.vue
  84. +1
    -1
      vue.config.js

+ 15
- 2
.gitignore Целия файл

@@ -1,3 +1,16 @@
node_modules/
dist/
.env
.env.local
.env.*.local

/dist
/build
/dist-*
/build-*

/node_modules

*.log
npm-debug.log*

.DS_Store
Thumbs.db

+ 3
- 3
app.config.json Целия файл

@@ -1,4 +1,4 @@
{
"title": "NovinPlast",
"description": "NovinPlast"
}
"title": "TruckShop",
"description": "TruckShop"
}

+ 0
- 1
dist/css/1203.1fa6b175.css
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 1
dist/css/1353.0f1e0cc5.css
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 1
dist/css/1521.9e99b6a1.css
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 1
dist/css/1756.a8f32166.css
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 1
dist/css/1919.1ef8e781.css
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 1
dist/css/2348.bdb4a037.css
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 1
dist/css/2482.7ca1fb1d.css Целия файл

@@ -1 +0,0 @@
.quill-editor[data-v-a2cbff30]{height:300px;border:1px solid #ccc;border-radius:5px}.quill-editor .ql-container[data-v-a2cbff30]{font-family:Vazir,Arial,sans-serif;font-size:14px}.quill-editor .ql-editor[data-v-a2cbff30]{padding:10px;text-align:right}.ql-editor[data-v-a2cbff30]{direction:rtl;text-align:right}.ql-editor[data-v-a2cbff30]:before{content:attr(placeholder);direction:rtl!important;text-align:right}.Image-Preview[data-v-a2cbff30]{min-width:200px;max-height:200px;max-width:200px;-o-object-fit:cover;object-fit:cover;border-radius:8px;border:1px solid #ddd}.delete-btn[data-v-a2cbff30]{display:flex;align-items:center;padding:3px;font-size:10px;background-color:#e74c3c;color:#fff;border:none;border-radius:5px;cursor:pointer;transition:background-color .3s ease,transform .2s ease;gap:8px;margin-right:100px}.delete-btn[data-v-a2cbff30]:hover{background-color:#c0392b;transform:scale(1.05)}.delete-btn[data-v-a2cbff30]:active{background-color:#a93226}.delete-btn[data-v-a2cbff30]:focus{outline:none}

+ 0
- 1
dist/css/2983.16754f31.css
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 1
dist/css/5053.6317593b.css
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 1
dist/css/5768.30642346.css
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 1
dist/css/7282.946dace5.css
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 1
dist/css/7285.b299370e.css
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 1
dist/css/7353.6ad37414.css
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 1
dist/css/8880.dae9879e.css Целия файл

@@ -1 +0,0 @@
.quill-editor[data-v-099ca948]{height:300px;border:1px solid #ccc;border-radius:5px}.quill-editor .ql-container[data-v-099ca948]{font-family:Vazir,Arial,sans-serif;font-size:14px}.quill-editor .ql-editor[data-v-099ca948]{padding:10px;text-align:right}.ql-editor[data-v-099ca948]{direction:rtl;text-align:right}.ql-editor[data-v-099ca948]:before{content:attr(placeholder);direction:rtl!important;text-align:right}.Image-Preview[data-v-099ca948]{min-width:200px;max-height:200px;max-width:200px;-o-object-fit:cover;object-fit:cover;border-radius:8px;border:1px solid #ddd}.delete-btn[data-v-099ca948]{display:flex;align-items:center;padding:3px;font-size:10px;background-color:#e74c3c;color:#fff;border:none;border-radius:5px;cursor:pointer;transition:background-color .3s ease,transform .2s ease;gap:8px;margin-right:200px}.delete-btn[data-v-099ca948]:hover{background-color:#c0392b;transform:scale(1.05)}.delete-btn[data-v-099ca948]:active{background-color:#a93226}.delete-btn[data-v-099ca948]:focus{outline:none}

+ 1
- 1
dist/index.html Целия файл

@@ -1,4 +1,4 @@
<!doctype html><html lang=""><head><meta charset="utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge"/><meta name="viewport" content="width=device-width,initial-scale=1"/><link rel="icon" id="favicon" href="/panel/favicon.svg"/><link rel="stylesheet" href="/panel/fonts/vazir.css"/><title>TruckShop</title><script defer="defer" src="/panel/js/chunk-vendors.f38378b4.js"></script><script defer="defer" src="/panel/js/app.67eaa993.js"></script><link href="/panel/css/chunk-vendors.8ada15f4.css" rel="stylesheet"><link href="/panel/css/app.4211482e.css" rel="stylesheet"></head><body lang><noscript><strong>We're sorry but TruckShop doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script>document.addEventListener("DOMContentLoaded", function () {
<!doctype html><html lang=""><head><meta charset="utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge"/><meta name="viewport" content="width=device-width,initial-scale=1"/><link rel="icon" id="favicon" href="/panel/favicon.svg"/><link rel="stylesheet" href="/panel/fonts/vazir.css"/><title>TruckShop</title><script defer="defer" src="/panel/js/chunk-vendors.f38378b4.js"></script><script defer="defer" src="/panel/js/app.472e38d2.js"></script><link href="/panel/css/chunk-vendors.8ada15f4.css" rel="stylesheet"><link href="/panel/css/app.4211482e.css" rel="stylesheet"></head><body lang><noscript><strong>We're sorry but TruckShop doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script>document.addEventListener("DOMContentLoaded", function () {
const faviconUrl = localStorage.getItem("logo");
if (faviconUrl) {
const faviconLink = document.getElementById("favicon");


+ 0
- 2
dist/js/1203.412136f8.js
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 1
dist/js/1203.412136f8.js.map
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 2
dist/js/1353.7187d530.js
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 1
dist/js/1353.7187d530.js.map
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 2
dist/js/1521.26aa8887.js
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 1
dist/js/1521.26aa8887.js.map
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 2
dist/js/1756.9856eeee.js
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 1
dist/js/1756.9856eeee.js.map
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 2
dist/js/1919.df6414e8.js
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 1
dist/js/1919.df6414e8.js.map
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 2
dist/js/2348.c4bf36ce.js
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 1
dist/js/2348.c4bf36ce.js.map
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 2
dist/js/2482.bccd2223.js
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 1
dist/js/2482.bccd2223.js.map
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 2
dist/js/2983.f00900c5.js
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 1
dist/js/2983.f00900c5.js.map
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 2
dist/js/5053.95704f9e.js
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 1
dist/js/5053.95704f9e.js.map
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 2
dist/js/518.e2b86785.js
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 1
dist/js/518.e2b86785.js.map
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 2
dist/js/5768.f1b2dd7b.js
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 1
dist/js/5768.f1b2dd7b.js.map
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 2
dist/js/6215.838ca982.js
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 1
dist/js/6215.838ca982.js.map
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 2
dist/js/7282.7b0e4d35.js
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 1
dist/js/7282.7b0e4d35.js.map
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 2
dist/js/7285.1636212e.js
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 1
dist/js/7285.1636212e.js.map
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 2
dist/js/7353.9f915fe2.js
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 1
dist/js/7353.9f915fe2.js.map
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 2
dist/js/7571.9af754dc.js
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 1
dist/js/7571.9af754dc.js.map
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 2
dist/js/8880.a1679da2.js
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 1
dist/js/8880.a1679da2.js.map
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 2
dist/js/app.67eaa993.js
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 0
- 1
dist/js/app.67eaa993.js.map
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 2
- 2
package-lock.json Целия файл

@@ -1,11 +1,11 @@
{
"name": "NovinPlast",
"name": "TruckShop",
"version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "NovinPlast",
"name": "TruckShop",
"version": "0.1.0",
"dependencies": {
"@amcharts/amcharts4": "^4.10.38",


+ 1
- 1
package.json Целия файл

@@ -1,5 +1,5 @@
{
"name": "NovinPlast",
"name": "TruckShop",
"version": "0.1.0",
"private": true,
"scripts": {


+ 0
- 1
public/index.html Целия файл

@@ -6,7 +6,6 @@
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<link rel="icon" id="favicon" href="<%= BASE_URL %>favicon.svg" />
<link rel="stylesheet" href="<%= BASE_URL %>fonts/vazir.css" />
<script defer src="https://bazarce.liara.run/script.js" data-website-id="7baabdd5-3224-41c1-9267-d2a1abd29d01"></script>
<title><%= htmlWebpackPlugin.options.title %></title>
</head>



+ 12
- 12
src/components/AtrributesProduct.vue Целия файл

@@ -135,18 +135,18 @@
}
}

const handlerChangeCheckbox = async (e, attr) => {
if (!e.target.checked) {
try {
const { data: { success, message } } = await ApiService.delete(`admin/products/${props.productId}/attributes/${attr.id}`)
if (success) {
toast.success(message)
}
} catch (e) {
toast.error(e.response?.data?.message)
}
}
const handlerChangeCheckbox = async () => {
// if (!e.target.checked) {
// try {
// const { data: { success, message } } = await ApiService.delete(`admin/products/${props.productId}/attributes/${attr.id}`)
//
// if (success) {
// toast.success(message)
// }
// } catch (e) {
// toast.error(e.response?.data?.message)
// }
// }
}

getAttributes()


+ 75
- 3
src/components/ProductInfo.vue Целия файл

@@ -1,8 +1,9 @@
<script setup>
import {ref, reactive, defineProps, defineExpose, defineEmits } from "vue"
import {ref, reactive, defineProps, defineExpose, defineEmits, computed} from "vue"
import ApiService from "@/services/ApiService";
import { toast } from "vue3-toastify";
import {BRow} from "bootstrap-vue-next";
import ApiServiece from "@/services/ApiService";

const defaultFormState = {
title: null,
@@ -16,10 +17,14 @@
productId: {
type: Number,
required: true,
}
},
product: {
type: Object,
required: true,
},
})

const emit = defineEmits(["changeLng", "data"]);
const emit = defineEmits(["changeLng", "data", "update:productRow"]);

const form = reactive({ ...defaultFormState });

@@ -27,6 +32,34 @@

const loading = ref(false)

const loadingDelete = ref(false)

const productRowModel = computed({
get: () => props.product,
set: (newValue) => emit('update:productRow', newValue)
});

const findLocaleTranslation = computed(() => {
const foundTranslation = props.product?.translations?.find(
item => item?.locale === form.locale
);
if (foundTranslation) {
switch (foundTranslation?.locale) {
case "en":
return "انگلیسی";
case "fa":
return "فارسی";
case "ar":
return "عربی";
default:
return null;
}
}

return null;
});

const clearError = (field) => {
errors.value[field] = "";
};
@@ -53,11 +86,50 @@
}
}

const handlerRemoveTranslation = async () => {
const findLocale = props.product?.translations?.find(item => item?.locale === form.locale);

if (findLocale) {
try {
loadingDelete.value = true;

const { data: { success, message, data } } = await ApiServiece.delete(
`admin/products/${props.product?.id}/translations/${findLocale?.id}`
)

if (success) {
const updatedCategory = props.product

updatedCategory.translations = data?.translations

productRowModel.value = updatedCategory

Object.assign(form, defaultFormState)

toast.success(message)
}
} catch (e) {
toast.error(e?.response?.data?.message)
}finally {
loadingDelete.value = false
}
}
}

defineExpose({ form })
</script>

<template>
<div class="p-2">
<BButton
:disabled="!findLocaleTranslation"
:loading="loadingDelete"
@click="handlerRemoveTranslation"
class="btn btn-sm rounded btn-danger d-block mt-2"
style="margin-right: auto"
>
حذف ترجمه {{ findLocaleTranslation }}
</BButton>
<BRow class="g-3">
<BCol md="6">
<div class="form-group">


+ 1
- 1
src/components/customSidebar.vue Целия файл

@@ -44,7 +44,7 @@ export default {
if (result.isConfirmed) {
await store.dispatch("user/logout");

router.push({ name: "otpLogin" });
router.push({ name: "login-v2" });
console.log("User logged out successfully.");
}
} catch (error) {


+ 2
- 1
src/components/modals/Brands/addBrand.vue Целия файл

@@ -18,6 +18,7 @@
class="btn-close"
data-bs-dismiss="modal"
aria-label="Close"
@click="step = 1"
></button>
</div>
<div class="modal-body">
@@ -163,6 +164,7 @@
class="btn btn-secondary"
data-bs-dismiss="modal"
id="close"
@click="step = 1"
>
بستن
</button>
@@ -296,7 +298,6 @@ export default {
}, 500);
})
.catch((error) => {
console.error(error);
toast.error(`${error.response.data.message}`, {
position: "top-right",
autoClose: 1000,


+ 22
- 12
src/components/modals/Brands/editBrand.vue Целия файл

@@ -338,14 +338,19 @@ export default {
);

if (data?.success) {
const updatedBrands = brandRowModel.value ? {...brandRowModel.value} : null;

if (updatedBrands) {
updatedBrands.translations = [...(updatedBrands.translations || []), data?.data];

brandRowModel.value = updatedBrands;
const updatedCategory = brandRowModel.value;

if (existingTranslation) {
updatedCategory.translations = data?.data?.translations || [];
} else {
updatedCategory.translations = [
...(updatedCategory.translations || []),
...(data?.data?.translations || [])
];
}

brandRowModel.value = updatedCategory;

toast.success(data?.message)

setTimeout(() => {
@@ -405,14 +410,19 @@ export default {
)

if (success) {
const updatedBrands = brandRowModel.value ? {...brandRowModel.value} : null;

if (updatedBrands) {
updatedBrands.translations = [...(updatedBrands.translations || []), data];

brandRowModel.value = updatedBrands;
const updatedBrand = brandRowModel.value;

if (findLocale) {
updatedBrand.translations = data?.translations || [];
} else {
updatedBrand.translations = [
...(updatedBrand.translations || []),
...(data?.translations || [])
];
}

brandRowModel.value = updatedBrand;

localTitle.value = null

localDesc.value = null


+ 10
- 7
src/components/modals/attribute-value/addAttributeValue.vue Целия файл

@@ -123,6 +123,7 @@ getAttributes()
class="btn-close"
data-bs-dismiss="modal"
aria-label="Close"
@click="step = 1"
></button>
</div>

@@ -195,6 +196,7 @@ getAttributes()
class="btn btn-secondary"
data-bs-dismiss="modal"
id="close"
@click="step = 1"
>
بستن
</button>
@@ -269,20 +271,21 @@ getAttributes()
style="margin-top: 20px"
>
<button
type="button"
class="btn btn-secondary"
data-bs-dismiss="modal"
id="close"
@click="step = 1"
>
بستن
</button>

<button type="submit" class="btn btn-primary" :disabled="loadingAttr">
<span
v-if="loadingAttr"
class="spinner-border spinner-border-sm"
role="status"
aria-hidden="true"
/>
<span
v-if="loadingAttr"
class="spinner-border spinner-border-sm"
role="status"
aria-hidden="true"
/>
ذخیره
</button>
</div>


+ 4
- 22
src/components/modals/attribute-value/editAttributeValue.vue Целия файл

@@ -159,11 +159,11 @@ const handlerRemoveTranslation = async () => {
const updatedCategory = props.attrRow;

if (findLocale) {
updatedCategory.translations = data?.data?.translations || [];
updatedCategory.translations = data?.translations || [];
} else {
updatedCategory.translations = [
...(updatedCategory.translations || []),
...(data?.data?.translations || [])
...(updatedCategory?.translations || []),
...(data?.translations || [])
];
}

@@ -184,25 +184,6 @@ const handlerRemoveTranslation = async () => {
const clearError = (field) => {
errors.value[field] = "";
}

// const handlerSubmitColor = async () => {
// try {
// loading.value = true
//
// const { data: { message, success } } = await ApiService.put(
// `admin/attribute-values/${attrRowModel.value?.id}`, {
// code: colorCode.value,
// })
//
// if (success) {
// toast.success(message)
// }
// } catch (e) {
// toast.error(e?.response?.data?.message)
// } finally {
// loading.value = false
// }
// }
</script>

<template>
@@ -298,6 +279,7 @@ const clearError = (field) => {
style="margin-top: 20px"
>
<button
type="button"
class="btn btn-secondary"
data-bs-dismiss="modal"
id="close"


+ 13
- 6
src/components/modals/attribute/addAttribute.vue Целия файл

@@ -60,6 +60,7 @@
class="btn btn-secondary"
data-bs-dismiss="modal"
id="close"
@click="step = 1"
>
بستن
</button>
@@ -134,20 +135,22 @@
style="margin-top: 20px"
>
<button
type="button"
class="btn btn-secondary"
data-bs-dismiss="modal"
id="close"
@click="step = 1"
>
بستن
</button>

<button type="submit" class="btn btn-primary" :disabled="loadingAttr">
<span
v-if="loadingAttr"
class="spinner-border spinner-border-sm"
role="status"
aria-hidden="true"
/>
<span
v-if="loadingAttr"
class="spinner-border spinner-border-sm"
role="status"
aria-hidden="true"
/>
ذخیره
</button>
</div>
@@ -255,6 +258,9 @@ export default {
if (success) {
toast.success(message)
//document.getElementById("close").click();

attrName.value = undefined;

emit("attribute-updated");
}
} catch (e) {
@@ -276,6 +282,7 @@ export default {
}
}


getAttributes()

return {


+ 39
- 14
src/components/modals/attribute/editAttribute.vue Целия файл

@@ -10,7 +10,7 @@
<div class="modal-dialog modal-sm" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">ویرایش رنگ</h5>
<h5 class="modal-title" id="exampleModalLabel">ویرایش ویژگی</h5>
<button
type="button"
class="btn-close"
@@ -44,6 +44,7 @@
style="margin-top: 20px"
>
<button
type="button"
class="btn btn-secondary"
data-bs-dismiss="modal"
id="close"
@@ -51,9 +52,9 @@
بستن
</button>

<button @click="handlerSubmitCategory" class="btn btn-primary" :disabled="loading">
<button @click="handlerSubmitAttribute" class="btn btn-primary" :disabled="loadingAttr">
<span
v-if="loading"
v-if="loadingAttr"
class="spinner-border spinner-border-sm"
role="status"
aria-hidden="true"
@@ -133,6 +134,7 @@
style="margin-top: 20px"
>
<button
type="button"
class="btn btn-secondary"
data-bs-dismiss="modal"
id="close"
@@ -141,12 +143,12 @@
</button>

<button type="submit" class="btn btn-primary" :disabled="loading">
<span
v-if="loading"
class="spinner-border spinner-border-sm"
role="status"
aria-hidden="true"
/>
<span
v-if="loading"
class="spinner-border spinner-border-sm"
role="status"
aria-hidden="true"
/>
ذخیره
</button>
</div>
@@ -200,6 +202,7 @@ export default {
const categories = ref([]);
const locale = ref('fa');
const loadingDelete = ref(false);
const loadingAttr = ref(false);

const attrRowModel = computed({
get: () => props.attrRow,
@@ -304,11 +307,9 @@ export default {

attrRowModel.value = updatedCategory;

console.log(attrRowModel.value,'attrRowModel.value')

toast.success(data?.message)

emit("cat-updated");
emit("attribute-updated");
}

} catch (error) {
@@ -337,11 +338,11 @@ export default {
const updatedCategory = props.attrRow;

if (findLocale) {
updatedCategory.translations = data?.data?.translations || [];
updatedCategory.translations = data?.translations || [];
} else {
updatedCategory.translations = [
...(updatedCategory.translations || []),
...(data?.data?.translations || [])
...(data?.translations || [])
];
}

@@ -381,6 +382,28 @@ export default {
}
}

const handlerSubmitAttribute = async () => {
try {
loadingAttr.value = true;

const params = {
category_id: categoryId.value,
}

const { data: { success, message } } = await ApiServiece.put(`admin/attributes/${props.attrRow?.id}`, params)

if (success) {
toast.success(message)

emit("attribute-updated");
}
} catch (e) {
toast.error(e?.response?.data?.message)
} finally {
loadingAttr.value = false;
}
}

getAttributes()

return {
@@ -399,6 +422,8 @@ export default {
findLocaleTranslation,
handlerRemoveTranslation,
loadingDelete,
handlerSubmitAttribute,
loadingAttr,
};
},
};


+ 4
- 1
src/components/modals/blogCat/addBlogCat.vue Целия файл

@@ -4,8 +4,10 @@
id="addBlogCat"
tabindex="-1"
role="dialog"
aria-labelledby="exampleModalLabel"
aria-hidden="true"
data-bs-backdrop="static"
aria-labelledby="staticBackdropLabel"
data-bs-keyboard="false"
>
<div class="modal-dialog modal-sm" role="document">
<div class="modal-content">
@@ -18,6 +20,7 @@
class="btn-close"
data-bs-dismiss="modal"
aria-label="Close"
@click="step = 1"
></button>
</div>
<div class="modal-body">


+ 13
- 7
src/components/modals/blogCat/editBlogCat.vue Целия файл

@@ -209,13 +209,18 @@ export default {
}
);

console.log(data,'data data data')
if (data?.success) {
const updatedCategory = props.catRow

toast.success("!دسته با موفقیت ویرایش شد", {
position: "top-right",
autoClose: 1000,
});
updatedCategory.translations = data?.data?.translations

categoryRowModel.value = updatedCategory

toast.success(data?.message, {
position: "top-right",
autoClose: 1000,
});
}
} catch (e) {
toast.error(`${e?.response?.data?.message}`, {
position: "top-right",
@@ -273,10 +278,10 @@ export default {

updatedCategory.translations = data?.translations

titleCat.value = null

categoryRowModel.value = updatedCategory

titleCat.value = null

toast.success(message)
}
} catch (e) {
@@ -298,6 +303,7 @@ export default {
handlerChangeLocale,
findLocaleTranslation,
handlerRemoveTranslation,
loadingDelete,
};
},
};


+ 8
- 9
src/components/modals/categories/addCat.vue Целия файл

@@ -4,10 +4,12 @@
id="addCat"
tabindex="-1"
role="dialog"
aria-labelledby="exampleModalLabel"
aria-hidden="true"
data-bs-backdrop="static"
aria-labelledby="staticBackdropLabel"
data-bs-keyboard="false"
>
<div class="modal-dialog modal-sm" role="document">
<div class="modal-dialog modal-sm" role="document" >
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">
@@ -18,6 +20,7 @@
class="btn-close"
data-bs-dismiss="modal"
aria-label="Close"
@click="step = 1"
></button>
</div>
<div class="modal-body">
@@ -153,13 +156,6 @@
class="d-flex justify-content-between gap-2"
style="margin-top: 20px"
>
<button
class="btn btn-secondary"
@click="step--"
>
قبلی
</button>

<button type="submit" class="btn btn-primary" :disabled="loading">
<span
v-if="loading"
@@ -287,6 +283,9 @@ export default {
try {
loadingStep.value = true;

if (selectedPaernt.value.trim() === '')
selectedPaernt.value = undefined

const { data: { success, data, message } } = await ApiServiece.post(`admin/categories`, {
parent_id: selectedPaernt.value
}, {


+ 4
- 1
src/components/modals/categories/editCat.vue Целия файл

@@ -63,7 +63,6 @@
</BTab>
<BTab title="ترجمه ها">
<form @submit.prevent="editCat" class="mt-4">

<BButton
:disabled="!findLocaleTranslation"
:loading="loadingDelete"
@@ -385,6 +384,10 @@ export default {

categoryRowModel.value = updatedCategory

title.value = ""

description.value = ""

toast.success(message)
}
} catch (e) {


+ 1
- 1
src/router/index.js Целия файл

@@ -4,7 +4,7 @@ import appConfig from "../../app.config";
//import store from "../state/store";

const router = createRouter({
history: createWebHistory("/"),
history: createWebHistory("/panel"),
routes,
});



+ 2
- 2
src/services/ApiService.js Целия файл

@@ -1,7 +1,7 @@
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({
baseURL: url,
@@ -30,7 +30,7 @@ ApiServiece.interceptors.response.use(
},
(error) => {
if (error?.status === 401) {
router.push({ name: "otpLogin" });
router.push({ name: "login-v2" });
}
return Promise.reject(error);
}


+ 3
- 3
src/views/live-preview/pages/attributes-value/attributes-value.vue Целия файл

@@ -130,11 +130,11 @@ export default {

const deleteAttribute = (id, title) => {
Swal.fire({
text: `می خواهید رنگ ${title ?? ''} را حذف کنید ؟`,
text: `می خواهید ${title ?? ''} را حذف کنید ؟`,
icon: "warning",
showCancelButton: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
confirmButtonColor: "#d33",
cancelButtonColor: "red",
confirmButtonText: "بله!",
cancelButtonText: "خیر",
}).then((result) => {


+ 0
- 8
src/views/live-preview/pages/auth2/login.vue Целия файл

@@ -8,14 +8,6 @@
<div class="text-center mb-4">
<img :src="logo" alt="Logo" class="styled-logo" />
</div>
<h4 class="f-w-500 mb-1">ورود با شماره موبایل</h4>

<p class="mb-3">
یا
<router-link to="/otpLogin" class="link-primary">
ورود با کد یکبار مصرف
</router-link>
</p>
<div class="mb-3">
<input
@input="clearError('mobile')"


+ 15
- 9
src/views/live-preview/pages/banners/editBanner.vue Целия файл

@@ -491,11 +491,11 @@ export default {
const locale = ref('fa')

const handleSearch = async (searchTerm) => {
if (searchTerm.length < 3) return;
if (searchTerm?.length < 3) return;
categorySelectorLoader.value = true;
try {
const response = await ApiServiece.get(
`admin/categories?title=${searchTerm}`
`admin/categories?title=${searchTerm ?? ''}`
);
cats.value = response.data.data;
categorySelectorLoader.value = false;
@@ -516,19 +516,19 @@ export default {

const formattedProducts = computed(() =>
Array.isArray(products.value)
? products.value.map((product) => ({
value: product.id,
label: product.title,
? products.value?.map((product) => ({
value: product?.id,
label: product?.translation?.title || 'بدون عنوان',
}))
: []
);

const handleProductSearch = async (searchTerm) => {
if (searchTerm.length < 3) return;
if (searchTerm?.length < 3) return;
productSelectorLoader.value = true;
try {
const response = await ApiServiece.get(
`admin/products?title=${searchTerm}`
`admin/products?title=${searchTerm ?? ''}`
);
products.value = response.data.data;
productSelectorLoader.value = false;
@@ -572,11 +572,11 @@ export default {
);

const handleBrandSearch = async (searchTerm) => {
if (searchTerm.length < 3) return;
if (searchTerm?.length < 3) return;
brandSelectorLoader.value = true;
try {
const response = await ApiServiece.get(
`admin/brands?title=${searchTerm}`
`admin/brands?title=${searchTerm ?? ''}`
);
brands.value = response.data.data;
brandSelectorLoader.value = false;
@@ -682,6 +682,12 @@ export default {

onMounted(() => {
getBanner();

handleProductSearch()

handleSearch()

handleBrandSearch()
});

const submitForm = () => {


+ 3
- 3
src/views/live-preview/pages/blogCats/blogCat.vue Целия файл

@@ -124,7 +124,7 @@ export default {
};
const deleteCat = (id, title) => {
Swal.fire({
title: `می خواهید دسته ${title} را حذف کنید ؟`,
title: `می خواهید دسته ${title ?? ''} را حذف کنید ؟`,
icon: "warning",
showCancelButton: true,
confirmButtonColor: "#3085d6",
@@ -230,7 +230,7 @@ export default {
<tr v-for="cat in cats" :key="cat.id">
<td>{{ cat?.translation?.title }}</td>

<td>{{ convertToJalali(cat.created_at) }}</td>
<td>{{ convertToJalali(cat?.created_at) }}</td>

<td>
<button
@@ -242,7 +242,7 @@ export default {
ویرایش
</button>
<button
@click="deleteCat(cat.id, cat.title)"
@click="deleteCat(cat.id, cat?.translation?.title)"
class="btn btn-sm btn-outline-danger"
>
حذف


+ 18
- 8
src/views/live-preview/pages/blogs/addBlog.vue Целия файл

@@ -206,12 +206,12 @@
class="d-flex justify-content-between gap-2"
style="margin-top: 20px"
>
<button
class="btn btn-secondary"
@click="step--"
>
قبلی
</button>
<!-- <button-->
<!-- class="btn btn-secondary"-->
<!-- @click="step&#45;&#45;"-->
<!-- >-->
<!-- قبلی-->
<!-- </button>-->

<button type="submit" class="btn btn-primary" :disabled="loading">
<span
@@ -272,6 +272,7 @@ export default {
const step = ref(1)
const blogCategoryId = ref(null)
const locale = ref('fa')
const quillInstance = ref()

const handleSearch = async (searchTerm) => {
if (searchTerm.length < 3) return;
@@ -371,11 +372,17 @@ export default {
position: "top-right",
autoClose: 1000,
});

title.value = ""

slug.value = ""

summary.value = ""
editorContent.value = ""

quillInstance.value.root.innerHTML = ""

author.value = ""

locale.value = "fa"
})

@@ -445,6 +452,8 @@ export default {
},
});

quillInstance.value = quill

quill.root.setAttribute("dir", "rtl");

quill.format("direction", "rtl");
@@ -487,7 +496,8 @@ export default {
formattedCategories,
handlerAddCategory,
blogCategoryId,
locale
locale,
quillInstance
};
},
};


+ 14
- 1
src/views/live-preview/pages/blogs/editBlog.vue Целия файл

@@ -437,6 +437,13 @@ export default {

blog.value = updatedCategory;

// title.value = ""
// slug.value = ""
// quillInstance.value.root.innerHTML = ""
// author.value = ""
// summary.value = ""
// locale.value = "fa"

toast.success(resp?.data?.message, {
position: "top-right",
autoClose: 1000,
@@ -480,7 +487,7 @@ export default {

author.value = undefined;

quillInstance.value.root.innerHTML = undefined
quillInstance.value.root.innerHTML = ""
}
}

@@ -538,6 +545,12 @@ export default {

blog.value = updatedCategory

title.value = ""
slug.value = ""
summary.value = ""
quillInstance.value.root.innerHTML = ""
author.value = ""

toast.success(message)
}
} catch (e) {


+ 1
- 25
src/views/live-preview/pages/countries/countries.vue Целия файл

@@ -45,6 +45,7 @@ export default {
params: {
paginate: paginate.value,
page: currentPage.value,
title: searchQuery.value,
}
})

@@ -256,31 +257,6 @@ export default {
class="form-control form-control-sm d-inline-block me-2"
style="width: 250px; border-radius: 15px"
/>

<!-- User Role Selector -->
<select
class="form-select form-select-sm"
v-model="selectedRole"
style="width: 120px; border-radius: 15px"
>
<option value="" disabled selected>نقش کاربر</option>
<option value="">همه</option>
<option value="admin">فقط مدیران</option>
<option value="client">فقط مشتریان</option>
<option value="operator">فقط اپراتورها</option>
</select>

<select
class="form-select form-select-sm"
v-model="selectedStatus"
style="width: 120px; border-radius: 15px"
>
<option value="" disabled selected>وضعیت</option>
<option value="">همه</option>
<option value="0">فعال</option>
<option value="1">بلاک</option>
</select>
<!-- Add User Button -->
</div>
<button
v-if="userProfile?.role === 'admin'"


+ 4
- 5
src/views/live-preview/pages/discounts/discounts.vue Целия файл

@@ -166,8 +166,8 @@ export default {
const formattedCategories = computed(() =>
Array.isArray(categories.value)
? categories.value.map((category) => ({
value: category.id,
label: category.title,
value: category?.id,
label: category?.translation?.title || '',
}))
: []
);
@@ -181,7 +181,6 @@ export default {
);
products.value = response.data.data;
} catch (error) {
console.error("Error fetching products:", error);
products.value = [];
}
};
@@ -189,8 +188,8 @@ export default {
const formattedProducts = computed(() =>
Array.isArray(products.value)
? products.value.map((product) => ({
value: product.id,
label: product.title,
value: product?.id,
label: product?.translation?.title,
}))
: []
);


+ 11
- 19
src/views/live-preview/pages/products/addProduct.vue Целия файл

@@ -260,25 +260,16 @@
</BRow>

<div class="d-flex justify-content-between align-items-center mt-4">
<div class="d-flex gap-3">
<button
@click="step--"
class="btn btn-outline btn-primary rounded-pill px-5 py-3"
>
مرحله قبل
</button>

<button
@click="addImage"
class="btn btn-primary rounded-pill px-5 py-3"
style="
<button
@click="addImage"
class="btn btn-primary rounded-pill px-5 py-3"
style="
font-size: 16px;
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
"
>
<i class="fa fa-plus-circle me-2"></i> افزودن عکس جدید
</button>
</div>
>
<i class="fa fa-plus-circle me-2"></i> افزودن عکس جدید
</button>

<button
@click="step++"
@@ -296,7 +287,7 @@
@next-step="step++"
/>

<div class="d-flex justify-content-between">
<div class="d-flex justify-content-between mt-5">
<button class="btn btn-primary" @click="step--">مرحله قبلی</button>
<button class="btn btn-primary" @click="step++">مرحله بعد</button>
</div>
@@ -452,11 +443,11 @@ export default {
};

const handleBrandSearch = async (searchTerm) => {
if (searchTerm.length < 3) return;
if (searchTerm?.length < 3) return;
brandSelectorLoader.value = true;
try {
const response = await ApiServiece.get(
`admin/brands?title=${searchTerm}`
`admin/brands?title=${searchTerm ?? ''}`
);
brands.value = response.data.data;
brandSelectorLoader.value = false;
@@ -661,6 +652,7 @@ export default {
// });
//getAttrebuteValues();
getAttributeValues();
handleBrandSearch();
});

const submitForm = () => {


+ 8
- 7
src/views/live-preview/pages/products/editProduct.vue Целия файл

@@ -284,10 +284,10 @@
<ProductInfo
ref="productInfo"
:product-id="productId"
:product="product"
@previousStep="step--"
@changeLng="handleChangeLanguage"
@data="(data) => product = data"
class="mt-5"
/>
</BTab>
</BTabs>
@@ -376,6 +376,7 @@ export default {
const description = ref(null);
const step = ref(1);
const product = ref(null);
const loadingDelete = ref(false);
const route = useRoute()


@@ -412,11 +413,11 @@ export default {
};

const handleBrandSearch = async (searchTerm) => {
if (searchTerm.length < 3) return;
if (searchTerm?.length < 3) return;
brandSelectorLoader.value = true;
try {
const response = await ApiServiece.get(
`admin/brands?title=${searchTerm}`
`admin/brands?title=${searchTerm ?? ''}`
);
brands.value = response.data.data;
brandSelectorLoader.value = false;
@@ -719,7 +720,7 @@ export default {
const handleChangeLanguage = (lang) => {
const translation = product.value.translations?.find(item => item?.locale === lang);

Object.assign(productInfo.value.form, {
Object.assign(productInfo.value?.form, {
id: translation?.id ?? undefined,
title: translation?.title ?? undefined,
slug: translation?.slug ?? undefined,
@@ -733,6 +734,7 @@ export default {
getProduct()
getAttributeValues();
handleSearch()
handleBrandSearch()
});

watch(categoryId, async (newCategoryId) => {
@@ -744,8 +746,6 @@ export default {
id: spec.id,
}))

//attributesProductRef.value.selectedAttributes = product.value?.product_attributes?.map(item => item.attribute_id)

const uniqueAttributes = product.value?.product_attributes?.filter(
(item, index, self) =>
index === self.findIndex(t => t.attribute_id === item.attribute_id)
@@ -841,7 +841,8 @@ export default {
handleChangeLanguage,
specificationsProductRef,
loadingProduct,
attributesProductRef
attributesProductRef,
loadingDelete
};
},
};


+ 7
- 8
src/views/live-preview/pages/products/products.vue Целия файл

@@ -57,20 +57,19 @@ export default {

const getProducts = () => {
filterLoading.value = true;
let isSpecial = 0;
let isChosen = 0;
let isSpecial;
if (selectedProductType.value === "special") {
isSpecial = 1;
}
if (selectedProductType.value === "chosen") {
isChosen = 1;
isSpecial = 2;
}
ApiServiece.get(
`admin/products?title=${searchQuery.value || ""}&category_id=${
selectedcategory.value || ""
}&brand_id=${
selectedBrand.value || ""
}&is_chosen=${isChosen}&is_special=${isSpecial}&paginate=${
}&discount_type=${isSpecial || ''}&paginate=${
paginate.value || 10
}&page=${page.value || 1}`
)
@@ -232,8 +231,8 @@ export default {
const formattedCategories = computed(() =>
Array.isArray(categories.value)
? categories.value.map((category) => ({
value: category.id,
label: category.title,
value: category?.id,
label: category?.translation?.title || "",
}))
: []
);
@@ -256,8 +255,8 @@ export default {
const formattedBrands = computed(() =>
Array.isArray(brands.value)
? brands.value.map((brand) => ({
value: brand.id,
label: brand.title,
value: brand?.id,
label: brand?.translation?.title || '',
}))
: []
);


+ 0
- 1
src/views/live-preview/pages/users/users.vue Целия файл

@@ -270,7 +270,6 @@ export default {
<option value="" disabled selected>نقش کاربر</option>
<option value="">همه</option>
<option value="admin">فقط مدیران</option>
<option value="client">فقط مشتریان</option>
<option value="operator">فقط اپراتورها</option>
</select>



+ 1
- 1
vue.config.js Целия файл

@@ -1,7 +1,7 @@
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
publicPath: "/",
publicPath: "/panel",
chainWebpack: (config) => {
config.plugin('define').tap((definitions) => {
Object.assign(definitions[0], {


Зареждане…
Отказ
Запис