bug fix reported

This commit is contained in:
Hesabix 2025-05-26 01:49:14 +00:00
parent e269a26d50
commit 17af4bfaa9
8 changed files with 269 additions and 117 deletions

View file

@ -186,9 +186,38 @@ class ReportController extends AbstractController
} }
} }
$labels = [ $labels = [
'کد حسابداری' 'ردیف',
'کد کالا',
'نام کالا',
'واحد',
'تعداد',
'قیمت واحد',
'قیمت کل',
'تاریخ',
'شماره سند',
'نوع سند',
'خدمات'
]; ];
return new BinaryFileResponse($provider->createExcellFromArray($response));
// اضافه کردن شماره ردیف به داده‌ها
$responseWithRow = [];
foreach ($response as $index => $item) {
$responseWithRow[] = [
'row' => $index + 1,
'code' => $item['code'],
'name' => $item['name'],
'unit' => $item['unit'],
'count' => $item['count'],
'priceOne' => $item['priceOne'],
'priceAll' => $item['priceAll'],
'date' => $item['date'],
'docCode' => $item['docCode'],
'type' => $item['type'],
'khadamat' => $item['khadamat']
];
}
return new BinaryFileResponse($provider->createExcellFromArray($responseWithRow, $labels));
} }
#[Route('/api/report/commodity/buysell', name: 'app_report_commodity_buysell')] #[Route('/api/report/commodity/buysell', name: 'app_report_commodity_buysell')]

View file

@ -1219,14 +1219,16 @@ class SellController extends AbstractController
$itemDiscount = $row->getDiscount() ?? 0; $itemDiscount = $row->getDiscount() ?? 0;
$itemDiscountType = $row->getDiscountType() ?? 'fixed'; $itemDiscountType = $row->getDiscountType() ?? 'fixed';
$itemDiscountPercent = $row->getDiscountPercent() ?? 0; $itemDiscountPercent = $row->getDiscountPercent() ?? 0;
$itemTax = $row->getTax() ?? 0;
// محاسبه تخفیف سطری // محاسبه تخفیف سطری
if ($itemDiscountType === 'percent') { if ($itemDiscountType === 'percent') {
$itemDiscount = round(($basePrice * $itemDiscountPercent) / 100); $itemDiscount = round(($basePrice * $itemDiscountPercent) / 100);
} }
$itemTotal = $basePrice - $itemDiscount; // محاسبه قیمت خالص (بدون مالیات)
$totalInvoice += $itemTotal; $netPrice = $basePrice - $itemDiscount;
$totalInvoice += $netPrice;
$items[] = [ $items[] = [
'name' => [ 'name' => [
@ -1235,13 +1237,13 @@ class SellController extends AbstractController
'code' => $row->getCommodity()->getCode() 'code' => $row->getCommodity()->getCode()
], ],
'count' => $row->getCommdityCount(), 'count' => $row->getCommdityCount(),
'price' => $row->getCommdityCount() > 0 ? $basePrice / $row->getCommdityCount() : 0, 'price' => $row->getCommdityCount() > 0 ? $netPrice / $row->getCommdityCount() : 0,
'discountPercent' => $itemDiscountPercent, 'discountPercent' => $itemDiscountPercent,
'discountAmount' => $itemDiscount, 'discountAmount' => $itemDiscount,
'total' => $itemTotal, 'total' => $netPrice,
'description' => $row->getDes(), 'description' => $row->getDes(),
'showPercentDiscount' => $itemDiscountType === 'percent', 'showPercentDiscount' => $itemDiscountType === 'percent',
'tax' => $row->getTax() ?? 0 'tax' => $itemTax
]; ];
} }
} }

View file

