Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 

452 rader
12 KiB

  1. <script>
  2. import Layout from "@/layout/custom.vue";
  3. import ApiServiece from "@/services/ApiService";
  4. import moment from "jalali-moment";
  5. import { onMounted, ref, watch, computed } from "vue";
  6. import { toast } from "vue3-toastify";
  7. import "vue3-toastify/dist/index.css";
  8. import Swal from "sweetalert2";
  9. import addIdentity from "@/components/modals/identity/addIdentity.vue";
  10. import editIdentity from "@/components/modals/identity/editIdentity.vue";
  11. export default {
  12. name: "BORDER",
  13. components: {
  14. Layout,
  15. addIdentity,
  16. editIdentity,
  17. },
  18. setup() {
  19. const cats = ref([]);
  20. const searchPage = ref();
  21. const currentPage = ref(1);
  22. const totalPages = ref(1);
  23. const paginate = ref(20);
  24. const page = ref(1);
  25. const attributeValues = ref();
  26. const filterLoading = ref(false);
  27. const searchQuery = ref("");
  28. const attributes = ref();
  29. const attributeTitle = ref();
  30. const attributeId = ref();
  31. const attrebuteCat = ref();
  32. const convertToJalali = (date) => {
  33. return moment(date, "YYYY-MM-DD HH:mm:ss")
  34. .locale("fa")
  35. .format("YYYY/MM/DD");
  36. };
  37. watch(searchQuery, () => {
  38. getAttributes();
  39. });
  40. const getAttributes = () => {
  41. filterLoading.value = true;
  42. ApiServiece.get(
  43. `admin/attributes?title=${searchQuery.value || ""}
  44. &paginate=${paginate.value || 10}&page=${page.value || 1}
  45. `
  46. )
  47. .then((resp) => {
  48. filterLoading.value = false;
  49. console.log(resp.data);
  50. attributes.value = resp.data.data.data;
  51. currentPage.value = resp.data.data.current_page;
  52. totalPages.value = resp.data.data.last_page;
  53. console.log(attributes.value);
  54. })
  55. .catch(() => {
  56. filterLoading.value = false;
  57. });
  58. };
  59. const getCategories = () => {
  60. ApiServiece.get("admin/categories").then((resp) => {
  61. console.log(resp.data.data);
  62. cats.value = resp.data.data;
  63. });
  64. };
  65. const handleAttributeUpdated = () => {
  66. getAttributes();
  67. };
  68. const nextPage = () => {
  69. if (currentPage.value < totalPages.value) {
  70. page.value++;
  71. getAttributes();
  72. }
  73. };
  74. const prevPage = () => {
  75. if (currentPage.value > 1) {
  76. page.value--;
  77. getAttributes();
  78. }
  79. };
  80. function handlePageInput() {
  81. if (searchPage.value < 1) {
  82. searchPage.value = 1;
  83. } else if (searchPage.value > totalPages.value) {
  84. searchPage.value = totalPages.value;
  85. }
  86. if (searchPage.value >= 1 && searchPage.value <= totalPages.value) {
  87. page.value = searchPage.value;
  88. }
  89. }
  90. const visiblePages = computed(() => {
  91. const pages = [];
  92. if (totalPages.value <= 5) {
  93. for (let i = 1; i <= totalPages.value; i++) {
  94. pages.push(i);
  95. }
  96. } else {
  97. let start = currentPage.value - 2;
  98. let end = currentPage.value + 2;
  99. if (start < 1) start = 1;
  100. if (end > totalPages.value) end = totalPages.value;
  101. for (let i = start; i <= end; i++) {
  102. pages.push(i);
  103. }
  104. }
  105. return pages;
  106. });
  107. watch(page, () => {
  108. getAttributes();
  109. });
  110. const deleteAttribute = (id, title) => {
  111. Swal.fire({
  112. text: `می خواهید ویژگی ${title} را حذف کنید؟`,
  113. icon: "warning",
  114. showCancelButton: true,
  115. confirmButtonColor: "#3085d6",
  116. cancelButtonColor: "#d33",
  117. confirmButtonText: "بله!",
  118. cancelButtonText: "خیر",
  119. }).then((result) => {
  120. if (result.isConfirmed) {
  121. ApiServiece.delete(`admin/attribute-values/${id}`)
  122. .then(() => {
  123. toast.success("!ویژگی با موفقیت حذف شد", {
  124. position: "top-right",
  125. autoClose: 3000,
  126. });
  127. attributes.value = attributes.value.filter(
  128. (attribute) => attribute.id !== id
  129. );
  130. })
  131. .catch((err) => {
  132. console.log(err);
  133. toast.error("!مشکلی در حذف کردن ویژگی پیش آمد", {
  134. position: "top-right",
  135. autoClose: 3000,
  136. });
  137. });
  138. }
  139. });
  140. };
  141. const editModalData = (id, title, cat) => {
  142. attributeId.value = id;
  143. attributeTitle.value = title;
  144. attrebuteCat.value = cat;
  145. };
  146. watch(searchQuery, () => {
  147. getAttributes();
  148. });
  149. onMounted(() => {
  150. getAttributes();
  151. getCategories();
  152. });
  153. return {
  154. attributes,
  155. convertToJalali,
  156. handleAttributeUpdated,
  157. editModalData,
  158. deleteAttribute,
  159. searchQuery,
  160. filterLoading,
  161. attributeId,
  162. attrebuteCat,
  163. attributeTitle,
  164. attributeValues,
  165. searchPage,
  166. currentPage,
  167. totalPages,
  168. paginate,
  169. page,
  170. prevPage,
  171. nextPage,
  172. handlePageInput,
  173. visiblePages,
  174. getCategories,
  175. cats,
  176. };
  177. },
  178. };
  179. </script>
  180. <template>
  181. <Layout>
  182. <BRow>
  183. <div class="col-md-12">
  184. <div class="card shadow-sm border-0 rounded">
  185. <div
  186. class="card-header d-flex justify-content-between align-items-center p-3 "
  187. dir="rtl"
  188. >
  189. <div class="d-flex align-items-center">
  190. <input
  191. v-model="searchQuery"
  192. type="text"
  193. placeholder="جستجو..."
  194. class="form-control form-control-sm d-inline-block me-2"
  195. style="width: 250px; border-radius: 15px"
  196. />
  197. <button
  198. data-bs-toggle="modal"
  199. data-bs-target="#addIdentity"
  200. class="btn btn-light text-primary btn-sm px-3"
  201. >
  202. افزودن مشخصه
  203. </button>
  204. </div>
  205. </div>
  206. <div v-if="!filterLoading" class="card-body table-border-style p-0">
  207. <div class="table-responsive">
  208. <table class="table table-hover table-bordered m-0" dir="rtl">
  209. <thead class="table-light">
  210. <tr>
  211. <th>نام</th>
  212. <th>دسته</th>
  213. <th>تاریخ ایجاد</th>
  214. <th>عملیات</th>
  215. </tr>
  216. </thead>
  217. <tbody>
  218. <tr v-for="attribute in attributes" :key="attribute.id">
  219. <td>{{ attribute.title }}</td>
  220. <td
  221. :style="{
  222. backgroundColor: attribute.code,
  223. textAlign: 'center',
  224. }"
  225. ></td>
  226. <td>{{ convertToJalali(attribute?.created_at) }}</td>
  227. <td>
  228. <button
  229. @click="
  230. editModalData(
  231. attribute?.id,
  232. attribute?.title,
  233. attribute.category_id
  234. )
  235. "
  236. data-bs-toggle="modal"
  237. data-bs-target="#editIdentity"
  238. class="btn btn-sm btn-outline-warning me-1"
  239. >
  240. ویرایش
  241. </button>
  242. <button
  243. @click="deleteAttribute(attribute.id, attribute.title)"
  244. class="btn btn-sm btn-outline-danger"
  245. :disabled="attribute.id == 1"
  246. >
  247. حذف
  248. </button>
  249. </td>
  250. </tr>
  251. </tbody>
  252. </table>
  253. </div>
  254. </div>
  255. <div
  256. v-else
  257. class="filter-loader card table-card user-profile-list"
  258. ></div>
  259. </div>
  260. </div>
  261. <addIdentity @attribute-updated="handleAttributeUpdated()" :cats="cats" />
  262. <editIdentity
  263. @attribute-updated="handleAttributeUpdated()"
  264. :title="attributeTitle"
  265. :catId="attrebuteCat"
  266. :id="attributeId"
  267. :cats="cats"
  268. />
  269. </BRow>
  270. <BRow>
  271. <BCol sm="12">
  272. <div class="d-flex justify-content-center">
  273. <nav aria-label="Page navigation">
  274. <ul class="pagination">
  275. <li class="page-item" :class="{ disabled: currentPage === 1 }">
  276. <span class="page-link" @click="prevPage">قبلی</span>
  277. </li>
  278. <li v-if="currentPage > 2" class="page-item" @click="page = 1">
  279. <a class="page-link" href="javascript:void(0)">1</a>
  280. </li>
  281. <li v-if="currentPage > 3" class="page-item" disabled>
  282. <span class="page-link">...</span>
  283. </li>
  284. <li
  285. v-for="n in visiblePages"
  286. :key="n"
  287. class="page-item"
  288. :class="{ active: currentPage === n }"
  289. >
  290. <a
  291. class="page-link"
  292. href="javascript:void(0)"
  293. @click="page = n"
  294. >
  295. {{ n }}
  296. </a>
  297. </li>
  298. <li
  299. v-if="currentPage < totalPages - 2"
  300. class="page-item"
  301. disabled
  302. >
  303. <span class="page-link">...</span>
  304. </li>
  305. <li
  306. v-if="currentPage < totalPages - 1"
  307. class="page-item"
  308. @click="page = totalPages"
  309. >
  310. <a class="page-link" href="javascript:void(0)">{{
  311. totalPages
  312. }}</a>
  313. </li>
  314. <li
  315. class="page-item"
  316. :class="{ disabled: currentPage === totalPages }"
  317. >
  318. <span class="page-link" @click="nextPage">بعدی</span>
  319. </li>
  320. </ul>
  321. </nav>
  322. </div>
  323. </BCol>
  324. <BCol sm="4">
  325. <div class="ms-0 search-number">
  326. <input
  327. v-model="searchPage"
  328. type="text"
  329. class="form-control"
  330. placeholder="برو به صفحه"
  331. :max="totalPages"
  332. min="1"
  333. @input="handlePageInput"
  334. />
  335. </div>
  336. </BCol>
  337. </BRow>
  338. </Layout>
  339. </template>
  340. <style scoped>
  341. .card {
  342. transition: transform 0.3s ease;
  343. }
  344. .card:hover {
  345. transform: translateY(-3px);
  346. }
  347. .table th,
  348. .table td {
  349. vertical-align: middle;
  350. text-align: center;
  351. }
  352. .filter-loader {
  353. border: 4px solid rgba(0, 123, 255, 0.3);
  354. border-top: 4px solid #007bff;
  355. border-radius: 50%;
  356. width: 40px;
  357. height: 40px;
  358. animation: spin 1s linear infinite;
  359. margin: 20px auto;
  360. }
  361. .Brand-Image {
  362. width: 100px;
  363. height: 100px;
  364. object-fit: cover;
  365. border-radius: 8px;
  366. border: 1px solid #ddd;
  367. }
  368. .subject-box {
  369. padding: 8px 14px;
  370. background: linear-gradient(135deg, #fff3e0, #ffe0b2);
  371. color: #ef6c00;
  372. font-weight: 600;
  373. border-radius: 10px;
  374. box-shadow: 0px 2px 6px rgba(0, 0, 0, 0.1);
  375. display: inline-flex;
  376. align-items: center;
  377. gap: 8px;
  378. transition: transform 0.2s ease, box-shadow 0.2s ease;
  379. }
  380. .subject-box i {
  381. color: #ef6c00;
  382. font-size: 1rem;
  383. }
  384. .subject-box:hover {
  385. transform: translateY(-2px);
  386. box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.15);
  387. }
  388. .search-number {
  389. display: flex;
  390. align-items: center;
  391. }
  392. .search-number input {
  393. width: 150px;
  394. padding: 0.5rem;
  395. font-size: 1rem;
  396. border-radius: 0.375rem;
  397. margin-bottom: 7px;
  398. border: 1px solid #ced4da;
  399. transition: border-color 0.3s ease, box-shadow 0.3s ease;
  400. }
  401. .search-number input:focus {
  402. border-color: #007bff;
  403. box-shadow: 0 0 0 0.2rem rgba(38, 143, 255, 0.25);
  404. }
  405. .search-number input::placeholder {
  406. color: #6c757d;
  407. }
  408. .search-number input:disabled {
  409. background-color: #f8f9fa;
  410. cursor: not-allowed;
  411. }
  412. .pagination {
  413. display: flex;
  414. flex-wrap: wrap;
  415. gap: 5px;
  416. }
  417. .page-item {
  418. flex: 0 0 auto;
  419. }
  420. .page-link {
  421. cursor: pointer;
  422. user-select: none;
  423. }
  424. </style>