update core
This commit is contained in:
parent
3ad815ec7f
commit
04550d2171
|
@ -4,56 +4,56 @@
|
|||
"minimum-stability": "stable",
|
||||
"prefer-stable": true,
|
||||
"require": {
|
||||
"php": ">=8.1",
|
||||
"php": ">=8.2",
|
||||
"ext-ctype": "*",
|
||||
"ext-curl": "*",
|
||||
"ext-fileinfo": "*",
|
||||
"ext-iconv": "*",
|
||||
"doctrine/annotations": "^1.0",
|
||||
"doctrine/dbal": "^3.9",
|
||||
"doctrine/doctrine-bundle": "^2.8",
|
||||
"doctrine/doctrine-migrations-bundle": "^3.2",
|
||||
"doctrine/orm": "^2.14",
|
||||
"dompdf/dompdf": "^2.0",
|
||||
"melipayamak/php": "1.0.0",
|
||||
"doctrine/annotations": "^2.0",
|
||||
"doctrine/dbal": "^4.2",
|
||||
"doctrine/doctrine-bundle": "^2.13",
|
||||
"doctrine/doctrine-migrations-bundle": "^3.4",
|
||||
"doctrine/orm": "^3.2",
|
||||
"dompdf/dompdf": "^3.0",
|
||||
"melipayamak/php": "^1.0",
|
||||
"mpdf/mpdf": "^8.2",
|
||||
"nelmio/api-doc-bundle": "^4.34",
|
||||
"nelmio/api-doc-bundle": "^4.35",
|
||||
"nelmio/cors-bundle": "^2.5",
|
||||
"phpdocumentor/reflection-docblock": "^5.3",
|
||||
"phpoffice/phpspreadsheet": "^1.29",
|
||||
"phpstan/phpdoc-parser": "^1.16",
|
||||
"phpdocumentor/reflection-docblock": "^5.4",
|
||||
"phpoffice/phpspreadsheet": "^2.3",
|
||||
"phpstan/phpdoc-parser": "^1.33",
|
||||
"ramsey/uuid": "^4.7",
|
||||
"symfony/apache-pack": "^1.0",
|
||||
"symfony/asset": "7.1.*",
|
||||
"symfony/console": "7.1.*",
|
||||
"symfony/doctrine-messenger": "7.1.*",
|
||||
"symfony/dotenv": "7.1.*",
|
||||
"symfony/expression-language": "7.1.*",
|
||||
"symfony/asset": "7.2.*",
|
||||
"symfony/console": "7.2.*",
|
||||
"symfony/doctrine-messenger": "7.2.*",
|
||||
"symfony/dotenv": "7.2.*",
|
||||
"symfony/expression-language": "7.2.*",
|
||||
"symfony/flex": "^2",
|
||||
"symfony/form": "7.1.*",
|
||||
"symfony/framework-bundle": "7.1.*",
|
||||
"symfony/http-client": "7.1.*",
|
||||
"symfony/lock": "7.1.*",
|
||||
"symfony/mailer": "7.1.*",
|
||||
"symfony/mime": "7.1.*",
|
||||
"symfony/monolog-bundle": "^3.0",
|
||||
"symfony/notifier": "7.1.*",
|
||||
"symfony/process": "7.1.*",
|
||||
"symfony/property-access": "7.1.*",
|
||||
"symfony/property-info": "7.1.*",
|
||||
"symfony/runtime": "7.1.*",
|
||||
"symfony/security-bundle": "7.1.*",
|
||||
"symfony/serializer": "7.1.*",
|
||||
"symfony/string": "7.1.*",
|
||||
"symfony/translation": "7.1.*",
|
||||
"symfony/twig-bundle": "7.1.*",
|
||||
"symfony/validator": "7.1.*",
|
||||
"symfony/web-link": "7.1.*",
|
||||
"symfony/yaml": "7.1.*",
|
||||
"symfonycasts/verify-email-bundle": "^1.13",
|
||||
"tecnickcom/tcpdf": "^6.6",
|
||||
"twig/extra-bundle": "^2.12|^3.0",
|
||||
"twig/twig": "^2.12|^3.0"
|
||||
"symfony/form": "7.2.*",
|
||||
"symfony/framework-bundle": "7.2.*",
|
||||
"symfony/http-client": "7.2.*",
|
||||
"symfony/lock": "7.2.*",
|
||||
"symfony/mailer": "7.2.*",
|
||||
"symfony/mime": "7.2.*",
|
||||
"symfony/monolog-bundle": "^3.10",
|
||||
"symfony/notifier": "7.2.*",
|
||||
"symfony/process": "7.2.*",
|
||||
"symfony/property-access": "7.2.*",
|
||||
"symfony/property-info": "7.2.*",
|
||||
"symfony/runtime": "7.2.*",
|
||||
"symfony/security-bundle": "7.2.*",
|
||||
"symfony/serializer": "7.2.*",
|
||||
"symfony/string": "7.2.*",
|
||||
"symfony/translation": "7.2.*",
|
||||
"symfony/twig-bundle": "7.2.*",
|
||||
"symfony/validator": "7.2.*",
|
||||
"symfony/web-link": "7.2.*",
|
||||
"symfony/yaml": "7.2.*",
|
||||
"symfonycasts/verify-email-bundle": "^1.17",
|
||||
"tecnickcom/tcpdf": "^6.7",
|
||||
"twig/extra-bundle": "^3.14",
|
||||
"twig/twig": "^3.14"
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
|
@ -99,19 +99,19 @@
|
|||
"extra": {
|
||||
"symfony": {
|
||||
"allow-contrib": true,
|
||||
"require": "7.1.*",
|
||||
"require": "7.2.*",
|
||||
"docker": true
|
||||
},
|
||||
"public-dir": "../public_html"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"symfony/browser-kit": "7.1.*",
|
||||
"symfony/css-selector": "7.1.*",
|
||||
"symfony/debug-bundle": "7.1.*",
|
||||
"symfony/maker-bundle": "^1.48",
|
||||
"symfony/phpunit-bridge": "^7.1",
|
||||
"symfony/stopwatch": "7.1.*",
|
||||
"symfony/web-profiler-bundle": "7.1.*"
|
||||
"phpunit/phpunit": "^11.4",
|
||||
"symfony/browser-kit": "7.2.*",
|
||||
"symfony/css-selector": "7.2.*",
|
||||
"symfony/debug-bundle": "7.2.*",
|
||||
"symfony/maker-bundle": "^1.62",
|
||||
"symfony/phpunit-bridge": "^7.2",
|
||||
"symfony/stopwatch": "7.2.*",
|
||||
"symfony/web-profiler-bundle": "7.2.*"
|
||||
}
|
||||
}
|
||||
|
|
11385
hesabixCore/composer.lock
generated
Normal file
11385
hesabixCore/composer.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
11
hesabixCore/config/packages/csrf.yaml
Normal file
11
hesabixCore/config/packages/csrf.yaml
Normal file
|
@ -0,0 +1,11 @@
|
|||
# Enable stateless CSRF protection for forms and logins/logouts
|
||||
framework:
|
||||
form:
|
||||
csrf_protection:
|
||||
token_id: submit
|
||||
|
||||
csrf_protection:
|
||||
stateless_token_ids:
|
||||
- submit
|
||||
- authenticate
|
||||
- logout
|
|
@ -19,6 +19,7 @@ use App\Entity\Cashdesk;
|
|||
use App\Entity\Salary;
|
||||
use App\Entity\Person;
|
||||
use App\Service\Log;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
|
||||
class CostController extends AbstractController
|
||||
{
|
||||
|
@ -138,7 +139,10 @@ class CostController extends AbstractController
|
|||
->andWhere('r.bd != 0')
|
||||
->groupBy('t.id, t.name')
|
||||
->orderBy('total_cost', 'DESC')
|
||||
->setParameters($parameters);
|
||||
->setParameter('bid', $acc['bid'])
|
||||
->setParameter('money', $acc['money'])
|
||||
->setParameter('type', 'cost')
|
||||
->setParameter('year', $acc['year']);
|
||||
|
||||
// اعمال فیلتر تاریخ فقط برای امروز و ماه
|
||||
if ($period === 'today') {
|
||||
|
|
|
@ -1134,4 +1134,36 @@ class HesabdariController extends AbstractController
|
|||
return $this->json($extractor->operationSuccess($pdfPid));
|
||||
|
||||
}
|
||||
|
||||
#[Route('/api/hesabdari/tables/{id}/children', name: 'get_hesabdari_table_children', methods: ['GET'])]
|
||||
public function getHesabdariTableChildren(int $id, Access $access, EntityManagerInterface $entityManager): JsonResponse
|
||||
{
|
||||
$acc = $access->hasRole('accounting');
|
||||
if (!$acc) {
|
||||
throw $this->createAccessDeniedException();
|
||||
}
|
||||
|
||||
$node = $entityManager->getRepository(HesabdariTable::class)->find($id);
|
||||
if (!$node) {
|
||||
return $this->json(['Success' => false, 'message' => 'نود مورد نظر یافت نشد'], 404);
|
||||
}
|
||||
|
||||
$children = $entityManager->getRepository(HesabdariTable::class)->findBy([
|
||||
'upper' => $node,
|
||||
'bid' => [$acc['bid']->getId(), null] // حسابهای عمومی و خصوصی
|
||||
]);
|
||||
|
||||
$result = [];
|
||||
foreach ($children as $child) {
|
||||
$result[] = [
|
||||
'id' => $child->getId(),
|
||||
'name' => $child->getName(),
|
||||
'code' => $child->getCode(),
|
||||
'type' => $child->getType(),
|
||||
'children' => $this->hasChild($entityManager, $child) ? [] : null
|
||||
];
|
||||
}
|
||||
|
||||
return $this->json(['Success' => true, 'data' => $result]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
|||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
|
||||
class IncomeController extends AbstractController
|
||||
{
|
||||
|
@ -111,14 +112,6 @@ class IncomeController extends AbstractController
|
|||
$today = $jdate->jdate('Y/m/d', time());
|
||||
$monthStart = $jdate->jdate('Y/m/01', time());
|
||||
|
||||
// پارامترهای پایه
|
||||
$parameters = [
|
||||
'bid' => $acc['bid'],
|
||||
'money' => $acc['money'],
|
||||
'type' => 'income',
|
||||
'year' => $acc['year'],
|
||||
];
|
||||
|
||||
// کوئری پایه
|
||||
$qb = $entityManager->createQueryBuilder()
|
||||
->select('t.name AS center_name, SUM(COALESCE(r.bs, 0)) AS total_income')
|
||||
|
@ -132,7 +125,10 @@ class IncomeController extends AbstractController
|
|||
->andWhere('r.bs != 0') // فقط ردیفهایی که bs صفر نیست
|
||||
->groupBy('t.id, t.name')
|
||||
->orderBy('total_income', 'DESC')
|
||||
->setParameters($parameters);
|
||||
->setParameter('bid', $acc['bid'])
|
||||
->setParameter('money', $acc['money'])
|
||||
->setParameter('type', 'income')
|
||||
->setParameter('year', $acc['year']);
|
||||
|
||||
// اعمال فیلتر تاریخ فقط برای امروز و ماه
|
||||
if ($period === 'today') {
|
||||
|
|
|
@ -5,24 +5,24 @@ use Doctrine\ORM\Query\AST\Functions\FunctionNode;
|
|||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
use Doctrine\ORM\Query\TokenType;
|
||||
|
||||
class Cast extends FunctionNode
|
||||
{
|
||||
private $expression;
|
||||
|
||||
public function parse(Parser $parser)
|
||||
public function parse(Parser $parser): void
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER); // CAST
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
$parser->match(TokenType::T_IDENTIFIER); // CAST
|
||||
$parser->match(TokenType::T_OPEN_PARENTHESIS);
|
||||
$this->expression = $parser->ArithmeticExpression();
|
||||
$parser->match(Lexer::T_AS);
|
||||
$parser->match(Lexer::T_IDENTIFIER); // INTEGER یا هر نوع دیگه
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
$parser->match(TokenType::T_AS);
|
||||
$parser->match(TokenType::T_IDENTIFIER); // INTEGER یا هر نوع دیگه
|
||||
$parser->match(TokenType::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
|
||||
public function getSql(SqlWalker $sqlWalker)
|
||||
public function getSql(SqlWalker $sqlWalker): string
|
||||
{
|
||||
// به جای استفاده از $this->type، مستقیماً SIGNED رو میذاریم
|
||||
return 'CAST(' . $sqlWalker->walkArithmeticPrimary($this->expression) . ' AS SIGNED)';
|
||||
}
|
||||
}
|
|
@ -39,7 +39,7 @@ class HesabdariDoc
|
|||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $type = null;
|
||||
|
||||
#[ORM\Column(type: Types::BIGINT)]
|
||||
#[ORM\Column(type: Types::STRING, length: 255)]
|
||||
private ?string $code = null;
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'hesabdariDocs')]
|
||||
|
@ -50,8 +50,8 @@ class HesabdariDoc
|
|||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $des = null;
|
||||
|
||||
#[ORM\Column(type: 'string', length: 255, nullable: true)]
|
||||
private int $amount = 0;
|
||||
#[ORM\Column(type: Types::INTEGER, nullable: true)]
|
||||
private ?int $amount = 0;
|
||||
|
||||
#[ORM\ManyToOne]
|
||||
#[ORM\JoinColumn(nullable: false)]
|
||||
|
@ -94,7 +94,7 @@ class HesabdariDoc
|
|||
#[Ignore]
|
||||
private Collection $storeroomTickets;
|
||||
|
||||
#[ORM\Column(type: Types::ARRAY , nullable: true)]
|
||||
#[ORM\Column(type: Types::JSON, nullable: true)]
|
||||
private ?array $tempStatus = null;
|
||||
|
||||
#[ORM\OneToMany(mappedBy: 'doc', targetEntity: Log::class)]
|
||||
|
@ -375,7 +375,7 @@ class HesabdariDoc
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @return Collection<int, self>
|
||||
*/
|
||||
public function getRelatedDocs(): Collection
|
||||
|
@ -399,7 +399,6 @@ class HesabdariDoc
|
|||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function getStatus(): ?string
|
||||
{
|
||||
return $this->status;
|
||||
|
|
|
@ -59,8 +59,8 @@ class HesabdariRow
|
|||
#[Ignore]
|
||||
private ?Commodity $commodity = null;
|
||||
|
||||
#[ORM\Column(type: 'string', length: 255,nullable: true)]
|
||||
private ?string $commdityCount = null;
|
||||
#[ORM\Column(type: Types::INTEGER, nullable: true)]
|
||||
private ?int $commdityCount = null;
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'hesabdariRows')]
|
||||
#[Ignore]
|
||||
|
@ -79,7 +79,7 @@ class HesabdariRow
|
|||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $plugin = null;
|
||||
|
||||
#[ORM\Column(type: Types::ARRAY, nullable: true)]
|
||||
#[ORM\Column(type: Types::JSON, nullable: true)]
|
||||
private ?array $tempData = null;
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'hesabdariRows')]
|
||||
|
@ -91,12 +91,8 @@ class HesabdariRow
|
|||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $tax = null;
|
||||
|
||||
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
|
@ -224,12 +220,12 @@ class HesabdariRow
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function getCommdityCount(): ?string
|
||||
public function getCommdityCount(): ?int
|
||||
{
|
||||
return $this->commdityCount;
|
||||
}
|
||||
|
||||
public function setCommdityCount(?string $commdityCount): self
|
||||
public function setCommdityCount(?int $commdityCount): self
|
||||
{
|
||||
$this->commdityCount = $commdityCount;
|
||||
|
||||
|
|
|
@ -122,6 +122,18 @@
|
|||
"./.env"
|
||||
]
|
||||
},
|
||||
"symfony/form": {
|
||||
"version": "7.2",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "7.2",
|
||||
"ref": "7d86a6723f4a623f59e2bf966b6aad2fc461d36b"
|
||||
},
|
||||
"files": [
|
||||
"config/packages/csrf.yaml"
|
||||
]
|
||||
},
|
||||
"symfony/framework-bundle": {
|
||||
"version": "6.2",
|
||||
"recipe": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "hesabix",
|
||||
"version": "0.45.0",
|
||||
"version": "0.48.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
@ -10,68 +10,62 @@
|
|||
"type-check": "vue-tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@chenfengyuan/vue-countdown": "^2.1.2",
|
||||
"@ckeditor/ckeditor5-build-classic": "^36.0.1",
|
||||
"@ckeditor/ckeditor5-image": "^36.0.1",
|
||||
"@ckeditor/ckeditor5-vue": "^4.0.1",
|
||||
"@ckeditor/vite-plugin-ckeditor5": "^0.1.1",
|
||||
"@chenfengyuan/vue-countdown": "^2.1.3",
|
||||
"@date-io/date-fns-jalali": "^3.2.0",
|
||||
"@mdi/font": "^7.4.47",
|
||||
"@syncfusion/ej2-vue-dropdowns": "^21.2.5",
|
||||
"@syncfusion/ej2-vue-dropdowns": "^29.1.38",
|
||||
"@tiptap/extension-text-align": "^2.11.7",
|
||||
"@tiptap/pm": "^2.11.7",
|
||||
"@tiptap/starter-kit": "^2.11.7",
|
||||
"@tiptap/vue-3": "^2.11.7",
|
||||
"@vuelidate/core": "^2.0.0",
|
||||
"@vuelidate/validators": "^2.0.0",
|
||||
"@vueuse/core": "^12.0.0",
|
||||
"@vuelidate/core": "^2.0.3",
|
||||
"@vuelidate/validators": "^2.0.4",
|
||||
"@vueuse/core": "^13.1.0",
|
||||
"animate.css": "^4.1.1",
|
||||
"apexcharts": "^4.4.0",
|
||||
"axios": "^1.2.3",
|
||||
"apexcharts": "^4.6.0",
|
||||
"axios": "^1.8.4",
|
||||
"date-fns": "^4.1.0",
|
||||
"date-fns-jalali": "^3.2.0-0",
|
||||
"downloadjs": "^1.4.7",
|
||||
"file-saver": "^2.0.5",
|
||||
"jalali-moment": "^3.3.11",
|
||||
"libphonenumber-js": "^1.10.44",
|
||||
"libphonenumber-js": "^1.12.7",
|
||||
"lodash": "^4.17.21",
|
||||
"maska": "^3.0.4",
|
||||
"maz-ui": "^3.11.4",
|
||||
"pinia": "^2.2.6",
|
||||
"sweetalert2": "^11.6.13",
|
||||
"v-money3": "^3.24.0",
|
||||
"v-skeleton-loader": "^0.1.9",
|
||||
"maska": "^3.1.1",
|
||||
"maz-ui": "^3.50.1",
|
||||
"pinia": "^3.0.2",
|
||||
"sweetalert2": "^11.4.8",
|
||||
"v-money3": "^3.24.1",
|
||||
"vue": "^3.5.13",
|
||||
"vue-avatar-cropper": "^6.1.1",
|
||||
"vue-currency-input": "^3.0.4",
|
||||
"vue-i18n": "^10.0.4",
|
||||
"vue-loading-overlay": "^6.0.3",
|
||||
"vue-media-upload": "^2.1.2",
|
||||
"vue-currency-input": "^3.2.1",
|
||||
"vue-i18n": "^11.1.3",
|
||||
"vue-loading-overlay": "^6.0.6",
|
||||
"vue-media-upload": "^2.2.4",
|
||||
"vue-persian-datetime-picker": "^2.10.4",
|
||||
"vue-router": "^4.1.6",
|
||||
"vue-router": "^4.5.0",
|
||||
"vue-select": "^4.0.0-beta.6",
|
||||
"vue-spinner": "^1.0.4",
|
||||
"vue3-apexcharts": "^1.8.0",
|
||||
"vue3-easy-data-table": "^1.5.42",
|
||||
"vue3-easy-data-table": "^1.5.47",
|
||||
"vue3-perfect-scrollbar": "^2.0.0",
|
||||
"vue3-persian-datetime-picker": "^1.2.2",
|
||||
"vue3-tel-input": "^1.0.4",
|
||||
"vue3-treeselect": "^0.1.10",
|
||||
"vue3-treeview": "^0.4.1",
|
||||
"vuetify": "^3.7.4"
|
||||
"vue3-treeview": "^0.4.2",
|
||||
"vuetify": "^3.8.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/file-saver": "^2.0.5",
|
||||
"@types/node": "^18.11.12",
|
||||
"@vitejs/plugin-vue": "^4.0.0",
|
||||
"@vitejs/plugin-vue-jsx": "^3.0.0",
|
||||
"@vue/test-utils": "^2.3.2",
|
||||
"@vue/tsconfig": "^0.1.3",
|
||||
"@types/file-saver": "^2.0.7",
|
||||
"@types/node": "^22.14.1",
|
||||
"@vitejs/plugin-vue": "^5.2.3",
|
||||
"@vitejs/plugin-vue-jsx": "^4.1.2",
|
||||
"@vue/test-utils": "^2.4.6",
|
||||
"@vue/tsconfig": "^0.7.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"sass": "^1.67.0",
|
||||
"typescript": "~4.7.4",
|
||||
"vite": "^4.0.0",
|
||||
"vue-tsc": "^1.0.12"
|
||||
"sass": "^1.87.0",
|
||||
"typescript": "^5.8.3",
|
||||
"vite": "^6.3.2",
|
||||
"vue-tsc": "^2.2.10"
|
||||
},
|
||||
"build:pwa": "vue-cli-service build && workbox generateSW workbox-config.js"
|
||||
}
|
||||
|
|
303
webUI/src/components/forms/Haccountsearch.vue
Normal file
303
webUI/src/components/forms/Haccountsearch.vue
Normal file
|
@ -0,0 +1,303 @@
|
|||
<template>
|
||||
<v-menu
|
||||
v-model="menu"
|
||||
:close-on-content-click="false"
|
||||
location="bottom"
|
||||
width="400"
|
||||
>
|
||||
<template v-slot:activator="{ props }">
|
||||
<v-text-field
|
||||
v-bind="props"
|
||||
:model-value="selectedAccountName"
|
||||
:label="label"
|
||||
:rules="rules"
|
||||
readonly
|
||||
hide-details
|
||||
density="compact"
|
||||
@click="openMenu"
|
||||
>
|
||||
<template v-slot:append-inner>
|
||||
<v-icon>{{ menu ? 'mdi-chevron-up' : 'mdi-chevron-down' }}</v-icon>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</template>
|
||||
|
||||
<v-card>
|
||||
<v-progress-linear v-if="isLoading" indeterminate color="primary" />
|
||||
<v-card-text v-if="accountData.length > 0" class="pa-0">
|
||||
<div class="tree-container">
|
||||
<div
|
||||
v-for="item in accountData"
|
||||
:key="item.id"
|
||||
class="tree-node"
|
||||
:class="{ 'has-children': item.children && item.children.length > 0 }"
|
||||
>
|
||||
<div class="tree-node-content" @click="handleNodeClick(item)">
|
||||
<div class="tree-node-toggle" @click.stop="toggleNode(item)">
|
||||
<v-icon v-if="item.children && item.children.length > 0">
|
||||
{{ item.isOpen ? 'mdi-chevron-down' : 'mdi-chevron-right' }}
|
||||
</v-icon>
|
||||
</div>
|
||||
<div class="tree-node-icon">
|
||||
<v-icon v-if="item.children && item.children.length > 0">mdi-folder</v-icon>
|
||||
<v-icon v-else>mdi-file-document</v-icon>
|
||||
</div>
|
||||
<div class="tree-node-label" :class="{ 'selected': selectedAccount?.id === item.id }">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="item.isOpen && item.children && item.children.length > 0" class="tree-children">
|
||||
<div
|
||||
v-for="child in item.children"
|
||||
:key="child.id"
|
||||
class="tree-node"
|
||||
:class="{ 'has-children': child.children && child.children.length > 0 }"
|
||||
>
|
||||
<div class="tree-node-content" @click="handleNodeClick(child)">
|
||||
<div class="tree-node-toggle" @click.stop="toggleNode(child)">
|
||||
<v-icon v-if="child.children && child.children.length > 0">
|
||||
{{ child.isOpen ? 'mdi-chevron-down' : 'mdi-chevron-right' }}
|
||||
</v-icon>
|
||||
</div>
|
||||
<div class="tree-node-icon">
|
||||
<v-icon v-if="child.children && child.children.length > 0">mdi-folder</v-icon>
|
||||
<v-icon v-else>mdi-file-document</v-icon>
|
||||
</div>
|
||||
<div class="tree-node-label" :class="{ 'selected': selectedAccount?.id === child.id }">
|
||||
{{ child.name }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="child.isOpen && child.children && child.children.length > 0" class="tree-children">
|
||||
<div
|
||||
v-for="grandChild in child.children"
|
||||
:key="grandChild.id"
|
||||
class="tree-node"
|
||||
>
|
||||
<div class="tree-node-content" @click="handleNodeClick(grandChild)">
|
||||
<div class="tree-node-icon">
|
||||
<v-icon>mdi-file-document</v-icon>
|
||||
</div>
|
||||
<div class="tree-node-label" :class="{ 'selected': selectedAccount?.id === grandChild.id }">
|
||||
{{ grandChild.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</v-card-text>
|
||||
<v-card-text v-else>
|
||||
در حال بارگذاری...
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-menu>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, computed, watch } from 'vue';
|
||||
import axios from 'axios';
|
||||
import { debounce } from 'lodash'; // برای دیبانس کردن loadChildren
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Number,
|
||||
default: null
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
default: 'حساب'
|
||||
},
|
||||
rules: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'select']);
|
||||
|
||||
const menu = ref(false);
|
||||
const accountData = ref([]);
|
||||
const selectedAccount = ref(null);
|
||||
const cache = ref(new Map());
|
||||
const isLoading = ref(false);
|
||||
|
||||
const selectedAccountName = computed(() => {
|
||||
return selectedAccount.value?.name || '';
|
||||
});
|
||||
|
||||
// تابع برای رمزگشایی کاراکترهای یونیکد
|
||||
const decodeUnicode = (str: string): string => {
|
||||
try {
|
||||
return decodeURIComponent(
|
||||
str.replace(/\\u([\dA-F]{4})/gi, (match, grp) =>
|
||||
String.fromCharCode(parseInt(grp, 16))
|
||||
)
|
||||
);
|
||||
} catch (e) {
|
||||
console.error('خطا در رمزگشایی یونیکد:', e);
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
// پردازش دادهها برای رمزگشایی نامها
|
||||
const processTreeData = (items: any[]): any[] => {
|
||||
return items.map(item => {
|
||||
if (cache.value.has(`processed-${item.id}`)) {
|
||||
return cache.value.get(`processed-${item.id}`);
|
||||
}
|
||||
const processedItem = {
|
||||
...item,
|
||||
name: decodeUnicode(item.name),
|
||||
children: item.children ? processTreeData(item.children) : [],
|
||||
isOpen: false
|
||||
};
|
||||
cache.value.set(`processed-${item.id}`, processedItem);
|
||||
return processedItem;
|
||||
});
|
||||
};
|
||||
|
||||
// بارگذاری تنبل زیرشاخهها با دیبانس
|
||||
const loadChildren = debounce(async (node: any) => {
|
||||
if (cache.value.has(node.id)) {
|
||||
node.children = cache.value.get(node.id);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const response = await axios.get(`/api/hesabdari/tables/${node.id}/children`);
|
||||
if (response.data.Success) {
|
||||
const children = processTreeData(response.data.data || []);
|
||||
node.children = children;
|
||||
cache.value.set(node.id, children);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`خطا در بارگذاری زیرشاخههای گره ${node.id}:`, error);
|
||||
}
|
||||
}, 300);
|
||||
|
||||
const toggleNode = (node: any) => {
|
||||
if (node.children && node.children.length > 0) {
|
||||
node.isOpen = !node.isOpen;
|
||||
if (node.isOpen && (!node.children || node.children.length === 0)) {
|
||||
loadChildren(node);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// مدیریت انتخاب آیتمها
|
||||
const handleNodeClick = (node: any) => {
|
||||
selectedAccount.value = node;
|
||||
emit('update:modelValue', node.id);
|
||||
emit('select', node);
|
||||
menu.value = false;
|
||||
};
|
||||
|
||||
// باز کردن منو
|
||||
const openMenu = () => {
|
||||
menu.value = true;
|
||||
if (!accountData.value.length && !isLoading.value) {
|
||||
fetchHesabdariTables();
|
||||
}
|
||||
};
|
||||
|
||||
// بارگذاری اولیه گرههای ریشه
|
||||
const fetchHesabdariTables = async () => {
|
||||
if (cache.value.has('root')) {
|
||||
accountData.value = cache.value.get('root');
|
||||
return;
|
||||
}
|
||||
isLoading.value = true;
|
||||
try {
|
||||
const response = await axios.get('/api/hesabdari/tables');
|
||||
if (response.data.Success && response.data.data) {
|
||||
accountData.value = processTreeData(response.data.data[0].children || []);
|
||||
cache.value.set('root', accountData.value);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('خطا در بارگذاری حسابها:', error);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// دیباگ تعداد مونتها
|
||||
onMounted(() => {
|
||||
fetchHesabdariTables();
|
||||
});
|
||||
|
||||
// بررسی تغییرات در vue-router
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
() => {
|
||||
console.log('modelValue تغییر کرد، احتمالاً به دلیل ناوبری');
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tree-container {
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.tree-node {
|
||||
margin-left: 24px;
|
||||
}
|
||||
|
||||
.tree-node-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.tree-node-content:hover {
|
||||
background-color: rgba(var(--v-theme-primary), 0.1);
|
||||
}
|
||||
|
||||
.tree-node-toggle {
|
||||
width: 24px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.tree-node-icon {
|
||||
width: 24px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.tree-node-label {
|
||||
flex: 1;
|
||||
font-size: 0.9rem;
|
||||
font-family: 'Vazir', sans-serif;
|
||||
}
|
||||
|
||||
.tree-node-label.selected {
|
||||
color: rgb(var(--v-theme-primary));
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.tree-children {
|
||||
margin-left: 24px;
|
||||
border-right: 2px solid rgba(var(--v-theme-primary), 0.1);
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
:deep(.v-menu__content) {
|
||||
position: fixed !important;
|
||||
z-index: 9999 !important;
|
||||
transform-origin: center top !important;
|
||||
}
|
||||
|
||||
:deep(.v-overlay__content) {
|
||||
position: fixed !important;
|
||||
}
|
||||
</style>
|
|
@ -7,7 +7,6 @@
|
|||
v-model="showBarChart"
|
||||
:label="$t('dashboard.topCommodities.chartToggle')"
|
||||
color="primary"
|
||||
size="small"
|
||||
density="compact"
|
||||
hide-details
|
||||
></v-switch>
|
||||
|
|
|
@ -13,10 +13,6 @@ import faIR from 'date-fns-jalali/locale/fa-IR';
|
|||
import { createPinia } from 'pinia'
|
||||
const pinia = createPinia();
|
||||
|
||||
import CKEditor from '@ckeditor/ckeditor5-vue';
|
||||
// Import translations for the Persian language.
|
||||
import '@ckeditor/ckeditor5-build-classic/build/translations/fa';
|
||||
|
||||
// Vuetify
|
||||
import 'vuetify/styles'
|
||||
import { createVuetify } from 'vuetify'
|
||||
|
@ -156,7 +152,7 @@ app.component('v-cob', vSelect)
|
|||
import Hdatepicker from "@/components/forms/Hdatepicker.vue";
|
||||
import calendarLocalConfig from "@/i18n/calendarLocalConfig";
|
||||
app.component('h-date-picker', Hdatepicker);
|
||||
app.use(CKEditor)
|
||||
|
||||
app.use(Vue3PersianDatetimePicker, {
|
||||
name: 'CustomDatePicker',
|
||||
props: {
|
||||
|
|
|
@ -1,4 +1,27 @@
|
|||
<template>
|
||||
|
||||
<v-toolbar color="toolbar" :title="$t('dialog.accounting_doc')">
|
||||
<template v-slot:prepend>
|
||||
<v-tooltip :text="$t('dialog.back')" location="bottom">
|
||||
<template v-slot:activator="{ props }">
|
||||
<v-btn v-bind="props" @click="$router.back()" class="d-none d-sm-flex" variant="text"
|
||||
icon="mdi-arrow-right" />
|
||||
</template>
|
||||
</v-tooltip>
|
||||
</template>
|
||||
<v-spacer></v-spacer>
|
||||
<v-tooltip text="ثبت سند" location="bottom">
|
||||
<template v-slot:activator="{ props }">
|
||||
<v-btn v-bind="props" variant="text" icon="mdi-content-save" color="success" @click="submitForm" :loading="loading"></v-btn>
|
||||
</template>
|
||||
</v-tooltip>
|
||||
<v-tooltip v-if="docId" text="حذف سند" location="bottom">
|
||||
<template v-slot:activator="{ props }">
|
||||
<v-btn v-bind="props" variant="text" icon="mdi-delete" color="error" @click="deleteDialog = true" :loading="loading"></v-btn>
|
||||
</template>
|
||||
</v-tooltip>
|
||||
</v-toolbar>
|
||||
|
||||
<v-container>
|
||||
<v-form @submit.prevent="submitForm">
|
||||
<v-row>
|
||||
|
@ -17,78 +40,137 @@
|
|||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-data-table
|
||||
:headers="headers"
|
||||
:items="form.rows"
|
||||
class="elevation-1"
|
||||
hide-default-footer
|
||||
:header-props="{ class: 'custom-header' }"
|
||||
>
|
||||
<template v-slot:top>
|
||||
<v-toolbar flat>
|
||||
<v-toolbar-title>ردیفهای سند</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="primary" @click="addRow">افزودن ردیف</v-btn>
|
||||
</v-toolbar>
|
||||
</template>
|
||||
<v-table class="border rounded d-none d-sm-table mt-3" style="width: 100%;">
|
||||
<thead>
|
||||
<tr style="background-color: #0D47A1; color: white; height: 40px;">
|
||||
<th class="text-center" style="font-size: 0.8rem; padding: 0 4px;">حساب</th>
|
||||
<th class="text-center" style="font-size: 0.8rem; padding: 0 4px;">تفصیل</th>
|
||||
<th class="text-center" style="font-size: 0.8rem; padding: 0 4px;">توضیحات</th>
|
||||
<th class="text-center" style="font-size: 0.8rem; padding: 0 4px;">بدهکار</th>
|
||||
<th class="text-center" style="font-size: 0.8rem; padding: 0 4px;">بستانکار</th>
|
||||
<th class="text-center" style="width: 50px; font-size: 0.8rem; padding: 0 4px;">عملیات</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template v-for="(row, index) in form.rows" :key="index">
|
||||
<tr :style="{ backgroundColor: index % 2 === 0 ? '#f8f9fa' : 'white', height: '40px' }">
|
||||
<td class="text-center" style="min-width: 150px; padding: 0 4px;">
|
||||
<Haccountsearch
|
||||
v-model="row.ref"
|
||||
:rules="[v => !!v || 'حساب الزامی است']"
|
||||
@account-selected="(account) => handleAccountSelect(row, account)"
|
||||
/>
|
||||
</td>
|
||||
<td class="text-center" style="min-width: 100px; padding: 0 4px;">
|
||||
</td>
|
||||
<td class="text-center" style="padding: 0 4px;">
|
||||
<v-text-field
|
||||
v-model="row.des"
|
||||
label="توضیحات"
|
||||
density="compact"
|
||||
class="my-0"
|
||||
style="font-size: 0.7rem;"
|
||||
hide-details
|
||||
></v-text-field>
|
||||
</td>
|
||||
<td class="text-center" style="width: 100px; padding: 0 4px;">
|
||||
<v-text-field
|
||||
v-model="row.bd"
|
||||
label="بدهکار"
|
||||
type="number"
|
||||
density="compact"
|
||||
@input="calculateTotals"
|
||||
class="my-0"
|
||||
style="font-size: 0.7rem;"
|
||||
hide-details
|
||||
></v-text-field>
|
||||
</td>
|
||||
<td class="text-center" style="width: 100px; padding: 0 4px;">
|
||||
<v-text-field
|
||||
v-model="row.bs"
|
||||
label="بستانکار"
|
||||
type="number"
|
||||
density="compact"
|
||||
@input="calculateTotals"
|
||||
class="my-0"
|
||||
style="font-size: 0.7rem;"
|
||||
hide-details
|
||||
></v-text-field>
|
||||
</td>
|
||||
<td class="text-center" style="width: 50px; padding: 0 4px;">
|
||||
<v-tooltip text="حذف" location="bottom">
|
||||
<template v-slot:activator="{ props }">
|
||||
<v-btn v-bind="props" icon="mdi-delete" variant="text" size="x-small" color="error"
|
||||
@click="removeRow(row)" style="min-width: 30px;"></v-btn>
|
||||
</template>
|
||||
</v-tooltip>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
<tr>
|
||||
<td colspan="6" class="text-center pa-1" style="height: 40px;">
|
||||
<v-btn color="primary" prepend-icon="mdi-plus" size="x-small" @click="addRow">افزودن سطر جدید</v-btn>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</v-table>
|
||||
|
||||
<template v-slot:item.ref="{ item }">
|
||||
<v-menu offset-y>
|
||||
<template v-slot:activator="{ props }">
|
||||
<!-- جدول موبایل -->
|
||||
<div class="d-sm-none">
|
||||
<v-card v-for="(row, index) in form.rows" :key="index" class="mb-4" variant="outlined">
|
||||
<v-card-text>
|
||||
<div class="d-flex justify-space-between align-center mb-2">
|
||||
<span class="text-subtitle-2 font-weight-bold">ردیف:</span>
|
||||
<span>{{ index + 1 }}</span>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<Haccountsearch
|
||||
v-model="row.ref"
|
||||
:rules="[v => !!v || 'حساب الزامی است']"
|
||||
@account-selected="(account) => handleAccountSelect(row, account)"
|
||||
/>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<v-text-field
|
||||
v-model="item.refName"
|
||||
label="حساب"
|
||||
dense
|
||||
readonly
|
||||
v-bind="props"
|
||||
:rules="[v => !!item.ref || 'حساب الزامی است']"
|
||||
v-model="row.des"
|
||||
label="توضیحات"
|
||||
density="compact"
|
||||
class="my-0"
|
||||
style="font-size: 0.8rem;"
|
||||
></v-text-field>
|
||||
</template>
|
||||
<v-treeview
|
||||
:items="hesabdariTables"
|
||||
item-key="id"
|
||||
item-text="name"
|
||||
item-children="children"
|
||||
selectable
|
||||
return-object
|
||||
v-model="item.selectedAccounts"
|
||||
@update:active="selectAccount(item, $event)"
|
||||
>
|
||||
<template v-slot:label="{ item: treeItem }">
|
||||
{{ treeItem.name }}
|
||||
</template>
|
||||
</v-treeview>
|
||||
</v-menu>
|
||||
</template>
|
||||
|
||||
<template v-slot:item.bd="{ item }">
|
||||
<v-text-field
|
||||
v-model="item.bd"
|
||||
label="بدهکار"
|
||||
type="number"
|
||||
dense
|
||||
@input="calculateTotals"
|
||||
></v-text-field>
|
||||
</template>
|
||||
|
||||
<template v-slot:item.bs="{ item }">
|
||||
<v-text-field
|
||||
v-model="item.bs"
|
||||
label="بستانکار"
|
||||
type="number"
|
||||
dense
|
||||
@input="calculateTotals"
|
||||
></v-text-field>
|
||||
</template>
|
||||
|
||||
<template v-slot:item.des="{ item }">
|
||||
<v-text-field v-model="item.des" label="توضیحات" dense></v-text-field>
|
||||
</template>
|
||||
|
||||
<template v-slot:item.actions="{ item }">
|
||||
<v-btn color="error" small @click="removeRow(item)">حذف</v-btn>
|
||||
</template>
|
||||
</v-data-table>
|
||||
</div>
|
||||
<div class="d-flex justify-space-between mb-2">
|
||||
<div style="width: 48%;">
|
||||
<v-text-field
|
||||
v-model="row.bd"
|
||||
label="بدهکار"
|
||||
type="number"
|
||||
density="compact"
|
||||
@input="calculateTotals"
|
||||
class="my-0"
|
||||
style="font-size: 0.8rem;"
|
||||
></v-text-field>
|
||||
</div>
|
||||
<div style="width: 48%;">
|
||||
<v-text-field
|
||||
v-model="row.bs"
|
||||
label="بستانکار"
|
||||
type="number"
|
||||
density="compact"
|
||||
@input="calculateTotals"
|
||||
class="my-0"
|
||||
style="font-size: 0.8rem;"
|
||||
></v-text-field>
|
||||
</div>
|
||||
</div>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn icon="mdi-delete" variant="text" color="error" @click="removeRow(row)"></v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
<v-btn color="primary" prepend-icon="mdi-plus" block class="mb-4" @click="addRow">افزودن ردیف جدید</v-btn>
|
||||
</div>
|
||||
|
||||
<v-row class="mt-4">
|
||||
<v-col cols="6">
|
||||
|
@ -110,21 +192,41 @@
|
|||
</v-row>
|
||||
|
||||
<v-alert v-if="error" type="error" class="mt-4">{{ error }}</v-alert>
|
||||
|
||||
<v-btn type="submit" color="success" class="mt-4" :disabled="totalBd !== totalBs || !form.date">
|
||||
ثبت سند
|
||||
</v-btn>
|
||||
</v-form>
|
||||
</v-container>
|
||||
|
||||
<!-- دیالوگ تأیید حذف -->
|
||||
<v-dialog v-model="deleteDialog" max-width="400">
|
||||
<v-card>
|
||||
<v-card-title class="text-h5">
|
||||
حذف سند
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
آیا مطمئن هستید که میخواهید این سند را حذف کنید؟
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="grey-darken-1" variant="text" @click="deleteDialog = false">
|
||||
انصراف
|
||||
</v-btn>
|
||||
<v-btn color="error" variant="text" @click="confirmDelete" :loading="loading">
|
||||
حذف
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
import moment from 'jalali-moment';
|
||||
import Hdatepicker from '@/components/forms/Hdatepicker.vue';
|
||||
import Haccountsearch from '@/components/forms/Haccountsearch.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Hdatepicker,
|
||||
Haccountsearch
|
||||
},
|
||||
props: {
|
||||
docId: {
|
||||
|
@ -135,7 +237,7 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
form: {
|
||||
date: '', // تاریخ به فرمت ISO (مثلاً 2025-03-24)
|
||||
date: '',
|
||||
des: '',
|
||||
rows: [
|
||||
{ ref: null, refName: '', bd: '0', bs: '0', des: '', selectedAccounts: [] },
|
||||
|
@ -145,13 +247,8 @@ export default {
|
|||
totalBd: 0,
|
||||
totalBs: 0,
|
||||
error: null,
|
||||
headers: [
|
||||
{ text: 'حساب', value: 'ref' },
|
||||
{ text: 'بدهکار', value: 'bd' },
|
||||
{ text: 'بستانکار', value: 'bs' },
|
||||
{ text: 'توضیحات', value: 'des' },
|
||||
{ text: 'عملیات', value: 'actions', sortable: false },
|
||||
],
|
||||
deleteDialog: false,
|
||||
loading: false,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
|
@ -173,7 +270,7 @@ export default {
|
|||
async fetchDoc() {
|
||||
try {
|
||||
const response = await axios.get(`/api/hesabdari/doc/${this.docId}`);
|
||||
const serverDate = response.data.data.date; // فرض: تاریخ شمسی از سرور
|
||||
const serverDate = response.data.data.date;
|
||||
this.form.date = moment(serverDate, 'YYYY/MM/DD').format('YYYY-MM-DD');
|
||||
this.form.des = response.data.data.des || '';
|
||||
this.form.rows = response.data.data.rows.map(row => ({
|
||||
|
@ -219,7 +316,7 @@ export default {
|
|||
}
|
||||
|
||||
const payload = {
|
||||
date: moment(this.form.date, 'YYYY-MM-DD').locale('fa').format('YYYY/MM/DD'), // ارسال به فرمت شمسی
|
||||
date: moment(this.form.date, 'YYYY-MM-DD').locale('fa').format('YYYY/MM/DD'),
|
||||
des: this.form.des,
|
||||
rows: this.form.rows.map(row => ({
|
||||
ref: row.ref,
|
||||
|
@ -230,6 +327,7 @@ export default {
|
|||
};
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
if (this.docId) {
|
||||
await axios.put(`/api/hesabdari/doc/${this.docId}`, payload);
|
||||
this.$emit('saved', 'سند با موفقیت ویرایش شد');
|
||||
|
@ -239,6 +337,21 @@ export default {
|
|||
}
|
||||
} catch (error) {
|
||||
this.error = error.response?.data?.message || 'خطا در ثبت سند';
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
async confirmDelete() {
|
||||
try {
|
||||
this.loading = true;
|
||||
await axios.delete(`/api/hesabdari/doc/${this.docId}`);
|
||||
this.$router.push('/acc/accounting/list');
|
||||
} catch (error) {
|
||||
this.error = 'خطا در حذف سند';
|
||||
console.error(error);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
this.deleteDialog = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
|
@ -1,42 +1,28 @@
|
|||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import ClassicEditor from '@ckeditor/ckeditor5-build-classic';
|
||||
import axios from "axios";
|
||||
import Swal from "sweetalert2";
|
||||
import { defineComponent } from 'vue';
|
||||
import axios from 'axios';
|
||||
import Swal from 'sweetalert2';
|
||||
import Loading from 'vue-loading-overlay';
|
||||
import 'vue-loading-overlay/dist/css/index.css';
|
||||
|
||||
export default defineComponent({
|
||||
name: "mod",
|
||||
name: 'mod',
|
||||
components: { Loading },
|
||||
data: () => {
|
||||
return {
|
||||
loading: true,
|
||||
id: '',
|
||||
version: '',
|
||||
body: '',
|
||||
editor: ClassicEditor,
|
||||
editorConfig: {
|
||||
language: 'fa',
|
||||
fontFamily: {
|
||||
options: [
|
||||
'default',
|
||||
'vazir', 'sans-serif',
|
||||
'Ubuntu Mono, Courier New, Courier, monospace'
|
||||
]
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
data: () => ({
|
||||
loading: true,
|
||||
id: '',
|
||||
version: '',
|
||||
body: '',
|
||||
}),
|
||||
mounted() {
|
||||
this.id = this.$route.params.id;
|
||||
if (this.id != 0) {
|
||||
if (this.id !== '0') {
|
||||
axios.post('/api/admin/reportchange/get/' + this.id).then((response) => {
|
||||
this.version = response.data.version;
|
||||
this.body = response.data.body;
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
@ -48,29 +34,30 @@ export default defineComponent({
|
|||
icon: 'error',
|
||||
confirmButtonText: 'قبول',
|
||||
});
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this.loading = true;
|
||||
axios.post('/api/admin/reportchange/mod/' + this.id, {
|
||||
id: this.id,
|
||||
version: this.version,
|
||||
body: this.body
|
||||
}).then((response) => {
|
||||
if (response.data.result == 1) {
|
||||
this.loading = false;
|
||||
Swal.fire({
|
||||
text: 'گزارش ثبت شد',
|
||||
icon: 'success',
|
||||
confirmButtonText: 'قبول',
|
||||
}).then((res) => {
|
||||
this.$router.push('/profile/manager/changes/list');
|
||||
})
|
||||
}
|
||||
})
|
||||
axios
|
||||
.post('/api/admin/reportchange/mod/' + this.id, {
|
||||
id: this.id,
|
||||
version: this.version,
|
||||
body: this.body,
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.data.result === 1) {
|
||||
this.loading = false;
|
||||
Swal.fire({
|
||||
text: 'گزارش ثبت شد',
|
||||
icon: 'success',
|
||||
confirmButtonText: 'قبول',
|
||||
}).then(() => {
|
||||
this.$router.push('/profile/manager/changes/list');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -82,20 +69,38 @@ export default defineComponent({
|
|||
<v-card-text class="pa-2">
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<v-text-field class="" hide-details="auto" :label="$t('pages.manager.version')" v-model="version" type="text"
|
||||
<v-text-field
|
||||
hide-details="auto"
|
||||
:label="$t('pages.manager.version')"
|
||||
v-model="version"
|
||||
type="text"
|
||||
prepend-inner-icon="mdi-power-socket-uk"
|
||||
:rules="[() => version.length > 0 || $t('validator.required')]"></v-text-field>
|
||||
:rules="[() => version.length > 0 || $t('validator.required')]"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="12">
|
||||
<h3 class="mb-2">{{ $t('app.body') }}</h3>
|
||||
<ckeditor :editor="editor" v-model="body" :config="editorConfig"
|
||||
:rules="[() => version.length > 0 || $t('validator.required')]"></ckeditor>
|
||||
<v-textarea
|
||||
v-model="body"
|
||||
: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 cols="12" sm="12" md="12">
|
||||
<v-btn type="submit" @click="submit()" color="primary" prepend-icon="mdi-content-save" :loading="loading"
|
||||
:title="$t('dialog.save')">
|
||||
<v-btn
|
||||
type="submit"
|
||||
@click="submit()"
|
||||
color="primary"
|
||||
prepend-icon="mdi-content-save"
|
||||
:loading="loading"
|
||||
:title="$t('dialog.save')"
|
||||
>
|
||||
{{ $t('dialog.save') }}
|
||||
</v-btn>
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card-text>
|
||||
|
@ -103,4 +108,12 @@ export default defineComponent({
|
|||
</v-container>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped>
|
||||
.v-textarea {
|
||||
font-family: 'Vazirmatn FD', sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 1.8;
|
||||
text-align: right;
|
||||
direction: rtl;
|
||||
}
|
||||
</style>
|
|
@ -1,8 +1,13 @@
|
|||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.node.json",
|
||||
"include": ["vite.config.*", "vitest.config.*", "cypress.config.*", "playwright.config.*"],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"target": "esnext",
|
||||
"types": ["node"],
|
||||
}
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true
|
||||
},
|
||||
"include": ["vite.config.*", "vitest.config.*", "cypress.config.*", "playwright.config.*"]
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.web.json",
|
||||
"extends": "@vue/tsconfig/tsconfig.json",
|
||||
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
|
@ -7,9 +7,13 @@
|
|||
"@/*": ["./src/*"]
|
||||
},
|
||||
"allowJs": true,
|
||||
"verbatimModuleSyntax": true
|
||||
"verbatimModuleSyntax": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"types": ["vite/client"]
|
||||
},
|
||||
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.config.json"
|
||||
|
|
Loading…
Reference in a new issue