@ -62,7 +62,7 @@ class CommodityRepository extends ServiceEntityRepository
{ {
return $this->createQueryBuilder('p') return $this->createQueryBuilder('p')
->where('p.bid = :val') ->where('p.bid = :val')
->andWhere("p.name LIKE :search OR p.barcodes LIKE :search") ->andWhere("p.name LIKE :search OR p.barcodes LIKE :search OR p.code LIKE :search")
->setParameter('val', $bid) ->setParameter('val', $bid)
->setParameter('search', '%' . $search . '%') ->setParameter('search', '%' . $search . '%')
->setMaxResults($maxResults) ->setMaxResults($maxResults)

View file

@ -3,10 +3,11 @@
v-model="inputValue" v-model="inputValue"
v-bind="$attrs" v-bind="$attrs"
:class="$attrs.class" :class="$attrs.class"
type="text" type="number"
:rules="combinedRules" :rules="combinedRules"
:error-messages="errorMessages" :error-messages="errorMessages"
@keypress="restrictToNumbers" @keydown="restrictToNumbers"
@input="handleInput"
dir="ltr" dir="ltr"
dense dense
:hide-details="$attrs['hide-details'] || 'auto'" :hide-details="$attrs['hide-details'] || 'auto'"
@ -34,6 +35,10 @@ export default {
allowDecimal: { allowDecimal: {
type: Boolean, type: Boolean,
default: false default: false
},
allowNegative: {
type: Boolean,
default: false
} }
}, },
@ -47,7 +52,17 @@ export default {
computed: { computed: {
combinedRules() { combinedRules() {
return [ return [
v => !v || (this.allowDecimal ? /^\d*\.?\d*$/.test(v.replace(/[^0-9.]/g, '')) : /^\d+$/.test(v.replace(/[^0-9]/g, ''))) || this.$t('numberinput.invalid_number'), v => {
if (!v && v !== '0') return true // اجازه خالی بودن
const pattern = this.allowDecimal
? this.allowNegative
? /^-?\d*\.?\d*$/
: /^\d*\.?\d*$/
: this.allowNegative
? /^-?\d+$/
: /^\d+$/
return pattern.test(v) || this.$t('numberinput.invalid_number')
},
...this.rules ...this.rules
] ]
} }
@ -57,48 +72,98 @@ export default {
modelValue: { modelValue: {
immediate: true, immediate: true,
handler(newVal) { handler(newVal) {
if (newVal !== null && newVal !== undefined) { if (newVal === null || newVal === undefined) {
const cleaned = String(newVal).replace(this.allowDecimal ? /[^0-9.]/g : /[^0-9]/g, '')
this.inputValue = cleaned ? (this.allowDecimal ? cleaned : Number(cleaned).toLocaleString('en-US')) : ''
} else {
this.inputValue = '' this.inputValue = ''
} else {
const cleaned = String(newVal).replace(this.allowDecimal ? /[^0-9.-]/g : /[^0-9-]/g, '')
this.inputValue = cleaned
} }
} }
}, },
inputValue(newVal) { inputValue(newVal) {
if (newVal === '' || newVal === null || newVal === undefined) { if (newVal === '' || newVal === null || newVal === undefined) {
this.$emit('update:modelValue', 0) this.$emit('update:modelValue', null)
this.errorMessages = []
return
}
const cleaned = String(newVal).replace(this.allowDecimal ? /[^0-9.-]/g : /[^0-9-]/g, '')
const pattern = this.allowDecimal
? this.allowNegative
? /^-?\d*\.?\d*$/
: /^\d*\.?\d*$/
: this.allowNegative
? /^-?\d+$/
: /^\d+$/
if (pattern.test(cleaned)) {
let numericValue
if (this.allowDecimal) {
numericValue = cleaned === '' || cleaned === '-' ? null : parseFloat(cleaned)
} else {
numericValue = cleaned === '' || cleaned === '-' ? null : parseInt(cleaned, 10)
}
this.$emit('update:modelValue', isNaN(numericValue) ? null : numericValue)
this.errorMessages = [] this.errorMessages = []
} else { } else {
const cleaned = String(newVal).replace(this.allowDecimal ? /[^0-9.]/g : /[^0-9]/g, '') this.errorMessages = [this.$t('numberinput.invalid_number')]
if (this.allowDecimal ? /^\d*\.?\d*$/.test(cleaned) : /^\d+$/.test(cleaned)) {
const numericValue = cleaned ? (this.allowDecimal ? parseFloat(cleaned) : Number(cleaned)) : 0
this.$emit('update:modelValue', numericValue)
this.errorMessages = []
} else {
this.errorMessages = [this.$t('numberinput.invalid_number')]
}
} }
} }
}, },
methods: { methods: {
restrictToNumbers(event) { restrictToNumbers(event) {
const charCode = event.charCode const key = event.key
const input = this.inputValue || ''
// اجازه دادن به کلیدهای کنترلی
if (
['Backspace', 'Delete', 'ArrowLeft', 'ArrowRight', 'Tab', 'Enter'].includes(key) ||
(event.ctrlKey || event.metaKey)
) {
return
}
if (this.allowDecimal) { if (this.allowDecimal) {
// اجازه ورود اعداد و نقطه اعشاری // اجازه ورود اعداد، ممیز، کاما (برای کیبوردهای محلی) و (در صورت اجازه) منفی
if ((charCode < 48 || charCode > 57) && charCode !== 46) { if (!/[0-9.,]/.test(key) && (!this.allowNegative || key !== '-')) {
event.preventDefault() event.preventDefault()
} }
// جلوگیری از ورود بیش از یک نقطه اعشاری // جلوگیری از بیش از یک ممیز
if (charCode === 46 && this.inputValue.includes('.')) { if ((key === '.' || key === ',') && input.includes('.')) {
event.preventDefault()
}
// جلوگیری از ممیز در ابتدا یا بعد از منفی
if ((key === '.' || key === ',') && (input === '' || input === '-')) {
event.preventDefault()
}
// جلوگیری از بیش از یک منفی
if (key === '-' && (input.includes('-') || !this.allowNegative)) {
event.preventDefault()
}
// منفی فقط در ابتدا
if (key === '-' && input !== '') {
event.preventDefault() event.preventDefault()
} }
} else { } else {
// فقط اجازه ورود اعداد // فقط اعداد و (در صورت اجازه) منفی
if (charCode < 48 || charCode > 57) { if (!/[0-9]/.test(key) && (!this.allowNegative || key !== '-')) {
event.preventDefault() event.preventDefault()
} }
// جلوگیری از بیش از یک منفی
if (key === '-' && (input.includes('-') || !this.allowNegative)) {
event.preventDefault()
}
// منفی فقط در ابتدا
if (key === '-' && input !== '') {
event.preventDefault()
}
}
},
handleInput(event) {
// تبدیل کاما به ممیز برای کیبوردهای محلی
if (this.allowDecimal && event.target.value.includes(',')) {
this.inputValue = event.target.value.replace(',', '.')
} }
} }
} }

View file

@ -194,6 +194,7 @@ const fa_lang = {
repservice_reqs: "درخواست‌ها", repservice_reqs: "درخواست‌ها",
hrm: 'منابع انسانی', hrm: 'منابع انسانی',
hrm_docs: 'سند حقوق', hrm_docs: 'سند حقوق',
buysellByPerson: "گزارش خرید و فروش های اشخاص",
}, },
time: { time: {
month: "{id} ماه", month: "{id} ماه",
@ -524,7 +525,26 @@ const fa_lang = {
description: "توضیحات الزامی است", description: "توضیحات الزامی است",
person: "انتخاب شخص الزامی است" person: "انتخاب شخص الزامی است"
} }
} },
buysell_report: {
person: "شخص",
type: "نوع",
date_start: "تاریخ شروع",
date_end: "تاریخ پایان",
search: "جست و جو ...",
goods: "کالا",
services: "خدمات",
unit: "واحد شمارش",
count: "تعداد",
unit_price: "مبلغ فی",
total_price: "مبلغ کل",
cumulative: "تجمعی",
buy: "خرید",
sell: "فروش",
return_buy: "برگشت از خرید",
return_sell: "برگشت از فروش",
all_types: "همه موارد"
},
}, },
app: { app: {
loading: "در حال بارگذاری...", loading: "در حال بارگذاری...",

View file

@ -1,36 +1,40 @@
<template> <template>
<div class="block block-content-full "> <v-toolbar color="toolbar" :title="$t('drawer.buysellByPerson')">
<div id="fixed-header" class="block-header block-header-default bg-gray-light pt-2 pb-1"> <template v-slot:prepend>
<h3 class="block-title text-primary-dark"> <v-tooltip :text="$t('dialog.back')" location="bottom">
<button @click="$router.back()" type="button" class="float-start d-none d-sm-none d-md-block btn btn-sm btn-link text-warning"> <template v-slot:activator="{ props }">
<i class="fa fw-bold fa-arrow-right"></i> <v-btn v-bind="props" @click="$router.back()" class="d-none d-sm-flex" variant="text"
</button> icon="mdi-arrow-right" />
<i class="fa-solid fa-chart-simple px-2"></i> </template>
گزارش خرید و فروش های اشخاص </v-tooltip>
</h3> </template>
<div class="block-options"> <v-spacer />
<div hidden class="dropdown">
<a class="btn btn-sm btn-danger ms-2 dropdown-toggle text-end" href="#" role="button" <v-menu>
data-bs-toggle="dropdown" aria-expanded="false"> <template v-slot:activator="{ props }">
<i class="fa fa-file-pdf"></i> <v-btn v-bind="props" icon="" color="green">
</a> <v-tooltip activator="parent" :text="$t('dialog.export_excel')" location="bottom" />
<ul class="dropdown-menu"> <v-icon icon="mdi-file-excel-box" />
<li><a @click.prevent="print(false)" class="dropdown-item" href="#">انتخاب شدهها</a></li> </v-btn>
<li><a @click.prevent="print(true)" class="dropdown-item" href="#">همه موارد</a></li> </template>
</ul> <v-list>
</div> <v-list-subheader color="primary">{{ $t('dialog.export_excel') }}</v-list-subheader>
<div class="dropdown"> <v-list-item :disabled="!itemsSelected.length" class="text-dark" :title="$t('dialog.selected')"
<a class="btn btn-sm btn-success ms-2 dropdown-toggle text-end" href="#" role="button" @click="excellOutput(false)">
data-bs-toggle="dropdown" aria-expanded="false"> <template v-slot:prepend>
<i class="fa fa-file-excel"></i> <v-icon color="green-darken-4" icon="mdi-check" />
</a> </template>
<ul class="dropdown-menu"> </v-list-item>
<li><a @click.prevent="excellOutput(false)" class="dropdown-item" href="#">انتخاب شدهها</a></li> <v-list-item class="text-dark" :title="$t('dialog.all')" @click="excellOutput(true)">
<li><a @click.prevent="excellOutput(true)" class="dropdown-item" href="#">همه موارد</a></li> <template v-slot:prepend>
</ul> <v-icon color="indigo-darken-4" icon="mdi-expand-all" />
</div> </template>
</div> </v-list-item>
</div> </v-list>
</v-menu>
</v-toolbar>
<div class="block block-content-full">
<div class="block-content pt-1 pb-3"> <div class="block-content pt-1 pb-3">
<div class="row"> <div class="row">
<div class="col-sm-12 col-md-12 m-0 p-0"> <div class="col-sm-12 col-md-12 m-0 p-0">

View file

@ -67,7 +67,7 @@
<Hcommoditysearch v-model="item.name" density="compact" hide-details class="my-0" style="font-size: 0.8rem;" return-object @update:modelValue="handleCommodityChange(item)"></Hcommoditysearch> <Hcommoditysearch v-model="item.name" density="compact" hide-details class="my-0" style="font-size: 0.8rem;" return-object @update:modelValue="handleCommodityChange(item)"></Hcommoditysearch>
</td> </td>
<td class="text-center px-2"> <td class="text-center px-2">
<Hnumberinput v-model="item.count" density="compact" @update:modelValue="recalculateTotals" class="my-0" style="font-size: 0.8rem;"></Hnumberinput> <Hnumberinput v-model="item.count" density="compact" @update:modelValue="recalculateTotals" class="my-0" style="font-size: 0.8rem;" :allow-decimal="true"></Hnumberinput>
</td> </td>
<td class="text-center px-2"> <td class="text-center px-2">
<div class="d-flex align-center justify-center"> <div class="d-flex align-center justify-center">
@ -145,7 +145,7 @@
</div> </div>
<div class="d-flex justify-space-between mb-2"> <div class="d-flex justify-space-between mb-2">
<div class="flex-grow-1 mr-2"> <div class="flex-grow-1 mr-2">
<Hnumberinput v-model="item.count" density="compact" label="تعداد" hide-details class="my-0" style="font-size: 0.8rem; margin: 0; padding: 0;" @update:modelValue="recalculateTotals"></Hnumberinput> <Hnumberinput v-model="item.count" density="compact" label="تعداد" hide-details class="my-0" style="font-size: 0.8rem; margin: 0; padding: 0;" @update:modelValue="recalculateTotals" :allow-decimal="true"></Hnumberinput>
</div> </div>
<div class="flex-grow-1"> <div class="flex-grow-1">
<div class="d-flex align-center"> <div class="d-flex align-center">
@ -906,21 +906,29 @@ export default {
this.totalInvoice = Number(data.totalInvoice); this.totalInvoice = Number(data.totalInvoice);
this.finalTotal = Number(data.finalTotal); this.finalTotal = Number(data.finalTotal);
this.items = data.items.map(item => ({ // تبدیل قیمتها به قیمت خالص (بدون مالیات)
name: { this.items = data.items.map(item => {
id: item.name.id, const basePrice = Number(item.price);
name: item.name.name, const tax = Number(item.tax);
code: item.name.code const netPrice = Math.round(basePrice - tax);
},
count: Number(item.count), return {
price: Number(item.price), name: {
discountPercent: Number(item.discountPercent), id: item.name.id,
discountAmount: Number(item.discountAmount), name: item.name.name,
total: Number(item.total), code: item.name.code,
description: item.description, priceSell: netPrice // قیمت فروش بدون مالیات
showPercentDiscount: item.showPercentDiscount, },
tax: Number(item.tax) count: Number(item.count),
})); price: netPrice, // قیمت واحد بدون مالیات
discountPercent: Number(item.discountPercent),
discountAmount: Number(item.discountAmount),
total: netPrice, // جمع ردیف بدون مالیات
description: item.description,
showPercentDiscount: item.showPercentDiscount,
tax: tax
};
});
// بارگذاری اسناد پرداخت // بارگذاری اسناد پرداخت
this.paymentItems = data.payments.map(payment => ({ this.paymentItems = data.payments.map(payment => ({
@ -963,7 +971,12 @@ export default {
shippingCost: this.shippingCost, shippingCost: this.shippingCost,
showTotalPercentDiscount: this.showTotalPercentDiscount, showTotalPercentDiscount: this.showTotalPercentDiscount,
items: this.items.map(item => ({ items: this.items.map(item => ({
name: { id: item.name.id }, name: {
id: item.name.id,
name: item.name.name,
code: item.name.code,
priceSell: item.price
},
count: item.count, count: item.count,
price: item.price, price: item.price,
discountType: item.showPercentDiscount ? 'percent' : 'fixed', discountType: item.showPercentDiscount ? 'percent' : 'fixed',
@ -1063,7 +1076,7 @@ export default {
this.recalculateTotals(); this.recalculateTotals();
}, },
handleCommodityChange(item) { handleCommodityChange(item) {
if (item.name && item.name.priceSell !== undefined) { if (item.name && item.name.priceSell !== undefined && !item.price) {
item.price = Number(item.name.priceSell); item.price = Number(item.name.priceSell);
this.recalculateTotals(); this.recalculateTotals();
} }
@ -1075,13 +1088,15 @@ export default {
recalculateTotals() { recalculateTotals() {
let total = 0; let total = 0;
this.items.forEach(item => { this.items.forEach(item => {
const basePrice = (item.count || 0) * (item.price || 0); // محاسبه قیمت پایه (قیمت واحد * تعداد)
const basePrice = Math.round((item.count || 0) * (item.price || 0));
// محاسبه تخفیف
let totalDiscount = 0; let totalDiscount = 0;
if (item.showPercentDiscount) { if (item.showPercentDiscount) {
totalDiscount = Math.round((basePrice * (item.discountPercent || 0)) / 100); totalDiscount = Math.round((basePrice * (item.discountPercent || 0)) / 100);
} else { } else {
totalDiscount = item.discountAmount || 0; totalDiscount = Math.round(item.discountAmount || 0);
} }
if (totalDiscount > basePrice) { if (totalDiscount > basePrice) {
@ -1090,26 +1105,28 @@ export default {
this.showError = true; this.showError = true;
} }
const itemTotal = basePrice - totalDiscount; // محاسبه قیمت خالص (قیمت پایه - تخفیف)
item.total = itemTotal; const netPrice = Math.round(basePrice - totalDiscount);
total += itemTotal; item.total = netPrice;
}); total += netPrice;
this.totalInvoice = total;
// محاسبه مالیات برای هر آیتم // محاسبه مالیات برای هر آیتم (بر اساس قیمت خالص)
this.items.forEach(item => { item.tax = Math.round((netPrice * this.taxPercent) / 100);
item.tax = Math.round((item.total * this.taxPercent) / 100);
}); });
// جمع کل فاکتور (بدون مالیات)
this.totalInvoice = Math.round(total);
this.totalWithoutTax = Math.round(total);
// محاسبه کل مالیات // محاسبه کل مالیات
this.taxAmount = this.items.reduce((sum, item) => sum + (item.tax || 0), 0); this.taxAmount = Math.round(this.items.reduce((sum, item) => sum + (item.tax || 0), 0));
this.totalWithoutTax = total;
// محاسبه تخفیف کلی
let calculatedTotalDiscount = 0; let calculatedTotalDiscount = 0;
if (this.showTotalPercentDiscount) { if (this.showTotalPercentDiscount) {
calculatedTotalDiscount = Math.round((total * this.totalDiscountPercent) / 100); calculatedTotalDiscount = Math.round((total * this.totalDiscountPercent) / 100);
} else { } else {
calculatedTotalDiscount = this.totalDiscount; calculatedTotalDiscount = Math.round(this.totalDiscount);
} }
if (calculatedTotalDiscount > total) { if (calculatedTotalDiscount > total) {
@ -1118,7 +1135,9 @@ export default {
this.showDiscountError = true; this.showDiscountError = true;
} }
this.finalTotal = total + this.taxAmount - calculatedTotalDiscount + this.shippingCost; // محاسبه جمع کل نهایی
// جمع کل + مالیات - تخفیف کلی + هزینه حمل
this.finalTotal = Math.round(total + this.taxAmount - calculatedTotalDiscount + this.shippingCost);
this.totalAmount = this.finalTotal; this.totalAmount = this.finalTotal;
this.calculatePayments(); this.calculatePayments();
}, },
@ -1341,20 +1360,39 @@ export default {
--v-field-border-opacity: 0.12; --v-field-border-opacity: 0.12;
} }
:deep(.v-overlay__content) { /* تنظیم عرض ستون‌های جدول */
z-index: 9999 !important; :deep(.v-table th:nth-child(3)), /* ستون تعداد */
:deep(.v-table td:nth-child(3)) {
width: 120px;
} }
:deep(.v-menu__content) { :deep(.v-table th:nth-child(4)), /* ستون قیمت */
z-index: 9999 !important; :deep(.v-table td:nth-child(4)) {
width: 150px;
} }
:deep(.v-dialog) { :deep(.v-table th:nth-child(5)), /* ستون تخفیف */
z-index: 9999 !important; :deep(.v-table td:nth-child(5)) {
width: 200px;
} }
:deep(.v-date-picker) { /* تنظیم استایل باکس تخفیف */
z-index: 9999 !important; :deep(.v-table .v-field--variant-outlined.v-field--density-compact) {
max-width: 100%;
}
:deep(.v-table .v-checkbox) {
margin-right: 4px;
}
:deep(.v-table .v-checkbox .v-selection-control) {
margin: 0;
padding: 0;
}
:deep(.v-table .v-checkbox .v-selection-control__wrapper) {
width: 24px;
height: 24px;
} }
.settings-section-card { .settings-section-card {

View file

@ -2,12 +2,11 @@
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import axios from 'axios'; import axios from 'axios';
import Swal from 'sweetalert2'; import Swal from 'sweetalert2';
import Loading from 'vue-loading-overlay'; import CustomEditor from '@/components/Editor.vue';
import 'vue-loading-overlay/dist/css/index.css';
export default defineComponent({ export default defineComponent({
name: 'mod', name: 'mod',
components: { Loading }, components: { CustomEditor },
data: () => ({ data: () => ({
loading: true, loading: true,
id: '', id: '',
@ -65,7 +64,7 @@ export default defineComponent({
<v-spacer></v-spacer> <v-spacer></v-spacer>
</v-toolbar> </v-toolbar>
<v-container class="pa-0 ma-0"> <v-container class="pa-0 ma-0">
<v-card :loading="loading ? 'red' : null" :disabled="loading"> <v-card :loading="loading" :disabled="loading">
<v-card-text class="pa-2"> <v-card-text class="pa-2">
<v-row> <v-row>
<v-col cols="12" sm="12" md="6"> <v-col cols="12" sm="12" md="6">
@ -80,15 +79,10 @@ export default defineComponent({
</v-col> </v-col>
<v-col cols="12" sm="12" md="12"> <v-col cols="12" sm="12" md="12">
<h3 class="mb-2">{{ $t('app.body') }}</h3> <h3 class="mb-2">{{ $t('app.body') }}</h3>
<v-textarea <CustomEditor
v-model="body" v-model="body"
:rules="[() => body.length > 0 || $t('validator.required')]" :rules="[() => body.length > 0 || $t('validator.required')]"
auto-grow />
variant="outlined"
class="font-weight-regular"
style="font-family: 'Vazirmatn FD', sans-serif;"
></v-textarea>
</v-col> </v-col>
<v-col cols="12" sm="12" md="12"> <v-col cols="12" sm="12" md="12">
<v-btn <v-btn