fix(treasury): scope finance access and hide it when the module is off
Accounts can be edited, including the opening balance, and finance sections and accounts can be granted on a role or on one user. The finance menu stays hidden when the organization module is disabled. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -14,6 +14,7 @@ import {
|
||||
DATA_ACCESS_SECTIONS,
|
||||
ROLE_PERMISSION_ITEMS,
|
||||
type DataAccessPolicy,
|
||||
type FinancialAccountDto,
|
||||
type InviteUserRequest,
|
||||
type OrganizationDto,
|
||||
type OrgModuleKey,
|
||||
@@ -74,7 +75,16 @@ const PERMISSION_MODULES: Partial<Record<RolePermissionKey, OrgModuleKey[]>> = {
|
||||
conversations: ['conversations'],
|
||||
conversations_groups: ['conversations'],
|
||||
treasury: ['treasury'],
|
||||
treasury_dashboard: ['treasury'],
|
||||
treasury_incomes: ['treasury'],
|
||||
treasury_expenses: ['treasury'],
|
||||
treasury_receivables: ['treasury'],
|
||||
treasury_accounts: ['treasury'],
|
||||
treasury_payroll: ['treasury'],
|
||||
treasury_recurring: ['treasury'],
|
||||
treasury_reports: ['treasury'],
|
||||
treasury_audit: ['treasury'],
|
||||
treasury_categories: ['treasury'],
|
||||
behavior: ['behavior'],
|
||||
};
|
||||
|
||||
@@ -139,6 +149,10 @@ const roleFormDesc = ref('');
|
||||
const roleFormColor = ref<RoleColor>('teal');
|
||||
const roleFormParentId = ref('');
|
||||
const roleFormPerms = ref<RolePermissionKey[]>(ROLE_PERMISSION_ITEMS.map((p) => p.key));
|
||||
const roleFormAccountIds = ref<string[]>([]);
|
||||
const roleFormOwnAccounts = ref(false);
|
||||
const roleFormAccounts = ref<Array<{ id: string; name: string; responsibleName: string }>>([]);
|
||||
const roleAccountQuery = ref('');
|
||||
|
||||
const deleteOpen = ref(false);
|
||||
const deleteSaving = ref(false);
|
||||
@@ -616,7 +630,11 @@ function openCreateRole(parentId?: string | null) {
|
||||
? [...parent.permissions]
|
||||
: visibleRolePermissions.value.map((p) => p.key);
|
||||
roleFormDataAccess.value = clonePolicy(parent?.dataAccessPolicy);
|
||||
roleFormAccountIds.value = [...(parent?.treasuryAccountIds ?? [])];
|
||||
roleFormOwnAccounts.value = Boolean(parent?.treasuryOwnAccounts);
|
||||
roleAccountQuery.value = '';
|
||||
roleFormOpen.value = true;
|
||||
void loadRoleAccounts();
|
||||
}
|
||||
|
||||
function openCreateChildRole() {
|
||||
@@ -636,7 +654,40 @@ function openEditRole() {
|
||||
roleFormParentId.value = role.systemKey ? '' : (role.parentId ?? '');
|
||||
roleFormPerms.value = [...role.permissions];
|
||||
roleFormDataAccess.value = clonePolicy(role.dataAccessPolicy);
|
||||
roleFormAccountIds.value = [...(role.treasuryAccountIds ?? [])];
|
||||
roleFormOwnAccounts.value = Boolean(role.treasuryOwnAccounts);
|
||||
roleAccountQuery.value = '';
|
||||
roleFormOpen.value = true;
|
||||
void loadRoleAccounts();
|
||||
}
|
||||
|
||||
function isTreasuryDetail(key: RolePermissionKey) {
|
||||
return key.startsWith('treasury_');
|
||||
}
|
||||
|
||||
const filteredRoleAccounts = computed(() => {
|
||||
const query = roleAccountQuery.value.trim();
|
||||
if (!query) return roleFormAccounts.value;
|
||||
return roleFormAccounts.value.filter((account) => account.name.includes(query));
|
||||
});
|
||||
|
||||
async function loadRoleAccounts() {
|
||||
try {
|
||||
const { data } = await api.get<FinancialAccountDto[]>('/treasury/accounts');
|
||||
roleFormAccounts.value = data.map((account) => ({
|
||||
id: account.id,
|
||||
name: account.name,
|
||||
responsibleName: account.responsibleName?.trim() ?? '',
|
||||
}));
|
||||
} catch {
|
||||
roleFormAccounts.value = [];
|
||||
}
|
||||
}
|
||||
|
||||
function toggleRoleAccount(id: string) {
|
||||
roleFormAccountIds.value = roleFormAccountIds.value.includes(id)
|
||||
? roleFormAccountIds.value.filter((item) => item !== id)
|
||||
: [...roleFormAccountIds.value, id];
|
||||
}
|
||||
|
||||
function permOn(key: RolePermissionKey) {
|
||||
@@ -644,6 +695,14 @@ function permOn(key: RolePermissionKey) {
|
||||
}
|
||||
|
||||
function toggleFormPerm(key: RolePermissionKey) {
|
||||
if (key === 'treasury' && permOn('treasury')) {
|
||||
roleFormPerms.value = roleFormPerms.value.filter(
|
||||
(item) => item !== 'treasury' && !item.startsWith('treasury_'),
|
||||
);
|
||||
roleFormAccountIds.value = [];
|
||||
roleFormOwnAccounts.value = false;
|
||||
return;
|
||||
}
|
||||
roleFormPerms.value = permOn(key)
|
||||
? roleFormPerms.value.filter((p) => p !== key)
|
||||
: [...roleFormPerms.value, key];
|
||||
@@ -667,12 +726,16 @@ async function submitRoleForm() {
|
||||
permissions: RolePermissionKey[];
|
||||
dataAccessPolicy?: OrgRoleDto['dataAccessPolicy'];
|
||||
parentId?: string | null;
|
||||
treasuryAccountIds?: string[];
|
||||
treasuryOwnAccounts?: boolean;
|
||||
} = {
|
||||
name: roleFormName.value.trim(),
|
||||
description: roleFormDesc.value.trim(),
|
||||
color: roleFormColor.value,
|
||||
permissions: roleFormPerms.value,
|
||||
dataAccessPolicy: roleFormDataAccess.value,
|
||||
treasuryAccountIds: roleFormAccountIds.value,
|
||||
treasuryOwnAccounts: roleFormOwnAccounts.value,
|
||||
};
|
||||
if (!editing?.systemKey) {
|
||||
body.parentId = roleFormParentId.value || null;
|
||||
@@ -1491,11 +1554,48 @@ onUnmounted(() => {
|
||||
</label>
|
||||
<fieldset class="perm-set">
|
||||
<legend>مجوزهای دسترسی</legend>
|
||||
<label v-for="perm in visibleRolePermissions" :key="perm.key" class="perm-row">
|
||||
<p class="hint">
|
||||
تیک مدیریت مالی در را باز میکند. بخشهای ریز جدا انتخاب میشوند و با روشن کردن مدیریت مالی خودبهخود تیک نمیخورند.
|
||||
تا وقتی هیچ بخش ریزی ذخیره نشده، همه بخشها بهجز حقوق باز میمانند. با ذخیره حتی یک بخش، فقط همانها میمانند. حقوق جداست.
|
||||
</p>
|
||||
<label
|
||||
v-for="perm in visibleRolePermissions"
|
||||
v-show="!isTreasuryDetail(perm.key) || permOn('treasury')"
|
||||
:key="perm.key"
|
||||
class="perm-row"
|
||||
:class="{ 'perm-sub': isTreasuryDetail(perm.key) }"
|
||||
>
|
||||
<input type="checkbox" :checked="permOn(perm.key)" @change="toggleFormPerm(perm.key)" />
|
||||
{{ perm.label }}
|
||||
</label>
|
||||
</fieldset>
|
||||
<fieldset v-if="permOn('treasury')" class="perm-set">
|
||||
<legend>دسترسی حسابها</legend>
|
||||
<p class="hint">
|
||||
این بخش جدا از تیک بخشهای مالی است. میتوانید حسابهایی را بدهید که خود عضو مسئول آنهاست،
|
||||
و جدا از آن حسابهای دیگر را هم انتخاب کنید. اگر هیچکدام انتخاب نشود، همه حسابها باز میماند.
|
||||
</p>
|
||||
<label class="perm-row">
|
||||
<input
|
||||
type="checkbox"
|
||||
:checked="roleFormOwnAccounts"
|
||||
@change="roleFormOwnAccounts = !roleFormOwnAccounts"
|
||||
/>
|
||||
حسابهایی که خودش مسئول آنهاست
|
||||
</label>
|
||||
<p class="hint">حسابهای دیگر</p>
|
||||
<input v-model="roleAccountQuery" placeholder="جستجوی حساب" />
|
||||
<label v-for="account in filteredRoleAccounts" :key="account.id" class="perm-row">
|
||||
<input
|
||||
type="checkbox"
|
||||
:checked="roleFormAccountIds.includes(account.id)"
|
||||
@change="toggleRoleAccount(account.id)"
|
||||
/>
|
||||
{{ account.name }}
|
||||
<template v-if="account.responsibleName"> — مسئول: {{ account.responsibleName }}</template>
|
||||
</label>
|
||||
<p v-if="!roleFormAccounts.length" class="hint">حسابی برای انتخاب نیست.</p>
|
||||
</fieldset>
|
||||
<fieldset class="perm-set">
|
||||
<legend>محدوده داده</legend>
|
||||
<DataAccessPolicyPanel
|
||||
@@ -2381,6 +2481,10 @@ textarea {
|
||||
color: #0f172a;
|
||||
}
|
||||
|
||||
.perm-sub {
|
||||
padding-inline-start: 1.4rem;
|
||||
}
|
||||
|
||||
.sheet-handle,
|
||||
.sheet-backdrop {
|
||||
display: none;
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
message,
|
||||
} from 'ant-design-vue';
|
||||
import { api } from '@/lib/api';
|
||||
import type { FinancialAccountDto, FinancialAccountType } from '@mento/shared';
|
||||
import type { FinancialAccountDto, FinancialAccountType, OrgUserDto } from '@mento/shared';
|
||||
import MoneyInput from '@/components/MoneyInput.vue';
|
||||
import JalaliDateInput from '@/components/JalaliDateInput.vue';
|
||||
import { toman } from './treasury-format';
|
||||
@@ -35,12 +35,15 @@ const AListItemMeta = AList.Item.Meta;
|
||||
const ASelectOption = ASelect.Option;
|
||||
|
||||
const accounts = ref<FinancialAccountDto[]>([]);
|
||||
const users = ref<OrgUserDto[]>([]);
|
||||
const error = ref('');
|
||||
const ok = ref('');
|
||||
const openForm = ref(false);
|
||||
const editingId = ref<string | null>(null);
|
||||
const responsibleKey = ref<string | undefined>(undefined);
|
||||
const saving = ref(false);
|
||||
const transferOpen = ref(false);
|
||||
const form = ref({
|
||||
const emptyForm = () => ({
|
||||
name: '',
|
||||
type: 'cash' as FinancialAccountType,
|
||||
bankName: '',
|
||||
@@ -50,6 +53,7 @@ const form = ref({
|
||||
openingDate: '',
|
||||
notes: '',
|
||||
});
|
||||
const form = ref(emptyForm());
|
||||
const transfer = ref({
|
||||
fromAccountId: '',
|
||||
toAccountId: '',
|
||||
@@ -80,9 +84,54 @@ function apiMessage(e: unknown) {
|
||||
return Array.isArray(msg) ? msg.join('، ') : msg || 'عملیات ناموفق بود.';
|
||||
}
|
||||
|
||||
const responsibleOptions = computed(() => {
|
||||
const rows = users.value.map((user) => ({ id: user.id, fullName: user.fullName }));
|
||||
const current = form.value.responsibleName.trim();
|
||||
if (current && !rows.some((row) => row.fullName === current)) {
|
||||
rows.unshift({ id: `name:${current}`, fullName: current });
|
||||
}
|
||||
return rows;
|
||||
});
|
||||
|
||||
async function load() {
|
||||
const { data } = await api.get<FinancialAccountDto[]>('/treasury/accounts');
|
||||
accounts.value = data;
|
||||
try {
|
||||
const usersRes = await api.get<OrgUserDto[]>('/users');
|
||||
users.value = usersRes.data;
|
||||
} catch {
|
||||
users.value = [];
|
||||
}
|
||||
}
|
||||
|
||||
function resetForm() {
|
||||
editingId.value = null;
|
||||
responsibleKey.value = undefined;
|
||||
form.value = emptyForm();
|
||||
}
|
||||
|
||||
function startEdit(item: FinancialAccountDto) {
|
||||
editingId.value = item.id;
|
||||
form.value = {
|
||||
name: item.name,
|
||||
type: item.type,
|
||||
bankName: item.bankName ?? '',
|
||||
accountRef: item.accountRef ?? '',
|
||||
responsibleName: item.responsibleName ?? '',
|
||||
openingBalance: item.openingBalance,
|
||||
openingDate: item.openingDate.slice(0, 10),
|
||||
notes: item.notes ?? '',
|
||||
};
|
||||
const match = users.value.find((user) => user.fullName === item.responsibleName);
|
||||
responsibleKey.value = match?.id ?? (item.responsibleName ? `name:${item.responsibleName}` : undefined);
|
||||
openForm.value = true;
|
||||
}
|
||||
|
||||
function responsibleNameFromKey() {
|
||||
const key = responsibleKey.value;
|
||||
if (!key) return null;
|
||||
if (key.startsWith('name:')) return key.slice(5);
|
||||
return users.value.find((user) => user.id === key)?.fullName ?? null;
|
||||
}
|
||||
|
||||
function onFinishFailed() {
|
||||
@@ -95,23 +144,21 @@ async function createAccount() {
|
||||
ok.value = '';
|
||||
try {
|
||||
const openingBalance = parseMoneyNumber(String(form.value.openingBalance ?? ''), 0) ?? 0;
|
||||
await api.post('/treasury/accounts', {
|
||||
const body = {
|
||||
...form.value,
|
||||
responsibleName: responsibleNameFromKey(),
|
||||
openingBalance,
|
||||
openingDate: form.value.openingDate || undefined,
|
||||
});
|
||||
openForm.value = false;
|
||||
form.value = {
|
||||
name: '',
|
||||
type: 'cash',
|
||||
bankName: '',
|
||||
accountRef: '',
|
||||
responsibleName: '',
|
||||
openingBalance: '',
|
||||
openingDate: '',
|
||||
notes: '',
|
||||
};
|
||||
ok.value = 'حساب ثبت شد. موجودی اولیه درآمد دوره نیست.';
|
||||
if (editingId.value) {
|
||||
await api.patch(`/treasury/accounts/${editingId.value}`, body);
|
||||
ok.value = 'حساب بهروز شد. موجودی از مانده افتتاحیه و گردش قطعی محاسبه میشود.';
|
||||
} else {
|
||||
await api.post('/treasury/accounts', body);
|
||||
ok.value = 'حساب ثبت شد. موجودی اولیه درآمد دوره نیست.';
|
||||
}
|
||||
openForm.value = false;
|
||||
resetForm();
|
||||
await load();
|
||||
} catch (e) {
|
||||
error.value = apiMessage(e);
|
||||
@@ -193,12 +240,18 @@ onMounted(() => {
|
||||
|
||||
<a-card :bordered="false">
|
||||
<a-space>
|
||||
<a-button type="primary" @click="openForm = !openForm">افزودن حساب جدید</a-button>
|
||||
<a-button
|
||||
type="primary"
|
||||
@click="
|
||||
openForm = !openForm;
|
||||
if (!openForm) resetForm();
|
||||
"
|
||||
>افزودن حساب جدید</a-button>
|
||||
<a-button @click="transferOpen = !transferOpen">انتقال وجه</a-button>
|
||||
</a-space>
|
||||
|
||||
<template v-if="openForm">
|
||||
<a-divider orientation="right">حساب جدید</a-divider>
|
||||
<a-divider orientation="right">{{ editingId ? 'ویرایش حساب' : 'حساب جدید' }}</a-divider>
|
||||
<a-form
|
||||
layout="vertical"
|
||||
:model="form"
|
||||
@@ -217,10 +270,15 @@ onMounted(() => {
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="8">
|
||||
<a-form-item label="نوع" name="type" :rules="[{ required: true }]">
|
||||
<a-select v-model:value="form.type" style="width: 100%">
|
||||
<a-select-option value="cash">صندوق نقدی</a-select-option>
|
||||
<a-select-option value="bank">حساب بانکی</a-select-option>
|
||||
<a-select-option value="petty">تنخواه</a-select-option>
|
||||
<a-select
|
||||
v-model:value="form.type"
|
||||
show-search
|
||||
option-filter-prop="label"
|
||||
style="width: 100%"
|
||||
>
|
||||
<a-select-option value="cash" label="صندوق نقدی">صندوق نقدی</a-select-option>
|
||||
<a-select-option value="bank" label="حساب بانکی">حساب بانکی</a-select-option>
|
||||
<a-select-option value="petty" label="تنخواه">تنخواه</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
@@ -235,8 +293,24 @@ onMounted(() => {
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="8">
|
||||
<a-form-item label="مسئول" name="responsibleName">
|
||||
<a-input v-model:value="form.responsibleName" />
|
||||
<a-form-item label="مسئول">
|
||||
<a-select
|
||||
v-model:value="responsibleKey"
|
||||
show-search
|
||||
allow-clear
|
||||
option-filter-prop="label"
|
||||
style="width: 100%"
|
||||
placeholder="انتخاب کاربر"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="user in responsibleOptions"
|
||||
:key="user.id"
|
||||
:value="user.id"
|
||||
:label="user.fullName"
|
||||
>
|
||||
{{ user.fullName }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="8">
|
||||
@@ -255,7 +329,9 @@ onMounted(() => {
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-button type="primary" html-type="submit" :loading="saving">ثبت حساب</a-button>
|
||||
<a-button type="primary" html-type="submit" :loading="saving">
|
||||
{{ editingId ? 'ذخیره تغییرات' : 'ثبت حساب' }}
|
||||
</a-button>
|
||||
</a-form>
|
||||
</template>
|
||||
|
||||
@@ -276,11 +352,18 @@ onMounted(() => {
|
||||
>
|
||||
<a-select
|
||||
v-model:value="transfer.fromAccountId"
|
||||
show-search
|
||||
option-filter-prop="label"
|
||||
allow-clear
|
||||
style="width: 100%"
|
||||
placeholder="انتخاب"
|
||||
>
|
||||
<a-select-option v-for="account in active" :key="account.id" :value="account.id">
|
||||
<a-select-option
|
||||
v-for="account in active"
|
||||
:key="account.id"
|
||||
:value="account.id"
|
||||
:label="account.name"
|
||||
>
|
||||
{{ account.name }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
@@ -294,6 +377,8 @@ onMounted(() => {
|
||||
>
|
||||
<a-select
|
||||
v-model:value="transfer.toAccountId"
|
||||
show-search
|
||||
option-filter-prop="label"
|
||||
allow-clear
|
||||
style="width: 100%"
|
||||
placeholder="انتخاب"
|
||||
@@ -302,6 +387,7 @@ onMounted(() => {
|
||||
v-for="account in active"
|
||||
:key="`to-${account.id}`"
|
||||
:value="account.id"
|
||||
:label="account.name"
|
||||
>
|
||||
{{ account.name }}
|
||||
</a-select-option>
|
||||
@@ -339,6 +425,7 @@ onMounted(() => {
|
||||
<a-list-item>
|
||||
<template #actions>
|
||||
<a-typography-text strong>{{ toman(item.balance) }}</a-typography-text>
|
||||
<a-button type="link" @click="startEdit(item)">ویرایش</a-button>
|
||||
<RouterLink :to="`/finance/accounts/${item.id}`">جزئیات حساب</RouterLink>
|
||||
</template>
|
||||
<a-list-item-meta>
|
||||
@@ -347,7 +434,9 @@ onMounted(() => {
|
||||
<a-tag v-if="!item.isActive">غیرفعال</a-tag>
|
||||
</template>
|
||||
<template #description>
|
||||
{{ typeLabel[item.type] }} · مشاهده گردش حساب و جزئیات
|
||||
{{ typeLabel[item.type] }}
|
||||
<template v-if="item.responsibleName"> · {{ item.responsibleName }}</template>
|
||||
· موجودی اولیه {{ toman(item.openingBalance) }}
|
||||
</template>
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
|
||||
@@ -73,9 +73,9 @@ onMounted(() => {
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="8">
|
||||
<a-form-item label="نوع" name="kind" :rules="[{ required: true }]">
|
||||
<a-select v-model:value="form.kind" style="width: 100%">
|
||||
<a-select-option value="income">درآمد</a-select-option>
|
||||
<a-select-option value="expense">هزینه</a-select-option>
|
||||
<a-select show-search option-filter-prop="label" v-model:value="form.kind" style="width: 100%">
|
||||
<a-select-option value="income" label="درآمد">درآمد</a-select-option>
|
||||
<a-select-option value="expense" label="هزینه">هزینه</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
@@ -185,13 +185,13 @@ onMounted(() => {
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="8">
|
||||
<a-form-item label="دستهبندی" name="categoryId">
|
||||
<a-select
|
||||
<a-select show-search option-filter-prop="label"
|
||||
v-model:value="form.categoryId"
|
||||
allow-clear
|
||||
style="width: 100%"
|
||||
placeholder="بدون دسته"
|
||||
>
|
||||
<a-select-option v-for="cat in categories" :key="cat.id" :value="cat.id">
|
||||
<a-select-option v-for="cat in categories" :key="cat.id" :value="cat.id" :label="cat.name">
|
||||
{{ cat.name }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
@@ -204,13 +204,13 @@ onMounted(() => {
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="8">
|
||||
<a-form-item label="حساب" name="accountId">
|
||||
<a-select
|
||||
<a-select show-search option-filter-prop="label"
|
||||
v-model:value="form.accountId"
|
||||
allow-clear
|
||||
style="width: 100%"
|
||||
placeholder="انتخاب حساب"
|
||||
>
|
||||
<a-select-option v-for="account in accounts" :key="account.id" :value="account.id">
|
||||
<a-select-option v-for="account in accounts" :key="account.id" :value="account.id" :label="account.name">
|
||||
{{ account.name }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
@@ -218,8 +218,8 @@ onMounted(() => {
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="8">
|
||||
<a-form-item label="روش" name="method">
|
||||
<a-select v-model:value="form.method" style="width: 100%">
|
||||
<a-select-option v-for="opt in methodOptions" :key="opt.value" :value="opt.value">
|
||||
<a-select show-search option-filter-prop="label" v-model:value="form.method" style="width: 100%">
|
||||
<a-select-option v-for="opt in methodOptions" :key="opt.value" :value="opt.value" :label="opt.label">
|
||||
{{ opt.label }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
|
||||
@@ -372,11 +372,12 @@ onMounted(() => {
|
||||
<span>روش دریافت</span>
|
||||
</a-space>
|
||||
</template>
|
||||
<a-select v-model:value="form.method" style="width: 100%">
|
||||
<a-select show-search option-filter-prop="label" v-model:value="form.method" style="width: 100%">
|
||||
<a-select-option
|
||||
v-for="opt in methodOptions"
|
||||
:key="opt.value"
|
||||
:value="opt.value"
|
||||
:label="opt.label"
|
||||
>
|
||||
{{ opt.label }}
|
||||
</a-select-option>
|
||||
@@ -393,13 +394,13 @@ onMounted(() => {
|
||||
</a-space>
|
||||
</template>
|
||||
<a-flex :gap="8">
|
||||
<a-select
|
||||
<a-select show-search option-filter-prop="label"
|
||||
v-model:value="form.categoryId"
|
||||
allow-clear
|
||||
placeholder="انتخاب دسته"
|
||||
style="flex: 1; min-width: 0"
|
||||
>
|
||||
<a-select-option v-for="cat in categories" :key="cat.id" :value="cat.id">
|
||||
<a-select-option v-for="cat in categories" :key="cat.id" :value="cat.id" :label="cat.name">
|
||||
{{ cat.name }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
@@ -471,7 +472,7 @@ onMounted(() => {
|
||||
<span>حساب مقصد</span>
|
||||
</a-space>
|
||||
</template>
|
||||
<a-select
|
||||
<a-select show-search option-filter-prop="label"
|
||||
v-model:value="form.accountId"
|
||||
allow-clear
|
||||
placeholder="انتخاب حساب"
|
||||
@@ -481,6 +482,7 @@ onMounted(() => {
|
||||
v-for="account in accounts"
|
||||
:key="account.id"
|
||||
:value="account.id"
|
||||
:label="account.name"
|
||||
>
|
||||
{{ account.name }}
|
||||
</a-select-option>
|
||||
@@ -617,13 +619,13 @@ onMounted(() => {
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="8">
|
||||
<a-form-item label="دستهبندی" name="categoryId">
|
||||
<a-select
|
||||
<a-select show-search option-filter-prop="label"
|
||||
v-model:value="form.categoryId"
|
||||
allow-clear
|
||||
style="width: 100%"
|
||||
placeholder="بدون دسته"
|
||||
>
|
||||
<a-select-option v-for="cat in categories" :key="cat.id" :value="cat.id">
|
||||
<a-select-option v-for="cat in categories" :key="cat.id" :value="cat.id" :label="cat.name">
|
||||
{{ cat.name }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
@@ -636,7 +638,7 @@ onMounted(() => {
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="8">
|
||||
<a-form-item label="حساب" name="accountId">
|
||||
<a-select
|
||||
<a-select show-search option-filter-prop="label"
|
||||
v-model:value="form.accountId"
|
||||
allow-clear
|
||||
style="width: 100%"
|
||||
@@ -646,6 +648,7 @@ onMounted(() => {
|
||||
v-for="account in accounts"
|
||||
:key="account.id"
|
||||
:value="account.id"
|
||||
:label="account.name"
|
||||
>
|
||||
{{ account.name }}
|
||||
</a-select-option>
|
||||
@@ -654,11 +657,12 @@ onMounted(() => {
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="8">
|
||||
<a-form-item label="روش" name="method">
|
||||
<a-select v-model:value="form.method" style="width: 100%">
|
||||
<a-select show-search option-filter-prop="label" v-model:value="form.method" style="width: 100%">
|
||||
<a-select-option
|
||||
v-for="opt in methodOptions"
|
||||
:key="opt.value"
|
||||
:value="opt.value"
|
||||
:label="opt.label"
|
||||
>
|
||||
{{ opt.label }}
|
||||
</a-select-option>
|
||||
|
||||
@@ -166,13 +166,13 @@ onMounted(() => {
|
||||
name="userId"
|
||||
:rules="[{ required: true, message: 'پرسنل الزامی است' }]"
|
||||
>
|
||||
<a-select
|
||||
<a-select show-search option-filter-prop="label"
|
||||
v-model:value="form.userId"
|
||||
allow-clear
|
||||
style="width: 100%"
|
||||
placeholder="انتخاب"
|
||||
>
|
||||
<a-select-option v-for="user in users" :key="user.id" :value="user.id">
|
||||
<a-select-option v-for="user in users" :key="user.id" :value="user.id" :label="user.fullName">
|
||||
{{ user.fullName }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
@@ -239,7 +239,7 @@ onMounted(() => {
|
||||
name="accountId"
|
||||
:rules="[{ required: true, message: 'حساب الزامی است' }]"
|
||||
>
|
||||
<a-select
|
||||
<a-select show-search option-filter-prop="label"
|
||||
v-model:value="pay.accountId"
|
||||
allow-clear
|
||||
style="width: 100%"
|
||||
@@ -249,6 +249,7 @@ onMounted(() => {
|
||||
v-for="account in accounts"
|
||||
:key="account.id"
|
||||
:value="account.id"
|
||||
:label="account.name"
|
||||
>
|
||||
{{ account.name }}
|
||||
</a-select-option>
|
||||
|
||||
@@ -244,13 +244,13 @@ onMounted(() => {
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="8">
|
||||
<a-form-item label="حساب پیشپرداخت" name="accountId">
|
||||
<a-select
|
||||
<a-select show-search option-filter-prop="label"
|
||||
v-model:value="form.accountId"
|
||||
allow-clear
|
||||
style="width: 100%"
|
||||
placeholder="انتخاب"
|
||||
>
|
||||
<a-select-option v-for="account in accounts" :key="account.id" :value="account.id">
|
||||
<a-select-option v-for="account in accounts" :key="account.id" :value="account.id" :label="account.name">
|
||||
{{ account.name }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
@@ -263,9 +263,9 @@ onMounted(() => {
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="8">
|
||||
<a-form-item label="دوره" name="interval">
|
||||
<a-select v-model:value="form.interval" style="width: 100%" :disabled="custom">
|
||||
<a-select-option value="monthly">ماهانه</a-select-option>
|
||||
<a-select-option value="weekly">هفتگی</a-select-option>
|
||||
<a-select show-search option-filter-prop="label" v-model:value="form.interval" style="width: 100%" :disabled="custom">
|
||||
<a-select-option value="monthly" label="ماهانه">ماهانه</a-select-option>
|
||||
<a-select-option value="weekly" label="هفتگی">هفتگی</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
@@ -329,7 +329,7 @@ onMounted(() => {
|
||||
name="accountId"
|
||||
:rules="[{ required: true, message: 'حساب الزامی است' }]"
|
||||
>
|
||||
<a-select
|
||||
<a-select show-search option-filter-prop="label"
|
||||
v-model:value="collect.accountId"
|
||||
allow-clear
|
||||
style="width: 100%"
|
||||
@@ -339,6 +339,7 @@ onMounted(() => {
|
||||
v-for="account in accounts"
|
||||
:key="account.id"
|
||||
:value="account.id"
|
||||
:label="account.name"
|
||||
>
|
||||
{{ account.name }}
|
||||
</a-select-option>
|
||||
|
||||
@@ -111,9 +111,9 @@ onMounted(() => {
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="8">
|
||||
<a-form-item label="نوع" name="kind" :rules="[{ required: true }]">
|
||||
<a-select v-model:value="form.kind" style="width: 100%">
|
||||
<a-select-option value="expense">هزینه</a-select-option>
|
||||
<a-select-option value="income">درآمد</a-select-option>
|
||||
<a-select show-search option-filter-prop="label" v-model:value="form.kind" style="width: 100%">
|
||||
<a-select-option value="expense" label="هزینه">هزینه</a-select-option>
|
||||
<a-select-option value="income" label="درآمد">درآمد</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
@@ -128,10 +128,10 @@ onMounted(() => {
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="8">
|
||||
<a-form-item label="دوره" name="interval" :rules="[{ required: true }]">
|
||||
<a-select v-model:value="form.interval" style="width: 100%">
|
||||
<a-select-option value="monthly">ماهانه</a-select-option>
|
||||
<a-select-option value="weekly">هفتگی</a-select-option>
|
||||
<a-select-option value="yearly">سالانه</a-select-option>
|
||||
<a-select show-search option-filter-prop="label" v-model:value="form.interval" style="width: 100%">
|
||||
<a-select-option value="monthly" label="ماهانه">ماهانه</a-select-option>
|
||||
<a-select-option value="weekly" label="هفتگی">هفتگی</a-select-option>
|
||||
<a-select-option value="yearly" label="سالانه">سالانه</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
Reference in New Issue
Block a user