@coopenomics/desktop 2025.4.29 → 2025.5.4
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/alias-resolver.js +35 -0
- package/package.json +13 -7
- package/quasar.config.cjs +24 -4
- package/src/app/providers/router.ts +4 -3
- package/src/boot/sentry.ts +14 -13
- package/src/entities/Session/model/store.ts +3 -3
- package/src/env.d.ts +2 -0
- package/src/features/Request/CreateParentOffer/ui/CreateParentOfferForm/CreateParentOfferForm.vue +2 -1
- package/src/features/Request/CreateParentOffer/ui/ImageUploaderWithPreview/ImageUploaderWithPreview.vue +2 -1
- package/src/features/Union/AddCooperative/model/index.ts +5 -4
- package/src/features/Union/AddCooperative/ui/AddCooperativeForm.vue +2 -4
- package/src/features/User/LoginUser/model/index.ts +0 -4
- package/src/features/User/Logout/model/index.ts +0 -1
- package/src/features/Wallet/DepositToWallet/ui/DepositButton/DepositButton.vue +4 -2
- package/src/features/Wallet/WithdrawFromWallet/ui/withdrawButton.vue +4 -2
- package/src/pages/Cooperative/ChangeRegisterPayments/ui/ChangeRegisterPayments.vue +7 -5
- package/src/pages/ExtensionStore/ExtensionPage/ExtensionPage.vue +22 -8
- package/src/pages/Registrator/SignUp/EmailInput.vue +3 -1
- package/src/pages/Registrator/SignUp/Welcome.vue +3 -1
- package/src/shared/api/axios.ts +5 -4
- package/src/shared/api/client.ts +4 -3
- package/src/shared/api/eosio.ts +2 -1
- package/src/shared/api/indexDB.ts +3 -0
- package/src/shared/api/utils.ts +3 -1
- package/src/shared/config/Environment.ts +68 -0
- package/src/shared/config/index.ts +2 -0
- package/src/shared/lib/proxy/dicebear-collection.cjs +21 -0
- package/src/shared/lib/proxy/dicebear-core.cjs +20 -0
- package/src/shared/lib/proxy/email-regex.cjs +19 -0
- package/src/shared/ui/ClientOnly/ClientOnly.vue +15 -0
- package/src/shared/ui/ClientOnly/index.ts +1 -0
- package/src/shared/ui/ZodForm/ZodForm.vue +2 -2
- package/src/widgets/Header/CommonHeader/MainHeader.vue +2 -1
- package/src/widgets/Marketplace/SupplyOrderRequestCard/ui/Base/Base.vue +2 -1
- package/src-ssr/middlewares/injectEnv.ts +49 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
// Перенаправление импортов для ESM модулей в SSR
|
2
|
+
const path = require('path');
|
3
|
+
const fs = require('fs');
|
4
|
+
|
5
|
+
// Список модулей, которые нужно перенаправить
|
6
|
+
const modulesToResolve = {
|
7
|
+
'@dicebear/core': path.resolve(__dirname, 'src/shared/lib/proxy/dicebear-core.cjs'),
|
8
|
+
'@dicebear/collection': path.resolve(__dirname, 'src/shared/lib/proxy/dicebear-collection.cjs'),
|
9
|
+
'email-regex': path.resolve(__dirname, 'src/shared/lib/proxy/email-regex.cjs')
|
10
|
+
};
|
11
|
+
|
12
|
+
// Проверяем, существуют ли прокси-файлы
|
13
|
+
Object.entries(modulesToResolve).forEach(([moduleName, proxyPath]) => {
|
14
|
+
if (!fs.existsSync(proxyPath)) {
|
15
|
+
console.error(`Прокси-файл для ${moduleName} не найден по пути ${proxyPath}`);
|
16
|
+
process.exit(1);
|
17
|
+
}
|
18
|
+
});
|
19
|
+
|
20
|
+
// Регистрируем перехватчик для require
|
21
|
+
require.extensions['.js'] = function(module, filename) {
|
22
|
+
const originalCompile = module._compile;
|
23
|
+
|
24
|
+
module._compile = function(content, filename) {
|
25
|
+
// Заменяем импорты проблемных модулей на наши прокси
|
26
|
+
Object.keys(modulesToResolve).forEach(moduleName => {
|
27
|
+
const regex = new RegExp(`require\\(['"]${moduleName}['"]\\)`, 'g');
|
28
|
+
content = content.replace(regex, `require('${modulesToResolve[moduleName]}')`);
|
29
|
+
});
|
30
|
+
|
31
|
+
return originalCompile.call(this, content, filename);
|
32
|
+
};
|
33
|
+
|
34
|
+
module._compile(fs.readFileSync(filename, 'utf8'), filename);
|
35
|
+
};
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@coopenomics/desktop",
|
3
|
-
"version": "2025.4
|
3
|
+
"version": "2025.5.4",
|
4
4
|
"description": "A Desktop Project",
|
5
5
|
"productName": "Desktop App",
|
6
6
|
"author": "Alex Ant <dacom.dark.sun@gmail.com>",
|
@@ -16,13 +16,16 @@
|
|
16
16
|
"test": "echo \"No test specified\" && exit 0",
|
17
17
|
"dev": "concurrently -n 'DESKTOP' -c 'bgRed.white' \"quasar dev\"",
|
18
18
|
"devnet": "quasar dev",
|
19
|
+
"ssr": "quasar dev --mode ssr",
|
19
20
|
"build:lib": "vite build",
|
20
|
-
"build": "quasar build",
|
21
|
-
"
|
21
|
+
"build:spa": "quasar build",
|
22
|
+
"build": "quasar build --mode ssr",
|
23
|
+
"prepublishOnly": "npm run build:lib",
|
24
|
+
"start": "node -r ./alias-resolver.js dist/ssr/index.js"
|
22
25
|
},
|
23
26
|
"dependencies": {
|
24
|
-
"@coopenomics/controller": "2025.4
|
25
|
-
"@coopenomics/sdk": "2025.
|
27
|
+
"@coopenomics/controller": "2025.5.4",
|
28
|
+
"@coopenomics/sdk": "2025.5.3",
|
26
29
|
"@dicebear/collection": "^9.0.1",
|
27
30
|
"@dicebear/core": "^9.0.1",
|
28
31
|
"@fortawesome/fontawesome-svg-core": "^6.5.2",
|
@@ -46,13 +49,15 @@
|
|
46
49
|
"@wharfkit/wallet-plugin-privatekey": "^1.1.0",
|
47
50
|
"axios": "^1.2.1",
|
48
51
|
"compression": "^1.7.4",
|
49
|
-
"cooptypes": "2025.
|
52
|
+
"cooptypes": "2025.5.3",
|
50
53
|
"dompurify": "^3.1.7",
|
51
54
|
"dotenv": "^16.4.5",
|
52
55
|
"email-regex": "^5.0.0",
|
53
56
|
"eosjs": "^22.1.0",
|
54
57
|
"express": "^4.21.0",
|
58
|
+
"graphql-ws": "^5.16.0",
|
55
59
|
"idb": "^8.0.0",
|
60
|
+
"isomorphic-ws": "^5.0.0",
|
56
61
|
"lodash": "^4.17.21",
|
57
62
|
"moment-with-locales-es6": "^1.0.1",
|
58
63
|
"pinia": "^2.0.11",
|
@@ -60,6 +65,7 @@
|
|
60
65
|
"pug": "^3.0.3",
|
61
66
|
"qrcode": "^1.5.4",
|
62
67
|
"quasar": "^2.16.0",
|
68
|
+
"serialize-javascript": "^6.0.2",
|
63
69
|
"swiper": "^11.1.7",
|
64
70
|
"vite": "2.9.16",
|
65
71
|
"vue": "^3.4.18",
|
@@ -95,5 +101,5 @@
|
|
95
101
|
"npm": ">= 6.13.4",
|
96
102
|
"yarn": ">= 1.21.1"
|
97
103
|
},
|
98
|
-
"gitHead": "
|
104
|
+
"gitHead": "8d7c91933210969a574f111dd24e8270142e6717"
|
99
105
|
}
|
package/quasar.config.cjs
CHANGED
@@ -7,11 +7,22 @@
|
|
7
7
|
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js
|
8
8
|
|
9
9
|
// const config = require('./src/shared/config/Env.ts');
|
10
|
-
|
10
|
+
|
11
11
|
const { configure } = require('quasar/wrappers');
|
12
12
|
const path = require('path');
|
13
13
|
|
14
|
-
|
14
|
+
|
15
|
+
module.exports = configure(function (ctx) {
|
16
|
+
|
17
|
+
const isSSR = ctx.mode.ssr;
|
18
|
+
const isDev = ctx.dev;
|
19
|
+
|
20
|
+
// Загружаем переменные окружения всегда в режиме разработки
|
21
|
+
// или только для клиентской части в продакшн
|
22
|
+
const env = (isDev || !isSSR) ? require('dotenv').config().parsed : {
|
23
|
+
CLIENT: process.env.CLIENT,
|
24
|
+
SERVER: process.env.SERVER,
|
25
|
+
};
|
15
26
|
|
16
27
|
return {
|
17
28
|
htmlVariables: {
|
@@ -72,7 +83,8 @@ module.exports = configure(function (/* ctx */) {
|
|
72
83
|
|
73
84
|
// publicPath: '/',
|
74
85
|
// analyze: true,
|
75
|
-
env: require('dotenv').config().parsed,
|
86
|
+
// env: require('dotenv').config().parsed,
|
87
|
+
env,
|
76
88
|
// rawDefine: {}
|
77
89
|
// ignorePublicFolder: true,
|
78
90
|
// minify: false,
|
@@ -111,6 +123,10 @@ module.exports = configure(function (/* ctx */) {
|
|
111
123
|
{ server: false },
|
112
124
|
],
|
113
125
|
],
|
126
|
+
|
127
|
+
optimizeDeps: {
|
128
|
+
include: ['@dicebear/core', '@dicebear/collection']
|
129
|
+
},
|
114
130
|
},
|
115
131
|
|
116
132
|
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#devServer
|
@@ -120,7 +136,7 @@ module.exports = configure(function (/* ctx */) {
|
|
120
136
|
open: false, // opens browser window automatically
|
121
137
|
port: 3005,
|
122
138
|
hmr:{
|
123
|
-
clientPort: 3005,
|
139
|
+
// clientPort: 3005,
|
124
140
|
// overlay: false
|
125
141
|
}
|
126
142
|
},
|
@@ -183,8 +199,12 @@ module.exports = configure(function (/* ctx */) {
|
|
183
199
|
// (gets superseded if process.env.PORT is specified at runtime)
|
184
200
|
|
185
201
|
middlewares: [
|
202
|
+
'injectEnv', // middleware для инъекции process.env в window.__ENV__
|
186
203
|
'render', // keep this as last one
|
187
204
|
],
|
205
|
+
|
206
|
+
// Не обрабатывать эти модули для SSR
|
207
|
+
noExternal: ['@dicebear/core', '@dicebear/collection']
|
188
208
|
},
|
189
209
|
|
190
210
|
// https://v2.quasar.dev/quasar-cli-vite/developing-pwa/configuring-pwa
|
@@ -7,17 +7,18 @@ import {
|
|
7
7
|
createWebHistory,
|
8
8
|
} from 'vue-router';
|
9
9
|
import { routes } from 'src/app/providers/routes';
|
10
|
+
import { env } from 'src/shared/config';
|
10
11
|
|
11
12
|
// Helper function to determine router history mode
|
12
13
|
function getHistoryMode() {
|
13
|
-
if (
|
14
|
-
return
|
14
|
+
if (env.SERVER) return createMemoryHistory;
|
15
|
+
return env.VUE_ROUTER_MODE === 'history' ? createWebHistory : createWebHashHistory;
|
15
16
|
}
|
16
17
|
|
17
18
|
// Main route export
|
18
19
|
export default route(function () {
|
19
20
|
const Router = createRouter({
|
20
|
-
history: getHistoryMode()(
|
21
|
+
history: getHistoryMode()(env.VUE_ROUTER_BASE),
|
21
22
|
routes, // Базовые маршруты
|
22
23
|
scrollBehavior(to, from, savedPosition) {
|
23
24
|
return savedPosition || { top: 0 };
|
package/src/boot/sentry.ts
CHANGED
@@ -1,25 +1,26 @@
|
|
1
1
|
import { boot } from 'quasar/wrappers';
|
2
2
|
import { App } from 'vue';
|
3
3
|
import { Router } from 'vue-router';
|
4
|
-
import
|
5
|
-
import
|
6
|
-
import
|
4
|
+
import { env } from 'src/shared/config';
|
5
|
+
// import Tracker from '@openreplay/tracker';
|
6
|
+
// import trackerAssist from '@openreplay/tracker-assist'
|
7
|
+
// import { useSessionStore } from 'src/entities/Session';
|
7
8
|
export default boot(
|
8
9
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
9
10
|
({ app, router }: { app: App<Element>; router: Router }) => {
|
10
|
-
if ((
|
11
|
-
const session = useSessionStore()
|
11
|
+
if ((env.NODE_ENV as string) === 'production') {
|
12
|
+
// const session = useSessionStore()
|
12
13
|
|
13
|
-
const tracker = new Tracker({
|
14
|
-
|
15
|
-
});
|
14
|
+
// const tracker = new Tracker({
|
15
|
+
// projectKey: 'mgaCVSShnDNbPRFDZehd',
|
16
|
+
// });
|
16
17
|
|
17
|
-
if (session.username)
|
18
|
-
|
18
|
+
// if (session.username)
|
19
|
+
// tracker.setUserID(session.username)
|
19
20
|
|
20
|
-
// .start() returns a promise
|
21
|
-
tracker.start().then(sessionData => console.log(sessionData) ).catch(e => console.error('on tracker: ', e) )
|
22
|
-
tracker.use(trackerAssist({}));
|
21
|
+
// // .start() returns a promise
|
22
|
+
// tracker.start().then(sessionData => console.log(sessionData) ).catch(e => console.error('on tracker: ', e) )
|
23
|
+
// tracker.use(trackerAssist({}));
|
23
24
|
}
|
24
25
|
}
|
25
26
|
);
|
@@ -6,7 +6,7 @@ import { WalletPluginPrivateKey } from '@wharfkit/wallet-plugin-privatekey';
|
|
6
6
|
import { FailAlert, readBlockchain } from 'src/shared/api';
|
7
7
|
import { PrivateKey, Serializer } from '@wharfkit/antelope';
|
8
8
|
import { GetInfoResult } from 'eosjs/dist/eosjs-rpc-interfaces';
|
9
|
-
|
9
|
+
import { env } from 'src/shared/config';
|
10
10
|
interface ISessionStore {
|
11
11
|
isAuth: Ref<boolean>;
|
12
12
|
username: ComputedRef<string>;
|
@@ -67,8 +67,8 @@ export const useSessionStore = defineStore('session', (): ISessionStore => {
|
|
67
67
|
actor: globalStore.username,
|
68
68
|
permission: 'active',
|
69
69
|
chain: {
|
70
|
-
id:
|
71
|
-
url:
|
70
|
+
id: env.CHAIN_ID as string,
|
71
|
+
url: env.CHAIN_URL as string,
|
72
72
|
},
|
73
73
|
walletPlugin: new WalletPluginPrivateKey(
|
74
74
|
globalStore.wif as PrivateKey
|
package/src/env.d.ts
CHANGED
@@ -6,6 +6,7 @@ declare namespace NodeJS {
|
|
6
6
|
VUE_ROUTER_MODE: 'hash' | 'history' | 'abstract' | undefined;
|
7
7
|
VUE_ROUTER_BASE: string | undefined;
|
8
8
|
}
|
9
|
+
|
9
10
|
}
|
10
11
|
|
11
12
|
declare global {
|
@@ -13,6 +14,7 @@ declare global {
|
|
13
14
|
YooMoneyCheckoutWidget: any;
|
14
15
|
chatwootSDK: any;
|
15
16
|
}
|
17
|
+
|
16
18
|
}
|
17
19
|
|
18
20
|
import 'vue-router';
|
package/src/features/Request/CreateParentOffer/ui/CreateParentOfferForm/CreateParentOfferForm.vue
CHANGED
@@ -6,6 +6,7 @@ import { computed, ref } from 'vue'
|
|
6
6
|
import { Form } from 'src/shared/ui/Form'
|
7
7
|
import { useCooperativeStore } from 'src/entities/Cooperative'
|
8
8
|
import { ImageUploaderWithPreview } from '../ImageUploaderWithPreview'
|
9
|
+
import { env } from 'src/shared/config'
|
9
10
|
|
10
11
|
const props = defineProps({
|
11
12
|
username: {
|
@@ -48,7 +49,7 @@ const handlerSubmit = async () => {
|
|
48
49
|
coopname: props.coopname,
|
49
50
|
program_id: formData.value.program_id,
|
50
51
|
units: formData.value.units,
|
51
|
-
unit_cost: parseFloat(unit_cost.toString()).toFixed(4) + ' ' +
|
52
|
+
unit_cost: parseFloat(unit_cost.toString()).toFixed(4) + ' ' + env.CURRENCY,
|
52
53
|
product_lifecycle_secs: 86400 * formData.value.product_lifecycle_days,
|
53
54
|
data: {
|
54
55
|
title: formData.value.title,
|
@@ -1,6 +1,7 @@
|
|
1
1
|
<script lang="ts" setup>
|
2
2
|
import { ref, computed } from 'vue'
|
3
3
|
import { ImagesPreview } from '../ImagesPreview'
|
4
|
+
import { env } from 'src/shared/config'
|
4
5
|
|
5
6
|
const emit = defineEmits(['updateImages'])
|
6
7
|
|
@@ -38,7 +39,7 @@ const triggerUploader = () => {
|
|
38
39
|
uploaderRef.value.pickFiles()
|
39
40
|
}
|
40
41
|
|
41
|
-
const upload_url = computed(() =>
|
42
|
+
const upload_url = computed(() => env.UPLOAD_URL)
|
42
43
|
</script>
|
43
44
|
|
44
45
|
<template lang="pug">
|
@@ -2,6 +2,7 @@ import { TransactResult } from '@wharfkit/session';
|
|
2
2
|
import { RegistratorContract } from 'cooptypes';
|
3
3
|
import { useSessionStore } from 'src/entities/Session';
|
4
4
|
import { useGlobalStore } from 'src/shared/store';
|
5
|
+
import { env } from 'src/shared/config';
|
5
6
|
|
6
7
|
export function useAddCooperative() {
|
7
8
|
async function addCooperative(
|
@@ -9,10 +10,10 @@ export function useAddCooperative() {
|
|
9
10
|
): Promise<TransactResult | undefined> {
|
10
11
|
const session = useSessionStore();
|
11
12
|
|
12
|
-
data.params.initial = `${parseFloat(data.params.initial).toFixed(4)} ${
|
13
|
-
data.params.minimum = `${parseFloat(data.params.minimum).toFixed(4)} ${
|
14
|
-
data.params.org_initial = `${parseFloat(data.params.org_initial).toFixed(4)} ${
|
15
|
-
data.params.org_minimum = `${parseFloat(data.params.org_minimum).toFixed(4)} ${
|
13
|
+
data.params.initial = `${parseFloat(data.params.initial).toFixed(4)} ${env.CURRENCY}`
|
14
|
+
data.params.minimum = `${parseFloat(data.params.minimum).toFixed(4)} ${env.CURRENCY}`
|
15
|
+
data.params.org_initial = `${parseFloat(data.params.org_initial).toFixed(4)} ${env.CURRENCY}`
|
16
|
+
data.params.org_minimum = `${parseFloat(data.params.org_minimum).toFixed(4)} ${env.CURRENCY}`
|
16
17
|
|
17
18
|
const result = await useGlobalStore().transact({
|
18
19
|
account: RegistratorContract.contractName.production,
|
@@ -29,11 +29,12 @@ import { useSessionStore } from 'src/entities/Session';
|
|
29
29
|
import { RegistratorContract } from 'cooptypes';
|
30
30
|
import { FailAlert, SuccessAlert } from 'src/shared/api';
|
31
31
|
import type { IObjectedDocument } from 'src/shared/lib/types/document';
|
32
|
+
import { env } from 'src/shared/config';
|
32
33
|
|
33
34
|
const emit = defineEmits(['finish'])
|
34
35
|
|
35
36
|
const {addCooperative} = useAddCooperative()
|
36
|
-
const currency = computed(() =>
|
37
|
+
const currency = computed(() => env.CURRENCY)
|
37
38
|
const isSubmitting = ref(false)
|
38
39
|
|
39
40
|
const props = defineProps({
|
@@ -82,9 +83,6 @@ const addNow = async () => {
|
|
82
83
|
} catch(e: any){
|
83
84
|
FailAlert(e.message)
|
84
85
|
}
|
85
|
-
|
86
|
-
|
87
|
-
|
88
86
|
}
|
89
87
|
|
90
88
|
</script>
|
@@ -14,7 +14,6 @@ export function useLoginUser() {
|
|
14
14
|
async function login(email: string, wif: string): Promise<void> {
|
15
15
|
const auth = await api.loginUser(email, wif);
|
16
16
|
const { tokens, account } = await client.login(email, wif);
|
17
|
-
|
18
17
|
// Создаём объект tokens с правильными типами
|
19
18
|
const adaptedTokens: ITokens = {
|
20
19
|
access: {
|
@@ -36,7 +35,6 @@ export function useLoginUser() {
|
|
36
35
|
|
37
36
|
const { run } = useInitWalletProcess()
|
38
37
|
await run() //запускаем фоновое обновление кошелька - заменить на подписку потом
|
39
|
-
|
40
38
|
if (!currentUser.isRegistrationComplete){
|
41
39
|
const {state, steps} = useRegistratorStore()
|
42
40
|
state.userData.type = currentUser.userAccount?.type as 'individual' | 'entrepreneur' | 'organization'
|
@@ -48,7 +46,6 @@ export function useLoginUser() {
|
|
48
46
|
organization: state.userData.organization_data,
|
49
47
|
entrepreneur: state.userData.entrepreneur_data
|
50
48
|
};
|
51
|
-
|
52
49
|
const data = dataMap[state.userData.type];
|
53
50
|
if (data) {
|
54
51
|
for (const key of Object.keys(privateData)) {
|
@@ -74,7 +71,6 @@ export function useLoginUser() {
|
|
74
71
|
else if (currentUser.userAccount?.status === 'registered')
|
75
72
|
state.step = steps.Welcome
|
76
73
|
}
|
77
|
-
|
78
74
|
}
|
79
75
|
|
80
76
|
return {
|
@@ -8,7 +8,6 @@ export function useLogoutUser() {
|
|
8
8
|
async function logout(): Promise<void> {
|
9
9
|
const global = useGlobalStore()
|
10
10
|
//TODO: "начать с начала" при регистрации бажит на это - да и в целом пора бы маршруты срезать эти
|
11
|
-
// if (global.tokens?.refresh.token) await api.logoutUser(global.tokens?.refresh.token)
|
12
11
|
await useRegistratorStore().clearUserData()
|
13
12
|
|
14
13
|
await global.logout()
|
@@ -32,6 +32,8 @@ import { useSessionStore } from 'src/entities/Session'
|
|
32
32
|
import type { IPaymentOrder } from 'src/shared/lib/types/payments'
|
33
33
|
import { formatAssetToReadable } from 'src/shared/lib/utils/formatAssetToReadable'
|
34
34
|
import { useSystemStore } from 'src/entities/System/model';
|
35
|
+
import { env } from 'src/shared/config';
|
36
|
+
|
35
37
|
const { info } = useSystemStore()
|
36
38
|
|
37
39
|
const { createDeposit, loadUserWallet } = useWalletStore()
|
@@ -54,7 +56,7 @@ const handlerSubmit = async (): Promise<void> => {
|
|
54
56
|
isSubmitting.value = true
|
55
57
|
try {
|
56
58
|
paymentOrder.value = (await createDeposit({
|
57
|
-
quantity: `${parseFloat(quantity.value.toString()).toFixed(4)} ${
|
59
|
+
quantity: `${parseFloat(quantity.value.toString()).toFixed(4)} ${env.CURRENCY}`
|
58
60
|
})) as IPaymentOrder
|
59
61
|
isSubmitting.value = false
|
60
62
|
} catch (e: any) {
|
@@ -64,7 +66,7 @@ const handlerSubmit = async (): Promise<void> => {
|
|
64
66
|
}
|
65
67
|
}
|
66
68
|
|
67
|
-
const currency = computed(() =>
|
69
|
+
const currency = computed(() => env.CURRENCY)
|
68
70
|
|
69
71
|
const paymentFail = (): void => {
|
70
72
|
clear()
|
@@ -18,7 +18,9 @@ q-btn(@click="showDialog = true" color="primary")
|
|
18
18
|
import { ref, computed } from 'vue';
|
19
19
|
import { ModalBase } from 'src/shared/ui/ModalBase';
|
20
20
|
import { Form } from 'src/shared/ui/Form';
|
21
|
-
|
21
|
+
import { env } from 'src/shared/config';
|
22
|
+
|
23
|
+
const currency = computed(() => env.CURRENCY)
|
22
24
|
const showDialog = ref(false)
|
23
25
|
const quantity = ref(1000)
|
24
26
|
const isSubmitting = ref(false)
|
@@ -33,7 +35,7 @@ const handlerSubmit = async (): Promise<void> => {
|
|
33
35
|
isSubmitting.value = true
|
34
36
|
try {
|
35
37
|
// paymentOrder.value = (await createDeposit({
|
36
|
-
// quantity: `${parseFloat(quantity.value.toString()).toFixed(4)} ${
|
38
|
+
// quantity: `${parseFloat(quantity.value.toString()).toFixed(4)} ${env.CURRENCY}`,
|
37
39
|
// provider: 'yookassa',
|
38
40
|
// })) as IPaymentOrder
|
39
41
|
isSubmitting.value = false
|
@@ -7,8 +7,10 @@ import { FailAlert, SuccessAlert } from 'src/shared/api';
|
|
7
7
|
import { formatToAsset } from 'src/shared/lib/utils/formatToAsset';
|
8
8
|
import { ref, watch, computed } from 'vue';
|
9
9
|
import { useSystemStore } from 'src/entities/System/model';
|
10
|
+
import { env } from 'src/shared/config';
|
11
|
+
|
10
12
|
const { info } = useSystemStore()
|
11
|
-
const currency = computed(() =>
|
13
|
+
const currency = computed(() => env.CURRENCY)
|
12
14
|
const coop = useCooperativeStore()
|
13
15
|
coop.loadPublicCooperativeData(info.coopname)
|
14
16
|
coop.loadPrivateCooperativeData()
|
@@ -28,10 +30,10 @@ const save = async () => {
|
|
28
30
|
await updateCoop({
|
29
31
|
coopname: info.coopname,
|
30
32
|
username: session.username,
|
31
|
-
initial: formatToAsset(localCoop.value.initial,
|
32
|
-
minimum: formatToAsset(localCoop.value.minimum,
|
33
|
-
org_initial: formatToAsset(localCoop.value.org_initial,
|
34
|
-
org_minimum: formatToAsset(localCoop.value.org_minimum,
|
33
|
+
initial: formatToAsset(localCoop.value.initial, env.CURRENCY as string),
|
34
|
+
minimum: formatToAsset(localCoop.value.minimum, env.CURRENCY as string),
|
35
|
+
org_initial: formatToAsset(localCoop.value.org_initial, env.CURRENCY as string),
|
36
|
+
org_minimum: formatToAsset(localCoop.value.org_minimum, env.CURRENCY as string),
|
35
37
|
announce: coop.publicCooperativeData?.announce,
|
36
38
|
description: coop.publicCooperativeData?.description
|
37
39
|
})
|
@@ -33,7 +33,7 @@ div(v-if="extension").row
|
|
33
33
|
span.q-ml-xs удалить
|
34
34
|
|
35
35
|
div.col-md-9.col-sm-8.col-xs-12.q-pa-md
|
36
|
-
div(v-if="isMain")
|
36
|
+
div(v-if="isMain").info-card
|
37
37
|
div
|
38
38
|
span.text-h1 {{extension.title}}
|
39
39
|
//- q-chip(square dense size="sm" color="green" outline v-if="extension.is_installed && extension.enabled").q-ml-sm установлено
|
@@ -42,29 +42,43 @@ div(v-if="extension").row
|
|
42
42
|
div
|
43
43
|
q-chip(outline v-for="tag in extension.tags" v-bind:key="tag" dense size="sm") {{tag}}
|
44
44
|
|
45
|
-
|
46
|
-
|
45
|
+
ClientOnly
|
46
|
+
template(#default)
|
47
|
+
vue-markdown(:source="extension.readme").description.q-mt-md
|
48
|
+
div(v-if="(isSettings || isInstall) && extension.schema").info-card
|
47
49
|
q-form(ref="myFormRef")
|
48
50
|
div(v-if="isEmpty && !isInstall")
|
49
51
|
div.q-pa-md
|
50
52
|
p.text-h6 Нет настроек
|
51
53
|
span Расширение не предоставило настроек для изменения.
|
52
|
-
div(v-if="!isEmpty")
|
53
|
-
|
54
|
-
|
54
|
+
div(v-if="!isEmpty && !isInstall")
|
55
|
+
|
56
|
+
//- vue-markdown(:source="extension.instructions").description.q-mt-md
|
57
|
+
ClientOnly
|
58
|
+
template(#default)
|
59
|
+
vue-markdown(v-if="extension.instructions && isInstall" :source="extension.instructions").description.q-mt-md
|
60
|
+
div
|
61
|
+
p.text-h5 Настройки
|
62
|
+
ZodForm(:schema="extension.schema" v-model="data").q-mt-lg
|
55
63
|
|
56
64
|
</template>
|
57
65
|
<script lang="ts" setup>
|
58
66
|
import { useExtensionStore } from 'src/entities/Extension/model';
|
59
|
-
import { computed, onMounted, ref, watch } from 'vue';
|
67
|
+
import { computed, onMounted, ref, watch, defineAsyncComponent } from 'vue';
|
60
68
|
import { useRoute, useRouter } from 'vue-router';
|
61
69
|
import { ZodForm } from 'src/shared/ui/ZodForm';
|
62
|
-
import VueMarkdown from 'vue-markdown-render'
|
70
|
+
// import VueMarkdown from 'vue-markdown-render'
|
63
71
|
import { extractGraphQLErrorMessages, FailAlert, SuccessAlert } from 'src/shared/api';
|
64
72
|
import { useUpdateExtension } from 'src/features/Extension/UpdateExtension';
|
65
73
|
import { useUninstallExtension } from 'src/features/Extension/UninstallExtension';
|
66
74
|
import { useInstallExtension } from 'src/features/Extension/InstallExtension';
|
67
75
|
import { useDesktopStore } from 'src/entities/Desktop/model';
|
76
|
+
import { ClientOnly } from 'src/shared/ui/ClientOnly';
|
77
|
+
|
78
|
+
// Клиентский компонент для markdown, загружаемый только на клиенте
|
79
|
+
const VueMarkdown = defineAsyncComponent(() =>
|
80
|
+
import('vue-markdown-render').then(mod => mod.default)
|
81
|
+
);
|
68
82
|
|
69
83
|
const route = useRoute();
|
70
84
|
const router = useRouter();
|
@@ -28,12 +28,14 @@ import { ref, computed, watch } from 'vue'
|
|
28
28
|
import { useCreateUser } from 'src/features/User/CreateUser'
|
29
29
|
import { debounce } from 'quasar'
|
30
30
|
import { useRegistratorStore } from 'src/entities/Registrator'
|
31
|
+
import { env } from 'src/shared/config'
|
32
|
+
|
31
33
|
const store = useRegistratorStore()
|
32
34
|
|
33
35
|
const api = useCreateUser()
|
34
36
|
|
35
37
|
watch(() => store.state.email, () => email.value = store.state.email)
|
36
|
-
const coopTitle = computed(() =>
|
38
|
+
const coopTitle = computed(() => env.COOP_SHORT_NAME)
|
37
39
|
const email = ref(store.state.email)
|
38
40
|
|
39
41
|
const inLoading = ref(false)
|
@@ -20,9 +20,11 @@ div
|
|
20
20
|
import { computed } from 'vue'
|
21
21
|
import { useRouter } from 'vue-router';
|
22
22
|
import { useRegistratorStore } from 'src/entities/Registrator';
|
23
|
+
import { env } from 'src/shared/config';
|
24
|
+
|
23
25
|
const router = useRouter()
|
24
26
|
const store = useRegistratorStore()
|
25
|
-
const coopTitle = computed(() =>
|
27
|
+
const coopTitle = computed(() => env.COOP_SHORT_NAME)
|
26
28
|
|
27
29
|
const next = () => {
|
28
30
|
router.push({ name: 'index' })
|
package/src/shared/api/axios.ts
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
import axios from 'axios';
|
2
2
|
import { useGlobalStore } from '../store';
|
3
|
+
import { env } from 'src/shared/config';
|
3
4
|
|
4
5
|
export async function sendGET(
|
5
6
|
url: string,
|
@@ -13,7 +14,7 @@ export async function sendGET(
|
|
13
14
|
// if (!tokens || !tokens.access || !tokens.access.token)
|
14
15
|
// throw new Error('Ошибка авторизации: токен доступа не найден');
|
15
16
|
|
16
|
-
const response = await axios.get(
|
17
|
+
const response = await axios.get(env.BACKEND_URL + url, {
|
17
18
|
params,
|
18
19
|
headers: {
|
19
20
|
Authorization: `Bearer ${tokens?.access?.token}`,
|
@@ -21,7 +22,7 @@ export async function sendGET(
|
|
21
22
|
});
|
22
23
|
return response.data;
|
23
24
|
} else {
|
24
|
-
const response = await axios.get(
|
25
|
+
const response = await axios.get(env.BACKEND_URL + url, {
|
25
26
|
params,
|
26
27
|
});
|
27
28
|
return response.data;
|
@@ -49,14 +50,14 @@ export async function sendPOST(
|
|
49
50
|
// if (!tokens || !tokens.access || !tokens.access.token)
|
50
51
|
// throw new Error('Ошибка авторизации: токен доступа не найден');
|
51
52
|
|
52
|
-
const response = await axios.post(
|
53
|
+
const response = await axios.post(env.BACKEND_URL + url, data, {
|
53
54
|
headers: {
|
54
55
|
Authorization: `Bearer ${tokens?.access?.token}`,
|
55
56
|
},
|
56
57
|
});
|
57
58
|
return response.data;
|
58
59
|
} else {
|
59
|
-
const response = await axios.post(
|
60
|
+
const response = await axios.post(env.BACKEND_URL + url, data);
|
60
61
|
return response.data;
|
61
62
|
}
|
62
63
|
} catch (e: any) {
|
package/src/shared/api/client.ts
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
import { Client } from '@coopenomics/sdk'
|
2
|
+
import { env } from 'src/shared/config'
|
2
3
|
|
3
4
|
// Создаем и экспортируем экземпляр API-клиента
|
4
5
|
export const client = Client.create({
|
5
|
-
api_url:
|
6
|
+
api_url: env.BACKEND_URL + '/v1/graphql',
|
6
7
|
headers: {
|
7
8
|
'Content-Type': 'application/json',
|
8
9
|
},
|
9
|
-
chain_url:
|
10
|
-
chain_id:
|
10
|
+
chain_url: env.CHAIN_URL as string,
|
11
|
+
chain_id: env.CHAIN_ID as string,
|
11
12
|
})
|
12
13
|
|
package/src/shared/api/eosio.ts
CHANGED
@@ -3,9 +3,10 @@ import { APIClient, PrivateKey } from '@wharfkit/antelope';
|
|
3
3
|
import { ContractKit } from '@wharfkit/contract';
|
4
4
|
import { useGlobalStore } from '../store';
|
5
5
|
import { Account } from '@wharfkit/account'
|
6
|
+
import { env } from 'src/shared/config';
|
6
7
|
|
7
8
|
export const readBlockchain = new APIClient({
|
8
|
-
url:
|
9
|
+
url: env.CHAIN_URL,
|
9
10
|
});
|
10
11
|
|
11
12
|
export const contractKit = new ContractKit({
|
@@ -1,6 +1,8 @@
|
|
1
1
|
import { openDB } from 'idb';
|
2
|
+
import { env } from '../config';
|
2
3
|
|
3
4
|
async function openIndexedDB(dbName: string, storeName: string) {
|
5
|
+
|
4
6
|
if (!process.env.CLIENT) {
|
5
7
|
return;
|
6
8
|
}
|
@@ -21,6 +23,7 @@ export async function getFromIndexedDB(dbName: string, storeName: string, key: s
|
|
21
23
|
return;
|
22
24
|
}
|
23
25
|
|
26
|
+
|
24
27
|
const db = await openIndexedDB(dbName, storeName);
|
25
28
|
if (db) {
|
26
29
|
return db.get(storeName, key);
|
package/src/shared/api/utils.ts
CHANGED
@@ -0,0 +1,68 @@
|
|
1
|
+
// Типы для переменных окружения
|
2
|
+
export interface EnvVars {
|
3
|
+
NODE_ENV?: string;
|
4
|
+
BACKEND_URL?: string;
|
5
|
+
CHAIN_URL?: string;
|
6
|
+
CHAIN_ID?: string;
|
7
|
+
CURRENCY?: string;
|
8
|
+
COOP_SHORT_NAME?: string;
|
9
|
+
SITE_DESCRIPTION?: string;
|
10
|
+
SITE_IMAGE?: string;
|
11
|
+
STORAGE_URL?: string;
|
12
|
+
UPLOAD_URL?: string;
|
13
|
+
CLIENT?: boolean;
|
14
|
+
SERVER?: boolean;
|
15
|
+
VUE_ROUTER_MODE?: string;
|
16
|
+
VUE_ROUTER_BASE?: string;
|
17
|
+
[key: string]: string | boolean | undefined;
|
18
|
+
}
|
19
|
+
|
20
|
+
// Расширяем глобальный Window чтобы TypeScript понимал window.__ENV__
|
21
|
+
declare global {
|
22
|
+
interface Window {
|
23
|
+
__ENV__?: EnvVars;
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
/**
|
28
|
+
* Определение переменных окружения для разных сред
|
29
|
+
* - На сервере (SSR): берем напрямую из process.env
|
30
|
+
* - На клиенте (SSR): используем window.__ENV__, инжектированные с сервера
|
31
|
+
* - В SPA режиме: переменные заменяются при сборке
|
32
|
+
*/
|
33
|
+
function getEnv(): EnvVars {
|
34
|
+
// SSR сервер или SPA сборка
|
35
|
+
|
36
|
+
if (typeof process !== 'undefined' && process.env) {
|
37
|
+
// Для SSR сервера - берем реальные переменные
|
38
|
+
// Для SPA - эти значения заменятся при сборке
|
39
|
+
return {
|
40
|
+
NODE_ENV: process.env.NODE_ENV,
|
41
|
+
BACKEND_URL: process.env.BACKEND_URL,
|
42
|
+
CHAIN_URL: process.env.CHAIN_URL,
|
43
|
+
CHAIN_ID: process.env.CHAIN_ID,
|
44
|
+
CURRENCY: process.env.CURRENCY,
|
45
|
+
COOP_SHORT_NAME: process.env.COOP_SHORT_NAME,
|
46
|
+
SITE_DESCRIPTION: process.env.SITE_DESCRIPTION,
|
47
|
+
SITE_IMAGE: process.env.SITE_IMAGE,
|
48
|
+
STORAGE_URL: process.env.STORAGE_URL,
|
49
|
+
UPLOAD_URL: process.env.UPLOAD_URL,
|
50
|
+
CLIENT: process.env.CLIENT as unknown as boolean,
|
51
|
+
SERVER: process.env.SERVER as unknown as boolean,
|
52
|
+
VUE_ROUTER_MODE: process.env.VUE_ROUTER_MODE,
|
53
|
+
VUE_ROUTER_BASE: process.env.VUE_ROUTER_BASE
|
54
|
+
};
|
55
|
+
}
|
56
|
+
|
57
|
+
// SSR клиент - берем из window.__ENV__
|
58
|
+
if (typeof window !== 'undefined' && window.__ENV__) {
|
59
|
+
return window.__ENV__;
|
60
|
+
}
|
61
|
+
|
62
|
+
// Запасной вариант, если ничего не сработало
|
63
|
+
console.warn('Не удалось получить переменные окружения!');
|
64
|
+
return {};
|
65
|
+
}
|
66
|
+
|
67
|
+
// Экспортируем переменные окружения
|
68
|
+
export const env: EnvVars = getEnv();
|
@@ -0,0 +1,21 @@
|
|
1
|
+
// Прокси-файл для @dicebear/collection
|
2
|
+
let cachedModule = null;
|
3
|
+
|
4
|
+
async function loadModule() {
|
5
|
+
if (!cachedModule) {
|
6
|
+
cachedModule = await import('@dicebear/collection');
|
7
|
+
}
|
8
|
+
return cachedModule;
|
9
|
+
}
|
10
|
+
|
11
|
+
// Экспортируем пустой объект для CommonJS
|
12
|
+
// В SSR мы можем проверять наличие функций перед их использованием
|
13
|
+
module.exports = {
|
14
|
+
loadModule,
|
15
|
+
// Добавляем заглушки для основных стилей
|
16
|
+
thumbs: {},
|
17
|
+
lorelei: {},
|
18
|
+
bottts: {},
|
19
|
+
avataaars: {},
|
20
|
+
// Другие стили можно добавить при необходимости
|
21
|
+
};
|
@@ -0,0 +1,20 @@
|
|
1
|
+
// Прокси-файл для @dicebear/core
|
2
|
+
let cachedModule = null;
|
3
|
+
|
4
|
+
async function loadModule() {
|
5
|
+
if (!cachedModule) {
|
6
|
+
cachedModule = await import('@dicebear/core');
|
7
|
+
}
|
8
|
+
return cachedModule;
|
9
|
+
}
|
10
|
+
|
11
|
+
// Экспортируем пустой объект для CommonJS
|
12
|
+
// В SSR мы можем проверять наличие функций перед их использованием
|
13
|
+
module.exports = {
|
14
|
+
loadModule,
|
15
|
+
// Добавляем заглушки для основных функций
|
16
|
+
createAvatar: async function(...args) {
|
17
|
+
const module = await loadModule();
|
18
|
+
return module.createAvatar(...args);
|
19
|
+
}
|
20
|
+
};
|
@@ -0,0 +1,19 @@
|
|
1
|
+
// CJS прокси для email-regex
|
2
|
+
const originalModule = require('email-regex');
|
3
|
+
|
4
|
+
// Преобразуем default export из ESM в CJS
|
5
|
+
module.exports = function emailRegex(options = {}) {
|
6
|
+
// Проверяем, является ли оригинальный модуль функцией или объектом с default
|
7
|
+
if (typeof originalModule === 'function') {
|
8
|
+
return originalModule(options);
|
9
|
+
} else if (originalModule && typeof originalModule.default === 'function') {
|
10
|
+
return originalModule.default(options);
|
11
|
+
} else {
|
12
|
+
// Запасная реализация, если что-то пошло не так
|
13
|
+
const exact = options && options.exact;
|
14
|
+
const pattern = exact
|
15
|
+
? /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/
|
16
|
+
: /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*/g;
|
17
|
+
return pattern;
|
18
|
+
}
|
19
|
+
};
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<template lang="pug">
|
2
|
+
slot(v-if="isMounted")
|
3
|
+
template(v-else)
|
4
|
+
slot(name="fallback")
|
5
|
+
</template>
|
6
|
+
|
7
|
+
<script lang="ts" setup>
|
8
|
+
import { ref, onMounted } from 'vue'
|
9
|
+
|
10
|
+
const isMounted = ref(false)
|
11
|
+
|
12
|
+
onMounted(() => {
|
13
|
+
isMounted.value = true
|
14
|
+
})
|
15
|
+
</script>
|
@@ -0,0 +1 @@
|
|
1
|
+
export { default as ClientOnly } from './ClientOnly.vue';
|
@@ -1,12 +1,12 @@
|
|
1
1
|
<template lang="pug">
|
2
2
|
div
|
3
|
-
|
3
|
+
div(flat v-for="(property, propertyName) in schema.properties" :key="propertyName")
|
4
4
|
div(v-if="isVisible(property)")
|
5
5
|
component(
|
6
6
|
standout="bg-teal text-white"
|
7
7
|
:is="getComponentType(property)"
|
8
8
|
v-bind="getComponentProps(property, propertyName)"
|
9
|
-
).q-mt-
|
9
|
+
).q-mt-lg
|
10
10
|
// Слот для prepend, если указано
|
11
11
|
template(v-slot:prepend v-if="property.description?.prepend")
|
12
12
|
span {{ property.description.prepend }}
|
@@ -41,6 +41,7 @@ import { useWindowSize } from 'src/shared/hooks'
|
|
41
41
|
import { SettingsDropdown } from 'src/widgets/Header/SettingsDropdown'
|
42
42
|
import { BackButton } from 'src/widgets/Header/BackButton'
|
43
43
|
import './HeaderStyles.scss'
|
44
|
+
// import { env } from 'src/shared/config'
|
44
45
|
|
45
46
|
const router = useRouter()
|
46
47
|
const route = useRoute()
|
@@ -50,7 +51,7 @@ const { isMobile } = useWindowSize()
|
|
50
51
|
const emit = defineEmits(['toggle-left-drawer'])
|
51
52
|
|
52
53
|
// Получаем информацию для навигации назад
|
53
|
-
// const coopTitle = computed(() =>
|
54
|
+
// const coopTitle = computed(() => env.COOP_SHORT_NAME)
|
54
55
|
|
55
56
|
const isDark = computed(() => $q.dark.isActive)
|
56
57
|
const headerClass = computed(() =>
|
@@ -11,6 +11,7 @@ import {
|
|
11
11
|
SeventhStep,
|
12
12
|
EightStep,
|
13
13
|
} from '../Steps'
|
14
|
+
import { env } from 'src/shared/config'
|
14
15
|
|
15
16
|
//TODO изменить на обязательный импорт с типом
|
16
17
|
const props = defineProps<{
|
@@ -53,7 +54,7 @@ const src = computed(() => {
|
|
53
54
|
if (preview && preview.startsWith('https://')) {
|
54
55
|
return preview // Превью уже содержит HTTPS, оставляем его как есть
|
55
56
|
} else {
|
56
|
-
return
|
57
|
+
return env.STORAGE_URL + preview // Иначе, добавляем config.storageUrl
|
57
58
|
}
|
58
59
|
})
|
59
60
|
</script>
|
@@ -0,0 +1,49 @@
|
|
1
|
+
import { ssrMiddleware } from 'quasar/wrappers';
|
2
|
+
import { EnvVars } from '../../src/shared/config/Environment';
|
3
|
+
|
4
|
+
/**
|
5
|
+
* SSR middleware для инъекции переменных окружения в браузер
|
6
|
+
* Создает window.__ENV__ со всеми переменными, которые должны быть доступны на клиенте
|
7
|
+
*/
|
8
|
+
export default ssrMiddleware(({ app }) => {
|
9
|
+
// Регистрируем middleware для всех запросов
|
10
|
+
app.use((req, res, next) => {
|
11
|
+
// Получаем переменные из process.env, которые нужны клиенту
|
12
|
+
const envForClient: EnvVars = {
|
13
|
+
NODE_ENV: process.env.NODE_ENV,
|
14
|
+
BACKEND_URL: process.env.BACKEND_URL,
|
15
|
+
CHAIN_URL: process.env.CHAIN_URL,
|
16
|
+
CHAIN_ID: process.env.CHAIN_ID,
|
17
|
+
CURRENCY: process.env.CURRENCY,
|
18
|
+
COOP_SHORT_NAME: process.env.COOP_SHORT_NAME,
|
19
|
+
SITE_DESCRIPTION: process.env.SITE_DESCRIPTION,
|
20
|
+
SITE_IMAGE: process.env.SITE_IMAGE,
|
21
|
+
STORAGE_URL: process.env.STORAGE_URL,
|
22
|
+
UPLOAD_URL: process.env.UPLOAD_URL,
|
23
|
+
VUE_ROUTER_MODE: process.env.VUE_ROUTER_MODE,
|
24
|
+
VUE_ROUTER_BASE: process.env.VUE_ROUTER_BASE
|
25
|
+
};
|
26
|
+
|
27
|
+
// Создаем скрипт, который добавит переменные в window.__ENV__
|
28
|
+
const script = `
|
29
|
+
<script>
|
30
|
+
window.__ENV__ = ${JSON.stringify(envForClient)};
|
31
|
+
console.log('SSR: Переменные окружения загружены');
|
32
|
+
</script>
|
33
|
+
`;
|
34
|
+
|
35
|
+
// Оригинальный метод отправки HTML
|
36
|
+
const originalSend = res.send;
|
37
|
+
|
38
|
+
// Переопределяем метод, чтобы вставить наш скрипт перед закрывающим тегом </head>
|
39
|
+
res.send = function (html) {
|
40
|
+
if (typeof html === 'string') {
|
41
|
+
html = html.replace('</head>', `${script}</head>`);
|
42
|
+
}
|
43
|
+
return originalSend.call(this, html);
|
44
|
+
};
|
45
|
+
|
46
|
+
// Продолжаем обработку запроса
|
47
|
+
next();
|
48
|
+
});
|
49
|
+
});
|