bug fix in persons and progress in redesign cost mod
This commit is contained in:
parent
2f3a47fc49
commit
290f5689dc
|
@ -543,15 +543,11 @@ class PersonsController extends AbstractController
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($include) {
|
if ($include) {
|
||||||
$response[] = [
|
$result = Explore::ExplorePerson($person, $entityManager->getRepository(PersonType::class)->findAll());
|
||||||
'id' => $person->getId(),
|
$result['bs'] = $bs;
|
||||||
'name' => $person->getName(),
|
$result['bd'] = $bd;
|
||||||
'nikename' => $person->getNikename(),
|
$result['balance'] = $balance;
|
||||||
'code' => $person->getCode(),
|
$response[] = $result;
|
||||||
'bs' => $bs, // بستانکار
|
|
||||||
'bd' => $bd, // بدهکار
|
|
||||||
'balance' => $balance, // تراز
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1059,14 +1055,14 @@ class PersonsController extends AbstractController
|
||||||
if (!$acc) {
|
if (!$acc) {
|
||||||
throw $this->createAccessDeniedException();
|
throw $this->createAccessDeniedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
// دریافت پارامترها
|
// دریافت پارامترها
|
||||||
$params = json_decode($request->getContent(), true) ?? [];
|
$params = json_decode($request->getContent(), true) ?? [];
|
||||||
$page = (int) ($params['page'] ?? 1);
|
$page = (int) ($params['page'] ?? 1);
|
||||||
$itemsPerPage = (int) ($params['itemsPerPage'] ?? 10);
|
$itemsPerPage = (int) ($params['itemsPerPage'] ?? 10);
|
||||||
$search = $params['search'] ?? '';
|
$search = $params['search'] ?? '';
|
||||||
$dateFilter = $params['dateFilter'] ?? 'all';
|
$dateFilter = $params['dateFilter'] ?? 'all';
|
||||||
|
|
||||||
// کوئری پایه برای اسناد
|
// کوئری پایه برای اسناد
|
||||||
$queryBuilder = $entityManager->getRepository(HesabdariDoc::class)
|
$queryBuilder = $entityManager->getRepository(HesabdariDoc::class)
|
||||||
->createQueryBuilder('d')
|
->createQueryBuilder('d')
|
||||||
|
@ -1078,13 +1074,13 @@ class PersonsController extends AbstractController
|
||||||
->andWhere('d.year = :year')
|
->andWhere('d.year = :year')
|
||||||
->andWhere('d.money = :money')
|
->andWhere('d.money = :money')
|
||||||
->setParameters([
|
->setParameters([
|
||||||
'bid' => $acc['bid'],
|
'bid' => $acc['bid'],
|
||||||
'type' => 'person_receive',
|
'type' => 'person_receive',
|
||||||
'year' => $acc['year'],
|
'year' => $acc['year'],
|
||||||
'money' => $acc['money'],
|
'money' => $acc['money'],
|
||||||
])
|
])
|
||||||
->orderBy('d.id', 'DESC');
|
->orderBy('d.id', 'DESC');
|
||||||
|
|
||||||
// جستوجو
|
// جستوجو
|
||||||
if (!empty($search)) {
|
if (!empty($search)) {
|
||||||
$queryBuilder->andWhere(
|
$queryBuilder->andWhere(
|
||||||
|
@ -1095,7 +1091,7 @@ class PersonsController extends AbstractController
|
||||||
)
|
)
|
||||||
)->setParameter('search', "%$search%");
|
)->setParameter('search', "%$search%");
|
||||||
}
|
}
|
||||||
|
|
||||||
// فیلتر تاریخ
|
// فیلتر تاریخ
|
||||||
$today = $jdate->GetTodayDate();
|
$today = $jdate->GetTodayDate();
|
||||||
switch ($dateFilter) {
|
switch ($dateFilter) {
|
||||||
|
@ -1123,14 +1119,14 @@ class PersonsController extends AbstractController
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// محاسبه تعداد کل
|
// محاسبه تعداد کل
|
||||||
$totalQuery = (clone $queryBuilder)
|
$totalQuery = (clone $queryBuilder)
|
||||||
->select('COUNT(DISTINCT d.id) as total')
|
->select('COUNT(DISTINCT d.id) as total')
|
||||||
->getQuery()
|
->getQuery()
|
||||||
->getSingleResult();
|
->getSingleResult();
|
||||||
$total = (int) $totalQuery['total'];
|
$total = (int) $totalQuery['total'];
|
||||||
|
|
||||||
// گرفتن اسناد با صفحهبندی
|
// گرفتن اسناد با صفحهبندی
|
||||||
$docs = $queryBuilder
|
$docs = $queryBuilder
|
||||||
->setFirstResult(($page - 1) * $itemsPerPage)
|
->setFirstResult(($page - 1) * $itemsPerPage)
|
||||||
|
@ -1173,7 +1169,7 @@ class PersonsController extends AbstractController
|
||||||
'persons' => $persons[$doc['id']] ?? [],
|
'persons' => $persons[$doc['id']] ?? [],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->json([
|
return $this->json([
|
||||||
'items' => $items,
|
'items' => $items,
|
||||||
'total' => $total,
|
'total' => $total,
|
||||||
|
|
187
webUI/src/components/forms/Htabletreeselect.vue
Normal file
187
webUI/src/components/forms/Htabletreeselect.vue
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
<template>
|
||||||
|
<v-menu v-model="menu" :close-on-content-click="false">
|
||||||
|
<template v-slot:activator="{ props }">
|
||||||
|
<v-text-field
|
||||||
|
v-bind="props"
|
||||||
|
:model-value="selectedItem ? decodeLabel(selectedItem.label) + ` (${selectedItem.id})` : ''"
|
||||||
|
readonly
|
||||||
|
variant="outlined"
|
||||||
|
hide-details
|
||||||
|
density="compact"
|
||||||
|
:label="label"
|
||||||
|
class=""
|
||||||
|
prepend-inner-icon="mdi-table"
|
||||||
|
clearable
|
||||||
|
@click:clear="clearSelection"
|
||||||
|
>
|
||||||
|
<template v-slot:append-inner>
|
||||||
|
<v-icon>{{ menu ? 'mdi-chevron-up' : 'mdi-chevron-down' }}</v-icon>
|
||||||
|
</template>
|
||||||
|
</v-text-field>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<v-card min-width="300" max-width="400">
|
||||||
|
<v-card-text class="pa-2">
|
||||||
|
<v-text-field
|
||||||
|
v-model="searchQuery"
|
||||||
|
density="compact"
|
||||||
|
variant="outlined"
|
||||||
|
hide-details
|
||||||
|
class="mb-2"
|
||||||
|
placeholder="جستجو..."
|
||||||
|
prepend-inner-icon="mdi-magnify"
|
||||||
|
clearable
|
||||||
|
@click:clear="searchQuery = ''"
|
||||||
|
></v-text-field>
|
||||||
|
|
||||||
|
<v-treeview
|
||||||
|
:items="filteredItems"
|
||||||
|
item-children="children"
|
||||||
|
item-title="label"
|
||||||
|
item-value="id"
|
||||||
|
:loading="loading"
|
||||||
|
density="compact"
|
||||||
|
class="tree-container rtl-tree"
|
||||||
|
hoverable
|
||||||
|
>
|
||||||
|
<template v-slot:prepend="{ item }">
|
||||||
|
<div class="d-flex align-center">
|
||||||
|
<v-radio
|
||||||
|
:model-value="selectedItem?.id"
|
||||||
|
:value="item.id"
|
||||||
|
hide-details
|
||||||
|
density="compact"
|
||||||
|
@click.stop
|
||||||
|
@change="selectItem(item)"
|
||||||
|
></v-radio>
|
||||||
|
<v-icon size="small" class="mr-1">
|
||||||
|
{{ item.children && item.children.length > 0 ? 'mdi-folder' : 'mdi-file-outline' }}
|
||||||
|
</v-icon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-slot:label="{ item }">
|
||||||
|
{{ decodeLabel(item.label) }} ({{ item.id }})
|
||||||
|
</template>
|
||||||
|
</v-treeview>
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
</v-menu>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'CostTreeSelect',
|
||||||
|
props: {
|
||||||
|
modelValue: {
|
||||||
|
type: [Object, Number],
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
default: 'جدول حساب'
|
||||||
|
},
|
||||||
|
returnObject: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
selectedItem: null,
|
||||||
|
treeItems: [],
|
||||||
|
loading: false,
|
||||||
|
menu: false,
|
||||||
|
searchQuery: ''
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
filteredItems() {
|
||||||
|
if (!this.searchQuery) return this.treeItems;
|
||||||
|
|
||||||
|
const searchTerm = this.searchQuery.toLowerCase();
|
||||||
|
return this.filterNodes(this.treeItems, (node) => {
|
||||||
|
const labelMatch = this.decodeLabel(node.label).toLowerCase().includes(searchTerm);
|
||||||
|
const idMatch = node.id.toString().includes(searchTerm);
|
||||||
|
return labelMatch || idMatch;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
modelValue: {
|
||||||
|
handler(newVal) {
|
||||||
|
if (this.returnObject) {
|
||||||
|
this.selectedItem = newVal;
|
||||||
|
} else {
|
||||||
|
this.selectedItem = this.findItemById(this.treeItems, newVal);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
findItemById(items, id) {
|
||||||
|
for (const item of items) {
|
||||||
|
if (item.id === id) return item;
|
||||||
|
if (item.children?.length) {
|
||||||
|
const found = this.findItemById(item.children, id);
|
||||||
|
if (found) return found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
async fetchTreeData() {
|
||||||
|
this.loading = true;
|
||||||
|
try {
|
||||||
|
const response = await axios.get('/api/accounting/table/childs/cost');
|
||||||
|
this.treeItems = response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('خطا در دریافت دادهها:', error);
|
||||||
|
this.$toast.error('خطا در بارگذاری دادهها');
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
decodeLabel(label) {
|
||||||
|
try {
|
||||||
|
return decodeURIComponent(JSON.parse(`"${label}"`));
|
||||||
|
} catch (e) {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
selectItem(item) {
|
||||||
|
this.selectedItem = item;
|
||||||
|
this.$emit('update:modelValue', this.returnObject ? item : item.id);
|
||||||
|
this.menu = false;
|
||||||
|
},
|
||||||
|
clearSelection() {
|
||||||
|
this.selectedItem = null;
|
||||||
|
this.$emit('update:modelValue', null);
|
||||||
|
},
|
||||||
|
filterNodes(nodes, predicate) {
|
||||||
|
return nodes.reduce((filtered, node) => {
|
||||||
|
const clone = { ...node };
|
||||||
|
|
||||||
|
if (predicate(clone)) {
|
||||||
|
if (clone.children?.length) {
|
||||||
|
clone.children = this.filterNodes(clone.children, predicate);
|
||||||
|
}
|
||||||
|
filtered.push(clone);
|
||||||
|
} else if (clone.children?.length) {
|
||||||
|
clone.children = this.filterNodes(clone.children, predicate);
|
||||||
|
if (clone.children.length) {
|
||||||
|
filtered.push(clone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filtered;
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.fetchTreeData();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
|
@ -102,16 +102,7 @@
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="12" md="4">
|
<v-col cols="12" md="4">
|
||||||
<v-select
|
<Htabletreeselect v-model="item.id" :items="listscosts" label="مرکز هزینه" />
|
||||||
v-model="item.id"
|
|
||||||
:items="formattedCostItems"
|
|
||||||
item-title="label"
|
|
||||||
item-value="id"
|
|
||||||
label="مرکز هزینه"
|
|
||||||
variant="outlined"
|
|
||||||
density="compact"
|
|
||||||
return-object
|
|
||||||
></v-select>
|
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="12" md="4">
|
<v-col cols="12" md="4">
|
||||||
<Hnumberinput
|
<Hnumberinput
|
||||||
|
@ -203,19 +194,18 @@ import 'vue-loading-overlay/dist/css/index.css';
|
||||||
import archiveUpload from "../component/archive/archiveUpload.vue";
|
import archiveUpload from "../component/archive/archiveUpload.vue";
|
||||||
import Hdatepicker from "@/components/forms/Hdatepicker.vue";
|
import Hdatepicker from "@/components/forms/Hdatepicker.vue";
|
||||||
import Hnumberinput from "@/components/forms/Hnumberinput.vue";
|
import Hnumberinput from "@/components/forms/Hnumberinput.vue";
|
||||||
import Treeselect from 'vue3-treeselect'
|
import Htabletreeselect from '@/components/forms/Htabletreeselect.vue'
|
||||||
// import the styles
|
// import the styles
|
||||||
import 'vue3-treeselect/dist/vue3-treeselect.css'
|
|
||||||
import quickAdd from "../component/person/quickAdd.vue";
|
import quickAdd from "../component/person/quickAdd.vue";
|
||||||
export default {
|
export default {
|
||||||
name: "mod",
|
name: "mod",
|
||||||
components: {
|
components: {
|
||||||
Loading,
|
Loading,
|
||||||
Treeselect,
|
|
||||||
archiveUpload,
|
archiveUpload,
|
||||||
quickAdd,
|
quickAdd,
|
||||||
Hdatepicker,
|
Hdatepicker,
|
||||||
Hnumberinput
|
Hnumberinput,
|
||||||
|
Htabletreeselect,
|
||||||
},
|
},
|
||||||
data: () => {
|
data: () => {
|
||||||
return {
|
return {
|
||||||
|
|
Loading…
Reference in a new issue