Compare commits

...

17 Commits

Author SHA1 Message Date
Alex Ant 3632bea54e chore(release): publish
- terminal@0.1.32
2024-07-31 17:26:08 +05:00
Alex Ant 7d6266c241 chore(release): publish
- terminal@0.1.32-alpha.0
2024-07-31 16:28:53 +05:00
Alex Ant 1d69b9ffea Рабочие столы v1 2024-07-31 16:24:50 +05:00
Alex Ant 72674cba10 chore(release): publish
- coopback@1.7.28
 - terminal@0.1.31
2024-07-26 18:42:47 +05:00
Alex Ant 495a8e2d1e chore(release): publish
- coopback@1.7.28-alpha.0
 - terminal@0.1.31-alpha.0
2024-07-26 18:41:33 +05:00
Alex Ant 95ae221d60 Добавление платежных реквизитов | удаление | просмотр | свайп в рамках страницы 2024-07-26 18:38:14 +05:00
Alex Ant 857f746da1 bug fix 2024-07-26 11:03:52 +05:00
Alex Ant 0e2e3052b1 works 2024-07-25 21:00:04 +05:00
Alex Ant 167c04cc3f commit 2024-07-25 20:47:42 +05:00
Alex Ant 043f51479a looking for bug #2 2024-07-25 20:30:56 +05:00
Alex Ant 921282df81 looking for bug 2024-07-25 20:20:44 +05:00
Alex Ant b3c641501c migration 2024-07-25 20:07:44 +05:00
Alex Ant 3608e7601f chore(release): publish
- cooparser-ts@1.0.17
 - coopback@1.7.27
 - coopdoc-generator-ts@1.0.72
 - cooptypes@1.0.17
 - coop-notificator@0.0.21
 - terminal@0.1.30
2024-07-25 19:41:18 +05:00
Alex Ant a75cfa1056 chore(release): publish
- coopback@1.7.27-alpha.5
 - terminal@0.1.30-alpha.4
