@coopenomics/desktop 2.2.8 → 2.2.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/Env-testnet.ts +12 -0
- package/package.json +5 -5
- package/src/boot/init-stores.ts +8 -2
- package/src/desktops/User/model/index.ts +11 -10
- package/src/entities/Account/api/index.ts +11 -2
- package/src/entities/Account/model/store.ts +15 -5
- package/src/entities/Account/types/index.ts +9 -1
- package/src/entities/Session/model/store.ts +2 -3
- package/src/features/Account/UpdateAccount/api/index.ts +14 -0
- package/src/features/Account/UpdateAccount/index.ts +1 -0
- package/src/features/Account/UpdateAccount/model/index.ts +16 -0
- package/src/features/Branch/SelectBranch/ui/SelectBranchOverlay.vue +3 -2
- package/src/features/PaymentMethod/UpdateBankAccount/api/index.ts +1 -0
- package/src/features/PaymentMethod/UpdateBankAccount/model/index.ts +11 -4
- package/src/features/Request/CreateChildOrder/ui/CreateChildOrderButton/CreateChildOrderButton.vue +1 -1
- package/src/features/User/AddUser/ui/AddUserDialog/AddUserDialog.vue +3 -0
- package/src/features/User/Logout/model/index.ts +3 -3
- package/src/pages/Cooperative/ListOfBranches/ui/ListOfBranchesPage.vue +2 -4
- package/src/pages/Marketplace/OfferPage/ui/OfferPage.vue +2 -2
- package/src/shared/lib/composables/useEditableData.ts +1 -1
- package/src/shared/lib/consts/workspaces/index.ts +1 -0
- package/src/shared/ui/EditableEntrepreneurCard/EditableEntrepreneurCard.vue +170 -0
- package/src/shared/ui/EditableEntrepreneurCard/index.ts +1 -0
- package/src/shared/ui/EditableIndividualCard/EditableIndividualCard.vue +203 -0
- package/src/shared/ui/EditableIndividualCard/index.ts +1 -0
- package/src/shared/ui/EditableOrganizationCard/EditableOrganizationCard.vue +215 -0
- package/src/shared/ui/EditableOrganizationCard/index.ts +1 -0
- package/src/shared/ui/UserDataForm/OrganizationDataForm/OrganizationDataForm.vue +1 -0
- package/src/widgets/Cooperative/Participants/ListOfParticipants/ui/ListOfParticipantsWidget.vue +154 -71
- package/src/widgets/IndividualCard/ui/IndividualCard.vue +23 -23
- package/src/widgets/Request/RequestCard/RequestCard.vue +3 -3
@@ -0,0 +1,203 @@
|
|
1
|
+
<template lang="pug">
|
2
|
+
q-form(ref="form" v-if="data")
|
3
|
+
q-input(
|
4
|
+
dense
|
5
|
+
v-model="data.email"
|
6
|
+
standout="bg-teal text-white"
|
7
|
+
label="Email"
|
8
|
+
:readonly="readonly"
|
9
|
+
:rules="[val => validEmail(val)]"
|
10
|
+
autocomplete="off"
|
11
|
+
)
|
12
|
+
q-input(
|
13
|
+
dense
|
14
|
+
v-model="data.first_name"
|
15
|
+
standout="bg-teal text-white"
|
16
|
+
label="Имя"
|
17
|
+
:readonly="readonly"
|
18
|
+
:rules="[val => notEmpty(val)]"
|
19
|
+
autocomplete="off"
|
20
|
+
)
|
21
|
+
|
22
|
+
q-input(
|
23
|
+
dense
|
24
|
+
v-model="data.middle_name"
|
25
|
+
standout="bg-teal text-white"
|
26
|
+
label="Отчество"
|
27
|
+
:readonly="readonly"
|
28
|
+
:rules="[val => validatePersonalName(val)]"
|
29
|
+
autocomplete="off"
|
30
|
+
)
|
31
|
+
|
32
|
+
q-input(
|
33
|
+
dense
|
34
|
+
v-model="data.last_name"
|
35
|
+
standout="bg-teal text-white"
|
36
|
+
label="Фамилия"
|
37
|
+
:readonly="readonly"
|
38
|
+
:rules="[val => notEmpty(val), val => validatePersonalName(val)]"
|
39
|
+
autocomplete="off"
|
40
|
+
)
|
41
|
+
|
42
|
+
q-input(
|
43
|
+
dense
|
44
|
+
v-model="data.birthdate"
|
45
|
+
standout="bg-teal text-white"
|
46
|
+
mask="date"
|
47
|
+
label="Дата рождения"
|
48
|
+
placeholder="Формат: год/месяц/день"
|
49
|
+
:readonly="readonly"
|
50
|
+
:rules="['date', val => notEmpty(val)]"
|
51
|
+
autocomplete="off"
|
52
|
+
)
|
53
|
+
template(v-slot:append)
|
54
|
+
q-icon(name="event" class="cursor-pointer" v-if="!readonly")
|
55
|
+
q-popup-proxy(cover transition-show="scale" transition-hide="scale")
|
56
|
+
q-date(v-model="data.birthdate")
|
57
|
+
.row.items-center.justify-end
|
58
|
+
q-btn(v-close-popup label="Закрыть" color="primary" flat)
|
59
|
+
|
60
|
+
q-input(
|
61
|
+
dense
|
62
|
+
v-model="data.phone"
|
63
|
+
standout="bg-teal text-white"
|
64
|
+
label="Телефон"
|
65
|
+
:readonly="readonly"
|
66
|
+
:rules="[val => notEmpty(val)]"
|
67
|
+
autocomplete="off"
|
68
|
+
)
|
69
|
+
|
70
|
+
div(v-if="data.passport")
|
71
|
+
q-input(
|
72
|
+
dense
|
73
|
+
v-model="data.passport.code"
|
74
|
+
standout="bg-teal text-white"
|
75
|
+
label="Код подразделения"
|
76
|
+
mask="###-###"
|
77
|
+
:readonly="readonly"
|
78
|
+
:rules="[val => notEmpty(val), val => val.length === 7 || 'Код подразделения состоит из 6 цифр и тире (xxx-xxx)']"
|
79
|
+
autocomplete="off"
|
80
|
+
)
|
81
|
+
|
82
|
+
q-input(
|
83
|
+
dense
|
84
|
+
:model-value="data.passport.series"
|
85
|
+
@update:model-value="val => data.passport.series = Number(val)"
|
86
|
+
standout="bg-teal text-white"
|
87
|
+
label="Серия паспорта"
|
88
|
+
mask="####"
|
89
|
+
type="text"
|
90
|
+
:readonly="readonly"
|
91
|
+
:rules="[val => notEmpty(val), val => String(val).length === 4 || 'Серия должна состоять из 4 цифр']"
|
92
|
+
autocomplete="off"
|
93
|
+
)
|
94
|
+
|
95
|
+
q-input(
|
96
|
+
dense
|
97
|
+
:model-value="data.passport.number"
|
98
|
+
@update:model-value="val => data.passport.number = Number(val)"
|
99
|
+
standout="bg-teal text-white"
|
100
|
+
label="Номер паспорта"
|
101
|
+
mask="######"
|
102
|
+
type="text"
|
103
|
+
:readonly="readonly"
|
104
|
+
:rules="[val => notEmpty(val), val => String(val).length === 6 || 'Номер паспорта должен состоять из 6 цифр']"
|
105
|
+
autocomplete="off"
|
106
|
+
)
|
107
|
+
|
108
|
+
|
109
|
+
|
110
|
+
q-input(
|
111
|
+
dense
|
112
|
+
v-model="data.passport.issued_at"
|
113
|
+
standout="bg-teal text-white"
|
114
|
+
mask="date"
|
115
|
+
label="Дата выдачи"
|
116
|
+
:readonly="readonly"
|
117
|
+
:rules="['date', val => notEmpty(val)]"
|
118
|
+
autocomplete="off"
|
119
|
+
)
|
120
|
+
template(v-slot:append)
|
121
|
+
q-icon(name="event" class="cursor-pointer" v-if="!readonly")
|
122
|
+
q-popup-proxy(cover transition-show="scale" transition-hide="scale")
|
123
|
+
q-date(v-model="data.passport.issued_at")
|
124
|
+
.row.items-center.justify-end
|
125
|
+
q-btn(v-close-popup label="Закрыть" color="primary" flat)
|
126
|
+
|
127
|
+
q-input(
|
128
|
+
dense
|
129
|
+
v-model="data.passport.issued_by"
|
130
|
+
standout="bg-teal text-white"
|
131
|
+
label="Кем выдан"
|
132
|
+
:readonly="readonly"
|
133
|
+
:rules="[val => notEmpty(val)]"
|
134
|
+
autocomplete="off"
|
135
|
+
)
|
136
|
+
|
137
|
+
q-input(
|
138
|
+
dense
|
139
|
+
v-model="data.full_address"
|
140
|
+
standout="bg-teal text-white"
|
141
|
+
label="Адрес регистрации"
|
142
|
+
:readonly="readonly"
|
143
|
+
:rules="[val => notEmpty(val)]"
|
144
|
+
autocomplete="off"
|
145
|
+
)
|
146
|
+
|
147
|
+
EditableActions(
|
148
|
+
v-if="!readonly"
|
149
|
+
:isEditing="isEditing"
|
150
|
+
:isDisabled="isDisabled"
|
151
|
+
@save="saveChanges"
|
152
|
+
@cancel="cancelChanges"
|
153
|
+
)
|
154
|
+
</template>
|
155
|
+
|
156
|
+
<script lang="ts" setup>
|
157
|
+
import { ref } from 'vue';
|
158
|
+
import { useEditableData } from 'src/shared/lib/composables/useEditableData';
|
159
|
+
import { validEmail } from 'src/shared/lib/utils/validEmailRule';
|
160
|
+
import { validatePersonalName, notEmpty } from 'src/shared/lib/utils';
|
161
|
+
import { failAlert, SuccessAlert } from 'src/shared/api';
|
162
|
+
import { type IUpdateAccountInput, useUpdateAccount } from 'src/features/Account/UpdateAccount/model';
|
163
|
+
import { EditableActions } from 'src/shared/ui/EditableActions';
|
164
|
+
import { type IIndividualData } from 'src/entities/Account/types';
|
165
|
+
|
166
|
+
const { updateAccount } = useUpdateAccount()
|
167
|
+
|
168
|
+
const props = defineProps({
|
169
|
+
participantData: {
|
170
|
+
type: Object as () => IIndividualData,
|
171
|
+
required: true
|
172
|
+
},
|
173
|
+
readonly: {
|
174
|
+
type: Boolean,
|
175
|
+
default: false
|
176
|
+
}
|
177
|
+
});
|
178
|
+
|
179
|
+
const localParticipantData = ref(props.participantData);
|
180
|
+
const form = ref();
|
181
|
+
const emit = defineEmits(['update']);
|
182
|
+
|
183
|
+
const handleSave = async () => {
|
184
|
+
try {
|
185
|
+
const account_data: IUpdateAccountInput = {
|
186
|
+
username: props.participantData.username,
|
187
|
+
individual_data: data.value,
|
188
|
+
}
|
189
|
+
await updateAccount(account_data);
|
190
|
+
emit('update', JSON.parse(JSON.stringify(data.value)))
|
191
|
+
SuccessAlert('Данные аккаунта обновлены')
|
192
|
+
} catch (e: any) {
|
193
|
+
failAlert(e);
|
194
|
+
}
|
195
|
+
};
|
196
|
+
|
197
|
+
const { editableData: data, isEditing, isDisabled, saveChanges, cancelChanges } = useEditableData(
|
198
|
+
localParticipantData.value,
|
199
|
+
handleSave,
|
200
|
+
form
|
201
|
+
);
|
202
|
+
</script>
|
203
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
export {default as EditableIndividualCard} from './EditableIndividualCard.vue'
|
@@ -0,0 +1,215 @@
|
|
1
|
+
<template lang="pug">
|
2
|
+
q-form(ref="form" v-if="data")
|
3
|
+
q-select(
|
4
|
+
dense
|
5
|
+
v-model="data.type"
|
6
|
+
standout="bg-teal text-white"
|
7
|
+
label="Тип организации"
|
8
|
+
:options="[{ label: 'Потребительский Кооператив', value: 'coop' }, { label: 'Производственный Кооператив', value: 'prodcoop' }, { label: 'ООО', value: 'ooo' }]"
|
9
|
+
emit-value
|
10
|
+
map-options
|
11
|
+
:rules="[val => notEmpty(val)]"
|
12
|
+
:readonly="readonly"
|
13
|
+
)
|
14
|
+
|
15
|
+
q-input(
|
16
|
+
dense
|
17
|
+
v-model="data.short_name"
|
18
|
+
standout="bg-teal text-white"
|
19
|
+
label="Краткое наименование"
|
20
|
+
:rules="[val => notEmpty(val)]"
|
21
|
+
:readonly="readonly"
|
22
|
+
autocomplete="off"
|
23
|
+
)
|
24
|
+
q-input(
|
25
|
+
dense
|
26
|
+
v-model="data.full_name"
|
27
|
+
standout="bg-teal text-white"
|
28
|
+
label="Полное наименование"
|
29
|
+
:rules="[val => notEmpty(val)]"
|
30
|
+
:readonly="readonly"
|
31
|
+
autocomplete="off"
|
32
|
+
)
|
33
|
+
|
34
|
+
q-input(
|
35
|
+
dense
|
36
|
+
v-model="data.represented_by.last_name"
|
37
|
+
standout="bg-teal text-white"
|
38
|
+
label="Фамилия представителя"
|
39
|
+
:rules="[val => notEmpty(val), val => validatePersonalName(val)]"
|
40
|
+
:readonly="readonly"
|
41
|
+
autocomplete="off"
|
42
|
+
)
|
43
|
+
q-input(
|
44
|
+
dense
|
45
|
+
v-model="data.represented_by.first_name"
|
46
|
+
standout="bg-teal text-white"
|
47
|
+
label="Имя представителя"
|
48
|
+
:rules="[val => notEmpty(val), val => validatePersonalName(val)]"
|
49
|
+
:readonly="readonly"
|
50
|
+
autocomplete="off"
|
51
|
+
)
|
52
|
+
q-input(
|
53
|
+
dense
|
54
|
+
v-model="data.represented_by.middle_name"
|
55
|
+
standout="bg-teal text-white"
|
56
|
+
label="Отчество представителя"
|
57
|
+
:rules="[val => validatePersonalName(val)]"
|
58
|
+
:readonly="readonly"
|
59
|
+
autocomplete="off"
|
60
|
+
)
|
61
|
+
q-input(
|
62
|
+
dense
|
63
|
+
v-model="data.represented_by.based_on"
|
64
|
+
standout="bg-teal text-white"
|
65
|
+
label="На основании"
|
66
|
+
:rules="[val => notEmpty(val)]"
|
67
|
+
:readonly="readonly"
|
68
|
+
autocomplete="off"
|
69
|
+
)
|
70
|
+
q-input(
|
71
|
+
dense
|
72
|
+
v-model="data.represented_by.position"
|
73
|
+
standout="bg-teal text-white"
|
74
|
+
label="Должность представителя"
|
75
|
+
:rules="[val => notEmpty(val)]"
|
76
|
+
:readonly="readonly"
|
77
|
+
autocomplete="off"
|
78
|
+
)
|
79
|
+
|
80
|
+
q-input(
|
81
|
+
dense
|
82
|
+
v-model="data.phone"
|
83
|
+
standout="bg-teal text-white"
|
84
|
+
label="Телефон"
|
85
|
+
mask="+7 (###) ###-##-##"
|
86
|
+
fill-mask
|
87
|
+
:rules="[val => notEmpty(val), val => notEmptyPhone(val)]"
|
88
|
+
:readonly="readonly"
|
89
|
+
autocomplete="off"
|
90
|
+
)
|
91
|
+
|
92
|
+
q-input(
|
93
|
+
dense
|
94
|
+
v-model="data.country"
|
95
|
+
standout="bg-teal text-white"
|
96
|
+
label="Страна"
|
97
|
+
:rules="[val => notEmpty(val)]"
|
98
|
+
:readonly="readonly"
|
99
|
+
autocomplete="off"
|
100
|
+
)
|
101
|
+
q-input(
|
102
|
+
dense
|
103
|
+
v-model="data.city"
|
104
|
+
standout="bg-teal text-white"
|
105
|
+
label="Город"
|
106
|
+
:rules="[val => notEmpty(val)]"
|
107
|
+
:readonly="readonly"
|
108
|
+
autocomplete="off"
|
109
|
+
)
|
110
|
+
q-input(
|
111
|
+
dense
|
112
|
+
v-model="data.full_address"
|
113
|
+
standout="bg-teal text-white"
|
114
|
+
label="Юридический адрес"
|
115
|
+
:rules="[val => notEmpty(val)]"
|
116
|
+
:readonly="readonly"
|
117
|
+
autocomplete="off"
|
118
|
+
)
|
119
|
+
q-input(
|
120
|
+
dense
|
121
|
+
v-model="data.fact_address"
|
122
|
+
standout="bg-teal text-white"
|
123
|
+
label="Фактический адрес"
|
124
|
+
:rules="[val => notEmpty(val)]"
|
125
|
+
:readonly="readonly"
|
126
|
+
autocomplete="off"
|
127
|
+
)
|
128
|
+
|
129
|
+
q-input(
|
130
|
+
dense
|
131
|
+
v-model="data.details.inn"
|
132
|
+
standout="bg-teal text-white"
|
133
|
+
mask="############"
|
134
|
+
label="ИНН"
|
135
|
+
:rules="[val => notEmpty(val), val => (val.length === 10 || val.length === 12) || 'ИНН должен содержать 10 или 12 цифр']"
|
136
|
+
:readonly="readonly"
|
137
|
+
autocomplete="off"
|
138
|
+
)
|
139
|
+
q-input(
|
140
|
+
dense
|
141
|
+
v-model="data.details.ogrn"
|
142
|
+
standout="bg-teal text-white"
|
143
|
+
mask="###############"
|
144
|
+
label="ОГРН"
|
145
|
+
:rules="[val => notEmpty(val), val => (val.length === 13 || val.length === 15) || 'ОГРН должен содержать 13 или 15 цифр']"
|
146
|
+
:readonly="readonly"
|
147
|
+
autocomplete="off"
|
148
|
+
)
|
149
|
+
q-input(
|
150
|
+
dense
|
151
|
+
v-model="data.details.kpp"
|
152
|
+
standout="bg-teal text-white"
|
153
|
+
mask="#########"
|
154
|
+
label="КПП"
|
155
|
+
:rules="[val => notEmpty(val), val => val.length === 9 || 'КПП должен содержать 9 цифр']"
|
156
|
+
:readonly="readonly"
|
157
|
+
autocomplete="off"
|
158
|
+
)
|
159
|
+
|
160
|
+
EditableActions(
|
161
|
+
v-if="!readonly"
|
162
|
+
:isEditing="isEditing"
|
163
|
+
:isDisabled="isDisabled"
|
164
|
+
@save="saveChanges"
|
165
|
+
@cancel="cancelChanges"
|
166
|
+
)
|
167
|
+
</template>
|
168
|
+
|
169
|
+
<script lang="ts" setup>
|
170
|
+
import { ref } from 'vue';
|
171
|
+
import { useEditableData } from 'src/shared/lib/composables/useEditableData';
|
172
|
+
import { notEmpty, notEmptyPhone, validatePersonalName } from 'src/shared/lib/utils';
|
173
|
+
import { failAlert, SuccessAlert } from 'src/shared/api';
|
174
|
+
import { EditableActions } from 'src/shared/ui/EditableActions';
|
175
|
+
import { type IUpdateAccountInput, useUpdateAccount } from 'src/features/Account/UpdateAccount/model';
|
176
|
+
import { type IOrganizationData } from 'src/entities/Account/types';
|
177
|
+
|
178
|
+
const emit = defineEmits(['update']);
|
179
|
+
const { updateAccount } = useUpdateAccount();
|
180
|
+
|
181
|
+
const props = defineProps({
|
182
|
+
participantData: {
|
183
|
+
type: Object as () => IOrganizationData,
|
184
|
+
required: true
|
185
|
+
},
|
186
|
+
readonly: {
|
187
|
+
type: Boolean,
|
188
|
+
default: false
|
189
|
+
}
|
190
|
+
});
|
191
|
+
|
192
|
+
const localOrganizationData = ref(props.participantData);
|
193
|
+
const form = ref();
|
194
|
+
|
195
|
+
const handleSave = async () => {
|
196
|
+
try {
|
197
|
+
const account_data: IUpdateAccountInput = {
|
198
|
+
username: props.participantData.username,
|
199
|
+
organization_data: data.value,
|
200
|
+
};
|
201
|
+
await updateAccount(account_data);
|
202
|
+
emit('update', JSON.parse(JSON.stringify(data.value)));
|
203
|
+
SuccessAlert('Данные аккаунта обновлены');
|
204
|
+
} catch (e) {
|
205
|
+
console.log(e);
|
206
|
+
failAlert(e);
|
207
|
+
}
|
208
|
+
};
|
209
|
+
const { editableData: data, isEditing, isDisabled, saveChanges, cancelChanges } = useEditableData(
|
210
|
+
localOrganizationData.value,
|
211
|
+
handleSave,
|
212
|
+
form
|
213
|
+
);
|
214
|
+
</script>
|
215
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
export {default as EditableOrganizationCard} from './EditableOrganizationCard.vue'
|
@@ -7,6 +7,7 @@ div(v-if="userData.organization_data").q-gutter-sm.q-mt-md
|
|
7
7
|
:options="[{ label: 'Потребительский Кооператив', value: 'coop' }, { label: 'Производственный Кооператив', value: 'prodcoop' }, { label: 'ООО', value: 'ooo' }]"
|
8
8
|
emit-value
|
9
9
|
map-options).q-mb-md
|
10
|
+
|
10
11
|
q-input(v-model="userData.organization_data.short_name" standout="bg-teal text-white" hint="ПК Ромашка" label="Краткое наименование организации" :rules="[val => notEmpty(val)]" autocomplete="off")
|
11
12
|
q-input(v-model="userData.organization_data.full_name" standout="bg-teal text-white" hint="Потребительский Кооператив 'Ромашка'" label="Полное наименование организации" :rules="[val => notEmpty(val)]" autocomplete="off")
|
12
13
|
q-input(v-model="userData.organization_data.represented_by.last_name" standout="bg-teal text-white" label="Фамилия представителя" hint="" :rules="[val => notEmpty(val), val => validatePersonalName(val)]" autocomplete="off")
|
package/src/widgets/Cooperative/Participants/ListOfParticipants/ui/ListOfParticipantsWidget.vue
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
<template lang="pug">
|
2
|
+
|
2
3
|
q-table(
|
3
|
-
ref="tableRef"
|
4
|
+
ref="tableRef"
|
4
5
|
flat
|
5
|
-
:rows="
|
6
|
+
:rows="accountStore.accounts.items"
|
6
7
|
:columns="columns"
|
7
|
-
:table-colspan="9"
|
8
8
|
row-key="username"
|
9
9
|
:pagination="pagination"
|
10
10
|
virtual-scroll
|
@@ -15,12 +15,10 @@ q-table(
|
|
15
15
|
).full-height
|
16
16
|
template(#top)
|
17
17
|
slot(name="top")
|
18
|
-
|
18
|
+
|
19
19
|
template(#header="props")
|
20
|
-
|
21
20
|
q-tr(:props="props")
|
22
21
|
q-th(auto-width)
|
23
|
-
|
24
22
|
q-th(
|
25
23
|
v-for="col in props.cols"
|
26
24
|
:key="col.name"
|
@@ -28,76 +26,161 @@ q-table(
|
|
28
26
|
) {{ col.label }}
|
29
27
|
|
30
28
|
template(#body="props")
|
29
|
+
|
31
30
|
q-tr(:key="`m_${props.row.username}`" :props="props")
|
32
31
|
q-td(auto-width)
|
33
|
-
|
34
|
-
|
32
|
+
q-btn(
|
33
|
+
size="sm"
|
34
|
+
color="primary"
|
35
|
+
round
|
36
|
+
dense
|
37
|
+
:icon="expanded.get(props.row.username) ? 'remove' : 'add'"
|
38
|
+
@click="toggleExpand(props.row.username)"
|
39
|
+
)
|
40
|
+
|
41
|
+
q-td {{ getName(props.row) }}
|
42
|
+
q-td {{ props.row.private_account.type === AccountTypes.Individual ? 'физ. лицо' : (props.row.private_account.type === AccountTypes.Organization ? 'юр. лицо' : (props.row.private_account.type === AccountTypes.Entrepreneur ? 'инд. предприниматель' : 'неизвестно')) }}
|
35
43
|
q-td {{ props.row.username }}
|
36
|
-
q-td {{ props.row.
|
37
|
-
|
38
|
-
|
39
|
-
q-td
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
44
|
+
q-td {{ moment(props.row.blockchain_account?.created).format('DD.MM.YY HH:mm:ss') }}
|
45
|
+
|
46
|
+
q-tr(v-if="expanded.get(props.row.username)" :key="`e_${props.row.username}`" :props="props" class="q-virtual-scroll--with-prev")
|
47
|
+
q-td(colspan="100%" style="padding: 0 !important;")
|
48
|
+
q-tabs(
|
49
|
+
v-model="currentTab[props.row.username]"
|
50
|
+
align="justify"
|
51
|
+
stretch
|
52
|
+
dense
|
53
|
+
indicator-color="lime"
|
54
|
+
)
|
55
|
+
q-tab(name="info" label="Данные" class="bg-primary text-white")
|
56
|
+
q-tab(name="document" label="Документы" class="bg-primary text-white")
|
57
|
+
|
58
|
+
q-tab-panels(v-model="currentTab[props.row.username]" animated)
|
59
|
+
q-tab-panel(name="info")
|
60
|
+
component(:is="useComponent(props.row)" :participantData="usePrivateData(props.row)" @update="newData => update(props.row, newData)")
|
61
|
+
|
62
|
+
q-tab-panel(name="document")
|
63
|
+
slot(:expand="expanded.get(props.row.username)" :receiver="props.row.username")
|
64
|
+
|
49
65
|
</template>
|
50
|
-
|
51
66
|
<script setup lang="ts">
|
52
|
-
import { ref } from 'vue'
|
53
|
-
import { Notify } from 'quasar'
|
54
|
-
|
55
|
-
import {
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
import
|
60
|
-
|
61
|
-
const
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
}
|
67
|
+
import { ref, reactive } from 'vue'
|
68
|
+
import { Notify } from 'quasar'
|
69
|
+
import { EditableEntrepreneurCard } from 'src/shared/ui/EditableEntrepreneurCard';
|
70
|
+
import { EditableIndividualCard } from 'src/shared/ui/EditableIndividualCard';
|
71
|
+
import { EditableOrganizationCard } from 'src/shared/ui/EditableOrganizationCard';
|
72
|
+
import { useAccountStore } from 'src/entities/Account/model';
|
73
|
+
import moment from 'moment-with-locales-es6'
|
74
|
+
import { AccountTypes, type IAccount, type IIndividualData, type IOrganizationData, type IEntrepreneurData } from 'src/entities/Account/types';
|
75
|
+
|
76
|
+
const accountStore = useAccountStore()
|
77
|
+
|
78
|
+
const onLoading = ref(false)
|
79
|
+
|
80
|
+
const update = (
|
81
|
+
account: IAccount,
|
82
|
+
newData: IIndividualData | IOrganizationData | IEntrepreneurData
|
83
|
+
) => {
|
84
|
+
|
85
|
+
if (account.private_account?.type === AccountTypes.Individual) {
|
86
|
+
const individual = newData as IIndividualData;
|
87
|
+
account.private_account.individual_data = {
|
88
|
+
...individual,
|
89
|
+
passport: individual.passport ?? undefined, // заменяет null на undefined
|
90
|
+
};
|
91
|
+
} else if (account.private_account?.type === AccountTypes.Entrepreneur) {
|
92
|
+
account.private_account.entrepreneur_data = newData as IEntrepreneurData
|
93
|
+
} else if (account.private_account?.type === AccountTypes.Organization) {
|
94
|
+
account.private_account.organization_data = newData as IOrganizationData
|
95
|
+
}
|
96
|
+
|
97
|
+
};
|
98
|
+
|
99
|
+
|
100
|
+
// `Map` для отслеживания состояния раскрытых строк и вкладок
|
101
|
+
const expanded = reactive(new Map<string, boolean>())
|
102
|
+
const currentTab = reactive<Record<string, string>>({})
|
103
|
+
|
104
|
+
// Определяем, какой компонент использовать
|
105
|
+
const useComponent = (account: IAccount) => {
|
106
|
+
if (account.private_account)
|
107
|
+
switch (account.private_account.type) {
|
108
|
+
case AccountTypes.Individual:
|
109
|
+
return EditableIndividualCard
|
110
|
+
case AccountTypes.Entrepreneur:
|
111
|
+
return EditableEntrepreneurCard
|
112
|
+
case AccountTypes.Organization:
|
113
|
+
return EditableOrganizationCard
|
114
|
+
}
|
115
|
+
}
|
116
|
+
|
117
|
+
const usePrivateData = (account: IAccount) => {
|
118
|
+
if (account.private_account)
|
119
|
+
switch (account.private_account.type) {
|
120
|
+
case AccountTypes.Individual:
|
121
|
+
return account.private_account?.individual_data
|
122
|
+
case AccountTypes.Entrepreneur:
|
123
|
+
return account.private_account?.entrepreneur_data
|
124
|
+
case AccountTypes.Organization:
|
125
|
+
return account.private_account?.organization_data
|
126
|
+
}
|
127
|
+
}
|
128
|
+
|
129
|
+
// Загружаем данные
|
130
|
+
const loadParticipants = async () => {
|
131
|
+
try {
|
132
|
+
onLoading.value = true
|
133
|
+
|
134
|
+
await accountStore.getAccounts({options: {
|
135
|
+
page: 1,
|
136
|
+
limit: 1000,
|
137
|
+
sortOrder: 'DESC'
|
138
|
+
}})
|
139
|
+
|
140
|
+
onLoading.value = false
|
141
|
+
} catch (e: any) {
|
142
|
+
onLoading.value = false
|
143
|
+
Notify.create({
|
144
|
+
message: e.message,
|
145
|
+
type: 'negative',
|
146
|
+
})
|
147
|
+
}
|
76
148
|
}
|
77
|
-
}
|
78
|
-
|
79
|
-
loadParticipants()
|
80
|
-
|
81
|
-
const columns = [
|
82
|
-
{ name: 'username', align: 'left', label: 'Аккаунт', field: 'username', sortable: true },
|
83
|
-
{ name: 'last_name', align: 'left', label: 'Фамилия', field: 'last_name', sortable: true },
|
84
|
-
{ name: 'first_name', align: 'left', label: 'Имя', field: 'first_name', sortable: true },
|
85
|
-
{ name: 'middle_name', align: 'left', label: 'Отчество', field: 'middle_name', sortable: true },
|
86
|
-
|
87
|
-
{ name: 'phone', align: 'left', label: 'Телефон', field: 'phone', sortable: false },
|
88
|
-
{ name: 'email', align: 'left', label: 'Е-почта', field: 'email', sortable: false },
|
89
|
-
{ name: 'birthday', align: 'left', label: 'Дата рождения', field: 'birthday', sortable: true },
|
90
|
-
{
|
91
|
-
name: 'created_at',
|
92
|
-
align: 'left',
|
93
|
-
label: 'Зарегистрирован',
|
94
|
-
field: 'created_at',
|
95
|
-
sortable: true,
|
96
|
-
},
|
97
|
-
] as any
|
98
149
|
|
99
|
-
|
100
|
-
|
101
|
-
const
|
150
|
+
loadParticipants()
|
151
|
+
|
152
|
+
const columns = [
|
153
|
+
{ name: 'name', align: 'left', label: 'ФИО / Наименование', field: 'name', sortable: true },
|
154
|
+
{ name: 'type', align: 'left', label: 'Тип', field: 'type' },
|
155
|
+
{ name: 'username', align: 'left', label: 'Аккаунт', field: 'username', sortable: true },
|
156
|
+
{
|
157
|
+
name: 'created_at',
|
158
|
+
align: 'left',
|
159
|
+
label: 'Зарегистрирован',
|
160
|
+
field: 'created_at',
|
161
|
+
sortable: true,
|
162
|
+
},
|
163
|
+
] as any
|
164
|
+
|
165
|
+
const tableRef = ref(null)
|
166
|
+
const pagination = ref({ rowsPerPage: 10 })
|
167
|
+
|
168
|
+
// Функция для переключения раскрытия строки
|
169
|
+
const toggleExpand = (id: string) => {
|
170
|
+
expanded.set(id, !expanded.get(id))
|
171
|
+
if (!currentTab[id]) {
|
172
|
+
currentTab[id] = 'info' // Устанавливаем вкладку по умолчанию
|
173
|
+
}
|
174
|
+
}
|
175
|
+
|
176
|
+
const getName = (account: IAccount) => {
|
177
|
+
if (account?.private_account?.type === AccountTypes.Individual){
|
178
|
+
return `${account.private_account.individual_data?.last_name} ${account.private_account.individual_data?.first_name} ${account.private_account.individual_data?.middle_name}`
|
179
|
+
} else if (account?.private_account?.type === AccountTypes.Entrepreneur){
|
180
|
+
return `${account.private_account.entrepreneur_data?.last_name} ${account.private_account.entrepreneur_data?.first_name} ${account.private_account.entrepreneur_data?.middle_name}`
|
181
|
+
} else if (account?.private_account?.type === AccountTypes.Organization){
|
182
|
+
return `${account.private_account.organization_data?.short_name}`
|
183
|
+
}
|
184
|
+
}
|
102
185
|
|
103
|
-
</script>
|
186
|
+
</script>
|