2024-07-25 19:39:41 +05:00
Alex Ant f08c4102fd login with email 2024-07-25 19:37:13 +05:00
Alex Ant 9bfd7c7d9a chore(release): publish
- coopback@1.7.27-alpha.4
2024-07-25 18:24:15 +05:00
Alex Ant a359b4fbdb fix 2024-07-25 18:22:17 +05:00
99 changed files with 11842 additions and 13271 deletions
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.0.17](https://github.com/copenomics/cooparser/compare/cooparser-ts@1.0.17-alpha.2...cooparser-ts@1.0.17) (2024-07-25)
**Note:** Version bump only for package cooparser-ts
## [1.0.16](https://github.com/copenomics/cooparser/compare/cooparser-ts@1.0.16-alpha.0...cooparser-ts@1.0.16) (2024-07-15)
**Note:** Version bump only for package cooparser-ts
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "pkg-placeholder",
"version": "1.0.17-alpha.2",
"version": "1.0.17",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "pkg-placeholder",
"version": "1.0.17-alpha.2",
"version": "1.0.17",
"license": "MIT",
"devDependencies": {
"@antfu/eslint-config": "^2.16.0",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "cooparser-ts",
"type": "module",
"version": "1.0.17-alpha.2",
"version": "1.0.17",
"private": true,
"packageManager": "pnpm@9.0.6",
"description": "",
+16
View File
@@ -3,6 +3,22 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.7.28](https://github.com/hagopj13/node-express-boilerplate/compare/coopback@1.7.28-alpha.0...coopback@1.7.28) (2024-07-26)
**Note:** Version bump only for package coopback
## [1.7.27](https://github.com/hagopj13/node-express-boilerplate/compare/coopback@1.7.27-alpha.5...coopback@1.7.27) (2024-07-25)
**Note:** Version bump only for package coopback
## [1.7.26](https://github.com/hagopj13/node-express-boilerplate/compare/coopback@1.7.26-alpha.0...coopback@1.7.26) (2024-07-15)
**Note:** Version bump only for package coopback
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "create-nodejs-express-app",
"version": "1.7.27-alpha.3",
"version": "1.7.28",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "create-nodejs-express-app",
"version": "1.7.27-alpha.3",
"version": "1.7.28",
"license": "MIT",
"dependencies": {
"@a2seven/yoo-checkout": "^1.1.4",
+2 -1
View File
@@ -1,6 +1,6 @@
{
"name": "coopback",
"version": "1.7.27-alpha.3",
"version": "1.7.28",
"description": "",
"private": true,
"bin": "bin/createNodejsApp.js",
@@ -28,6 +28,7 @@
"docker:dev": "docker-compose -f docker-compose.yml -f docker-compose.dev.yml up",
"docker:test": "docker-compose -f docker-compose.yml -f docker-compose.test.yml up",
"types": "ts-node scripts/types.ts",
"init": "ts-node scripts/init.ts",
"swagger": "ts-node scripts/swagger.ts",
"typecheck": "tsc --noEmit",
"docs-watch": "swagger-ui-watcher ./src/docs/swagger.json",
@@ -1,7 +1,7 @@
import config from '../src/config/config';
import { User } from '../src/models';
import { tokenService } from '../src/services';
import userService from '../src/services/user.service';
import { userService } from '../src/services';
import mongoose from 'mongoose';
const args = process.argv.slice(2);
+101
View File
@@ -0,0 +1,101 @@
import config from '../src/config/config';
import { User } from '../src/models';
import { tokenService } from '../src/services';
import { userService } from '../src/services';
import mongoose from 'mongoose';
import { connectGenerator } from '../src/services/document.service';
import crypto from 'crypto';
import bcryptjs from 'bcryptjs';
const { compare, hash } = bcryptjs;
async function init() {
try {
await connectGenerator();
await mongoose.connect(config.mongoose.url, config.mongoose.options);
const wif = '5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3';
const password = await crypto.createHash('sha256').update(wif).digest('hex');
const hashed_password = await hash(password, 8);
console.log('password: ', hashed_password);
await userService.createUser({
username: 'ant',
email: 'dacom.dark.sun@gmail.com',
password,
public_key: 'EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV',
role: 'chairman',
type: 'individual',
individual_data: {
first_name: 'Иван',
last_name: 'Иванов',
middle_name: 'Иванович',
birthdate: '2000-01-01',
phone: '+1234567890',
email: 'ivanov.ivan@example.com',
full_address: 'Переулок Иванов д. 1',
},
});
const user = await userService.getUserByUsername('ant');
user.status = 'active';
user.is_registered = true;
await user.save();
const voskhod = await userService.createUser({
username: 'voskhod',
email: 'chairman.voskhod@gmail.com',
password,
public_key: 'EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV',
role: 'user',
type: 'organization',
organization_data: {
is_cooperative: true,
type: 'coop',
short_name: '"ПК ТЕСТ-Восход"',
full_name: 'Потребительский Кооператив "ТЕСТ-ВОСХОД"',
represented_by: {
first_name: 'Иван',
last_name: 'Иванов',
middle_name: 'Иванович',
position: 'Председатель',
based_on: 'Решения общего собрания №1',
},
country: 'Russia',
city: 'Москва',
full_address: 'Переулок Правды, дом 1',
email: 'chairman.voskhod@gmail.com',
phone: '+77077770707',
details: {
inn: '1234567890',
ogrn: '1234567890123',
},
bank_account: {
account_number: '40817810099910004312',
currency: 'RUB',
card_number: '1234567890123456',
bank_name: 'Sberbank',
details: {
bik: '123456789',
corr: '30101810400000000225',
kpp: '123456789',
},
},
},
});
const coop = await userService.getUserByUsername('voskhod');
coop.status = 'active';
coop.is_registered = true;
await coop.save();
console.log('ok');
} catch (e: any) {
console.log('Ошибка: ', e);
}
process.exit(0);
}
init();
@@ -0,0 +1,43 @@
import config from '../../src/config/config';
import { User } from '../../src/models';
import { tokenService } from '../../src/services';
import { userService } from '../../src/services';
import mongoose from 'mongoose';
import { connectGenerator } from '../../src/services/document.service';
import crypto from 'crypto';
import bcryptjs from 'bcryptjs';
const { compare, hash } = bcryptjs;
async function init() {
try {
await connectGenerator();
await mongoose.connect(config.mongoose.url, config.mongoose.options);
const orgs_collection = mongoose.connection.collection('OrgData');
const bankData_collection = mongoose.connection.collection('PaymentData');
const orgs = await orgs_collection.find().toArray();
for (const org of orgs) {
await bankData_collection.insertOne({
_created_at: org._created_at,
username: org.username,
method_id: 1,
user_type: 'organization',
method_type: 'bank_transfer',
is_default: true,
data: org.bank_account,
deleted: false,
block_num: org.block_num,
});
}
} catch (e: any) {
console.log('Ошибка: ', e);
}
process.exit(0);
}
init();
+4 -4
View File
@@ -3,12 +3,12 @@ import crypto from 'crypto';
const { compare, hash } = bcryptjs;
async function generate() {
const wif = '';
const wif = '5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3';
const hash_from_wif = await crypto.createHash('sha256').update(wif).digest('hex');
const password = await hash(hash_from_wif, 8)
console.log(password)
console.log('hash_from_wif: ', hash_from_wif);
const password = await hash(hash_from_wif, 8);
console.log(password);
}
generate();
@@ -10,8 +10,8 @@ export const login = catchAsync(async (req, res) => {
const { email, password } = req.body;
const user = await authService.loginUserWithEmailAndPassword(email, password);
if (user.is_registered === false)
throw new Error('Регистрация не была завершена. Пожалуйста, подождите решения совета или начните с начала. ');
// if (user.is_registered === false)
// throw new Error('Регистрация не была завершена. Пожалуйста, подождите решения совета или начните с начала. ');
const tokens = await tokenService.generateAuthTokens(user);
res.send({ user, tokens });
@@ -80,6 +80,14 @@ export const addPaymentMethod = catchAsync(async (req: RSavePaymentMethod, res)
const user = await getUserByUsername(req.body.username);
const method = req.body as any;
if (method.method_type === 'sbp' && !method.data.phone)
throw new ApiError(httpStatus.BAD_REQUEST, 'Не указан телефон для метода СБП');
if (method.method_type === 'bank_transfer' && !method.data.account_number)
throw new ApiError(httpStatus.BAD_REQUEST, 'Не верно указаны реквизиты для банковского платежа');
const paymentData: Cooperative.Payments.IPaymentData = {
username: req.body.username,
method_id: req.body.method_id,
@@ -40,23 +40,16 @@ export const getUsers = catchAsync(async (req, res) => {
const filter = pick(req.query, ['username', 'role']);
const options = pick(req.query, ['sortBy', 'limit', 'page']);
Object.keys(filter).forEach((key) => {
if (filter[key] !== undefined) {
filter[key] = { $eq: filter[key], $ne: 'service' };
} else {
filter[key] = { $ne: 'service' };
}
});
const users = await userService.queryUsers(filter, options);
const result = {} as IGetResponse<IUser>;
//TODO wrong format answer
const data = [] as any;
for await (let user of users.results) {
const json = user.toJSON();
json.private_data = (await user.getPrivateData()) || {};
data.push(json);
if (user.type != 'service') {
json.private_data = (await user.getPrivateData()) || {};
data.push(json);
}
}
result.results = data;
@@ -11,7 +11,7 @@ import ApiError from '../utils/ApiError';
import httpStatus from 'http-status';
import { ICreatedPayment, IYandexIPN, PaymentDetails } from '../types/common';
import { Cooperative } from 'cooptypes';
import type { Filter } from 'mongodb';
import { FilterQuery } from 'mongoose';
const { connection } = mongoose;
@@ -19,11 +19,11 @@ export const savePaymentMethod = async (data: Cooperative.Payments.IPaymentData)
return await generator.save('paymentMethod', data);
};
export const deletePaymentMethod = async (filter: Filter<Cooperative.Payments.IPaymentData>) => {
export const deletePaymentMethod = async (filter: FilterQuery<Cooperative.Payments.IPaymentData>) => {
return await generator.del('paymentMethod', filter as any);
};
export const listPaymentMethods = async (filter: Filter<Cooperative.Payments.IPaymentData>) => {
export const listPaymentMethods = async (filter: FilterQuery<Cooperative.Payments.IPaymentData>) => {
return await generator.list('paymentMethod', filter as any);
};
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.0.72](https://github.com/copenomics/coopdoc-generator-ts/compare/coopdoc-generator-ts@1.0.72-alpha.3...coopdoc-generator-ts@1.0.72) (2024-07-25)
**Note:** Version bump only for package coopdoc-generator-ts
## [1.0.71](https://github.com/copenomics/coopdoc-generator-ts/compare/coopdoc-generator-ts@1.0.71-alpha.0...coopdoc-generator-ts@1.0.71) (2024-07-15)
**Note:** Version bump only for package coopdoc-generator-ts
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "coopdoc-generator-ts",
"type": "module",
"version": "1.0.72-alpha.3",
"version": "1.0.72",
"private": true,
"packageManager": "pnpm@9.0.6",
"description": "",
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.0.17](https://github.com/coopenomics/cooptypes/compare/cooptypes@1.0.17-alpha.3...cooptypes@1.0.17) (2024-07-25)
**Note:** Version bump only for package cooptypes
## [1.0.16](https://github.com/coopenomics/cooptypes/compare/cooptypes@1.0.16-alpha.0...cooptypes@1.0.16) (2024-07-15)
**Note:** Version bump only for package cooptypes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "cooptypes",
"type": "module",
"version": "1.0.17-alpha.3",
"version": "1.0.17",
"description": "_description_",
"author": "Alex Ant <dacom.dark.sun@gmail.com>",
"license": "MIT",
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [0.0.21](https://github.com/copenomics/coop-notificator/compare/coop-notificator@0.0.21-alpha.3...coop-notificator@0.0.21) (2024-07-25)
**Note:** Version bump only for package coop-notificator
## [0.0.20](https://github.com/copenomics/coop-notificator/compare/coop-notificator@0.0.20-alpha.1...coop-notificator@0.0.20) (2024-07-15)
**Note:** Version bump only for package coop-notificator
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "coop-notificator",
"type": "module",
"version": "0.0.21-alpha.3",
"version": "0.0.21",
"private": true,
"packageManager": "pnpm@9.1.1",
"description": "_description_",
+24
View File
@@ -3,6 +3,30 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [0.1.32](https://github.com/coopenomics/monocoop/compare/terminal@0.1.32-alpha.0...terminal@0.1.32) (2024-07-31)
**Note:** Version bump only for package terminal
## [0.1.31](https://github.com/coopenomics/monocoop/compare/terminal@0.1.31-alpha.0...terminal@0.1.31) (2024-07-26)
**Note:** Version bump only for package terminal
## [0.1.30](https://github.com/coopenomics/monocoop/compare/terminal@0.1.30-alpha.4...terminal@0.1.30) (2024-07-25)
**Note:** Version bump only for package terminal
## [0.1.29](https://github.com/coopenomics/monocoop/compare/terminal@0.1.29-alpha.1...terminal@0.1.29) (2024-07-15)
**Note:** Version bump only for package terminal
+2 -1
View File
@@ -1,6 +1,6 @@
{
"name": "terminal",
"version": "0.1.30-alpha.3",
"version": "0.1.32",
"description": "A Terminal Project",
"productName": "Terminal App",
"author": "Alex Ant <dacom.dark.sun@gmail.com>",
@@ -44,6 +44,7 @@
"pinia-plugin-persistedstate": "^3.2.1",
"pug": "^3.0.3",
"quasar": "^2.16.0",
"swiper": "^11.1.7",
"vite": "2.9.16",
"vue": "^3.4.18",
"vue-i18n": "^9.2.2",
+2
View File
@@ -102,6 +102,7 @@ module.exports = configure(function (/* ctx */) {
eslint: {
lintCommand: 'eslint "./**/*.{js,ts,mjs,cjs,vue}"',
},
overlay: false
},
{ server: false },
],
@@ -111,6 +112,7 @@ module.exports = configure(function (/* ctx */) {
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#devServer
devServer: {
// https: true
vueDevtools: false,
open: false, // opens browser window automatically
port: 3005,
hmr:{
+2
View File
@@ -3,6 +3,8 @@ router-view(v-if="isLoaded")
</template>
<script setup lang="ts">
console.log('on start')
import { onMounted, ref } from 'vue'
import { FailAlert } from 'src/shared/api/alerts'
import { handleException } from 'src/shared/api';
@@ -0,0 +1,136 @@
import { defineStore } from 'pinia'
import * as Desktops from 'src/desktops'
import { computed, ComputedRef, ref, Ref } from 'vue'
import { FailAlert } from 'src/shared/api'
import { RouteRecordRaw, type RouteLocationNormalized} from 'vue-router'
interface IDesktop {
name: string
hash: string
authorizedHome: string
nonAuthorizedHome: string
routes: IRoute[]
config: object
}
interface IBlockchainDesktops {
defaultHash: string //hash
availableHashes: string[] //hashes
}
interface RouteMeta {
title: string;
icon: string;
roles: string[];
}
export interface IRoute {
path: string;
name: string;
component?: any;
children?: IRoute[];
meta: RouteMeta;
}
const desktopHashMap = {
'hash1': Desktops.UserDesktopModel.manifest, //User
'hash2': Desktops.ChairmanDesktopModel.manifest, //'Chairman',
'hash3': Desktops.MemberDesktopModel.manifest, //'Member',
'hash4': Desktops.SetupDesktopModel.manifest, //Setup
}
const namespace = 'desktops';
interface IDesktopStore {
currentDesktop: Ref<IDesktop | undefined>
availableDesktops: Ref<IDesktop[]>
defaultDesktopHash: Ref<string | undefined>
setActiveDesktop: (hash: string | undefined) => void;
loadDesktops: () => void;
getSecondLevel: (currentRoute: RouteLocationNormalized) => RouteRecordRaw[]
firstLevel: ComputedRef<IRoute[]>;
// secondLevel: ComputedRef<IRoute[]>;
}
function getNestedRoutes(route: RouteRecordRaw):RouteRecordRaw[] {
if (!route.children) {
return [];
}
let nestedRoutes: RouteRecordRaw[] = [];
for (const child of route.children) {
nestedRoutes.push(child);
nestedRoutes = nestedRoutes.concat(getNestedRoutes(child));
}
return nestedRoutes;
}
export const useDesktopStore = defineStore(namespace, (): IDesktopStore => {
const currentDesktop = ref<IDesktop>()
const availableDesktops = ref<IDesktop[]>([])
const defaultDesktopHash = ref<string>()
const firstLevel = computed(() => {
if (currentDesktop.value)
return currentDesktop.value.routes
else return []
});
const getSecondLevel = (currentRoute: RouteLocationNormalized): RouteRecordRaw[] => {
if (currentRoute.matched && currentDesktop.value && currentRoute) {
const matchingRootRoute = currentRoute.matched[1]
if (matchingRootRoute) {
return getNestedRoutes(matchingRootRoute)
}
}
return [];
}
const setActiveDesktop = (hash: string | undefined) => {
const desktop = availableDesktops.value.find(d => d.hash === hash)
if (desktop)
currentDesktop.value = desktop
else {
FailAlert('Рабочий стол не найден')
}
}
const loadAvailableDesktops = async(): Promise<IBlockchainDesktops> => {
return { //load it from bc later
defaultHash: 'hash1',
availableHashes: ['hash1','hash2', 'hash3']
}
}
const loadDesktops = async () => {
const {defaultHash, availableHashes} = await loadAvailableDesktops()
availableDesktops.value = []
defaultDesktopHash.value = defaultHash
availableHashes.map(hash => availableDesktops.value.push(
desktopHashMap[hash as keyof typeof desktopHashMap]
))
}
return {
defaultDesktopHash, //перезапишем через локал-сторадж для пользовательского управления стартовой страницей
currentDesktop,
availableDesktops,
setActiveDesktop,
loadDesktops,
getSecondLevel,
firstLevel,
}
})
+23 -13
View File
@@ -1,6 +1,7 @@
import { route } from 'quasar/wrappers';
import {
RouteLocationNormalizedGeneric,
RouteRecordRaw,
createMemoryHistory,
createRouter,
createWebHashHistory,
@@ -9,20 +10,30 @@ import {
import { routes } from 'src/app/providers/routes';
import { useSessionStore } from 'src/entities/Session';
import {
AUTHORIZED_HOME_PAGE,
COOPNAME,
NOT_AUTHORIZED_HOME_PAGE,
} from 'src/shared/config';
import { IUserAccountData, useCurrentUserStore } from 'src/entities/User';
import { useMenuStore } from 'src/entities/Menu';
import { useDesktopStore } from './desktops';
export default route(function (/* { store, ssrContext } */) {
export const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms))
export default route(async function (/* { store, ssrContext } */) {
const createHistory = process.env.SERVER
? createMemoryHistory
: process.env.VUE_ROUTER_MODE === 'history'
? createWebHistory
: createWebHashHistory;
const desktops = useDesktopStore()
await desktops.loadDesktops()
await desktops.setActiveDesktop(desktops.defaultDesktopHash)
desktops.currentDesktop?.routes.forEach(route => {
routes[0].children?.push(route as RouteRecordRaw)
})
const router = createRouter({
history: createHistory(process.env.VUE_ROUTER_BASE),
routes,
@@ -45,6 +56,7 @@ export default route(function (/* { store, ssrContext } */) {
from: RouteLocationNormalizedGeneric,
next: any
) => {
const currentUser = useCurrentUserStore();
const session = useSessionStore();
@@ -56,21 +68,19 @@ export default route(function (/* { store, ssrContext } */) {
} catch(e: any){
console.error(e)
}
}
const menuStore = useMenuStore()
menuStore.setRoutes(routes)
if (to.name == 'index') {
if (session.isAuth)
next({ name: AUTHORIZED_HOME_PAGE, params: { coopname: COOPNAME } });
else
if (session.isAuth){
next({ name: desktops.currentDesktop?.authorizedHome, params: { coopname: COOPNAME } });
return
} else {
next({
name: NOT_AUTHORIZED_HOME_PAGE,
name: desktops.currentDesktop?.nonAuthorizedHome,
params: { coopname: COOPNAME },
});
return;
return;
}
}
if (hasAccess(to, currentUser.userAccount)) {
@@ -2,24 +2,10 @@ import layout from 'src/pages/_layouts/default.vue';
import index from 'src/pages/index.vue';
import blank from 'src/pages/blank/blank.vue';
import permissionDenied from 'src/pages/_layouts/permissionDenied.vue';
// import sovietPage from 'src/components/soviet/index.vue'
import { CoopSettingsPage } from 'src/pages/CoopSettings';
import { UserHomePage } from 'src/pages/UserHome/ui';
import { ModerationPage } from 'src/pages/marketplace/Moderation';
import { CreateParentOfferPage } from 'src/pages/marketplace/CreateParentOffer';
import { ShowcasePage } from 'src/pages/marketplace/Showcase';
import { SuppliesListPage } from 'src/pages/marketplace/SuppliesList';
import { UserParentOffersPage } from 'src/pages/marketplace/UserParentOffers';
import { UserSuppliesListPage } from 'src/pages/marketplace/UserSuppliesList';
import { MainMarketplacePage } from 'src/pages/marketplace/MainPage';
import { SignUpPage } from 'src/pages/SignUp';
import { SignInPage } from 'src/pages/SignIn';
import { RouteRecordRaw } from 'vue-router';
import decisions from 'src/components/soviet/decisions.vue';
import participants from 'src/components/soviet/participants.vue';
import documents from 'src/components/soviet/documents.vue';
import { ContactsPage } from 'src/pages/Contacts';
const baseRoutes = [
{
@@ -31,66 +17,15 @@ const baseRoutes = [
name: 'index',
component: index,
},
//страница кошелька пользователя
{
path: '/:coopname/home',
name: 'home',
component: UserHomePage,
children: [],
meta: {
is_desktop_menu: true,
title: 'Профиль',
icon: 'fa-solid fa-id-card',
roles: [],
},
},
//страница управления кооперативом
{
path: ':coopname/settings',
name: 'soviet',
component: CoopSettingsPage,
meta: {
is_desktop_menu: true,
title: 'Настройки',
icon: 'fa-solid fa-cog',
roles: ['chairman', 'member'],
},
path: '/something-bad',
name: 'somethingBad',
component: blank,
},
{
path: ':coopname/agenda',
name: 'agenda',
component: decisions,
meta: {
is_desktop_menu: true,
title: 'Повестка',
icon: 'fa-solid fa-check-to-slot',
roles: ['chairman', 'member'],
},
},
{
path: ':coopname/participants',
name: 'participants',
component: participants,
meta: {
is_desktop_menu: true,
title: 'Пайщики',
icon: 'fa-solid fa-users',
roles: ['chairman', 'member'],
},
},
{
path: ':coopname/documents',
name: 'documents',
component: documents,
meta: {
is_desktop_menu: true,
title: 'Документы',
icon: 'fa-solid fa-file-invoice',
roles: ['chairman', 'member'],
},
path: '/permission-denied',
name: 'permissionDenied',
component: permissionDenied,
},
{
path: ':coopname/auth/signin',
@@ -104,80 +39,6 @@ const baseRoutes = [
component: SignUpPage,
children: [],
},
{
path: '/:coopname/marketplace',
name: 'marketplace',
component: MainMarketplacePage,
children: [
{
path: 'moderation',
name: 'marketplace-moderation',
component: ModerationPage,
},
{
path: 'create-offer',
name: 'marketplace-create-offer',
component: CreateParentOfferPage,
},
{
path: 'showcase',
name: 'marketplace-showcase',
component: ShowcasePage,
children: [
{
path: ':id',
name: 'marketplace-showcase-id',
component: ShowcasePage,
},
],
},
{
path: 'user-offers',
name: 'marketplace-user-offers',
component: UserParentOffersPage,
children: [
{
path: ':id',
name: 'marketplace-user-offer-id',
component: UserParentOffersPage,
},
],
},
{
path: 'supplies',
name: 'marketplace-supplies',
component: SuppliesListPage,
},
{
path: 'user-supplies',
name: 'marketplace-user-supplies',
component: UserSuppliesListPage,
},
],
},
//страница контактов
{
path: ':coopname/contacts',
name: 'contacts',
component: ContactsPage,
meta: {
is_desktop_menu: true,
title: 'Контакты',
icon: 'fa-solid fa-info',
roles: [],
},
},
{
path: '/something-bad',
name: 'somethingBad',
component: blank,
},
{
path: '/permission-denied',
name: 'permissionDenied',
component: permissionDenied,
},
{
path: '/:pathMatch(.*)*',
name: 'NotFound',
@@ -187,6 +48,109 @@ const baseRoutes = [
},
];
// const baseRoutes = [
// {
// path: '/',
// component: layout,
// children: [
// {
// path: '',
// name: 'index',
// component: index,
// },
// //страница кошелька пользователя
// {
// path: '/:coopname/home',
// name: 'home',
// component: UserHomePage,
// children: [],
// meta: {
// is_desktop_menu: true,
// title: 'Профиль',
// icon: 'fa-solid fa-id-card',
// roles: [],
// },
// },
// //страница управления кооперативом
// {
// path: ':coopname/settings',
// name: 'soviet',
// component: CoopSettingsPage,
// meta: {
// is_desktop_menu: true,
// title: 'Настройки',
// icon: 'fa-solid fa-cog',
// roles: ['chairman', 'member'],
// },
// },
// {
// path: ':coopname/agenda',
// name: 'agenda',
// component: decisions,
// meta: {
// is_desktop_menu: true,
// title: 'Повестка',
// icon: 'fa-solid fa-check-to-slot',
// roles: ['chairman', 'member'],
// },
// },
// {
// path: ':coopname/participants',
// name: 'participants',
// component: participants,
// meta: {
// is_desktop_menu: true,
// title: 'Пайщики',
// icon: 'fa-solid fa-users',
// roles: ['chairman', 'member'],
// },
// },
// {
// path: ':coopname/documents',
// name: 'documents',
// component: documents,
// meta: {
// is_desktop_menu: true,
// title: 'Документы',
// icon: 'fa-solid fa-file-invoice',
// roles: ['chairman', 'member'],
// },
// },
// {
// path: ':coopname/auth/signin',
// name: 'signin',
// component: SignInPage,
// children: [],
// },
// {
// path: ':coopname/auth/signup',
// name: 'signup',
// component: SignUpPage,
// children: [],
// },
// {
// path: '/something-bad',
// name: 'somethingBad',
// component: blank,
// },
// {
// path: '/permission-denied',
// name: 'permissionDenied',
// component: permissionDenied,
// },
// {
// path: '/:pathMatch(.*)*',
// name: 'NotFound',
// component: blank,
// },
// ],
// },
// ];
const rs = baseRoutes;
export const routes = rs as RouteRecordRaw[];
@@ -1,37 +1,36 @@
<template lang="pug">
div.menu-container
div.menu-items
div(v-for="route in menuRoutes" :key="route.path")
q-btn(
v-ripple
flat
class="cursor-pointer btn-menu"
:class="headerClass(route)"
@click="open(route)"
)
q-icon(:name="route.meta.icon").btn-icon.q-pt-xs
span.btn-font {{ t(route.meta.title) }}
q-btn(
v-for="route in menuRoutes" :key="route.path"
v-ripple
flat
class="cursor-pointer btn-menu"
:class="headerClass(route)"
@click="open(route)"
)
q-icon(:name="route.meta.icon").btn-icon.q-pt-xs
span.btn-font {{ route.meta.title }}
div.control-buttons
div
q-btn(flat @click="$q.dark.toggle()").btn-menu
q-icon(:name="isDark ? 'brightness_7' : 'brightness_3'").btn-icon
span.btn-font {{ isDark ? 'светлая' : 'тёмная' }}
div
q-btn(v-ripple flat class="cursor-pointer btn-menu" @click="logout")
q-icon( color="red" name="logout").btn-icon.q-pt-xs
div.btn-font Выход
q-btn(flat @click="$q.dark.toggle()" ).btn-menu
q-icon(:name="isDark ? 'brightness_7' : 'brightness_3'").q-pt-xs.btn-icon
span.btn-font {{ isDark ? 'светлая' : 'тёмная' }}
q-btn(v-ripple flat class="cursor-pointer btn-menu" @click="logout")
q-icon( color="red" name="logout").q-pt-xs.btn-icon
div.btn-font Выход
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
import { computed } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { useQuasar } from 'quasar'
import { useMenuStore } from 'src/entities/Menu'
import type { IMenu } from 'src/entities/Menu'
import { COOPNAME } from 'src/shared/config'
import { useLogoutUser } from 'src/features/User/Logout/model'
import { type IRoute, useDesktopStore } from 'src/app/providers/desktops'
import { useLogoutUser } from 'src/features/User/Logout'
import { FailAlert } from 'src/shared/api'
import { useCurrentUserStore } from 'src/entities/User'
@@ -41,27 +40,24 @@ const isDark = computed(() => $q.dark.isActive)
const router = useRouter()
const route = useRoute()
const user = useCurrentUserStore()
const isRouteActive = (currentRoute: IMenu) => {
return route.name === currentRoute.name
const isRouteActive = (currentRoute: IRoute) => {
return route.matched.find(r => r.path === currentRoute.path) || route.name == currentRoute.name
}
const headerClass = (route: IMenu) => {
const headerClass = (route: IRoute) => {
const isActive = isRouteActive(route)
return isActive ? (isDark.value ? 'text-white bg-teal-8' : 'text-black bg-teal-2') : ''
}
const currentUser = useCurrentUserStore()
const menuStore = useMenuStore()
const desktop = useDesktopStore()
const { t } = useI18n()
const open = (route: IRoute) => {
if (route.children)
router.push({ name: route.children[0].name, params: { coopname: COOPNAME } })
else router.push({ name: route.name, params: { coopname: COOPNAME } })
const menu = ref<IMenu[]>([])
menu.value = menuStore.getUserDesktopMenu(currentUser?.userAccount?.role)
const open = (route: IMenu) => {
router.push({ name: route.name, params: { coopname: COOPNAME } })
}
@@ -78,15 +74,23 @@ const logout = async () => {
}
}
const menuRoutes = computed(() => {
return menu.value
const userRole = user.userAccount?.role || 'user';
return desktop.firstLevel.filter(
(route) => route.meta.roles.includes(userRole) || route.meta.roles.length === 0
);
})
</script>
<style lang="scss" scoped>
.btn-menu {
height: 70px;
width: 70px;
height: 54px;
width: 65px;
}
.btn-icon {
@@ -99,13 +103,13 @@ const menuRoutes = computed(() => {
.logout-btn {
position: fixed;
bottom: 70px;
bottom: 54px;
width: 100%;
}
.menu-container {
display: flex;
flex-direction: column;
// flex-direction: column;
height: 100%;
}
@@ -1,77 +1,76 @@
<template lang="pug">
div.row.justify-center
div.col-12
q-card(flat)
q-table(
ref="tableRef" v-model:expanded="expanded"
flat
bordered
:rows="decisions"
:columns="columns"
:table-colspan="9"
row-key="table.id"
:pagination="pagination"
virtual-scroll
:virtual-scroll-item-size="48"
:rows-per-page-options="[10]"
:loading="onLoading"
:no-data-label="'У совета нет голосований на повестке'"
).full-height.full-width
template(#header="props")
q-tr(:props="props")
q-th(auto-width)
q-card(flat)
q-table(
ref="tableRef" v-model:expanded="expanded"
flat
bordered
:rows="decisions"
:columns="columns"
:table-colspan="9"
row-key="table.id"
:pagination="pagination"
virtual-scroll
:virtual-scroll-item-size="48"
:rows-per-page-options="[10]"
:loading="onLoading"
:no-data-label="'У совета нет голосований на повестке'"
).full-width
q-th(
v-for="col in props.cols"
:key="col.name"
:props="props"
) {{ col.label }}
template(#header="props")
q-tr(:props="props")
q-th(auto-width)
template(#body="props")
q-tr(:key="`m_${props.row.table.id}`" :props="props")
q-td(auto-width)
// q-toggle(v-model="props.expand" checked-icon="fas fa-chevron-circle-left" unchecked-icon="fas fa-chevron-circle-right" )
q-th(
v-for="col in props.cols"
:key="col.name"
:props="props"
) {{ col.label }}
q-btn(size="sm" color="primary" dense :icon="props.expand ? 'remove' : 'add'" round @click="props.expand = !props.expand")
q-td {{ props.row.table.id }}
q-td {{ props.row.table.username }}
q-td
q-badge {{ getTitle(props.row.table.type, props.row.documents.statement.action.user) }}
template(#body="props")
q-tr(:key="`m_${props.row.table.id}`" :props="props")
q-td(auto-width)
// q-toggle(v-model="props.expand" checked-icon="fas fa-chevron-circle-left" unchecked-icon="fas fa-chevron-circle-right" )
//- q-td
//- q-checkbox(@click="updateValidation(props.row.id)" :model-value="props.row.validated")
q-btn(size="sm" color="primary" dense :icon="props.expand ? 'remove' : 'add'" round @click="props.expand = !props.expand")
q-td {{ props.row.table.id }}
q-td {{ props.row.table.username }}
q-td
q-badge {{ getTitle(props.row.table.type, props.row.documents.statement.action.user) }}
q-td
//- p Проголосовало {{ props.row.table.votes_for.length + props.row.table.votes_against.length}} из {{totalMembers}}
//- q-td
//- q-checkbox(@click="updateValidation(props.row.id)" :model-value="props.row.validated")
q-td
//- p Проголосовало {{ props.row.table.votes_for.length + props.row.table.votes_against.length}} из {{totalMembers}}
q-btn(v-if="isVotedFor(props.row.table) || !isVotedAny(props.row.table)" :disabled="isVotedAny(props.row.table)" dense flat @click="voteAgainst(props.row.table.id)").text-red
q-icon(name="fa-regular fa-thumbs-down")
p.q-pl-xs {{props.row.table.votes_against.length}}
q-btn(v-if="isVotedFor(props.row.table) || !isVotedAny(props.row.table)" :disabled="isVotedAny(props.row.table)" dense flat @click="voteAgainst(props.row.table.id)").text-red
q-icon(name="fa-regular fa-thumbs-down")
p.q-pl-xs {{props.row.table.votes_against.length}}
q-btn(v-if="isVotedAgainst(props.row.table)" disabled dense flat).text-red
q-icon(name="fas fa-thumbs-down")
p.q-pl-xs {{props.row.table.votes_against.length}}
q-btn(v-if="isVotedAgainst(props.row.table)" disabled dense flat).text-red
q-icon(name="fas fa-thumbs-down")
p.q-pl-xs {{props.row.table.votes_against.length}}
q-checkbox( v-model="props.row.table.approved" disable :true-value="1" :false-value="0" )
q-checkbox( v-model="props.row.table.approved" disable :true-value="1" :false-value="0" )
q-btn(v-if="isVotedAgainst(props.row.table) || !isVotedAny(props.row.table)" :disabled="isVotedAny(props.row.table)" dense flat @click="voteFor(props.row.table.id)").text-green
p.q-pr-xs {{props.row.table.votes_for.length}}
q-icon(name="fa-regular fa-thumbs-up" style="transform: scaleX(-1)")
q-btn(v-if="isVotedAgainst(props.row.table) || !isVotedAny(props.row.table)" :disabled="isVotedAny(props.row.table)" dense flat @click="voteFor(props.row.table.id)").text-green
p.q-pr-xs {{props.row.table.votes_for.length}}
q-icon(name="fa-regular fa-thumbs-up" style="transform: scaleX(-1)")
q-btn(v-if="isVotedFor(props.row.table)" disabled dense flat ).text-green
p.q-pr-xs {{props.row.table.votes_for.length}}
q-icon(name="fas fa-thumbs-up" style="transform: scaleX(-1)")
q-btn(v-if="isVotedFor(props.row.table)" disabled dense flat ).text-green
p.q-pr-xs {{props.row.table.votes_for.length}}
q-icon(name="fas fa-thumbs-up" style="transform: scaleX(-1)")
q-td
q-btn( :loading="isProcess(props.row.table.id)" @click="updateAuthorized(props.row.table.username, props.row.table.id)") утвердить
//- q-checkbox(v-if="!isProcess(props.row.table.id)" :model-value="props.row.table.authorized" :true-value="1" :false-value="0" @click="updateAuthorized(props.row.table.username, props.row.table.id)")
//- q-spinner(v-if="isProcess(props.row.table.id)" size="md")
q-td
q-btn( :loading="isProcess(props.row.table.id)" @click="updateAuthorized(props.row.table.username, props.row.table.id)") утвердить
//- q-checkbox(v-if="!isProcess(props.row.table.id)" :model-value="props.row.table.authorized" :true-value="1" :false-value="0" @click="updateAuthorized(props.row.table.username, props.row.table.id)")
//- q-spinner(v-if="isProcess(props.row.table.id)" size="md")
q-tr(v-show="props.expand" :key="`e_${props.row.table.id}`" :props="props" class="q-virtual-scroll--with-prev")
q-td(colspan="100%")
joincoopdoc(v-if="props.row.table.type == 'joincoop'" :documents="props.row.documents")
q-tr(v-show="props.expand" :key="`e_${props.row.table.id}`" :props="props" class="q-virtual-scroll--with-prev")
q-td(colspan="100%")
joincoopdoc(v-if="props.row.table.type == 'joincoop'" :documents="props.row.documents")
@@ -76,7 +76,7 @@ const receiver = computed(() => props.receiver)
const loadDocuments = async () => {
try {
onLoading.value = true
documents.value = (await sendGET('/v1/data/get-documents', {
documents.value = (await sendGET('/v1/documents/get-documents', {
filter: {
receiver: receiver.value ? receiver.value : route.params.coopname
},
@@ -0,0 +1 @@
export * as ChairmanDesktopModel from './model'
@@ -0,0 +1,30 @@
import { UserHomePage } from 'src/pages/UserHome';
export const manifest = {
'name': 'ChairmanDesktop',
'hash': 'hash2',
'authorizedHome': 'home',
'nonAuthorizedHome': 'signup',
'routes': [
{
path: '/:coopname/home',
name: 'home',
component: UserHomePage,
children: [],
meta: {
is_desktop_menu: true,
title: 'Профиль',
icon: 'fa-solid fa-id-card',
roles: [],
},
},
],
'config': {
'layout': 'default',
'theme': 'light'
},
'schemas': {
'layout': 'avj schema here',
'theme': 'avj schema here'
}
}
@@ -0,0 +1 @@
export * as MemberDesktopModel from './model'
@@ -0,0 +1,30 @@
import { UserHomePage } from 'src/pages/UserHome';
export const manifest = {
'name': 'ChairmanDesktop',
'hash': 'hash2',
'authorizedHome': 'home',
'nonAuthorizedHome': 'signup',
'routes': [
{
path: '/:coopname/home',
name: 'home',
component: UserHomePage,
children: [],
meta: {
is_desktop_menu: true,
title: 'Профиль',
icon: 'fa-solid fa-id-card',
roles: [],
},
},
],
'config': {
'layout': 'default',
'theme': 'light'
},
'schemas': {
'layout': 'avj schema here',
'theme': 'avj schema here'
}
}
@@ -0,0 +1 @@
export * as SetupDesktopModel from './model'
@@ -0,0 +1,30 @@
import { UserHomePage } from 'src/pages/UserHome';
export const manifest = {
'name': 'ChairmanDesktop',
'hash': 'hash2',
'authorizedHome': 'home',
'nonAuthorizedHome': 'signup',
'routes': [
{
path: '/:coopname/home',
name: 'home',
component: UserHomePage,
children: [],
meta: {
is_desktop_menu: true,
title: 'Профиль',
icon: 'fa-solid fa-id-card',
roles: [],
},
},
],
'config': {
'layout': 'default',
'theme': 'light'
},
'schemas': {
'layout': 'avj schema here',
'theme': 'avj schema here'
}
}
@@ -0,0 +1 @@
export * as UserDesktopModel from './model'
@@ -0,0 +1,289 @@
import { UserIdentityPage } from 'src/pages/User/IdentityPage';
import { UserPaymentMethodsPage } from 'src/pages/User/PaymentMethodsPage';
import { UserWalletPage } from 'src/pages/User/WalletPage';
import decisions from 'src/components/soviet/decisions.vue';
import participants from 'src/components/soviet/participants.vue';
import documents from 'src/components/soviet/documents.vue';
import { markRaw } from 'vue';
// import { Commutator } from 'src/widgets/Commutator';
// import { MainMarketplacePage } from 'src/pages/marketplace/MainPage';
// import { ModerationPage } from 'src/pages/marketplace/Moderation';
// import { CreateParentOfferPage } from 'src/pages/marketplace/CreateParentOffer';
// import { ShowcasePage } from 'src/pages/marketplace/Showcase';
// import { UserParentOffersPage } from 'src/pages/marketplace/UserParentOffers';
// import { SuppliesListPage } from 'src/pages/marketplace/SuppliesList';
// import { UserSuppliesListPage } from 'src/pages/marketplace/UserSuppliesList';
import { ContactsPage } from 'src/pages/Contacts';
import { CooperativeDetails } from 'src/widgets/Cooperative/Details';
import { CooperativeMembers } from 'src/widgets/Cooperative/Members';
import { ChangeCooperativeContributions } from 'src/widgets/Cooperative/Contributions';
import { ChangeCooperativeContacts } from 'src/widgets/Cooperative/Contacts';
export const manifest = {
'name': 'UserDesktop',
'hash': 'hash1',
'authorizedHome': 'user-identity',
'nonAuthorizedHome': 'signin',
'routes': [
{
meta: {
title: 'Пайщик',
icon: 'fa-solid fa-id-card',
roles: [],
},
path: '/:coopname/user',
name: 'home',
// component: markRaw(UserHomePage),
children: [{
meta: {
title: 'Удостоверение',
icon: '',
roles: [],
},
path: 'identity',
name: 'user-identity',
component: markRaw(UserIdentityPage),
children: [],
},{
meta: {
title: 'Кошелёк',
icon: '',
roles: [],
},
path: 'wallet',
name: 'user-wallet',
component: markRaw(UserWalletPage),
children: [],
},
{
meta: {
title: 'Реквизиты',
icon: '',
roles: [],
},
path: 'payment-methods',
name: 'user-payment-methods',
component: markRaw(UserPaymentMethodsPage),
children: [],
}
],
},
{
meta: {
title: 'Совет',
icon: 'fa-regular fa-circle',
roles: ['chairman', 'member'],
},
path: '/:coopname/soviet',
name: 'soviet',
children: [
{
path: 'agenda',
name: 'agenda',
component: markRaw(decisions),
meta: {
title: 'Повестка',
icon: 'fa-solid fa-check-to-slot',
roles: [],
},
},
{
path: 'participants',
name: 'participants',
component: markRaw(participants),
meta: {
title: 'Пайщики',
icon: 'fa-solid fa-users',
roles: ['chairman', 'member'],
},
},
{
path: 'documents',
name: 'documents',
component: markRaw(documents),
meta: {
title: 'Документы',
icon: 'fa-solid fa-file-invoice',
roles: ['chairman', 'member'],
},
},
]
},
//КООПЕРАТИВ
{
meta: {
title: 'Кооператив',
icon: 'fa-solid fa-cog',
roles: ['chairman', 'member'],
},
path: '/:coopname/settings',
name: 'settings',
children: [
{
path: 'details',
name: 'settings-details',
component: markRaw(CooperativeDetails),
meta: {
title: 'Реквизиты',
icon: 'fa-solid fa-check-to-slot',
roles: [],
},
},
{
path: 'members',
name: 'settings-members',
component: markRaw(CooperativeMembers),
meta: {
title: 'Члены Совета',
icon: 'fa-solid fa-users',
roles: ['chairman', 'member'],
},
},
{
path: 'contributions',
name: 'settings-contributions',
component: markRaw(ChangeCooperativeContributions),
meta: {
title: 'Взносы',
icon: 'fa-solid fa-file-invoice',
roles: ['chairman', 'member'],
},
},
{
path: 'contacts',
name: 'settings-contacts',
component: markRaw(ChangeCooperativeContacts),
meta: {
title: 'Контакты',
icon: 'fa-solid fa-file-invoice',
roles: ['chairman', 'member'],
},
},
]
},
// //страница управления кооперативом
// {
// meta: {
// title: 'Маркетплейс',
// icon: 'fa-solid fa-cog',
// roles: [],
// },
// path: '/:coopname/marketplace',
// name: 'marketplace',
// component: markRaw(MainMarketplacePage),
// children: [
// {
// path: 'moderation',
// name: 'marketplace-moderation',
// component: markRaw(ModerationPage),
// meta: {
// title: 'Модерация',
// icon: '',
// roles: ['member', 'chairman'],
// },
// },
// {
// path: 'create-offer',
// name: 'marketplace-create-offer',
// component: markRaw(CreateParentOfferPage),
// meta: {
// title: 'Создать объявление',
// icon: '',
// roles: [],
// },
// },
// {
// path: 'showcase',
// name: 'marketplace-showcase',
// component: markRaw(ShowcasePage),
// children: [
// {
// path: ':id',
// name: 'marketplace-showcase-id',
// component: markRaw(ShowcasePage),
// },
// ],
// meta: {
// title: 'Витрина',
// icon: '',
// roles: [],
// },
// },
// {
// path: 'user-offers',
// name: 'marketplace-user-offers',
// component: markRaw(UserParentOffersPage),
// children: [
// {
// path: ':id',
// name: 'marketplace-user-offer-id',
// component: markRaw(UserParentOffersPage),
// },
// ],
// meta: {
// title: 'Мои объявления',
// icon: '',
// roles: [],
// },
// },
// {
// path: 'supplies',
// name: 'marketplace-supplies',
// component: markRaw(SuppliesListPage),
// meta: {
// title: 'Все заказы',
// icon: '',
// roles: ['member', 'chairman'],
// },
// },
// {
// path: 'user-supplies',
// name: 'marketplace-user-supplies',
// component: markRaw(UserSuppliesListPage),
// meta: {
// title: 'Мои заказы',
// icon: '',
// roles: [],
// },
// },
// ],
// },
//страница контактов
{
path: ':coopname/contacts',
name: 'contacts',
component: markRaw(ContactsPage),
meta: {
title: 'Контакты',
icon: 'fa-solid fa-info',
roles: [],
},
},
// {
// path: ':coopname/commutator',
// name: 'commutator',
// component: markRaw(Commutator),
// meta: {
// title: 'Коммутатор',
// icon: '',
// roles: [],
// },
// },
],
'config': {
'layout': 'default',
'theme': 'light'
},
'schemas': {
'layout': 'avj schema here',
'theme': 'avj schema here'
}
}
@@ -0,0 +1,9 @@
export * from './Chairman'
export * from './Member'
export * from './User'
export * from './Setup'
// export desktopsMap {
// Chairman: ChairmanDesktop,
// }
@@ -0,0 +1 @@
export * from './ui'
@@ -0,0 +1,5 @@
<template lang="pug">
div menu
</template>
<script lang="ts" setup>
</script>
@@ -0,0 +1 @@
export {default as FirstLevelMenu} from './FirstLevelMenu.vue'
@@ -0,0 +1,50 @@
<template lang="pug">
q-tabs(
v-if="routes"
dense
switch-indicator
inline-label
outside-arrows
mobile-arrows
align="justify"
active-class="bg-teal"
active-bg-color="teal"
active-color="white"
indicator-color="secondary"
)
q-route-tab(
v-for="route in routes"
:key="route.name"
:name="route.meta.title"
:label="route.meta.title"
:to="{ name: route.name }"
:params="{coopname: 'voskhod'}"
)
</template>
<script lang="ts" setup>
import { type IRoute, useDesktopStore } from 'src/app/providers/desktops';
import { useCurrentUserStore } from 'src/entities/User';
import { ref, watch } from 'vue';
import { useRoute } from 'vue-router';
const desktop = useDesktopStore()
const routes = ref<IRoute[]>([])
const route = useRoute()
const user = useCurrentUserStore()
const init = () => {
const userRole = user.userAccount?.role || 'user';
routes.value = (desktop.getSecondLevel(route) as unknown as IRoute[]).filter(
(route) => route.meta?.roles?.includes(userRole) || route.meta?.roles?.length === 0
);
}
init()
watch(route, () => init())
</script>
@@ -0,0 +1 @@
export {default as SecondLevelMenu} from './SecondLevelMenu.vue'
@@ -0,0 +1,2 @@
export * from './FirstLevelMenu'
export * from './SecondLevelMenu'
@@ -3,7 +3,7 @@ import type { IGenerate, IGeneratedDocument } from '../model';
import { sendPOST } from 'src/shared/api';
async function generateDocument(data: IGenerate): Promise<IGeneratedDocument> {
return await sendPOST('/v1/data/generate', data);
return await sendPOST('/v1/documents/generate', data);
}
export const api = {
@@ -1,24 +0,0 @@
import { sendGET, sendPOST } from 'src/shared/api';
import { IAddPaymentMethod, IDeletePaymentMethod, IGetPaymentMethods, IPaymentData } from '../model';
async function loadMethods(params: IGetPaymentMethods): Promise<IPaymentData> {
const {username} = params
const methods = (await sendGET('/v1/payments/methods', {username})) as IPaymentData;
return methods;
}
async function addMethod(params: IAddPaymentMethod): Promise<void> {
await sendPOST(`/v1/payments/methods/${params.username}/add`, params)
}
async function deleteMethod(params: IDeletePaymentMethod): Promise<void>{
const {username, method_id} = params
await sendPOST(`/v1/payments/methods/${username}/delete`, {method_id})
}
export const api = {
loadMethods,
addMethod,
deleteMethod
}
@@ -1,2 +0,0 @@
export * from './stores'
export * from './types'
@@ -1,40 +0,0 @@
import { defineStore } from 'pinia';
import { ref, Ref } from 'vue';
import { api } from '../api';
import { IAddPaymentMethod, IDeletePaymentMethod, IGetPaymentMethods, IPaymentData } from './types';
interface IPaymentStore {
//методы
loadMethods(params: IGetPaymentMethods): Promise<void>;
addMethod(params: IAddPaymentMethod): Promise<void>
deleteMethod(params: IDeletePaymentMethod): Promise<void>
paymentMethods: Ref<IPaymentData | null>
}
const namespace = 'payments';
export const useCurrentUserStore = defineStore(
namespace,
(): IPaymentStore => {
const loadMethods = async(params: IGetPaymentMethods): Promise<void> => {
paymentMethods.value = await api.loadMethods(params)
}
const addMethod = async(params: IAddPaymentMethod): Promise<void> => {
await api.addMethod(params)
}
const deleteMethod = async(params: IDeletePaymentMethod): Promise<void> => {
await api.deleteMethod(params)
}
const paymentMethods = ref<IPaymentData | null>(null)
return {
loadMethods,
addMethod,
deleteMethod,
paymentMethods
}
})
@@ -1,31 +0,0 @@
import { Cooperative } from 'cooptypes';
export type IPaymentData = Cooperative.Documents.IGetResponse<Cooperative.Payments.IPaymentData>
export interface IGetPaymentMethods {
username?: number
}
export interface IDeletePaymentMethod {
username: number;
method_id: number;
}
export interface IAddPaymentMethod {
username: string;
method_id: number;
method_type: 'sbp' | 'bank_transfer';
data: {
phone: string;
} | ({
account_number: string;
bank_name: string;
card_number?: string;
currency: 'RUB' | 'Other';
details: {
bik: string;
corr: string;
kpp: string;
};
});
}
@@ -1,4 +1,4 @@
import { fetchTable } from '../../../shared/api';
import { fetchTable, sendGET } from '../../../shared/api';
import {
ContractsList,
@@ -14,6 +14,9 @@ import {
IProgramWalletData,
ICoopMarketProgramData,
ExtendedProgramWalletData,
IGetPaymentMethods,
IGetResponsePaymentMethodData,
IPaymentMethodData,
} from '../model';
import {
@@ -153,6 +156,14 @@ async function loadUserProgramWalletsData(
return extendedProgramWallets;
}
async function loadMethods(params: IGetPaymentMethods): Promise<IPaymentMethodData[]> {
const {username} = params
const methods = (await sendGET(`/v1/payments/methods/${username}`)) as IGetResponsePaymentMethodData;
return methods.results;
}
export const api = {
loadSingleUserWalletData,
loadSingleUserDepositData,
@@ -161,4 +172,5 @@ export const api = {
loadUserDepositsData,
loadUserWithdrawsData,
loadUserProgramWalletsData,
loadMethods
};
@@ -7,6 +7,7 @@ import {
IPaymentOrder,
ExtendedProgramWalletData,
ICreateWithdraw,
IPaymentMethodData,
} from './types';
import { ILoadUserWallet, ICreateDeposit } from './types';
import { Ref, ref } from 'vue';
@@ -21,16 +22,28 @@ interface IWalletStore {
program_wallets: Ref<ExtendedProgramWalletData[]>;
deposits: Ref<IDepositData[]>;
withdraws: Ref<IWithdrawData[]>;
methods: Ref<IPaymentMethodData[]>;
update: (params: ILoadUserWallet) => Promise<void>;
//TODO move to Features
createDeposit: (params: ICreateDeposit) => Promise<IPaymentOrder>;
createWithdraw: (params: ICreateWithdraw) => Promise<void>;
}
export const useWalletStore = defineStore(namespace, (): IWalletStore => {
const wallet = ref({} as IWalletData);
const deposits = ref([] as IDepositData[]);
const withdraws = ref([] as IWithdrawData[]);
const program_wallets = ref([] as ExtendedProgramWalletData[]);
const wallet = ref<IWalletData>({
username: '',
coopname: '',
available: `0.0000 ${CURRENCY}`,
blocked: `0.0000 ${CURRENCY}`,
minimum: `0.0000 ${CURRENCY}`,
});
const deposits = ref<IDepositData[]>([]);
const withdraws = ref<IWithdrawData[]>([]);
const program_wallets = ref<ExtendedProgramWalletData[]>([]);
const methods = ref<IPaymentMethodData[]>([]);
const createEmptyWallet = (): IWalletData => ({
username: '',
@@ -40,6 +53,7 @@ export const useWalletStore = defineStore(namespace, (): IWalletStore => {
minimum: `0.0000 ${CURRENCY}`,
});
const update = async (params: ILoadUserWallet) => {
try {
const data = await Promise.all([
@@ -47,11 +61,14 @@ export const useWalletStore = defineStore(namespace, (): IWalletStore => {
api.loadUserDepositsData(params),
api.loadUserWithdrawsData(params),
api.loadUserProgramWalletsData(params),
api.loadMethods(params)
]);
wallet.value = data[0] ?? createEmptyWallet();
deposits.value = data[1] ?? [];
withdraws.value = data[2] ?? [];
program_wallets.value = data[3] ?? [];
methods.value = data[4] ?? [];
} catch (e: any) {
console.log(e);
}
@@ -60,7 +77,7 @@ export const useWalletStore = defineStore(namespace, (): IWalletStore => {
const createDeposit = async (
params: ICreateDeposit
): Promise<IPaymentOrder> => {
return sendPOST('/v1/orders/deposit', params);
return sendPOST('/v1/payments/deposit', params);
};
const createWithdraw = async (params: ICreateWithdraw): Promise<void> => {
@@ -72,6 +89,7 @@ export const useWalletStore = defineStore(namespace, (): IWalletStore => {
program_wallets,
deposits,
withdraws,
methods,
update,
createDeposit,
createWithdraw,
@@ -74,3 +74,17 @@ export interface IPaymentOrder {
export interface ICreateWithdraw {
quantity: string;
}
import { Cooperative } from 'cooptypes';
export type IPaymentMethodData = Cooperative.Payments.IPaymentData
export type IGetResponsePaymentMethodData = Cooperative.Documents.IGetResponse<IPaymentMethodData>
export interface IGetPaymentMethods {
username?: string
}
export interface IDeletePaymentMethod {
username: string;
method_id: number;
}
@@ -4,13 +4,13 @@ const walletStore = useWalletStore()
</script>
<template lang="pug">
div.row.flex.justify-between.q-pa-sm
div
span.text-grey Паевый счёт
p {{ walletStore.wallet.available }}
div
q-input(readonly standout label="Паевый счёт" v-model="walletStore.wallet.available")
//- span.text-grey Паевый счёт
//- p.text-h3 {{ walletStore.wallet.available }}
q-input(readonly standout label="Членский счёт" v-model="walletStore.wallet.blocked")
div.text-right
span.text-grey Членский счёт
p {{ walletStore.wallet.blocked }}
</template>
@@ -5,7 +5,7 @@ const walletStore = useWalletStore()
<template lang="pug">
div.q-pa-md
q-list(v-if="walletStore.program_wallets.length > 0")
q-list
q-item(v-for="program_wallet of walletStore.program_wallets" :key="program_wallet.id" v-ripple clickable)
q-item-section
q-item-label {{ program_wallet.program_details.title }}
+2
View File
@@ -20,5 +20,7 @@ declare module 'vue-router' {
// Расширяем интерфейс RouteMeta, добавляя новые свойства
interface RouteMeta {
roles?: string[];
// title: string
// icon: string
}
}
@@ -20,7 +20,7 @@ async function createUser(data: ICreateUser): Promise<ICreatedUser> {
async function createInitialPayment(
data: ICreateInitialPayment
): Promise<ICreatedPayment> {
const response = await sendPOST('/v1/orders/initial', data);
const response = await sendPOST('/v1/payments/initial', data);
return response;
}
@@ -2,11 +2,11 @@ import { sendPOST } from 'src/shared/api';
import { hashSHA256 } from 'src/shared/api/crypto';
import { ICreatedUser } from 'src/shared/lib/types/user';
async function loginUser(username: string, wif: string): Promise<ICreatedUser> {
async function loginUser(email: string, wif: string): Promise<ICreatedUser> {
const password = await hashSHA256(wif);
const data = {
username,
email,
password,
};
@@ -0,0 +1,2 @@
export * as AddPaymentMethodModel from './model'
export * from './ui'
@@ -0,0 +1,56 @@
import { useSessionStore } from 'src/entities/Session'
import { useWalletStore } from 'src/entities/Wallet'
import { sendPOST } from 'src/shared/api';
import { COOPNAME } from 'src/shared/config'
export interface ISBPData {
phone: string;
}
export interface IBankTransferData {
account_number: string;
bank_name: string;
card_number?: string;
currency: string;
details: {
bik: string;
corr: string;
kpp: string;
};
}
export interface IAddPaymentMethod {
username: string;
method_id: number;
method_type: 'sbp' | 'bank_transfer';
data: ISBPData | IBankTransferData;
}
export function useAddPaymentMethod() {
const store = useWalletStore()
const session = useSessionStore()
async function addPaymentMethod(params: IAddPaymentMethod) {
await store.update({
coopname: COOPNAME,
username: params.username,
})
params.method_id = (store.methods.sort((a, b) => b.method_id - a.method_id)[0]?.method_id || 0) + 1
console.log(store.methods, store.methods.length, params.method_id)
await sendPOST(`/v1/payments/methods/${params.username}/add`, params)
await store.update({
coopname: COOPNAME,
username: session.username
})
}
return {
addPaymentMethod
}
}
@@ -0,0 +1,161 @@
<template lang="pug">
div
q-btn(@click="showDialog=true" outline) добавить метод
q-dialog(v-model="showDialog" @hide="clear")
ModalBase(:title='"Добавить метод платежа"' )
Form(:handler-submit="handlerSubmit" :is-submitting="isSubmitting" :button-cancel-txt="'Отменить'" :button-submit-txt="'Продолжить'" @cancel="clear").q-pa-sm
q-select(v-model="methodType" filled :options="methods" map-options emit-value option-label="title" option-value="value" label="Выберите способ получения платежа" :rules="[val => notEmpty(val)]")
div(v-if="methodType=='sbp'")
q-input(v-model="sbp.phone" filled mask="+7 (###) ###-##-##" fill-mask label="Номер телефона" hint="Имя и фамилия получателя должны совпадать с теми, которые указаны в Удостоверении." :rules="[val => notEmpty(val)]" autocomplete="off").q-mb-lg
div(v-if="methodType=='bank_transfer'")
q-select(
v-model="bank_transfer.currency"
label="Валюта счёта"
filled
:options="[{ label: 'RUB', value: 'RUB' }]"
emit-value
:rules="[val => notEmpty(val)]"
map-options
)
q-input(
v-model="bank_transfer.bank_name"
filled
label="Наименование банка"
:rules="[val => notEmpty(val)]"
autocomplete="off"
)
q-input(
v-model="bank_transfer.details.corr"
filled
mask="####################"
label="Корреспондентский счет"
:rules="[val => notEmpty(val), val => val.length === 20 || 'ожидаем 20 цифр']"
autocomplete="off"
)
q-input(
v-model="bank_transfer.details.bik"
filled
mask="#########"
label="БИК"
:rules="[val => notEmpty(val), val => val.length === 9 || 'ожидаем 9 цифр']"
autocomplete="off"
)
q-input(
v-model="bank_transfer.details.kpp"
filled
mask="#########"
label="КПП"
:rules="[val => notEmpty(val), val => val.length === 9 || 'ожидаем 9 цифр']"
autocomplete="off"
)
q-input(
v-model="bank_transfer.account_number"
filled
mask="####################"
label="Номер счета"
:rules="[val => notEmpty(val), val => val.length === 20 || 'ожидаем 20 цифр']"
autocomplete="off"
hint="Имя и фамилия получателя должны совпадать с теми, которые указаны в Удостоверении."
).q-mb-lg
</template>
<script lang="ts" setup>
import { computed, ref } from 'vue';
import { useAddPaymentMethod } from '../model';
import { FailAlert } from 'src/shared/api';
import { ModalBase } from 'src/shared/ui/ModalBase';
import { Form } from 'src/shared/ui/Form';
const props = defineProps({
username: {
type: String,
required: true,
},
})
const username = computed(() => props.username)
const methodType = ref()
const methods = ref([{
title: 'Система Быстрых Платежей (СБП)',
value: 'sbp'
}, {
title: 'Банковский перевод',
value: 'bank_transfer'
}])
const notEmpty = (val: any) => {
return !!val || 'Это поле обязательно для заполнения'
}
const showDialog = ref(false)
const isSubmitting = ref(false)
const sbp = ref({ phone: '' })
const bank_transfer = ref({
account_number: '',
bank_name: '',
currency: 'RUB',
details: {
bik: '',
corr: '',
kpp: '',
}
})
const clear = (): void => {
showDialog.value = false
sbp.value = { phone: '' }
bank_transfer.value = {
account_number: '',
bank_name: '',
currency: 'RUB',
details: {
bik: '',
corr: '',
kpp: '',
}
}
}
const { addPaymentMethod } = useAddPaymentMethod()
const handlerSubmit = async (): Promise<void> => {
isSubmitting.value = true
try {
let data = null
if (methodType.value === 'sbp')
data = sbp.value
else if (methodType.value === 'bank_transfer')
data = bank_transfer.value
if (data != null)
await addPaymentMethod({
username: username.value,
method_id: 0, //autogenerate
method_type: methodType.value,
data
})
showDialog.value = false
isSubmitting.value = false
clear()
} catch (e: any) {
showDialog.value = false
isSubmitting.value = false
FailAlert(e.message)
}
}
</script>
@@ -0,0 +1 @@
export {default as AddPaymentMethodButton } from './AddPaymentButton.vue'
@@ -1,2 +1 @@
export * from './api'
export * from './model'
@@ -0,0 +1,29 @@
import { useSessionStore } from 'src/entities/Session'
import { useWalletStore } from 'src/entities/Wallet'
import { sendPOST } from 'src/shared/api';
import { COOPNAME } from 'src/shared/config'
export interface IDeletePaymentMethod {
username: string;
method_id: number;
}
export function useDeletePaymentMethod() {
const store = useWalletStore()
const session = useSessionStore()
async function deletePaymentMethod(params: IDeletePaymentMethod) {
const {username, method_id} = params
await sendPOST(`/v1/payments/methods/${username}/delete`, {method_id})
await store.update({
coopname: COOPNAME,
username: session.username
})
}
return {
deletePaymentMethod
}
}
@@ -0,0 +1,67 @@
<template lang="pug">
div
q-btn(@click="showDialog=true" :size="size" flat) удалить
q-icon(name="close")
q-dialog(v-model="showDialog" @hide="clear")
ModalBase(:title='"Удалить метод платежа"' )
Form(:handler-submit="handlerSubmit" :is-submitting="isSubmitting" :button-cancel-txt="'Отменить'" :button-submit-txt="'Продолжить'" @cancel="clear").q-pa-sm
p Вы уверены, что хотите удалить метод платежа?
</template>
<script lang="ts" setup>
import { computed, ref } from 'vue';
import { useDeletePaymentMethod } from '../model';
import { FailAlert, SuccessAlert } from 'src/shared/api';
import { ModalBase } from 'src/shared/ui/ModalBase';
import { Form } from 'src/shared/ui/Form';
const props = defineProps({
username: {
type: String,
required: true,
},
method_id: {
type: Number,
required: true,
},
size: {
type: String,
required: false,
default: 'md'
}
})
const username = computed(() => props.username)
const showDialog = ref(false)
const isSubmitting = ref(false)
const clear = (): void => {
showDialog.value = false
}
const { deletePaymentMethod } = useDeletePaymentMethod()
const handlerSubmit = async (): Promise<void> => {
isSubmitting.value = true
try {
await deletePaymentMethod({
username: username.value,
method_id: props.method_id
})
showDialog.value = false
isSubmitting.value = false
SuccessAlert('Метод платежа успешно удалён')
} catch (e: any) {
showDialog.value = false
isSubmitting.value = false
FailAlert(e.message)
}
}
</script>
@@ -0,0 +1 @@
export {default as DeletePaymentButton} from './DeletePaymentMethodButton.vue'
@@ -1,6 +1,6 @@
<template lang="pug">
div.DepositPreparator
q-btn(color="primary" @click="showDialog=true") Совершить взнос
q-btn(@click="showDialog=true" outline) Совершить взнос
q-dialog(v-model="showDialog" @hide="clear")
ModalBase(v-if="!paymentOrder" :title='"Введите сумму"' )
Form(:handler-submit="handlerSubmit" :is-submitting="isSubmitting" :button-cancel-txt="'Отменить'" :button-submit-txt="'Продолжить'" @cancel="clear").q-pa-sm
@@ -1,6 +1,6 @@
<template lang="pug">
div
q-btn(color="primary" @click="showDialog = true") получить возврат
q-btn(@click="showDialog = true" outline) получить возврат
q-dialog(v-model="showDialog" @hide="clear")
ModalBase( :title='"Введите сумму"' )
@@ -1,7 +1,6 @@
<template lang="pug">
div.row.justify-center
div.col-md-6.col-xs-12.q-mt-lg
p.text-h6.text-center Контакты
div.col-md-6.col-xs-12
CooperativeContacts.full-width
@@ -0,0 +1 @@
export * from './ui'
@@ -0,0 +1,15 @@
<template lang="pug">
PersonalCard(:username="username")
</template>
<script lang="ts" setup>
import { PersonalCard } from 'src/widgets/Wallet/PersonalCard/ui'
import { computed } from 'vue';
import { useCurrentUserStore } from 'src/entities/User';
const currentUser = useCurrentUserStore()
const username = computed(() => currentUser.username)
</script>
@@ -0,0 +1 @@
export {default as UserIdentityPage} from './IdentityPage.vue'
@@ -0,0 +1 @@
export * from './ui'
@@ -0,0 +1,15 @@
<template lang="pug">
PaymentMethodsCard(:username="username")
</template>
<script lang="ts" setup>
import { PaymentMethodsCard } from 'src/widgets/Wallet/PaymentMethods';
import { computed } from 'vue';
import { useCurrentUserStore } from 'src/entities/User';
const currentUser = useCurrentUserStore()
const username = computed(() => currentUser.username)
</script>
@@ -0,0 +1 @@
export {default as UserPaymentMethodsPage} from './PaymentMethods.vue'
@@ -0,0 +1 @@
export * from './ui'
@@ -0,0 +1,14 @@
<template lang="pug">
WalletCard(:username="username")
</template>
<script lang="ts" setup>
import { WalletCard } from 'src/widgets/Wallet/WalletCard'
import { computed } from 'vue';
import { useCurrentUserStore } from 'src/entities/User';
const currentUser = useCurrentUserStore()
const username = computed(() => currentUser.username)
</script>
@@ -0,0 +1 @@
export {default as UserWalletPage} from './WalletPage.vue'
@@ -1,26 +1,41 @@
<template lang="pug">
div
q-tabs( v-model="tab" dense switch-indicator inline-label outside-arrows mobile-arrows align="justify" active-bg-color="teal" active-color="white" indicator-color="secondary" style="border-bottom: 1px solid teal;")
q-tabs( v-model="tab" dense switch-indicator inline-label outside-arrows mobile-arrows align="justify" active-bg-color="teal" active-color="white" indicator-color="secondary" style="border-bottom: 1px solid teal;")
q-tab(name="Удостоверение" label="Удостоверение")
q-tab(name="Кошелёк" label="Кошелёк")
q-tab(name="Реквизиты" label="Реквизиты")
q-tab-panels(
swipeable
v-model="tab"
animated
transition-prev="fade"
transition-next="fade"
style="background: none !important;"
style="background: none !important; min-height: 85vh;"
)
q-tab-panel(name="Удостоверение")
PersonalCard(:username="username")
q-tab-panel(name="Кошелёк")
CompositeWalletCard
WalletCard(:username="username")
q-tab-panel(name="Реквизиты")
PaymentMethodsCard(:username="username")
</template>
<script lang="ts" setup>
import { CompositeWalletCard } from 'src/widgets/Wallet';
// import { CompositeWalletCard } from 'src/widgets/Wallet';
import { PaymentMethodsCard } from 'src/widgets/Wallet/PaymentMethods';
import { PersonalCard } from 'src/widgets/Wallet/PersonalCard/ui'
import { WalletCard } from 'src/widgets/Wallet/WalletCard'
import { ref } from 'vue';
import { computed, ref } from 'vue';
import { useCurrentUserStore } from 'src/entities/User';
const tab = ref('Кошелёк')
const currentUser = useCurrentUserStore()
const username = computed(() => currentUser.username)
const tab = ref('Удостоверение')
</script>
@@ -6,7 +6,6 @@ q-layout(view="hHh LpR fFf")
q-btn(stretch flat class="btn-title" :dense="isMobile" @click="goToIndex").q-ml-sm
//- img(:src="HeaderLogo" alt="" style="height: 50px;").q-pa-sm
//- q-icon(name="far fa-circle").q-pa-sm
p {{ COOP_SHORT_NAME }}
q-btn(stretch flat @click="toogleDark")
@@ -20,27 +19,23 @@ q-layout(view="hHh LpR fFf")
p.q-pr-sm вход
i.fa-solid.fa-right-to-bracket
q-drawer(v-if="loggedIn" v-model="leftDrawerOpen" :mini="isMini" show-if-above side="left" persistent :mini-width="71" :width="71" class="drawer-left")
Menu(:mini="isMini")
//скрывающееся мобильное меню
q-drawer(v-if="loggedIn && isMobile" v-model="rightDrawerOpen" behavior="mobile" side="right" persistent :mini-width="71" :width="71" class="drawer-right")
Menu(:mini="false")
q-header(v-if="!isMobile && loggedIn" style="border-bottom: 1px solid #00800038 !important; " :style="{ 'background': $q.dark.isActive ? 'black' : 'white' }" :class="headerClass").header
Menu(style="border-bottom: 1px solid #00800038 !important; ")
SecondLevelMenu
//футер контактов
q-footer(v-if="!loggedIn" :class="headerClass")
ContactsFooter(:text="footerText")
q-footer(v-if="loggedIn && isMobile" style="border-top: 1px solid #00800038 !important; " :class="headerClass")
SecondLevelMenu
Menu(style="border-top: 1px solid #00800038 !important; " )
//футер мобильного меню
q-footer(v-if="loggedIn && isMobile" :class="footerClass" style="height: 55px; border-top: 1px solid #00800038 !important; " :style="{ 'background': $q.dark.isActive ? 'black' : 'white' }")
mobileMenu(@toogle-more="toggleRightDrawer")
//контейнер всех страниц
//контейнер
q-page-container
q-page(class="page" )
router-view(v-slot="{ Component }")
component(:is="Component" )
q-page
router-view
</template>
@@ -51,23 +46,28 @@ import { useRouter, useRoute } from 'vue-router'
import { useQuasar, Cookies, LocalStorage } from 'quasar'
import { useWindowSize } from 'vue-window-size'
import config from 'src/app/config'
const router = useRouter()
const route = useRoute()
// import HeaderLogo from '~/assets/logo-white.png?url'
import Menu from 'src/components/menu/drawerMenu.vue'
import mobileMenu from 'src/components/menu/footerMobileMenu.vue'
import { COOPNAME, COOP_SHORT_NAME } from 'src/shared/config'
import { useCurrentUserStore } from 'src/entities/User'
import { useSessionStore } from 'src/entities/Session'
const session = useSessionStore()
import { ContactsFooter } from 'src/shared/ui/Footer'
import { SecondLevelMenu } from 'src/entities/Desktop'
const $q = useQuasar()
const isDark = computed(() => $q.dark.isActive)
const headerClass = computed(() => (isDark.value ? 'text-white bg-dark' : 'text-black bg-light'))
const footerClass = computed(() => (isDark.value ? 'text-white' : 'text-black'))
import { useCooperativeStore } from 'src/entities/Cooperative';
const cooperativeStore = useCooperativeStore()
cooperativeStore.loadContacts()
@@ -82,29 +82,14 @@ defineExpose({
$q,
})
const router = useRouter()
const route = useRoute()
const { width } = useWindowSize()
const leftDrawerOpen = ref<boolean>(false)
const rightDrawerOpen = ref<boolean>(false)
// const toggleLeftDrawer = () => {
// leftDrawerOpen.value = !leftDrawerOpen.value
// }
const toggleRightDrawer = () => {
rightDrawerOpen.value = !rightDrawerOpen.value
}
const showRegisterButton = computed(() => {
if (!loggedIn.value) {
if (config.registrator.showRegisterButton) return true
else return false
// if (isIndexRoute.value) return config.registrator.showInIndexHeader
// else return config.registrator.showInOtherHeader
} else return false
})
@@ -122,10 +107,6 @@ if (isMobile.value == true) {
leftDrawerOpen.value = true
}
const isMini = computed(() => {
return !rightDrawerOpen.value && !rightDrawerOpen.value && !isMobile.value
})
const loggedIn = computed(() => {
return useCurrentUserStore().isRegistrationComplete && session.isAuth
})
@@ -136,6 +117,7 @@ watch(isMobile, (newValue) => {
})
watch(route, () => {
console.log('route', route)
checkAuth()
if (isMobile.value)
leftDrawerOpen.value = false
@@ -24,7 +24,7 @@ const cancel = (): void => {
q-form(@submit.prevent="handlerSubmit")
template(#default)
slot
div.flex.q-mt-sm
div.flex.q-mt-md
q-btn(v-if="showCancel" flat @click="cancel") {{ buttonCancelTxt }}
q-btn(:class="{'full-width': !showCancel}" type="submit" :loading="isSubmitting" color="primary") {{ buttonSubmitTxt }}
@@ -4,8 +4,8 @@ q-card.bordered.q-pa-md.signup(flat)
form(@submit.prevent="submit").full-width
q-input(
v-model="username"
label="Введите имя аккаунта"
v-model="email"
label="Введите электронную почту"
color="primary"
hint=""
outlined
@@ -37,7 +37,7 @@ q-card.bordered.q-pa-md.signup(flat)
:loading="loading"
:disable="!privateKey")
</template>
<script lang="ts" setup>
@@ -45,22 +45,25 @@ import { useCurrentUserStore } from 'src/entities/User';
import { useLoginUser } from 'src/features/User/LoginUser';
import { FailAlert } from 'src/shared/api';
import { COOPNAME } from 'src/shared/config';
import { useGlobalStore } from 'src/shared/store';
import { ref } from 'vue';
import { useRouter } from 'vue-router';
const router = useRouter()
const username = ref('')
const email = ref('')
const privateKey = ref('')
const loading = ref(false)
const currentUser = useCurrentUserStore()
const globalStore = useGlobalStore()
const submit = async () => {
loading.value = true
try {
const { login } = useLoginUser()
await login(username.value, privateKey.value)
await currentUser.loadProfile(username.value, COOPNAME)
await login(email.value, privateKey.value)
await currentUser.loadProfile(globalStore.username, COOPNAME)
if (!currentUser.isRegistrationComplete) {
router.push({ name: 'signup' })
@@ -1,15 +1,11 @@
<template lang='pug'>
div
q-step(:name='3', title='Получите приватный ключ для цифровой подписи', :done='step > 3')
q-step(:name='3', title='Получите приватный ключ и надежно сохраните его для цифровой подписи', :done='step > 3')
div
p.full-width Надёжно сохраните идентификатор аккаунта и приватный ключ.
p.full-width Приватный ключ используется для входа в систему и подписи документов. Мы рекомендуем сохранить его в менеджере паролей, таком как
a(href="https://bitwarden.com").q-ml-xs Bitwarden
| .
q-input.q-mt-lg(
v-if='account.username',
v-model='account.username',
label='Идентификатор аккаунта',
:readonly='true'
)
q-input.q-mt-lg(
v-if='account.private_key',
@@ -52,7 +48,7 @@ const step = computed(() => store.step)
const userData = computed(() => store.userData)
const copyMnemonic = () => {
const toCopy = `Имя пользователя: ${account.value.username} \nПриватный ключ: ${account.value.private_key}`
const toCopy = `Приватный ключ: ${account.value.private_key}`
copyToClipboard(toCopy)
.then(() => {
@@ -19,7 +19,7 @@ div
WaitingRegistration(v-model:data='store.userData', v-model:step='store.step')
Welcome(v-model:data='store.userData', v-model:step='store.step')
q-btn(@click="logout" size="sm" flat)
q-btn(@click="out" size="sm" flat)
q-icon(name="logout")
span.q-ml-sm начать с начала
</template>
@@ -54,7 +54,7 @@ onMounted(() => {
})
const logout = async () => {
const out = async () => {
const { logout } = await useLogoutUser()
await logout()
clearLocalStorage()
@@ -85,7 +85,6 @@ onBeforeUnmount(() => {
watch(() => currentUser.participantAccount, (newValue) => {
if (newValue) {
console.log('on watch: ', currentUser.participantAccount)
store.step = 8
clearLocalStorage()
}
@@ -18,15 +18,10 @@ import { useCurrentUserStore } from 'src/entities/User';
import { COOPNAME } from 'src/shared/config';
import { Loader } from 'src/shared/ui/Loader';
const props = defineProps({
step: {
type: Number,
required: true
}
})
const currentStep = 7
const step = computed(() => props.step)
const step = computed(() => store.step)
const interval = ref()
watch(step, (newValue) => {
@@ -52,9 +47,7 @@ onBeforeUnmount(() => {
})
const update = () => {
console.log('pn start upate')
if (store.account.username && !participantAccount.value) {
console.log('on update')
currentUser.loadProfile(store.account.username, COOPNAME)
} else {
clearInterval(interval.value)
@@ -62,8 +55,7 @@ const update = () => {
}
watch(() => participantAccount, (newValue) => {
if (newValue){
console.log('on wating move')
if (newValue) {
store.step++
}
@@ -0,0 +1,7 @@
<template lang="pug">
div
</template>
<script lang="ts" setup>
</script>
@@ -0,0 +1 @@
export {default as Commutator} from './Commutator.vue'
@@ -1,6 +1,7 @@
<template lang="pug">
div
q-card(v-if="contacts && contacts.details" flat bordered).q-pa-sm
//- p.text-h6.text-center Контакты
q-input(type="textarea" autogrow readonly label="Наименование организации" v-model="contacts.full_name")
q-input(type="textarea" autogrow readonly label="ИНН" v-model="contacts.details.inn")
q-input(type="textarea" autogrow readonly label="ОГРН" v-model="contacts.details.ogrn")
@@ -12,12 +13,12 @@ div
</template>
<script lang="ts" setup>
import { useCooperativeStore } from 'src/entities/Cooperative';
import { computed } from 'vue';
import { useCooperativeStore } from 'src/entities/Cooperative';
import { computed } from 'vue';
const cooperative = useCooperativeStore()
cooperative.loadContacts()
const cooperative = useCooperativeStore()
cooperative.loadContacts()
const contacts = computed(() => cooperative.contacts)
const chairman = computed(() => `${contacts.value?.chairman?.last_name} ${contacts.value?.chairman?.first_name} ${contacts.value?.chairman?.middle_name}`)
const contacts = computed(() => cooperative.contacts)
const chairman = computed(() => `${contacts.value?.chairman?.last_name} ${contacts.value?.chairman?.first_name} ${contacts.value?.chairman?.middle_name}`)
</script>
@@ -10,6 +10,7 @@ import { ref, watch } from 'vue';
const coop = useCooperativeStore()
coop.loadPublicCooperativeData(COOPNAME)
coop.loadPrivateCooperativeData()
const localCoop = ref({
initial: 0,
@@ -19,7 +20,7 @@ const localCoop = ref({
})
const save = async () => {
const {updateCoop} = useUpdateCoop()
const { updateCoop } = useUpdateCoop()
const session = useSessionStore()
if (coop.publicCooperativeData)
try {
@@ -36,7 +37,7 @@ const save = async () => {
await coop.loadPublicCooperativeData(COOPNAME)
SuccessAlert('Размеры взносов успешно обновлены')
} catch(e: any){
} catch (e: any) {
FailAlert(`${e.message}`)
}
else {
@@ -75,5 +76,6 @@ div.q-pa-md
q-input(filled v-model="localCoop.org_minimum" label="Минимальный паевый взнос")
template(#append)
p.q-pa-sm {{ CURRENCY }}
q-btn(@click="save") Сохранить
q-btn(@click="save" outline) Сохранить
</template>
@@ -24,6 +24,8 @@ import { computed } from 'vue';
const cooperative = useCooperativeStore()
cooperative.loadContacts()
cooperative.loadPrivateCooperativeData()
const details = computed(() => cooperative.privateCooperativeData)
const chairman = computed(() => `${details.value?.chairman?.last_name} ${details.value?.chairman?.first_name} ${details.value?.chairman?.middle_name}`)
@@ -16,7 +16,7 @@ div
).full-height
template(#top)
q-btn(icon="add" @click="showAdd = true") добавить участника
q-btn(icon="add" @click="showAdd = true" outline) добавить участника
template(#header="props")
@@ -124,7 +124,7 @@ const addMember = async () => {
try {
await updateBoard(members_for_send)
} catch(e:any){
} catch (e: any) {
}
@@ -147,7 +147,7 @@ const removeMember = async (username: string) => {
try {
await updateBoard(members_for_send)
} catch(e:any){
} catch (e: any) {
}
showLoading.value = false
@@ -1 +1 @@
export { default as CompositeWalletCard } from './WalletPage.vue'
export { default as CompositeWalletCard } from './CompositeWalletCard.vue'
@@ -0,0 +1 @@
export * from './ui'
@@ -0,0 +1,110 @@
<template lang="pug">
q-card(flat bordered).q-pa-md
AddPaymentMethodButton(:username="username")
q-list.full-width.q-mt-lg
q-item(v-for="method in wallet.methods" :key="method.method_id").q-mt-md.full-width
q-card(flat).full-width
div(v-if="method.method_type ==='sbp' && isSBPData(method.data)")
div.flex.justify-between
q-badge
span {{ method.method_id }}
span(v-if="method.method_type ==='sbp'").q-pl-xs СБП
DeletePaymentButton(:size="'xs'" :username="username" :method_id="method.method_id")
q-input(v-model="method.data.phone" label="Номер телефона" filled readonly)
div(v-if="method.method_type ==='bank_transfer' && isBankTransferData(method.data)")
div.flex.justify-between
q-badge
span {{ method.method_id }}
span(v-if="method.method_type ==='bank_transfer'").q-pl-xs Банковский перевод
DeletePaymentButton(:size="'xs'" :username="username" :method_id="method.method_id")
q-select(
v-model="method.data.currency"
readonly
label="Валюта счёта"
filled
:options="[{ label: 'RUB', value: 'RUB' }]"
emit-value
map-options
)
q-input(
v-model="method.data.bank_name"
readonly
filled
label="Наименование банка"
autocomplete="off"
)
q-input(
v-model="method.data.details.corr"
filled
readonly
mask="####################"
label="Корреспондентский счет"
autocomplete="off"
)
q-input(
v-model="method.data.details.bik"
readonly
filled
mask="#########"
label="БИК"
autocomplete="off"
)
q-input(
v-model="method.data.details.kpp"
readonly
filled
mask="#########"
label="КПП"
autocomplete="off"
)
q-input(
v-model="method.data.account_number"
filled
readonly
mask="####################"
label="Номер счета"
autocomplete="off"
)
</template>
<script lang="ts" setup>
import { useWalletStore } from 'src/entities/Wallet';
import { COOPNAME } from 'src/shared/config';
import { computed } from 'vue';
import { AddPaymentMethodButton } from 'src/features/Wallet/AddPaymentMethod';
import type { IBankTransferData, ISBPData } from 'src/features/Wallet/AddPaymentMethod/model';
import { DeletePaymentButton } from 'src/features/Wallet/DeletePaymentMethod/ui';
const props = defineProps({
username: {
type: String,
required: true,
},
})
const wallet = useWalletStore()
const username = computed(() => props.username)
wallet.update({ coopname: COOPNAME, username: username.value })
function isSBPData(data: ISBPData | IBankTransferData): data is ISBPData {
return (data as ISBPData).phone !== undefined;
}
function isBankTransferData(data: ISBPData | IBankTransferData): data is IBankTransferData {
return (data as IBankTransferData).account_number !== undefined;
}
</script>
@@ -0,0 +1 @@
export {default as PaymentMethodsCard} from './PaymentMethods.vue'
@@ -2,98 +2,87 @@
q-card(v-if="currentUser?.username" flat bordered).q-pa-md.digital-certificate
div.row
div.col-md-4.col-xs-12
p.text-bold.full-width.text-sm.text-center УДОСТОВЕРЕНИЕ ПАЙЩИКА
//- p.text-bold.full-width.text-sm.text-center УДОСТОВЕРЕНИЕ ПАЙЩИКА
div(style="flex-grow: 1; display: flex; justify-content: center;")
AutoAvatar(style="width: 125px;" :username="currentUser.username").q-pa-sm.q-pt-lg
div.col-md-8.col-xs-12
q-list( dense )
q-item
q-item-section
q-item-label(caption) Тип
q-item-section(side)
q-badge(v-if="userType === 'individual'") физическое лицо
q-badge(v-if="userType === 'entrepreneur'") индивидуальный предприниматель
q-badge(v-if="userType === 'organization'") юридическое лицо
div().text-center
q-badge(v-if="userType === 'individual'").text-center физическое лицо
q-badge(v-if="userType === 'entrepreneur'").text-center индивидуальный предприниматель
q-badge(v-if="userType === 'organization'").text-center юридическое лицо
q-item
q-item-section
q-item-label(caption) Идентификатор
q-item-section(side)
q-item-label(lines=2) {{ currentUser.username }}
q-input(standout dense label="Идентификатор" v-model="currentUser.username" readonly)
q-item
q-item-section
q-item-label(v-if="userType !== 'organization'" caption) ФИО
q-item-label(v-else caption) Наименование
q-item-section(side)
template(v-if="userType === 'individual'")
q-item-label(lines=2 caption) {{ individualProfile?.last_name }} {{ individualProfile?.first_name }} {{ individualProfile?.middle_name }}
template(v-else-if="userType === 'entrepreneur'")
q-item-label(lines=2 caption) {{ entrepreneurProfile?.last_name }} {{ entrepreneurProfile?.first_name }} {{ entrepreneurProfile?.middle_name }}
template(v-else)
q-item-label(caption) {{ organizationProfile?.short_name }}
q-input(standout dense label="Пайщик" readonly v-model="displayName")
q-item(v-if="userType === 'individual'")
q-item-section
q-item-label(caption) Дата рождения
q-item-section(side) {{ individualProfile?.birthdate }}
q-input(v-if="userType === 'individual' && individualProfile" standout dense label="Дата рождения" readonly v-model="individualProfile.birthdate")
q-item(v-if="userType === 'organization'")
q-item-section
q-item-label(caption) ИНН / ОГРН
q-item-section(side) {{ organizationProfile?.details.inn }} / {{ organizationProfile?.details.ogrn }}
q-input(v-if="userType === 'organization' && organizationProfile" standout dense label="ИНН / ОГРН" readonly v-model="inn_ogrn")
q-item
q-item-section
q-item-label(caption) Адрес регистрации
q-item-section(side)
q-item-label(lines=2) {{ userProfile?.full_address }}
q-input(v-if="userProfile" standout dense label="Телефон" readonly v-model="userProfile.phone")
q-item
q-item-section
q-item-label(caption) Телефон
q-item-section(side) {{ userProfile?.phone }}
q-input(v-if="userProfile" standout dense label="Почта" readonly v-model="userProfile.email")
q-item
q-item-section
q-item-label(caption) Почта
q-item-section(side) {{ userProfile?.email }}
</template>
<script lang="ts" setup>
import type { IEntrepreneurData, IIndividualData, IOrganizationData } from 'src/entities/User'
import { AutoAvatar } from '.';
import { useCurrentUserStore } from 'src/entities/User'
import { computed } from 'vue';
const currentUser = useCurrentUserStore()
import type { IEntrepreneurData, IIndividualData, IOrganizationData } from 'src/entities/User'
import { AutoAvatar } from '.';
import { useCurrentUserStore } from 'src/entities/User'
import { computed } from 'vue';
const currentUser = useCurrentUserStore()
const userType = computed(() => currentUser.userAccount?.type)
const userType = computed(() => currentUser.userAccount?.type)
const individualProfile = computed(() => {
if (userType.value === 'individual') {
return currentUser.userAccount?.private_data as IIndividualData
}
return null
})
const individualProfile = computed(() => {
if (userType.value === 'individual') {
return currentUser.userAccount?.private_data as IIndividualData
}
return null
})
const entrepreneurProfile = computed(() => {
if (userType.value === 'entrepreneur') {
return currentUser.userAccount?.private_data as IEntrepreneurData
}
return null
})
const entrepreneurProfile = computed(() => {
if (userType.value === 'entrepreneur') {
return currentUser.userAccount?.private_data as IEntrepreneurData
}
return null
})
const organizationProfile = computed(() => {
if (userType.value === 'organization') {
return currentUser.userAccount?.private_data as IOrganizationData
}
return null
})
const organizationProfile = computed(() => {
if (userType.value === 'organization') {
return currentUser.userAccount?.private_data as IOrganizationData
}
return null
})
const userProfile = computed(() => {
if (userType.value === 'individual' || userType.value === 'entrepreneur') {
return individualProfile?.value || entrepreneurProfile?.value
}
return organizationProfile?.value
})
</script>
const userProfile = computed(() => {
if (userType.value === 'individual' || userType.value === 'entrepreneur') {
return individualProfile?.value || entrepreneurProfile?.value
}
return organizationProfile?.value
})
const displayName = computed(() => {
if (userType.value === 'individual') {
return `${individualProfile.value?.last_name} ${individualProfile.value?.first_name} ${individualProfile.value?.middle_name}`
} else if (userType.value === 'entrepreneur') {
return `${entrepreneurProfile.value?.last_name} ${entrepreneurProfile.value?.first_name} ${entrepreneurProfile.value?.middle_name}`
} else {
return organizationProfile.value?.short_name
}
})
const inn_ogrn = computed(() => {
if (organizationProfile.value)
return `${organizationProfile.value.details.inn} / ${organizationProfile.value.details.ogrn}`
else return ''
})
</script>
<style>
.digital-certificate {
padding: 50px !important;
}
</style>
@@ -1,12 +1,16 @@
<template lang="pug">
q-card(flat bordered).q-pa-md
WalletBalance
div.flex.justify-center.q-gutter-sm.q-pa-md
DepositButton
WithdrawButton
div.row
div.col-md-6.col-xs-12.q-gutter-sm
div.flex.q-pa-sm
DepositButton.q-ma-sm
WithdrawButton.q-ma-sm
div.col-md-6.col-xs-12.q-gutter-sm
WalletBalance
WalletProgramsList
</template>
<script lang="ts" setup>
import { WalletBalance } from 'src/entities/Wallet/ui'
import { useWalletStore } from 'src/entities/Wallet/model/stores'
+10061 -12697
View File
File diff suppressed because it is too large Load Diff