Merge branch 'master' of git.flexites.org:Students/ITRadio

This commit is contained in:
Mike0001-droid 2024-06-25 18:43:38 +05:00
commit ac8db4a425
58 changed files with 6088 additions and 5934 deletions

View File

@ -8,7 +8,7 @@ ROBOTS_ALLOW=
ROBOTS_DISALLOW=["/"] ROBOTS_DISALLOW=["/"]
SERVICE_SELF_URL=//it-radio.flexidev.ru SERVICE_SELF_URL=//it-radio.flexidev.ru
SERVICE_URL=//it-radio.flexidev.ru SERVICE_URL=//it-radio.flexidev.ru
SERVICE_URL_AUDIO=//82.97.242.49:10084 SERVICE_URL_AUDIO=//azuracast.itradio.team
SERVICE_PROTOCOL=http SERVICE_PROTOCOL=http
SERVICE_PORT=8000 SERVICE_PORT=8000
SERVICE_API=/api SERVICE_API=/api

View File

@ -7,12 +7,14 @@ module.exports = {
parserOptions: { parserOptions: {
parser: '@babel/eslint-parser', parser: '@babel/eslint-parser',
ecmaVersion: 2021, // Allows for the parsing of modern ECMAScript features ecmaVersion: 2021, // Allows for the parsing of modern ECMAScript features
sourceType: 'module' // Allows for the use of imports sourceType: 'module', // Allows for the use of imports
requireConfigFile: false,
// babelOptions: { configFile: './babel.config.cjs' },
}, },
env: { env: {
browser: true, browser: true,
'vue/setup-compiler-macros': true 'vue/setup-compiler-macros': true,
}, },
// Rules order is important, please avoid shuffling them // Rules order is important, please avoid shuffling them
@ -30,14 +32,13 @@ module.exports = {
// 'plugin:vue/vue3-recommended', // Priority C: Recommended (Minimizing Arbitrary Choices and Cognitive Overhead) // 'plugin:vue/vue3-recommended', // Priority C: Recommended (Minimizing Arbitrary Choices and Cognitive Overhead)
// 'standard' // 'standard'
'plugin:prettier/recommended',
], ],
plugins: [ plugins: [
// https://eslint.vuejs.org/user-guide/#why-doesn-t-it-work-on-vue-files // https://eslint.vuejs.org/user-guide/#why-doesn-t-it-work-on-vue-files
// required to lint *.vue files // required to lint *.vue files
'vue', 'vue',
], ],
globals: { globals: {
@ -50,12 +51,11 @@ module.exports = {
__QUASAR_SSR_PWA__: 'readonly', __QUASAR_SSR_PWA__: 'readonly',
process: 'readonly', process: 'readonly',
Capacitor: 'readonly', Capacitor: 'readonly',
chrome: 'readonly' chrome: 'readonly',
}, },
// add your custom rules here // add your custom rules here
rules: { rules: {
// allow async-await // allow async-await
'generator-star-spacing': 'off', 'generator-star-spacing': 'off',
// allow paren-less arrow functions // allow paren-less arrow functions
@ -72,7 +72,7 @@ module.exports = {
'import/extensions': 'off', 'import/extensions': 'off',
'import/no-unresolved': 'off', 'import/no-unresolved': 'off',
'import/no-extraneous-dependencies': 'off', 'import/no-extraneous-dependencies': 'off',
'prefer-promise-reject-errors': 'off', 'prefer-promise-reject-errors': 'off',
'no-multiple-template-root': 'off', 'no-multiple-template-root': 'off',
@ -82,6 +82,6 @@ module.exports = {
'vue/no-v-for-template-key': 'warn', 'vue/no-v-for-template-key': 'warn',
'vue/multi-word-component-names': 'off', 'vue/multi-word-component-names': 'off',
// allow debugger during development only // allow debugger during development only
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
} },
} };

3
client/.prettierrc.cjs Normal file
View File

@ -0,0 +1,3 @@
module.exports = {
singleQuote: true,
};

View File

@ -1,14 +1,14 @@
/* eslint-disable */ /* eslint-disable */
module.exports = api => { module.exports = (api) => {
return { return {
presets: [ presets: [
[ [
'@quasar/babel-preset-app', '@quasar/babel-preset-app',
api.caller(caller => caller && caller.target === 'node') api.caller((caller) => caller && caller.target === 'node')
? { targets: { node: 'current' } } ? { targets: { node: 'current' } }
: {} : {},
] ],
] ],
} };
} };

4569
client/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -7,6 +7,7 @@
"private": true, "private": true,
"scripts": { "scripts": {
"lint": "eslint --ext .js,.vue ./", "lint": "eslint --ext .js,.vue ./",
"lint:fix": "eslint --ext .js,.vue --fix ./",
"test": "echo \"No test specified\" && exit 0", "test": "echo \"No test specified\" && exit 0",
"serve": "npx cross-env NODE_ENV=development quasar dev", "serve": "npx cross-env NODE_ENV=development quasar dev",
"serve:ssr": "quasar dev -m ssr", "serve:ssr": "quasar dev -m ssr",
@ -37,12 +38,14 @@
}, },
"devDependencies": { "devDependencies": {
"@babel/eslint-parser": "^7.13.14", "@babel/eslint-parser": "^7.13.14",
"@quasar/app-webpack": "^3.0.0", "@quasar/app-webpack": "^3.13.2",
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
"eslint": "^8.10.0", "eslint": "^8.10.0",
"eslint-config-prettier": "^9.1.0",
"eslint-config-standard": "^17.0.0", "eslint-config-standard": "^17.0.0",
"eslint-plugin-import": "^2.19.1", "eslint-plugin-import": "^2.19.1",
"eslint-plugin-n": "^15.0.0", "eslint-plugin-n": "^15.0.0",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-promise": "^6.0.0", "eslint-plugin-promise": "^6.0.0",
"eslint-plugin-vue": "^9.0.0", "eslint-plugin-vue": "^9.0.0",
"eslint-webpack-plugin": "^3.1.1", "eslint-webpack-plugin": "^3.1.1",
@ -59,6 +62,7 @@
"postcss-nested": "^6.0.1", "postcss-nested": "^6.0.1",
"postcss-preset-env": "^9.2.0", "postcss-preset-env": "^9.2.0",
"postcss-simple-vars": "^7.0.1", "postcss-simple-vars": "^7.0.1",
"prettier": "^3.3.2",
"sass-loader": "^13.3.2", "sass-loader": "^13.3.2",
"vue-loader": "^17.3.0" "vue-loader": "^17.3.0"
}, },

View File

@ -1,7 +1,9 @@
const path = require('path'); const path = require('path');
const webpack = require('webpack'); const webpack = require('webpack');
const nodeExternals = require("webpack-node-externals"); const nodeExternals = require('webpack-node-externals');
const env = require('dotenv').config({ path: `.env.${process.env.NODE_ENV.toLowerCase()}` }).parsed; const env = require('dotenv').config({
path: `.env.${process.env.NODE_ENV.toLowerCase()}`,
}).parsed;
/* eslint-env node */ /* eslint-env node */
/* /*
@ -12,8 +14,8 @@ const env = require('dotenv').config({ path: `.env.${process.env.NODE_ENV.toLowe
// Configuration for your app // Configuration for your app
// https://v2.quasar.dev/quasar-cli-webpack/quasar-config-js // https://v2.quasar.dev/quasar-cli-webpack/quasar-config-js
const ESLintPlugin = require('eslint-webpack-plugin') const ESLintPlugin = require('eslint-webpack-plugin');
const { configure } = require('quasar/wrappers') const { configure } = require('quasar/wrappers');
module.exports = configure(function (ctx) { module.exports = configure(function (ctx) {
return { return {
// https://v2.quasar.dev/quasar-cli-webpack/supporting-ts // https://v2.quasar.dev/quasar-cli-webpack/supporting-ts
@ -47,7 +49,6 @@ module.exports = configure(function (ctx) {
// 'themify', // 'themify',
// 'line-awesome', // 'line-awesome',
// 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both! // 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both!
// 'roboto-font', // optional, you are not bound to it // 'roboto-font', // optional, you are not bound to it
// 'material-icons' // optional, you are not bound to it // 'material-icons' // optional, you are not bound to it
], ],
@ -56,7 +57,7 @@ module.exports = configure(function (ctx) {
build: { build: {
vueRouterMode: 'history', // available values: 'hash', 'history' vueRouterMode: 'history', // available values: 'hash', 'history'
env: { env: {
...process.env ...process.env,
}, },
// transpile: false, // transpile: false,
// publicPath: '/', // publicPath: '/',
@ -78,20 +79,22 @@ module.exports = configure(function (ctx) {
// https://v2.quasar.dev/quasar-cli-webpack/handling-webpack // https://v2.quasar.dev/quasar-cli-webpack/handling-webpack
// "chain" is a webpack-chain object https://github.com/neutrinojs/webpack-chain // "chain" is a webpack-chain object https://github.com/neutrinojs/webpack-chain
chainWebpack (chain) { chainWebpack(chain) {
chain.plugin('eslint-webpack-plugin') chain
.use(ESLintPlugin, [{ extensions: ['js', 'vue'] }]) .plugin('eslint-webpack-plugin')
// chain.plugin('normal-module-replacement').use( .use(ESLintPlugin, [{ extensions: ['js', 'vue'] }]);
// new webpack.NormalModuleReplacementPlugin(/settings$/, function(resource) { // chain.plugin('normal-module-replacement').use(
// resource.request = resource.request.replace(/settings$/, `settings/${process.env.NODE_ENV}`); // new webpack.NormalModuleReplacementPlugin(/settings$/, function(resource) {
// }) // resource.request = resource.request.replace(/settings$/, `settings/${process.env.NODE_ENV}`);
// ) // })
// )
// require = require('esm')(module); // require = require('esm')(module);
// const settings = require(`./src/settings`); // const settings = require(`./src/settings`);
// chain.plugin('robotstxt-webpack-plugin') // chain.plugin('robotstxt-webpack-plugin')
// .use(new RobotstxtPlugin(settings.robotsTxt)) // .use(new RobotstxtPlugin(settings.robotsTxt))
chain.module.rule('images') chain.module
.rule('images')
.test(/\.(png|jpe?g|gif|svg|webp|avif|ico)(\?.*)?$/) .test(/\.(png|jpe?g|gif|svg|webp|avif|ico)(\?.*)?$/)
.type('javascript/auto') .type('javascript/auto')
.use('url-loader') .use('url-loader')
@ -99,35 +102,36 @@ module.exports = configure(function (ctx) {
.options({ .options({
esModule: false, esModule: false,
limit: 16384, limit: 16384,
name: `assets/img/[name].[hash:8].[ext]` name: `assets/img/[name].[hash:8].[ext]`,
}) });
chain.module.rule('videos') chain.module
.test(/\.(mp4|webm|mov)(\?.*)?$/) .rule('videos')
.type('javascript/auto') .test(/\.(mp4|webm|mov)(\?.*)?$/)
.use('url-loader') .type('javascript/auto')
.loader('url-loader') .use('url-loader')
.options({ .loader('url-loader')
esModule: false, .options({
limit: 32768, esModule: false,
name: `assets/media/[name].[hash:8].[ext]` limit: 32768,
}) name: `assets/media/[name].[hash:8].[ext]`,
});
}, },
extendWebpack (cfg) { extendWebpack(cfg) {
cfg.resolve.alias = { cfg.resolve.alias = {
...cfg.resolve.alias, ...cfg.resolve.alias,
'@': path.resolve(__dirname, './src'), '@': path.resolve(__dirname, './src'),
}; };
}, },
devtool: 'source-map' devtool: 'source-map',
}, },
// Full list of options: https://v2.quasar.dev/quasar-cli-webpack/quasar-config-js#Property%3A-devServer // Full list of options: https://v2.quasar.dev/quasar-cli-webpack/quasar-config-js#Property%3A-devServer
devServer: { devServer: {
server: { server: {
type: 'http' type: 'http',
}, },
port: 5173, port: 5173,
open: false // opens browser window automatically open: false, // opens browser window automatically
}, },
// https://v2.quasar.dev/quasar-cli-webpack/quasar-config-js#Property%3A-framework // https://v2.quasar.dev/quasar-cli-webpack/quasar-config-js#Property%3A-framework
@ -145,7 +149,7 @@ module.exports = configure(function (ctx) {
// directives: [], // directives: [],
// Quasar plugins // Quasar plugins
plugins: ['Meta'] plugins: ['Meta'],
}, },
// animations: 'all', // --- includes all animations // animations: 'all', // --- includes all animations
@ -188,15 +192,16 @@ module.exports = configure(function (ctx) {
maxAge: 1000 * 60 * 60 * 24 * 30, maxAge: 1000 * 60 * 60 * 24 * 30,
// Tell browser when a file from the server should expire from cache (in ms) // Tell browser when a file from the server should expire from cache (in ms)
chainWebpackWebserver (chain) { chainWebpackWebserver(chain) {
chain.plugin('eslint-webpack-plugin') chain
.use(ESLintPlugin, [{ extensions: ['js'] }]) .plugin('eslint-webpack-plugin')
.use(ESLintPlugin, [{ extensions: ['js'] }]);
}, },
middlewares: [ middlewares: [
ctx.prod ? 'compression' : '', ctx.prod ? 'compression' : '',
'render' // keep this as last one 'render', // keep this as last one
] ],
}, },
// https://v2.quasar.dev/quasar-cli-webpack/developing-pwa/configuring-pwa // https://v2.quasar.dev/quasar-cli-webpack/developing-pwa/configuring-pwa
@ -207,9 +212,10 @@ module.exports = configure(function (ctx) {
// for the custom service worker ONLY (/src-pwa/custom-service-worker.[js|ts]) // for the custom service worker ONLY (/src-pwa/custom-service-worker.[js|ts])
// if using workbox in InjectManifest mode // if using workbox in InjectManifest mode
chainWebpackCustomSW (chain) { chainWebpackCustomSW(chain) {
chain.plugin('eslint-webpack-plugin') chain
.use(ESLintPlugin, [{ extensions: ['js'] }]) .plugin('eslint-webpack-plugin')
.use(ESLintPlugin, [{ extensions: ['js'] }]);
}, },
manifest: { manifest: {
@ -224,30 +230,30 @@ module.exports = configure(function (ctx) {
{ {
src: 'icons/icon-128x128.png', src: 'icons/icon-128x128.png',
sizes: '128x128', sizes: '128x128',
type: 'image/png' type: 'image/png',
}, },
{ {
src: 'icons/icon-192x192.png', src: 'icons/icon-192x192.png',
sizes: '192x192', sizes: '192x192',
type: 'image/png' type: 'image/png',
}, },
{ {
src: 'icons/icon-256x256.png', src: 'icons/icon-256x256.png',
sizes: '256x256', sizes: '256x256',
type: 'image/png' type: 'image/png',
}, },
{ {
src: 'icons/icon-384x384.png', src: 'icons/icon-384x384.png',
sizes: '384x384', sizes: '384x384',
type: 'image/png' type: 'image/png',
}, },
{ {
src: 'icons/icon-512x512.png', src: 'icons/icon-512x512.png',
sizes: '512x512', sizes: '512x512',
type: 'image/png' type: 'image/png',
} },
] ],
} },
}, },
// Full list of options: https://v2.quasar.dev/quasar-cli-webpack/developing-cordova-apps/configuring-cordova // Full list of options: https://v2.quasar.dev/quasar-cli-webpack/developing-cordova-apps/configuring-cordova
@ -257,7 +263,7 @@ module.exports = configure(function (ctx) {
// Full list of options: https://v2.quasar.dev/quasar-cli-webpack/developing-capacitor-apps/configuring-capacitor // Full list of options: https://v2.quasar.dev/quasar-cli-webpack/developing-capacitor-apps/configuring-capacitor
capacitor: { capacitor: {
hideSplashscreen: true hideSplashscreen: true,
}, },
// Full list of options: https://v2.quasar.dev/quasar-cli-webpack/developing-electron-apps/configuring-electron // Full list of options: https://v2.quasar.dev/quasar-cli-webpack/developing-electron-apps/configuring-electron
@ -266,13 +272,11 @@ module.exports = configure(function (ctx) {
packager: { packager: {
// https://github.com/electron-userland/electron-packager/blob/master/docs/api.md#options // https://github.com/electron-userland/electron-packager/blob/master/docs/api.md#options
// OS X / Mac App Store // OS X / Mac App Store
// appBundleId: '', // appBundleId: '',
// appCategoryType: '', // appCategoryType: '',
// osxSign: '', // osxSign: '',
// protocol: 'myapp://path', // protocol: 'myapp://path',
// Windows only // Windows only
// win32metadata: { ... } // win32metadata: { ... }
}, },
@ -280,21 +284,22 @@ module.exports = configure(function (ctx) {
builder: { builder: {
// https://www.electron.build/configuration/configuration // https://www.electron.build/configuration/configuration
appId: 'tugan' appId: 'tugan',
}, },
// "chain" is a webpack-chain object https://github.com/neutrinojs/webpack-chain // "chain" is a webpack-chain object https://github.com/neutrinojs/webpack-chain
chainWebpackMain (chain) { chainWebpackMain(chain) {
chain.plugin('eslint-webpack-plugin') chain
.use(ESLintPlugin, [{ extensions: ['js'] }]) .plugin('eslint-webpack-plugin')
.use(ESLintPlugin, [{ extensions: ['js'] }]);
}, },
chainWebpackPreload (chain) { chainWebpackPreload(chain) {
chain.plugin('eslint-webpack-plugin') chain
.use(ESLintPlugin, [{ extensions: ['js'] }]) .plugin('eslint-webpack-plugin')
} .use(ESLintPlugin, [{ extensions: ['js'] }]);
},
} },
} };
}) });

View File

@ -1,72 +1,79 @@
<template> <template>
<div class="app"> <div class="app">
<AppHeader/> <AppHeader />
<div class="app__block"> <div class="app__block">
<Page404 v-if="showErrorPage404"/> <Page404 v-if="showErrorPage404" />
<Page500 v-if="showErrorPage500"/> <Page500 v-if="showErrorPage500" />
<routerView v-else/> <routerView v-else />
</div>
<Player/>
<AppFooter/>
</div> </div>
<Authentication/> <Player />
<ChangingUser/> <AppFooter />
</div>
<Authentication />
<ChangingUser />
</template> </template>
<script> <script>
import Page404 from '@/views/Page404.vue'; import Page404 from '@/views/Page404.vue';
import Page500 from '@/views/Page500.vue'; import Page500 from '@/views/Page500.vue';
import AppHeader from "@/components/app-header.vue"; import AppHeader from '@/components/app-header.vue';
import AppFooter from "@/components/app-footer.vue"; import AppFooter from '@/components/app-footer.vue';
import Authentication from "@/components/modal/authentication.vue"; import Authentication from '@/components/modal/authentication.vue';
import Player from "@/components/player.vue"; import Player from '@/components/player.vue';
import ChangingUser from "@/components/modal/сhanging-user.vue"; import ChangingUser from '@/components/modal/сhanging-user.vue';
export default { export default {
async preFetch({store, currentRoute, previousRoute, redirect, ssrContext, urlPath, publicPath}) { async preFetch({
store,
currentRoute,
previousRoute,
redirect,
ssrContext,
urlPath,
publicPath,
}) {},
components: {
ChangingUser,
Player,
Authentication,
AppFooter,
AppHeader,
Page404,
Page500,
},
data() {
return {
showSidebarBlock: false,
};
},
computed: {
user() {
return this.$store.state.user;
}, },
components: { showErrorPage404() {
ChangingUser, return false;
Player, // return this.$store.state.showErrorPage?.response?.status === 404;
Authentication,
AppFooter,
AppHeader,
Page404,
Page500,
}, },
data() { showErrorPage500() {
return { return false;
showSidebarBlock: false, // return this.$store.state.showErrorPage?.response?.status === 500;
};
}, },
computed: { currentPlay() {
user() { return this.$store.state.currentPlay;
return this.$store.state.user;
},
showErrorPage404() {
return false
// return this.$store.state.showErrorPage?.response?.status === 404;
},
showErrorPage500() {
return false
// return this.$store.state.showErrorPage?.response?.status === 500;
},
currentPlay() {
return this.$store.state.currentPlay
},
}, },
watch: {}, },
created() { watch: {},
this.$store.dispatch('setCurrentPlay', {...this.currentPlay, isPlay: false}); created() {
this.$store.dispatch('setCurrentPlay', {
}, ...this.currentPlay,
mounted() { isPlay: false,
}, });
methods: { },
} mounted() {},
methods: {},
}; };
</script> </script>
<style> <style>
@import "swiper/swiper.css"; @import 'swiper/swiper.css';
@import "assets/css/index.scss"; @import 'assets/css/index.scss';
</style> </style>

View File

@ -1,5 +1,5 @@
import { boot } from 'quasar/wrappers' import { boot } from 'quasar/wrappers';
import axios from 'axios' import axios from 'axios';
// Be careful when using SSR for cross-request state pollution // Be careful when using SSR for cross-request state pollution
// due to creating a Singleton instance here; // due to creating a Singleton instance here;
@ -7,18 +7,18 @@ import axios from 'axios'
// good idea to move this instance creation inside of the // good idea to move this instance creation inside of the
// "export default () => {}" function below (which runs individually // "export default () => {}" function below (which runs individually
// for each client) // for each client)
const api = axios.create({ baseURL: 'https://api.example.com' }) const api = axios.create({ baseURL: 'https://api.example.com' });
export default boot(({ app }) => { export default boot(({ app }) => {
// for use inside Vue files (Options API) through this.$axios and this.$api // for use inside Vue files (Options API) through this.$axios and this.$api
app.config.globalProperties.$axios = axios app.config.globalProperties.$axios = axios;
// ^ ^ ^ this will allow you to use this.$axios (for Vue Options API form) // ^ ^ ^ this will allow you to use this.$axios (for Vue Options API form)
// so you won't necessarily have to import axios in each vue file // so you won't necessarily have to import axios in each vue file
app.config.globalProperties.$api = api app.config.globalProperties.$api = api;
// ^ ^ ^ this will allow you to use this.$api (for Vue Options API form) // ^ ^ ^ this will allow you to use this.$api (for Vue Options API form)
// so you can easily perform requests against your app's API // so you can easily perform requests against your app's API
}) });
export { api } export { api };

View File

@ -1,6 +1,5 @@
import { boot } from 'quasar/wrappers' import { boot } from 'quasar/wrappers';
// "async" is optional; // "async" is optional;
// more info on params: https://v2.quasar.dev/quasar-cli/boot-files // more info on params: https://v2.quasar.dev/quasar-cli/boot-files
export default boot(async ({ app, router }) => { export default boot(async ({ app, router }) => {});
})

View File

@ -1,83 +1,81 @@
import { boot } from 'quasar/wrappers' import { boot } from 'quasar/wrappers';
import helpers from '@/utils/helpers' import helpers from '@/utils/helpers';
import VueScrollmagic from 'scrollmagic' import VueScrollmagic from 'scrollmagic';
import 'vue-final-modal/style.css' import 'vue-final-modal/style.css';
import { VueFinalModal } from 'vue-final-modal' import { VueFinalModal } from 'vue-final-modal';
import {plugin, defaultConfig, createInput} from '@formkit/vue' import { plugin, defaultConfig, createInput } from '@formkit/vue';
import { ru } from '@formkit/i18n' import { ru } from '@formkit/i18n';
import maskaInput from '@/components/inputs/maska-input'; import maskaInput from '@/components/inputs/maska-input';
import toggle from '@/components/inputs/toggle'; import toggle from '@/components/inputs/toggle';
import { vMaska } from 'maska' import { vMaska } from 'maska';
export default boot(async ({ app, router }) => { export default boot(async ({ app, router }) => {
app.config.globalProperties.$router = router app.config.globalProperties.$router = router;
app.use(helpers); app.use(helpers);
app.scrollMagic = VueScrollmagic; app.scrollMagic = VueScrollmagic;
app.component('VueFinalModal', VueFinalModal); app.component('VueFinalModal', VueFinalModal);
app.config.globalProperties.$scrollMagic = VueScrollmagic app.config.globalProperties.$scrollMagic = VueScrollmagic;
app.directive('Maska', vMaska); app.directive('Maska', vMaska);
const confFormKit = {
locales: { ru },
locale: 'ru',
config: {
validationVisibility: 'submit',
classes: {
outer: '$reset field',
wrapper: '$reset field__inner',
label: '$reset field__label',
help: '$reset field__help',
inner: '$reset field__input',
input: '$reset input',
messages: '$reset field__comment',
message: '$reset field__comment-item',
legend: '$reset field__legend',
fieldset: '$reset field__fieldset',
options: '$reset field__options',
option: '$reset field__option',
decorator: '$reset field__decorator'
},
},
messages: {
ru: {
// validation: {
// date_after({ name, args }) {
// if (args[1] === true) return `${name} должна быть в будущем.`;
// if (Array.isArray(args) && args.length) {
// return `${name} должна быть позже ${new Intl.DateTimeFormat(undefined, { year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric' }).format(typeof args[0] === 'string' ? new Date(Date.parse(args[0])) : args[0]) }`;
// }
// return `${name} должна быть в будущем.`;
// },
// date_before({ name, args }) {
// if (Array.isArray(args) && args.length) {
// return `${name} должна быть раньше ${new Intl.DateTimeFormat(undefined, { year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric' }).format(typeof args[0] === 'string' ? new Date(Date.parse(args[0])) : args[0]) }`;
// }
// return `${name} должна быть в прошлом.`;
// },
// },
}
},
inputs: {
// datepicker: createInput(datePickerInput, {
// props: ['mode'],
// }),
// select: createInput(multiselectInput, {
// props: ['options', 'placeholder', 'mode', 'searchable'],
// }),
// multiselect: createInput(multiselectInput, {
// props: ['options', 'placeholder', 'mode', 'searchable'],
// }),
maska: createInput(maskaInput, {
props: ['maska', 'placeholder', 'disabled', 'readonly'],
}),
toggle: createInput(toggle, {
props: ['placeholder', 'disabled', 'readonly'],
emits: ['toggle']
}),
},
};
app.use(plugin, defaultConfig(confFormKit));
})
const confFormKit = {
locales: { ru },
locale: 'ru',
config: {
validationVisibility: 'submit',
classes: {
outer: '$reset field',
wrapper: '$reset field__inner',
label: '$reset field__label',
help: '$reset field__help',
inner: '$reset field__input',
input: '$reset input',
messages: '$reset field__comment',
message: '$reset field__comment-item',
legend: '$reset field__legend',
fieldset: '$reset field__fieldset',
options: '$reset field__options',
option: '$reset field__option',
decorator: '$reset field__decorator',
},
},
messages: {
ru: {
// validation: {
// date_after({ name, args }) {
// if (args[1] === true) return `${name} должна быть в будущем.`;
// if (Array.isArray(args) && args.length) {
// return `${name} должна быть позже ${new Intl.DateTimeFormat(undefined, { year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric' }).format(typeof args[0] === 'string' ? new Date(Date.parse(args[0])) : args[0]) }`;
// }
// return `${name} должна быть в будущем.`;
// },
// date_before({ name, args }) {
// if (Array.isArray(args) && args.length) {
// return `${name} должна быть раньше ${new Intl.DateTimeFormat(undefined, { year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric' }).format(typeof args[0] === 'string' ? new Date(Date.parse(args[0])) : args[0]) }`;
// }
// return `${name} должна быть в прошлом.`;
// },
// },
},
},
inputs: {
// datepicker: createInput(datePickerInput, {
// props: ['mode'],
// }),
// select: createInput(multiselectInput, {
// props: ['options', 'placeholder', 'mode', 'searchable'],
// }),
// multiselect: createInput(multiselectInput, {
// props: ['options', 'placeholder', 'mode', 'searchable'],
// }),
maska: createInput(maskaInput, {
props: ['maska', 'placeholder', 'disabled', 'readonly'],
}),
toggle: createInput(toggle, {
props: ['placeholder', 'disabled', 'readonly'],
emits: ['toggle'],
}),
},
};
app.use(plugin, defaultConfig(confFormKit));
});

View File

@ -1,8 +1,15 @@
import { boot } from 'quasar/wrappers' import { boot } from 'quasar/wrappers';
// "async" is optional; // "async" is optional;
// more info on params: https://v2.quasar.dev/quasar-cli/boot-files // more info on params: https://v2.quasar.dev/quasar-cli/boot-files
export default boot(async ({ store }) => { export default boot(async ({ store }) => {
// For Vuex // For Vuex
if (window.__INITIAL_STATE__) store.replaceState(Object.assign(store.state, { metaScheme: window.__INITIAL_STATE__.metaScheme, data: window.__INITIAL_STATE__.data, meta: window.__INITIAL_STATE__.meta })); if (window.__INITIAL_STATE__)
}) store.replaceState(
Object.assign(store.state, {
metaScheme: window.__INITIAL_STATE__.metaScheme,
data: window.__INITIAL_STATE__.data,
meta: window.__INITIAL_STATE__.meta,
}),
);
});

View File

@ -1,33 +1,31 @@
<template> <template>
<div class="app__breadcrumbs breadcrumbs"> <div class="app__breadcrumbs breadcrumbs">
<router-link <router-link
v-for="(item, key) in breadcrumbs" v-for="(item, key) in breadcrumbs"
:key="key" :key="key"
v-slot="{ href, navigate }" v-slot="{ href, navigate }"
:to="item.route" :to="item.route"
custom custom
> >
<div v-if="item.name" class="breadcrumbs__item"> <div v-if="item.name" class="breadcrumbs__item">
<a <a :href="href" class="breadcrumbs__item-link" @click="navigate">
:href="href" {{ item.name }}
class="breadcrumbs__item-link" </a>
@click="navigate" </div>
> </router-link>
{{ item.name }} </div>
</a>
</div>
</router-link>
</div>
</template> </template>
<script> <script>
export default { export default {
name: 'AppBreadcrumbs', name: 'AppBreadcrumbs',
props: { props: {
breadcrumbs: { breadcrumbs: {
type: Array, type: Array,
default() { return []; } default() {
}, return [];
} },
},
},
}; };
</script> </script>

View File

@ -1,126 +1,118 @@
<template> <template>
<div class="app__content footer"> <div class="app__content footer">
<div class="footer__top"> <div class="footer__top">
<h2 class="h2 m--white">Напишите нам</h2> <h2 class="h2 m--white">Напишите нам</h2>
<div class="footer__question"> <div class="footer__question">
<div class="text">Остались вопросы? Мы с радостью вам ответим!</div> <div class="text">Остались вопросы? Мы с радостью вам ответим!</div>
<button class="button m--white m--arrow footer__question-button">Написать</button> <button class="button m--white m--arrow footer__question-button">
</div> Написать
</div> </button>
<div class="footer__bottom"> </div>
<ul class="footer__menu">
<li
v-for="(item, key) in menu"
:key="key"
:class="['footer__menu-item', item.class]"
>
<router-link
:to="{ name: item.name, params: item.params }"
class="footer__menu-link"
>
{{ item.title }}
</router-link>
</li>
</ul>
<div class="footer__connection">
<ul class="footer__social">
<li
v-for="(item, key) in socialMenu"
:key="key"
:class="['footer__menu-item', item.class]"
>
<router-link
:to="item.link"
class="footer__menu-link"
>
{{ item.title }}
</router-link>
</li>
</ul>
<ul class="footer__connection">
<li class="footer__menu-item"
>
<router-link
to="#"
class="m--underline"
>
it@radio.org
</router-link>
</li>
<li class="footer__menu-item">
<router-link
to="#"
class="m--underline"
>
+7 (900) 000-01-12
</router-link>
</li>
</ul>
</div>
</div>
</div> </div>
<div class="footer__bottom">
<ul class="footer__menu">
<li
v-for="(item, key) in menu"
:key="key"
:class="['footer__menu-item', item.class]"
>
<router-link
:to="{ name: item.name, params: item.params }"
class="footer__menu-link"
>
{{ item.title }}
</router-link>
</li>
</ul>
<div class="footer__connection">
<ul class="footer__social">
<li
v-for="(item, key) in socialMenu"
:key="key"
:class="['footer__menu-item', item.class]"
>
<router-link :to="item.link" class="footer__menu-link">
{{ item.title }}
</router-link>
</li>
</ul>
<ul class="footer__connection">
<li class="footer__menu-item">
<router-link to="#" class="m--underline">
it@radio.org
</router-link>
</li>
<li class="footer__menu-item">
<router-link to="#" class="m--underline">
+7 (900) 000-01-12
</router-link>
</li>
</ul>
</div>
</div>
</div>
</template> </template>
<script> <script>
export default { export default {
name: 'AppFooter', name: 'AppFooter',
data() { data() {
return { return {
menu: [ menu: [
{ {
name: 'home', name: 'home',
role: 'all', role: 'all',
title: 'О нас' title: 'О нас',
}, },
{ {
name: 'support', name: 'support',
role: 'all', role: 'all',
title: 'Поддержка' title: 'Поддержка',
}, },
{ {
name: 'rubric', name: 'rubric',
role: 'all', role: 'all',
title: 'Программы' title: 'Программы',
}, },
{ {
name: 'playlists', name: 'playlists',
role: 'all', role: 'all',
title: 'Контакты' title: 'Контакты',
}, },
{ {
name: 'contacts', name: 'contacts',
role: 'all', role: 'all',
title: 'Блог' title: 'Блог',
}, },
{ {
name: 'contacts', name: 'contacts',
role: 'all', role: 'all',
title: 'Карьера' title: 'Карьера',
}, },
], ],
socialMenu: [ socialMenu: [
{ {
link: '#', link: '#',
role: 'all', role: 'all',
title: 'Telegram' title: 'Telegram',
}, },
{ {
link: '#', link: '#',
role: 'all', role: 'all',
title: 'VKontakte' title: 'VKontakte',
}, },
{ {
link: '#', link: '#',
role: 'all', role: 'all',
title: 'Instagram' title: 'Instagram',
}, },
{ {
link: '#', link: '#',
role: 'all', role: 'all',
title: 'YouTube' title: 'YouTube',
}, },
] ],
} };
} },
} };
</script> </script>

View File

@ -1,147 +1,159 @@
<template> <template>
<div class="header"> <div class="header">
<div class="app__content header__wrapper"> <div class="app__content header__wrapper">
<div class="header__logo" @click="next('home')"> <div class="header__logo" @click="next('home')">
<img src="@/assets/img/icon/logo.svg" alt="logo"/> <img src="@/assets/img/icon/logo.svg" alt="logo" />
</div> </div>
<ul class="header__menu" :class="showMenu&&'m--active'"> <ul class="header__menu" :class="showMenu && 'm--active'">
<li class="header__burger m--active m--menu" @click="handlerShowMenu"> <li class="header__burger m--active m--menu" @click="handlerShowMenu">
<span></span> <span></span>
</li> </li>
<li class="header__logo m--menu" @click="next('home')"> <li class="header__logo m--menu" @click="next('home')">
<img src="@/assets/img/icon/logo.svg" alt="logo"/> <img src="@/assets/img/icon/logo.svg" alt="logo" />
</li> </li>
<li <li
v-for="(item, key) in menu" v-for="(item, key) in menu"
:key="key" :key="key"
:class="['header__menu-item', item.class]" :class="['header__menu-item', item.class]"
> >
<router-link <router-link
v-if="!item.action" v-if="!item.action"
:to="{ name: item.name, params: item.params }" :to="{ name: item.name, params: item.params }"
class="header__menu-link" class="header__menu-link"
> >
{{ item.title }} {{ item.title }}
</router-link> </router-link>
<button v-else-if="item.title" class="button" :class="[item.icon, showAuthentication&&'m--active']" @click="handlerClick(item.action)">{{ item.title }}</button> <button
<button v-else class="header__menu-icon" :class="[item.icon]" @click="handlerClick(item.action)"></button> v-else-if="item.title"
</li> class="button"
</ul> :class="[item.icon, showAuthentication && 'm--active']"
<div class="header__burger" @click="handlerShowMenu"> @click="handlerClick(item.action)"
<span></span> >
</div> {{ item.title }}
<div v-if="showMenu" class="app__overlay" @click="handlerShowMenu"></div> </button>
</div> <button
</div> v-else
class="header__menu-icon"
:class="[item.icon]"
@click="handlerClick(item.action)"
></button>
</li>
</ul>
<div class="header__burger" @click="handlerShowMenu">
<span></span>
</div>
<div v-if="showMenu" class="app__overlay" @click="handlerShowMenu"></div>
</div>
</div>
</template> </template>
<script> <script>
export default { export default {
name: 'app-header', name: 'app-header',
props:{}, props: {},
data(){ data() {
return{ return {
menuList:[ menuList: [
{ {
name: 'about', name: 'about',
role: 'all', role: 'all',
title: 'О нас' title: 'О нас',
},
{
name: 'rubric',
role: 'all',
title: 'Рубрики'
},
{
name: 'playlists',
role: 'all',
title: 'Плейлист'
},
{
name: 'podcasts',
role: 'all',
title: 'Подкасты'
},
{
name: 'support',
role: 'all',
title: 'Поддержка'
},
{
name: 'contacts',
role: 'all',
title: 'Контакты'
},
{
name: 'home',
role: 'login',
action: 'login',
icon: 'm--arrow',
title: 'Войти',
class: 'header__btn'
},
{
name: 'profile',
role: 'auth',
icon: 'm--profile',
action: 'profile',
class:'m--tools'
},
{
name: 'exit',
role: 'auth',
icon: 'm--exit',
action: 'exit',
class:'m--tools'
},
],
showMenu: true,
}
},
watch:{
'$route':{
handler(to){
if (this.showMenu){
this.showMenu = false;
}
}
}
},
computed:{
user() {
return this.$store.state.user;
},
menu(){
return this.menuList.filter(item=>{
if (item.role==='all') return true
if (item.role==='auth' && this.user?.id) return !!this.user?.id
if (item.role==='login' && !this.user?.id) return !this.user?.id
return false
})
},
showAuthentication(){
return this.$store.state.showAuthModal
},
},
methods:{
handlerClick(methods){
if (methods==='login'){
this.$store.dispatch('setModal', {auth: true});
}
if (methods==='profile'){
this.next('profile')
}
if(methods==='exit'){
this.$store.dispatch('deathUser');
this.next('home')
}
}, },
next(name){ {
this.$router.push({name}) name: 'rubric',
role: 'all',
title: 'Рубрики',
}, },
handlerShowMenu(){ {
this.showMenu = !this.showMenu; name: 'playlists',
} role: 'all',
} title: 'Плейлист',
} },
{
name: 'podcasts',
role: 'all',
title: 'Подкасты',
},
{
name: 'support',
role: 'all',
title: 'Поддержка',
},
{
name: 'contacts',
role: 'all',
title: 'Контакты',
},
{
name: 'home',
role: 'login',
action: 'login',
icon: 'm--arrow',
title: 'Войти',
class: 'header__btn',
},
{
name: 'profile',
role: 'auth',
icon: 'm--profile',
action: 'profile',
class: 'm--tools',
},
{
name: 'exit',
role: 'auth',
icon: 'm--exit',
action: 'exit',
class: 'm--tools',
},
],
showMenu: true,
};
},
watch: {
$route: {
handler(to) {
if (this.showMenu) {
this.showMenu = false;
}
},
},
},
computed: {
user() {
return this.$store.state.user;
},
menu() {
return this.menuList.filter((item) => {
if (item.role === 'all') return true;
if (item.role === 'auth' && this.user?.id) return !!this.user?.id;
if (item.role === 'login' && !this.user?.id) return !this.user?.id;
return false;
});
},
showAuthentication() {
return this.$store.state.showAuthModal;
},
},
methods: {
handlerClick(methods) {
if (methods === 'login') {
this.$store.dispatch('setModal', { auth: true });
}
if (methods === 'profile') {
this.next('profile');
}
if (methods === 'exit') {
this.$store.dispatch('deathUser');
this.next('home');
}
},
next(name) {
this.$router.push({ name });
},
handlerShowMenu() {
this.showMenu = !this.showMenu;
},
},
};
</script> </script>

View File

@ -1,59 +1,61 @@
<template> <template>
<div class="blog"> <div class="blog">
<div class="blog__header"> <div class="blog__header">
<h2 class="h2 blog__header-title">Наш блог</h2> <h2 class="h2 blog__header-title">Наш блог</h2>
<button class="button m--arrow blog__header-btn">Смотреть все</button> <button class="button m--arrow blog__header-btn">Смотреть все</button>
</div>
<div class="blog__content">
<div class="blog__cover"></div>
<div class="blog__list">
<div class="blog__item" v-for="article in articles" :key="article.id">
<div class="blog__item-header">
<div class="blog__item-title">{{article.title}}</div>
<button class="button m--circle blog__item-btn"></button>
</div>
<div class="blog__info">
<div class="blog__info-item">Читать {{article.time}} минуты</div>
<div class="blog__info-item">{{article.data}}</div>
</div>
</div>
</div>
</div>
</div> </div>
<div class="blog__content">
<div class="blog__cover"></div>
<div class="blog__list">
<div class="blog__item" v-for="article in articles" :key="article.id">
<div class="blog__item-header">
<div class="blog__item-title">{{ article.title }}</div>
<button class="button m--circle blog__item-btn"></button>
</div>
<div class="blog__info">
<div class="blog__info-item">Читать {{ article.time }} минуты</div>
<div class="blog__info-item">{{ article.data }}</div>
</div>
</div>
</div>
</div>
</div>
</template> </template>
<script> <script>
export default { export default {
name: 'blog', name: 'blog',
data(){ data() {
return{ return {
articles:[ articles: [
{ {
id: 1, id: 1,
title:'Топ-10 самых популярных языков программирования в 2023 году', title: 'Топ-10 самых популярных языков программирования в 2023 году',
time: '2', time: '2',
data: '21 октября' data: '21 октября',
}, },
{ {
id: 2, id: 2,
title:'Искусственный интеллект меняет мир технологий: возможности и вызовы', title:
time: '2', 'Искусственный интеллект меняет мир технологий: возможности и вызовы',
data: '21 октября' time: '2',
}, data: '21 октября',
{ },
id: 3, {
title:'Как кибербезопасность становится ключевым фактором успеха в IT', id: 3,
time: '2', title:
data: '21 октября' 'Как кибербезопасность становится ключевым фактором успеха в IT',
}, time: '2',
{ data: '21 октября',
id: 4, },
title:'5 советов по выбору правильной технологии для вашего проекта', {
time: '2', id: 4,
data: '21 октября' title: '5 советов по выбору правильной технологии для вашего проекта',
} time: '2',
] data: '21 октября',
} },
} ],
} };
},
};
</script> </script>

View File

@ -1,25 +1,25 @@
<template> <template>
<input <input
v-maska v-maska
class="input" class="input"
:data-maska="props.context.maska?.mask" :data-maska="props.context.maska?.mask"
:data-maska-tokens="props.context.maska?.tokens" :data-maska-tokens="props.context.maska?.tokens"
:value="props.context._value" :value="props.context._value"
:disabled="disabled" :disabled="disabled"
:readonly="readonly" :readonly="readonly"
type="text" type="text"
:placeholder="placeholder" :placeholder="placeholder"
@maska="handleMaska" @maska="handleMaska"
> />
</template> </template>
<script setup> <script setup>
import { defineProps, ref, onUpdated, computed } from 'vue'; import { defineProps, ref, onUpdated, computed } from 'vue';
const props = defineProps({ const props = defineProps({
context: { context: {
type: Object, type: Object,
default: () => {} default: () => {},
} },
}); });
const maska = props.context.maska; const maska = props.context.maska;
@ -29,7 +29,7 @@ const readonly = props.context.readonly || false;
//const required = props.context.validatin === 'required' && 'required'; //const required = props.context.validatin === 'required' && 'required';
function handleMaska($event) { function handleMaska($event) {
//console.log('handleInput', $event.target.disabled) //console.log('handleInput', $event.target.disabled)
props.context.node.input($event.target.value) props.context.node.input($event.target.value);
} }
</script> </script>

View File

@ -1,42 +1,39 @@
<template> <template>
<input <input
class="input field__checkbox-input" class="input field__checkbox-input"
:id="context.id" :id="context.id"
:checked="context._value" :checked="context._value"
:disabled="disabled" :disabled="disabled"
:readonly="readonly" :readonly="readonly"
type="checkbox" type="checkbox"
@change="change" @change="change"
> />
<label class="field__checkbox-label" :for="context.id"> <label class="field__checkbox-label" :for="context.id">
{{ context.label }} {{ context.label }}
</label> </label>
</template> </template>
<script> <script>
import {defineProps, ref, onUpdated, computed} from 'vue'; import { defineProps, ref, onUpdated, computed } from 'vue';
export default { export default {
props: { props: {
context: { context: {
type: Object, type: Object,
default: () => { default: () => {},
}
}
}, },
data() { },
return { data() {
placeholder: this.context.placeholder || '', return {
disabled: this.context.disabled || false, placeholder: this.context.placeholder || '',
readonly: this.context.readonly || false, disabled: this.context.disabled || false,
} readonly: this.context.readonly || false,
};
},
methods: {
change() {
this.context.node.input(!this.context._value);
}, },
methods: { },
change() { };
this.context.node.input(!this.context._value);
}
}
}
</script> </script>

View File

@ -1,202 +1,203 @@
<template> <template>
<vue-final-modal <vue-final-modal
v-model="show" v-model="show"
class="modal__container" class="modal__container"
content-class="modal__block" content-class="modal__block"
content-transition="vfm-fade" content-transition="vfm-fade"
overlay-transition="vfm-fade" overlay-transition="vfm-fade"
:clickToClose="false" :clickToClose="false"
@click-outside="close()" @click-outside="close()"
> >
<button <button class="button modal__close" @click="close"></button>
class="button modal__close" <div class="authentication">
@click="close" <div class="authentication__tabs tabs">
> <button
</button> v-for="item in tabsItems"
<div class="authentication"> :key="`tab-${item.name}`"
<div class="authentication__tabs tabs"> class="tabs__item"
<button :class="currentTabsItem === item.name && 'is-active'"
v-for="item in tabsItems" @click.prevent="changeTab(item.name)"
:key="`tab-${item.name}`" >
class="tabs__item" {{ item.label }}
:class="currentTabsItem === item.name && 'is-active'" </button>
@click.prevent="changeTab(item.name)" </div>
> <template v-if="currentTabsItem === 'login'">
{{ item.label }} <FormKit
</button> v-model="formLogin"
</div> type="form"
<template v-if="currentTabsItem === 'login'"> data-loading="showLoaderSending"
<FormKit form-class="$reset registration__form form"
v-model="formLogin" submit-label="Войти"
type="form" :disabled="showLoaderSending"
data-loading="showLoaderSending" :loading="showLoaderSending ? true : undefined"
form-class="$reset registration__form form" :submit-attrs="{
submit-label="Войти" inputClass: '$reset button m--white m--w-100',
:disabled="showLoaderSending" wrapperClass: '$reset registration__form-submit form__submit',
:loading="showLoaderSending ? true : undefined" outerClass: '$reset',
:submit-attrs="{ }"
inputClass: '$reset button m--white m--w-100', @submit="submitHandler"
wrapperClass: '$reset registration__form-submit form__submit', @click-outside="close"
outerClass: '$reset', >
}" <FormKitSchema :schema="loginForm" />
@submit="submitHandler" </FormKit>
@click-outside="close" </template>
> <template v-else>
<FormKitSchema :schema="loginForm"/> <FormKit
</FormKit> v-model="formRegistration"
</template> type="form"
<template v-else> data-loading="showLoaderSending"
<FormKit form-class="$reset registration__form form"
v-model="formRegistration" submit-label="Войти"
type="form" :disabled="showLoaderSending"
data-loading="showLoaderSending" :loading="showLoaderSending ? true : undefined"
form-class="$reset registration__form form" :submit-attrs="{
submit-label="Войти" inputClass: '$reset button m--white m--w-100',
:disabled="showLoaderSending" wrapperClass: '$reset registration__form-submit form__submit',
:loading="showLoaderSending ? true : undefined" outerClass: '$reset',
:submit-attrs="{ }"
inputClass: '$reset button m--white m--w-100', @submit="submitHandler"
wrapperClass: '$reset registration__form-submit form__submit', >
outerClass: '$reset', <FormKitSchema :schema="registerForm" />
}" </FormKit>
@submit="submitHandler" </template>
> </div>
<FormKitSchema :schema="registerForm"/> </vue-final-modal>
</FormKit>
</template>
</div>
</vue-final-modal>
</template> </template>
<script> <script>
import {app} from "@/services"; import { app } from '@/services';
export default { export default {
name: 'authentication', name: 'authentication',
data() { data() {
return { return {
currentTabsItem: 'login', currentTabsItem: 'login',
tabsItems: [ tabsItems: [
{ {
label: 'Войти', label: 'Войти',
name: 'login' name: 'login',
}, },
{ {
label: 'Зарегистрироваться', label: 'Зарегистрироваться',
name: 'register' name: 'register',
}, },
], ],
formLogin: {}, formLogin: {},
formRegistration: {}, formRegistration: {},
registerForm: [ registerForm: [
{ {
$formkit: 'text', $formkit: 'text',
name: 'email', name: 'email',
label: 'Ваша почта', label: 'Ваша почта',
placeholder: 'Ваша почта', placeholder: 'Ваша почта',
validation: 'required', validation: 'required',
outerClass: 'field--required' outerClass: 'field--required',
}, },
{ {
$formkit: 'password', $formkit: 'password',
name: 'password', name: 'password',
label: 'придумайте пароль', label: 'придумайте пароль',
placeholder: 'Придумайте пароль', placeholder: 'Придумайте пароль',
validation: 'required', validation: 'required',
outerClass: 'field--required' outerClass: 'field--required',
}, },
{ {
$formkit: 'password', $formkit: 'password',
name: 'repeatPassword', name: 'repeatPassword',
label: 'Повторите пароль', label: 'Повторите пароль',
placeholder: 'Повторите пароль', placeholder: 'Повторите пароль',
validation: 'required', validation: 'required',
outerClass: 'field--required' outerClass: 'field--required',
} },
], ],
loginForm: [ loginForm: [
{ {
$formkit: 'text', $formkit: 'text',
name: 'email', name: 'email',
label: 'Почта', label: 'Почта',
placeholder: 'Почта', placeholder: 'Почта',
validation: 'required', validation: 'required',
outerClass: 'field--required' outerClass: 'field--required',
}, },
{ {
$formkit: 'password', $formkit: 'password',
name: 'password', name: 'password',
label: 'пароль', label: 'пароль',
placeholder: 'Пароль', placeholder: 'Пароль',
validation: 'required', validation: 'required',
outerClass: 'field--required' outerClass: 'field--required',
} },
], ],
showLoaderSending: false, showLoaderSending: false,
} };
}, },
computed: { computed: {
show() { show() {
return this.$store.state.modal.auth return this.$store.state.modal.auth;
} },
}, },
methods: { methods: {
changeTab(tab) { changeTab(tab) {
this.currentTabsItem = tab; this.currentTabsItem = tab;
}, },
submitHandler(data, node) { submitHandler(data, node) {
if (this.currentTabsItem === 'login') { if (this.currentTabsItem === 'login') {
app.loginUser(this.formLogin).then(res => { app
this.$store.dispatch('setToken', res); .loginUser(this.formLogin)
app.user().then(user => { .then((res) => {
this.$store.dispatch('setUser', user); this.$store.dispatch('setToken', res);
this.close(); app
this.next('profile'); .user()
}).catch(err => { .then((user) => {
console.log(err) this.$store.dispatch('setUser', user);
}) this.close();
}).catch(err => { this.next('profile');
node.setErrors( })
[err.detail], .catch((err) => {
err.error console.log(err);
) });
}) })
} else { .catch((err) => {
if (this.formRegistration.password === this.formRegistration.repeatPassword) { node.setErrors([err.detail], err.error);
app.createUser(this.formRegistration).then(res => { });
this.$store.dispatch('setToken', res); } else {
app.user().then(user => { if (
this.$store.dispatch('setUser', user); this.formRegistration.password ===
this.close(); this.formRegistration.repeatPassword
this.next('profile'); ) {
}).catch(err => { app
console.log(err) .createUser(this.formRegistration)
}) .then((res) => {
}).catch(err => { this.$store.dispatch('setToken', res);
node.setErrors( app
[err.detail], .user()
err.error .then((user) => {
) this.$store.dispatch('setUser', user);
console.log(err) this.close();
}) this.next('profile');
} else { })
node.setErrors( .catch((err) => {
['Пароли не совпадают'], console.log(err);
{ });
password: '', })
repeatPassword: '', .catch((err) => {
} node.setErrors([err.detail], err.error);
) console.log(err);
} });
} } else {
node.setErrors(['Пароли не совпадают'], {
}, password: '',
close() { repeatPassword: '',
this.$store.dispatch('setModal', {auth: false}); });
}, }
next(name) { }
this.$router.push({name}); },
} close() {
} this.$store.dispatch('setModal', { auth: false });
} },
next(name) {
this.$router.push({ name });
},
},
};
</script> </script>

View File

@ -1,97 +1,100 @@
<template> <template>
<vue-final-modal <vue-final-modal
v-model="show" v-model="show"
class="modal__container m--right" class="modal__container m--right"
content-class="modal__block m--half rubric-modal" content-class="modal__block m--half rubric-modal"
content-transition="vfm-fade" content-transition="vfm-fade"
overlay-transition="vfm-fade" overlay-transition="vfm-fade"
:clickToClose="false" :clickToClose="false"
@click-outside="$emit('hideModal')" @click-outside="$emit('hideModal')"
> >
<template v-if="showLoader"> <template v-if="showLoader">
<div class="loader"> <div class="loader">
<div class="spinner"/> <div class="spinner" />
Загрузка данных Загрузка данных
</div> </div>
</template> </template>
<template v-else> <template v-else>
<div class="rubric-modal__header"> <div class="rubric-modal__header">
<div class="title m--white rubric-modal__title"> <div class="title m--white rubric-modal__title">
{{rubrik.name}} {{ rubrik.name }}
</div> </div>
<button <button
class="button modal__close rubric-modal__close" class="button modal__close rubric-modal__close"
@click="$emit('hideModal')" @click="$emit('hideModal')"
> ></button>
</button> </div>
</div> <div class="rubric-modal__cover">
<div class="rubric-modal__cover"> <img :src="`${selfUrl}${rubrik.img}`" alt="" />
<img :src="`${selfUrl}${rubrik.img}`" alt=""/> </div>
</div> <div class="rubric-modal__description">
<div class="rubric-modal__description"> {{ rubrik.description }}
{{rubrik.description}} </div>
</div> <button class="button m--fit-content m--white m--arrow" v-if="user?.id">
<button class="button m--fit-content m--white m--arrow" v-if="user?.id">Написать</button> Написать
</template> </button>
</vue-final-modal> </template>
</vue-final-modal>
</template> </template>
<script> <script>
import {app} from "@/services"; import { app } from '@/services';
import {selfUrl} from '@/settings'; import { selfUrl } from '@/settings';
export default { export default {
name: 'RubricModal', name: 'RubricModal',
props: { props: {
showModal: { showModal: {
type: Boolean, type: Boolean,
default() { default() {
return false; return false;
} },
}, },
selectRubric: { selectRubric: {
type: String, type: String,
default() { default() {
return ''; return '';
} },
}, },
}, },
data() { data() {
return { return {
selfUrl, selfUrl,
rubrik: {}, rubrik: {},
showLoader: false showLoader: false,
} };
}, },
computed: { computed: {
show() { show() {
return this.showModal; return this.showModal;
}, },
user() { user() {
return this.$store.state.user; return this.$store.state.user;
}, },
}, },
watch: { watch: {
'selectRubric': { selectRubric: {
handler() { handler() {
if (this.selectRubric){ if (this.selectRubric) {
this.getRubrik(); this.getRubrik();
} }
} },
} },
}, },
methods: { methods: {
getRubrik() { getRubrik() {
this.showLoader = true; this.showLoader = true;
app.getRubrik(this.selectRubric).then((data) => { app
this.showLoader = false; .getRubrik(this.selectRubric)
this.rubrik = data[0]; .then((data) => {
}).catch(err => { this.showLoader = false;
this.showLoader = false; this.rubrik = data[0];
console.log(err) })
}) .catch((err) => {
}, this.showLoader = false;
} console.log(err);
} });
},
},
};
</script> </script>

View File

@ -1,109 +1,105 @@
<template> <template>
<vue-final-modal <vue-final-modal
v-model="show" v-model="show"
class="modal__container" class="modal__container"
content-class="modal__block" content-class="modal__block"
content-transition="vfm-fade" content-transition="vfm-fade"
overlay-transition="vfm-fade" overlay-transition="vfm-fade"
:clickToClose="false" :clickToClose="false"
@click-outside="close()" @click-outside="close()"
> >
<button <button class="button modal__close" @click="close"></button>
class="button modal__close" <div class="modal__content">
@click="close" <div class="modal__title">Изменение данных</div>
> <FormKit
</button> v-model="formData"
<div class="modal__content"> type="form"
<div class="modal__title">Изменение данных</div> data-loading="showLoaderSending"
<FormKit form-class="$reset registration__form form"
v-model="formData" submit-label="Войти"
type="form" :disabled="showLoaderSending"
data-loading="showLoaderSending" :loading="showLoaderSending ? true : undefined"
form-class="$reset registration__form form" :submit-attrs="{
submit-label="Войти" inputClass: '$reset button m--white m--w-100',
:disabled="showLoaderSending" wrapperClass: '$reset registration__form-submit form__submit',
:loading="showLoaderSending ? true : undefined" outerClass: '$reset',
:submit-attrs="{ }"
inputClass: '$reset button m--white m--w-100', @submit="submitHandler"
wrapperClass: '$reset registration__form-submit form__submit', >
outerClass: '$reset', <FormKitSchema :schema="userForm" />
}" </FormKit>
@submit="submitHandler" </div>
> </vue-final-modal>
<FormKitSchema :schema="userForm"/>
</FormKit>
</div>
</vue-final-modal>
</template> </template>
<script> <script>
import {app} from "@/services"; import { app } from '@/services';
export default { export default {
name: 'recovery', name: 'recovery',
data(){ data() {
return{ return {
userForm:[ userForm: [
{ {
$formkit: 'text', $formkit: 'text',
name: 'email', name: 'email',
label: 'Ваша почта', label: 'Ваша почта',
placeholder: 'Ваша почта', placeholder: 'Ваша почта',
validation: 'required', validation: 'required',
outerClass: 'field--required' outerClass: 'field--required',
}, },
{ {
$formkit: 'password', $formkit: 'password',
name: 'old_password', name: 'old_password',
label: 'Введите старый пароль', label: 'Введите старый пароль',
placeholder: 'Введите старый пароль', placeholder: 'Введите старый пароль',
validation: 'required', validation: 'required',
outerClass: 'field--required' outerClass: 'field--required',
}, },
{ {
$formkit: 'password', $formkit: 'password',
name: 'password', name: 'password',
label: 'Введите новый пароль', label: 'Введите новый пароль',
placeholder: 'Введите новый пароль', placeholder: 'Введите новый пароль',
validation: 'required', validation: 'required',
outerClass: 'field--required' outerClass: 'field--required',
} },
], ],
formData: {}, formData: {},
showLoaderSending: false, showLoaderSending: false,
} };
}, },
computed: { computed: {
user() { user() {
return this.$store.state.user; return this.$store.state.user;
}, },
show(){ show() {
return this.$store.state.modal.changingUser; return this.$store.state.modal.changingUser;
} },
}, },
mounted() { mounted() {
this.formData.email = this.user.email; this.formData.email = this.user?.email;
}, },
methods:{ methods: {
submitHandler(data, node){ submitHandler(data, node) {
this.showLoaderSending = true; this.showLoaderSending = true;
app.updateUser(this.formData).then(user=>{ app
this.showLoaderSending = false; .updateUser(this.formData)
this.$store.dispatch('setUser', user); .then((user) => {
}).catch(err=>{ this.showLoaderSending = false;
this.showLoaderSending = false; this.$store.dispatch('setUser', user);
node.setErrors( })
[err.detail], .catch((err) => {
err.error this.showLoaderSending = false;
) node.setErrors([err.detail], err.error);
}) });
}, },
close() { close() {
this.$store.dispatch('setModal', {changingUser: false}); this.$store.dispatch('setModal', { changingUser: false });
}, },
next(name){ next(name) {
this.$router.push({name}); this.$router.push({ name });
} },
} },
} };
</script> </script>

View File

@ -1,123 +1,142 @@
<template> <template>
<div <div v-if="total && false" class="pagination">
v-if="total && false" <router-link
class="pagination" class="pagination__btn m--prev"
:to="{
path: url,
query: Object.assign({}, query, { page: goPrev }),
hash: hash,
}"
> >
<router-link class="pagination__btn m--prev" </router-link>
:to="{ path: url, query: Object.assign({}, query, { page: goPrev }), hash: hash }" <ul class="pagination__list">
<li v-for="page in pagesArray" :key="`page-${page.value}`">
<router-link
class="pagination__link"
:class="[page.value === currentPage && 'm--current']"
:to="{
path: url,
query: Object.assign({}, query, { page: page.value }),
hash: hash,
}"
:event="page.value ? 'click' : ''"
> >
{{ page.text }}
</router-link> </router-link>
<ul class="pagination__list"> </li>
<li </ul>
v-for="page in pagesArray" <router-link
:key="`page-${page.value}`" class="pagination__btn m--next"
> :to="{
<router-link path: url,
class="pagination__link" query: Object.assign({}, query, { page: goForward }),
:class="[page.value === currentPage && 'm--current']" hash: hash,
:to="{ path: url, query: Object.assign({}, query, { page: page.value }), hash: hash }" }"
:event="page.value ? 'click' : ''" >
> </router-link>
{{ page.text }} </div>
</router-link>
</li>
</ul>
<router-link class="pagination__btn m--next"
:to="{ path: url, query: Object.assign({}, query, { page: goForward }), hash: hash }"
>
</router-link>
</div>
</template> </template>
<script> <script>
export default { export default {
props: { props: {
total: { total: {
type: Number, type: Number,
default() { default() {
return 0; return 0;
} },
},
limit: {
type: Number,
default() {
return 10;
}
},
currentPage: {
type: Number,
default() {
return 1;
}
},
query: {
type: Object,
default() {
return {};
}
},
hash: {
type: String,
default() {
return '';
}
},
url: {
type: String,
default() {
return '';
}
}
}, },
data() { limit: {
return {} type: Number,
default() {
return 10;
},
}, },
computed: { currentPage: {
step() { type: Number,
return 1 default() {
}, return 1;
pages() { },
const pagesCount = Math.ceil(this.total / this.limit);
return this.$helpers.range(1, pagesCount || 1);
},
pagesArray() {
const count = Math.ceil(this.total / this.limit);
let items = [];
[...Array(count).keys()].map(i => i + 1).forEach(item => {
if (count <= 4) {
items.push({text: item, value: item});
} else {
if (item === 1 && this.currentPage !== item && this.currentPage - 1 !== 1 && this.currentPage - 2 !== 1) {
items.push({text: '1', value: 1});
items.push({text: '...', value: null});
} else if (item === count && this.currentPage + 1 !== count && this.currentPage + 2 !== count) {
items.push({text: '...', value: null});
items.push({text: count, value: count});
} else {
let deltaPrev = (count - this.currentPage <= 3) ? 3 : 2;
let deltaAfter = (this.currentPage <= 3) ? 4 - this.currentPage : 2;
if (item > this.currentPage - deltaPrev && item < this.currentPage + deltaAfter) {
console.log(item)
items.push({text: item, value: item});
}
}
}
});
return items
},
goForward() {
return `${this.currentPage + this.step}`
},
goPrev() {
return `${this.currentPage - this.step}`
},
}, },
mounted() { query: {
type: Object,
default() {
return {};
},
}, },
beforeDestroy() { hash: {
type: String,
default() {
return '';
},
}, },
created() { url: {
type: String,
default() {
return '';
},
}, },
methods: {}, },
data() {
return {};
},
computed: {
step() {
return 1;
},
pages() {
const pagesCount = Math.ceil(this.total / this.limit);
return this.$helpers.range(1, pagesCount || 1);
},
pagesArray() {
const count = Math.ceil(this.total / this.limit);
let items = [];
[...Array(count).keys()]
.map((i) => i + 1)
.forEach((item) => {
if (count <= 4) {
items.push({ text: item, value: item });
} else {
if (
item === 1 &&
this.currentPage !== item &&
this.currentPage - 1 !== 1 &&
this.currentPage - 2 !== 1
) {
items.push({ text: '1', value: 1 });
items.push({ text: '...', value: null });
} else if (
item === count &&
this.currentPage + 1 !== count &&
this.currentPage + 2 !== count
) {
items.push({ text: '...', value: null });
items.push({ text: count, value: count });
} else {
let deltaPrev = count - this.currentPage <= 3 ? 3 : 2;
let deltaAfter = this.currentPage <= 3 ? 4 - this.currentPage : 2;
if (
item > this.currentPage - deltaPrev &&
item < this.currentPage + deltaAfter
) {
console.log(item);
items.push({ text: item, value: item });
}
}
}
});
return items;
},
goForward() {
return `${this.currentPage + this.step}`;
},
goPrev() {
return `${this.currentPage - this.step}`;
},
},
mounted() {},
beforeDestroy() {},
created() {},
methods: {},
}; };
</script> </script>

View File

@ -1,318 +1,403 @@
<template> <template>
<div class="player"> <div class="player">
<div class="player__cover"> <div class="player__cover">
<q-skeleton v-if="loaderPlay" height="100%"/> <q-skeleton v-if="loaderPlay" height="100%" />
<img v-else :src="currentPlay.art" alt="player"/> <img v-else :src="currentPlay.art" alt="player" />
</div> </div>
<div class="player__content"> <div class="player__content">
<div class="player__top"> <div class="player__top">
<q-skeleton v-if="loaderPlay" type="circle" class="player__btn m--skeleton"/> <q-skeleton
<template v-else> v-if="loaderPlay"
<button v-if="currentPlay.isPlay" @click="handlerPause" class="button player__btn m--pause"> type="circle"
</button> class="player__btn m--skeleton"
<button v-else @click="handlerPlay" class="button player__btn m--play"> />
</button> <template v-else>
</template> <button
<div class="player__executor"> v-if="currentPlay.isPlay"
<q-skeleton v-if="loaderPlay" class="player__executor m--skeleton"/> @click="handlerPause"
<template v-else> class="button player__btn m--pause"
{{ currentPlay.title || '—' }} ></button>
</template> <button
<span> v-else
<q-skeleton v-if="loaderPlay"/> @click="handlerPlay"
<template v-else> class="button player__btn m--play"
{{ currentPlay.artist || '—' }} ></button>
</template> </template>
</span> <div class="player__executor">
</div> <q-skeleton v-if="loaderPlay" class="player__executor m--skeleton" />
<template v-if="user?.id"> <template v-else>
<q-skeleton v-if="loaderPlay" class="player__favorites m--skeleton"/> {{ currentPlay.title || '—' }}
<div v-else class="player__favorites" :class="[isFavorites&&'m--active']" @click="handlerFavorites"> </template>
</div> <span>
</template> <q-skeleton v-if="loaderPlay" />
<div class="player__tools"> <template v-else>
<q-skeleton v-if="loaderPlay" class="player__tools m--skeleton"/> {{ currentPlay.artist || '—' }}
<FormKit </template>
v-else </span>
v-model="isUserMusic" </div>
type="toggle" <template v-if="user?.id">
label="Включить мою музыку" <q-skeleton v-if="loaderPlay" class="player__favorites m--skeleton" />
:disabled="!user?.id || userSongList.length === 0" <div
/> v-else
<q-skeleton v-if="loaderPlay" class="player__tools m--skeleton"/> class="player__favorites"
<div v-else class="player__volume"> :class="[isFavorites && 'm--active']"
<span @click="changeVolume('set')"/> @click="handlerFavorites"
<input type="range" v-model="songVolume" @change="changeVolume"> ></div>
</div> </template>
</div> <div class="player__tools">
</div> <q-skeleton v-if="loaderPlay" class="player__tools m--skeleton" />
<div class="player__bottom"> <FormKit
<div class="player__time" :class="!loaderPlay&&!isUserMusic&&'m--ether'"> v-else
<q-skeleton v-if="loaderPlay"/> v-model="isUserMusic"
<template v-else-if="isUserMusic"> type="toggle"
{{ getTime(playerInfo.currentTime) }} / {{ getTime(playerInfo.duration) }} label="Включить мою музыку"
</template> :disabled="!user?.id || userSongList.length === 0"
<template v-else> />
Эфир <q-skeleton v-if="loaderPlay" class="player__tools m--skeleton" />
</template> <div v-else class="player__volume">
</div> <span @click="changeVolume('set')" />
<div class="player__progress"> <input type="range" v-model="songVolume" @change="changeVolume" />
<q-skeleton v-if="loaderPlay" height="5px"/> </div>
<input v-else :disabled="!isUserMusic" type="range" v-model="playerInfo.progress"> </div>
</div> </div>
</div> <div class="player__bottom">
</div> <div
</div> class="player__time"
:class="!loaderPlay && !isUserMusic && 'm--ether'"
>
<q-skeleton v-if="loaderPlay" />
<template v-else-if="isUserMusic">
{{ getTime(playerInfo.currentTime) }} /
{{ getTime(playerInfo.duration) }}
</template>
<template v-else> Эфир </template>
</div>
<div class="player__progress">
<q-skeleton v-if="loaderPlay" height="5px" />
<input
v-else
:disabled="!isUserMusic"
type="range"
v-model="playerInfo.progress"
/>
</div>
</div>
</div>
</div>
</template> </template>
<script> <script>
import {app, audio as Player} from "@/services"; import { app, audio as Player } from '@/services';
export default { export default {
name: 'player', name: 'player',
components: {}, components: {},
data() { data() {
return { return {
isFavorites: false, isFavorites: false,
isPlayRadio: false, isPlayRadio: false,
connection: null, connection: null,
isUserMusic: !this.$store.state.currentPlay.live, isUserMusic: !this.$store.state.currentPlay.live,
songVolume: this.$store.state.currentPlay.volume, songVolume: this.$store.state.currentPlay.volume,
playerInfo: { playerInfo: {
progress: 0, progress: 0,
currentTime: 0, currentTime: 0,
duration: 0 duration: 0,
}, },
} };
}, },
computed: { computed: {
user() { user() {
return this.$store.state.user; return this.$store.state.user;
}, },
currentPlay() { currentPlay() {
return this.$store.state.currentPlay return this.$store.state.currentPlay;
}, },
player() { player() {
return this.$store.state.player return this.$store.state.player;
}, },
userSongList() { userSongList() {
return this.$store.state.userFavorite?.songs || [] return this.$store.state.userFavorite?.songs || [];
}, },
loaderPlay() { loaderPlay() {
return this.$store.state.currentPlay.isLoader return this.$store.state.currentPlay.isLoader;
} },
}, },
watch: { watch: {
'currentPlay': { currentPlay: {
immediate: false, immediate: false,
handler(to, from) { handler(to, from) {
if (this.isUserMusic === this.currentPlay.live) { if (this.isUserMusic === this.currentPlay.live) {
this.isUserMusic = !this.currentPlay.live; this.isUserMusic = !this.currentPlay.live;
} }
if (this.user?.id && to.id !== from.id) { if (this.user?.id && to.id !== from.id) {
this.checkSongIsFavorite(); this.checkSongIsFavorite();
} }
if (!this.currentPlay.live && to.id !== from.id) { if (!this.currentPlay.live && to.id !== from.id) {
this.getAudio(this.currentPlay.azura_id); this.getAudio(this.currentPlay.azura_id);
} }
}, },
}, },
'userSongList': { userSongList: {
immediate: false, immediate: false,
handler(to, from) { handler(to, from) {
if (this.user?.id && to.length !== from.length) { if (this.user?.id && to.length !== from.length) {
this.checkSongIsFavorite(); this.checkSongIsFavorite();
} }
}, },
}, },
'isUserMusic': { isUserMusic: {
immediate: false, immediate: false,
handler() { handler() {
if (this.isUserMusic === this.currentPlay.live) { if (this.isUserMusic === this.currentPlay.live) {
this.changeLive(); this.changeLive();
} }
}, },
}, },
}, },
created() { created() {
this.connectionPlayer(); this.connectionPlayer();
}, },
mounted() { mounted() {
console.log(this.currentPlay) console.log(this.currentPlay);
this.$store.dispatch('initPlayer'); this.$store.dispatch('initPlayer');
if (this.user?.id) { if (this.user?.id) {
this.checkSongIsFavorite(); this.checkSongIsFavorite();
this.getSongList(); this.getSongList();
} }
this.playerInfo.progress = this.currentPlay.live ? 100 : 0; this.playerInfo.progress = this.currentPlay.live ? 100 : 0;
if (!this.currentPlay.live && this.userSongList?.length > 0) { if (!this.currentPlay.live && this.userSongList?.length > 0) {
this.$store.dispatch('setCurrentPlay', {...this.userSongList[this.currentPlay.currentIndex || 0], live: false}); this.$store.dispatch('setCurrentPlay', {
this.getAudio(this.userSongList[this.currentPlay.currentIndex || 0]?.azura_id); ...this.userSongList[this.currentPlay.currentIndex || 0],
if (this.player.target) { live: false,
this.player.target.addEventListener('timeupdate', this.updateProgress) });
} this.getAudio(
} this.userSongList[this.currentPlay.currentIndex || 0]?.azura_id,
if (!this.user?.id){ );
this.$store.dispatch('setCurrentPlay', {...this.currentPlay, live: true, isLoader: true, currentIndex: null}); if (this.player.target) {
} this.player.target.addEventListener('timeupdate', this.updateProgress);
}, }
methods: { }
connectionPlayer() { if (!this.user?.id) {
if (this.connection) { this.$store.dispatch('setCurrentPlay', {
this.connection.removePlay(); ...this.currentPlay,
} live: true,
this.connection = new Player(); isLoader: true,
this.connection.init(); currentIndex: null,
this.connection.onHandler(this.getPlaying); });
}, }
checkSongIsFavorite() { },
app.getCheckFavoriteSong(this.currentPlay.azura_id || this.currentPlay.id).then(res => { methods: {
this.isFavorites = res.is_favorite; connectionPlayer() {
}).catch(err => { if (this.connection) {
console.error(err) this.connection.removePlay();
}) }
}, this.connection = new Player();
removeFavorites(song) { this.connection.init();
app.removeFavorites(song).then(() => { this.connection.onHandler(this.getPlaying);
this.getSongList(); },
}).catch(err => { checkSongIsFavorite() {
this.showLoader = false; app
console.error(err) .getCheckFavoriteSong(this.currentPlay.azura_id || this.currentPlay.id)
}) .then((res) => {
}, this.isFavorites = res.is_favorite;
getPlaying(e) { })
const jsonData = JSON.parse(e.data) .catch((err) => {
if (jsonData?.pub?.data) { console.error(err);
const data = jsonData?.pub?.data; });
if (this.currentPlay.live) { },
if (data.np.station.listen_url !== this.player.target.src) { removeFavorites(song) {
console.log('data.np.station.listen_url', data.np.station.listen_url) app
this.$store.dispatch('changePlayer', data.np.station.listen_url); .removeFavorites(song)
const params = { .then(() => {
...this.currentPlay, this.getSongList();
...data.np.now_playing.song, })
azura_id: data.np.now_playing.song.id, .catch((err) => {
isLoader: false, this.showLoader = false;
live: true, console.error(err);
currentIndex: null });
} },
delete params.unique_id; getPlaying(e) {
this.$store.dispatch('setCurrentPlay', params); const jsonData = JSON.parse(e.data);
} if (jsonData?.pub?.data) {
} const data = jsonData?.pub?.data;
} if (this.currentPlay.live) {
}, if (data.np.station.listen_url !== this.player.target.src) {
updateProgress(e) { console.log(
this.playerInfo = { 'data.np.station.listen_url',
...this.playerInfo, data.np.station.listen_url,
progress: this.player.target.currentTime / this.player.target.duration * 100, );
currentTime: this.player.target.currentTime this.$store.dispatch('changePlayer', data.np.station.listen_url);
} const params = {
if (this.player.target.currentTime === this.player.target.duration){ ...this.currentPlay,
let currentIndex = this.currentPlay.currentIndex + 1; ...data.np.now_playing.song,
if (!this.userSongList[currentIndex]?.azura_id || currentIndex === null){ azura_id: data.np.now_playing.song.id,
currentIndex = 0; isLoader: false,
} live: true,
this.$store.dispatch('setCurrentPlay', {...this.currentPlay, ...this.userSongList[currentIndex], currentIndex}) currentIndex: null,
} };
}, delete params.unique_id;
handlerPlay() { this.$store.dispatch('setCurrentPlay', params);
console.log(this.currentPlay) }
console.log(this.player) }
this.$store.dispatch('handlerPlayer', {play: true}); }
}, },
handlerPause() { updateProgress(e) {
this.$store.dispatch('handlerPlayer', {pause: true}); this.playerInfo = {
}, ...this.playerInfo,
getSongList() { progress:
app.getFavoriteList().then(res => { (this.player.target.currentTime / this.player.target.duration) * 100,
this.$store.dispatch('setUserFavorite', {songs: res}) currentTime: this.player.target.currentTime,
console.log('res.length' ,res.length) };
if (res.length === 0){ if (this.player.target.currentTime === this.player.target.duration) {
this.$store.dispatch('setCurrentPlay', {...this.currentPlay, live: true, isLoader: true}); let currentIndex = this.currentPlay.currentIndex + 1;
} if (
}).catch(err => { !this.userSongList[currentIndex]?.azura_id ||
console.error(err) currentIndex === null
}) ) {
}, currentIndex = 0;
handlerFavorites() { }
if (this.user?.id) { this.$store.dispatch('setCurrentPlay', {
const params = {...this.currentPlay, azura_id: Number(this.currentPlay.id)?this.currentPlay.azura_id:this.currentPlay.id}; ...this.currentPlay,
if (!this.isFavorites) { ...this.userSongList[currentIndex],
delete params.id; currentIndex,
app.createFavoriteForUser(params).then(() => { });
this.isFavorites = !this.isFavorites; }
this.getSongList(); },
}).catch(err => { handlerPlay() {
console.error(err) console.log(this.currentPlay);
}) console.log(this.player);
} else { this.$store.dispatch('handlerPlayer', { play: true });
console.log(params) },
app.removeFavorites(params).then(()=>{ handlerPause() {
this.getSongList(); this.$store.dispatch('handlerPlayer', { pause: true });
}).catch(err=>{ },
console.error(err) getSongList() {
}) app
} .getFavoriteList()
} else { .then((res) => {
this.$emit('shopAuthentication', true) this.$store.dispatch('setUserFavorite', { songs: res });
} console.log('res.length', res.length);
if (res.length === 0) {
}, this.$store.dispatch('setCurrentPlay', {
changeVolume(type) { ...this.currentPlay,
let volume = this.songVolume; live: true,
if (type === 'set') { isLoader: true,
volume = this.songVolume === 0 ? 0.9 : 0.01; });
this.songVolume = this.songVolume === 0 ? 100 : 0; }
} else { })
volume = this.songVolume / 100; .catch((err) => {
} console.error(err);
if (volume === 0) volume = 0.01 });
this.$store.dispatch('handlerPlayer', {volume}); },
}, handlerFavorites() {
getAudio(id) { if (this.user?.id) {
app.getAudio(id).then(res => { const params = {
const blob = new Blob([res], {type: 'application/audio'}); ...this.currentPlay,
const audioUrl = URL.createObjectURL(blob); azura_id: Number(this.currentPlay.id)
this.$store.dispatch('changePlayer', audioUrl); ? this.currentPlay.azura_id
this.player.target.addEventListener('timeupdate', this.updateProgress); : this.currentPlay.id,
};
if (!this.isFavorites) {
blob.arrayBuffer().then(buffer => { delete params.id;
var audioContext = new (window.AudioContext || window.webkitAudioContext)(); app
audioContext.decodeAudioData(buffer, (decodedData) => { .createFavoriteForUser(params)
this.playerInfo.duration = decodedData.duration; .then(() => {
}); this.isFavorites = !this.isFavorites;
}); this.getSongList();
this.$store.dispatch('setCurrentPlay', {...this.currentPlay, isLoader: false}) })
}).catch(err => { .catch((err) => {
this.$store.dispatch('setCurrentPlay', {...this.currentPlay, isLoader: false}) console.error(err);
console.debug(err) });
}) } else {
}, console.log(params);
changeLive() { app
if (this.currentPlay.live) { .removeFavorites(params)
console.log('избранное') .then(() => {
this.playerInfo.progress = 0; this.getSongList();
const params = {...this.userSongList[this.currentPlay.currentIndex || 0], live: false, isLoader: true}; })
if (!this.currentPlay.currentIndex) params.currentIndex = 0; .catch((err) => {
this.$store.dispatch('setCurrentPlay', params); console.error(err);
} else { });
this.playerInfo.progress = 100; }
this.$store.dispatch('setCurrentPlay', {...this.currentPlay, live: true, isLoader: true}); } else {
console.log('поток') this.$emit('shopAuthentication', true);
} }
}, },
getTime(value) { changeVolume(type) {
let minutes = Math.floor(value / 60); let volume = this.songVolume;
let seconds = Math.round(value % 60); if (type === 'set') {
volume = this.songVolume === 0 ? 0.9 : 0.01;
let paddedMinutes = minutes < 10 ? "0" + minutes : minutes; this.songVolume = this.songVolume === 0 ? 100 : 0;
let paddedSeconds = seconds < 10 ? "0" + seconds : seconds; } else {
if (!paddedMinutes) paddedMinutes = '00'; volume = this.songVolume / 100;
if (!paddedSeconds) paddedSeconds = '00'; }
return `${paddedMinutes}:${paddedSeconds}`; if (volume === 0) volume = 0.01;
}, this.$store.dispatch('handlerPlayer', { volume });
} },
} getAudio(id) {
app
.getAudio(id)
.then((res) => {
const blob = new Blob([res], { type: 'application/audio' });
const audioUrl = URL.createObjectURL(blob);
this.$store.dispatch('changePlayer', audioUrl);
this.player.target.addEventListener(
'timeupdate',
this.updateProgress,
);
blob.arrayBuffer().then((buffer) => {
var audioContext = new (window.AudioContext ||
window.webkitAudioContext)();
audioContext.decodeAudioData(buffer, (decodedData) => {
this.playerInfo.duration = decodedData.duration;
});
});
this.$store.dispatch('setCurrentPlay', {
...this.currentPlay,
isLoader: false,
});
})
.catch((err) => {
this.$store.dispatch('setCurrentPlay', {
...this.currentPlay,
isLoader: false,
});
console.debug(err);
});
},
changeLive() {
if (this.currentPlay.live) {
console.log('избранное');
this.playerInfo.progress = 0;
const params = {
...this.userSongList[this.currentPlay.currentIndex || 0],
live: false,
isLoader: true,
};
if (!this.currentPlay.currentIndex) params.currentIndex = 0;
this.$store.dispatch('setCurrentPlay', params);
} else {
this.playerInfo.progress = 100;
this.$store.dispatch('setCurrentPlay', {
...this.currentPlay,
live: true,
isLoader: true,
});
console.log('поток');
}
},
getTime(value) {
let minutes = Math.floor(value / 60);
let seconds = Math.round(value % 60);
let paddedMinutes = minutes < 10 ? '0' + minutes : minutes;
let paddedSeconds = seconds < 10 ? '0' + seconds : seconds;
if (!paddedMinutes) paddedMinutes = '00';
if (!paddedSeconds) paddedSeconds = '00';
return `${paddedMinutes}:${paddedSeconds}`;
},
},
};
</script> </script>

View File

@ -1,27 +1,27 @@
<template> <template>
<div class="playlist-item" @click="selectPlaylist"> <div class="playlist-item" @click="selectPlaylist">
<div class="playlist-item__cover"></div> <div class="playlist-item__cover"></div>
<div>{{playlist.name}}</div> <div>{{ playlist.name }}</div>
<div @click="editPlaylist">...</div> <div @click="editPlaylist">...</div>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
name: 'playlist-item', name: 'playlist-item',
props:{ props: {
playlist:{ playlist: {
type: Object, type: Object,
default: () => {} default: () => {},
} },
}, },
methods:{ methods: {
editPlaylist(){ editPlaylist() {
this.$emit('editPlaylist', this.playlist) this.$emit('editPlaylist', this.playlist);
}, },
selectPlaylist(){ selectPlaylist() {
this.$emit('selectPlaylist', this.playlist) this.$emit('selectPlaylist', this.playlist);
} },
} },
} };
</script> </script>

View File

@ -1,41 +1,41 @@
<template> <template>
<div class="playlist-roster"> <div class="playlist-roster">
<PlaylistItem <PlaylistItem
v-for="item in list" v-for="item in list"
:key="`playlist_${item.id}`" :key="`playlist_${item.id}`"
:playlist="item" :playlist="item"
@selectPlaylist="selectPlaylist" @selectPlaylist="selectPlaylist"
@editPlaylist="editPlaylist" @editPlaylist="editPlaylist"
/> />
<div class="playlist-item m--create" @click="createPlaylist"> <div class="playlist-item m--create" @click="createPlaylist">
<div class="playlist-item__cover"></div> <div class="playlist-item__cover"></div>
<div>Создать плейлист</div> <div>Создать плейлист</div>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import PlaylistItem from "@/components/playlist-item.vue"; import PlaylistItem from '@/components/playlist-item.vue';
export default { export default {
name: 'playlist-roster', name: 'playlist-roster',
components: {PlaylistItem}, components: { PlaylistItem },
props: { props: {
list: { list: {
type: Array, type: Array,
default: () => [] default: () => [],
} },
}, },
methods: { methods: {
createPlaylist() { createPlaylist() {
this.$emit('createPlaylist') this.$emit('createPlaylist');
}, },
selectPlaylist(params) { selectPlaylist(params) {
this.$router.push({name: 'playlist', params: {id: params.id}}) this.$router.push({ name: 'playlist', params: { id: params.id } });
}, },
editPlaylist(params) { editPlaylist(params) {
this.$router.push({name: 'playlist-edit', params: {id: params.id}}) this.$router.push({ name: 'playlist-edit', params: { id: params.id } });
} },
} },
} };
</script> </script>

View File

@ -1,70 +1,93 @@
<template> <template>
<div class="rubric-block"> <div class="rubric-block">
<div class="rubric-block__header"> <div class="rubric-block__header">
<h2 class="h2 rubric-block__header-title"> <h2 class="h2 rubric-block__header-title">Рубрики</h2>
Рубрики <button
</h2> class="button m--arrow rubric-block__link"
<button class="button m--arrow rubric-block__link" v-if="$route.name !== 'rubric'" @click="next('rubric')">Смотреть все</button> v-if="$route.name !== 'rubric'"
<div class="p rubric-block__description"> @click="next('rubric')"
IT-радио - это уникальная платформа для обмена опытом, знаниями и обсуждения актуальных вопросов, связанных с разработкой программного обеспечения, искусственного интеллекта, интернета вещей и других направлений IT-индустрии >
</div> Смотреть все
</div> </button>
<template v-if="showLoader"> <div class="p rubric-block__description">
<div class="loader"> IT-радио - это уникальная платформа для обмена опытом, знаниями и
<div class="spinner"/> обсуждения актуальных вопросов, связанных с разработкой программного
Загрузка данных обеспечения, искусственного интеллекта, интернета вещей и других
</div> направлений IT-индустрии
</template> </div>
<div v-else class="rubric-block__list">
<div class="rubric-block__item" v-for="rubrik in rubriks" :key="`rubrik_${rubrik.id}`">
<div class="title rubric-block__title">{{rubrik.name}}</div>
<div class="p rubric-block__description m--50">{{rubrik.title}}</div>
<button class="button m--arrow rubric-block__btn" @click="showModalRubric(rubrik.id)">Узнать больше</button>
</div>
</div>
</div> </div>
<RubricModal :showModal="isShowModalRubric" @hideModal="hiddenModalRubric" :selectRubric="ModalTemplate"/> <template v-if="showLoader">
<div class="loader">
<div class="spinner" />
Загрузка данных
</div>
</template>
<div v-else class="rubric-block__list">
<div
class="rubric-block__item"
v-for="rubrik in rubriks"
:key="`rubrik_${rubrik.id}`"
>
<div class="title rubric-block__title">{{ rubrik.name }}</div>
<div class="p rubric-block__description m--50">{{ rubrik.title }}</div>
<button
class="button m--arrow rubric-block__btn"
@click="showModalRubric(rubrik.id)"
>
Узнать больше
</button>
</div>
</div>
</div>
<RubricModal
:showModal="isShowModalRubric"
@hideModal="hiddenModalRubric"
:selectRubric="ModalTemplate"
/>
</template> </template>
<script> <script>
import RubricModal from "@/components/modal/rubric-modal.vue"; import RubricModal from '@/components/modal/rubric-modal.vue';
import {app} from "@/services"; import { app } from '@/services';
export default { export default {
name: 'rubric-block', name: 'rubric-block',
components: {RubricModal}, components: { RubricModal },
data(){ data() {
return{ return {
isShowModalRubric: false, isShowModalRubric: false,
ModalTemplate:null, ModalTemplate: null,
rubriks: [], rubriks: [],
showLoader: false, showLoader: false,
} };
},
created() {
this.getRubriks();
},
methods: {
getRubriks() {
this.showLoader = true;
app
.getRubriks()
.then((data) => {
this.showLoader = false;
this.rubriks = data;
})
.catch((err) => {
this.showLoader = false;
console.log(err);
});
}, },
created() { showModalRubric(key) {
this.getRubriks(); this.ModalTemplate = key;
}, this.isShowModalRubric = true;
methods:{ },
getRubriks() { hiddenModalRubric() {
this.showLoader = true; this.isShowModalRubric = false;
app.getRubriks().then((data) => { },
this.showLoader = false; next(name) {
this.rubriks = data; this.$router.push({ name });
}).catch(err => { },
this.showLoader = false; },
console.log(err) };
})
},
showModalRubric(key){
this.ModalTemplate = key
this.isShowModalRubric = true;
},
hiddenModalRubric(){
this.isShowModalRubric = false;
},
next(name){
this.$router.push({name})
}
}
}
</script> </script>

View File

@ -1,92 +1,133 @@
<template> <template>
<div class="song-item" :class="[selectSong&&'m--select']" @click="handlerSelectSong"> <div
<div class="song-item__selected" :class="[!isPlay&&'m--stop']"> class="song-item"
<svg width="33" height="28" viewBox="0 0 33 28" fill="none" xmlns="http://www.w3.org/2000/svg"> :class="[selectSong && 'm--select']"
<path class="" d="M0 15C0 13.6193 1.11929 12.5 2.5 12.5C3.88071 12.5 5 13.6193 5 15V27.5H0V15Z" fill="#7138F4"/> @click="handlerSelectSong"
<path d="M7 9C7 7.61929 8.11929 6.5 9.5 6.5C10.8807 6.5 12 7.61929 12 9V27.5H7V9Z" fill="#7138F4"/> >
<path d="M14 12C14 10.6193 15.1193 9.5 16.5 9.5C17.8807 9.5 19 10.6193 19 12V27.5H14V12Z" fill="#7138F4"/> <div class="song-item__selected" :class="[!isPlay && 'm--stop']">
<path d="M21 3C21 1.61929 22.1193 0.5 23.5 0.5C24.8807 0.5 26 1.61929 26 3V27.5H21V3Z" fill="#7138F4"/> <svg
<path d="M28 20C28 18.6193 29.1193 17.5 30.5 17.5C31.8807 17.5 33 18.6193 33 20V27.5H28V20Z" fill="#7138F4"/> width="33"
</svg> height="28"
</div> viewBox="0 0 33 28"
<div> fill="none"
<button v-if="isPlay" @click.stop="handlerPause" class="button song-item__btn m--pause"> xmlns="http://www.w3.org/2000/svg"
</button> >
<button v-else @click.stop="handlerPlay" class="button song-item__btn m--play"> <path
</button> class=""
</div> d="M0 15C0 13.6193 1.11929 12.5 2.5 12.5C3.88071 12.5 5 13.6193 5 15V27.5H0V15Z"
<div class="song-item__info"> fill="#7138F4"
<span>{{song.title}}</span> />
{{song.artist}} <path
</div> d="M7 9C7 7.61929 8.11929 6.5 9.5 6.5C10.8807 6.5 12 7.61929 12 9V27.5H7V9Z"
<div class="song-item__tools"> fill="#7138F4"
<button class="button song-item__btn m--small m--favorites" @click.stop="removeSong"></button> />
<button class="button song-item__btn m--small m--add" :class="songAlreadyAddPlaylist&&'m--already'" @click.stop="songAlreadyAddPlaylist?removeToPlaylist():addPlaylist()"></button> <path
</div> d="M14 12C14 10.6193 15.1193 9.5 16.5 9.5C17.8807 9.5 19 10.6193 19 12V27.5H14V12Z"
</div> fill="#7138F4"
/>
<path
d="M21 3C21 1.61929 22.1193 0.5 23.5 0.5C24.8807 0.5 26 1.61929 26 3V27.5H21V3Z"
fill="#7138F4"
/>
<path
d="M28 20C28 18.6193 29.1193 17.5 30.5 17.5C31.8807 17.5 33 18.6193 33 20V27.5H28V20Z"
fill="#7138F4"
/>
</svg>
</div>
<div>
<button
v-if="isPlay"
@click.stop="handlerPause"
class="button song-item__btn m--pause"
></button>
<button
v-else
@click.stop="handlerPlay"
class="button song-item__btn m--play"
></button>
</div>
<div class="song-item__info">
<span>{{ song.title }}</span>
{{ song.artist }}
</div>
<div class="song-item__tools">
<button
class="button song-item__btn m--small m--favorites"
@click.stop="removeSong"
></button>
<button
class="button song-item__btn m--small m--add"
:class="songAlreadyAddPlaylist && 'm--already'"
@click.stop="
songAlreadyAddPlaylist ? removeToPlaylist() : addPlaylist()
"
></button>
</div>
</div>
</template> </template>
<script> <script>
export default { export default {
name: 'song-item', name: 'song-item',
props:{ props: {
selectSong:{ selectSong: {
type: Boolean, type: Boolean,
default(){ default() {
return false return false;
} },
}, },
song:{ song: {
type: Object, type: Object,
default(){ default() {
return {} return {};
} },
}, },
playSong:{ playSong: {
type: Boolean, type: Boolean,
default(){ default() {
return false return false;
} },
}, },
songAlreadyAddPlaylist:{ songAlreadyAddPlaylist: {
type: Boolean, type: Boolean,
default(){ default() {
return false return false;
} },
}, },
}, },
watch: { watch: {
'playSong': { playSong: {
immediate: true, immediate: true,
handler() { handler() {
this.isPlay = this.playSong; this.isPlay = this.playSong;
}, },
} },
}, },
data(){ data() {
return{ return {
isPlay: this.playSong isPlay: this.playSong,
} };
}, },
methods:{ methods: {
handlerPlay() { handlerPlay() {
this.$emit('playSong', {...this.song, live: false, isPlay: true,}) this.$emit('playSong', { ...this.song, live: false, isPlay: true });
}, },
handlerPause() { handlerPause() {
this.$emit('pauseSong', {...this.song, live: false, isPlay: false,}) this.$emit('pauseSong', { ...this.song, live: false, isPlay: false });
}, },
handlerSelectSong(){ handlerSelectSong() {
this.$emit('selectSong', {...this.song, live: false}) this.$emit('selectSong', { ...this.song, live: false });
}, },
removeSong(){ removeSong() {
this.$emit('removeSong', this.song); this.$emit('removeSong', this.song);
}, },
addPlaylist(){ addPlaylist() {
this.$emit('addPlaylist', this.song); this.$emit('addPlaylist', this.song);
}, },
removeToPlaylist(){ removeToPlaylist() {
this.$emit('removePlaylist', this.song); this.$emit('removePlaylist', this.song);
} },
} },
} };
</script> </script>

View File

@ -1,72 +1,76 @@
<template> <template>
<div class="song-list"> <div class="song-list">
<SongItem <SongItem
v-for="song in songList" v-for="song in songList"
:key="song" :key="song"
:song="song" :song="song"
:playSong="song.azura_id === currentPlay.azura_id? currentPlay.isPlay: false" :playSong="
:selectSong="song.azura_id === currentPlay.azura_id" song.azura_id === currentPlay.azura_id ? currentPlay.isPlay : false
:songAlreadyAddPlaylist="songAlreadyAdd" "
@selectSong="handlerSelectSong" :selectSong="song.azura_id === currentPlay.azura_id"
@playSong="handlerPlaySong" :songAlreadyAddPlaylist="songAlreadyAdd"
@pauseSong="handlerPauseSong" @selectSong="handlerSelectSong"
@removeSong="removeSong" @playSong="handlerPlaySong"
@addPlaylist="addPlaylist" @pauseSong="handlerPauseSong"
@removePlaylist="removePlaylist" @removeSong="removeSong"
/> @addPlaylist="addPlaylist"
</div> @removePlaylist="removePlaylist"
/>
</div>
</template> </template>
<script> <script>
import SongItem from "@/components/song-item.vue"; import SongItem from '@/components/song-item.vue';
export default { export default {
name: 'song-list', name: 'song-list',
components: {SongItem}, components: { SongItem },
props: { props: {
songList: { songList: {
type: Array, type: Array,
default: () => [] default: () => [],
}, },
songAlreadyAdd: { songAlreadyAdd: {
type: Boolean, type: Boolean,
default: () => false default: () => false,
} },
}, },
data() { data() {
return {} return {};
}, },
computed: { computed: {
currentPlay() { currentPlay() {
return this.$store.state.currentPlay return this.$store.state.currentPlay;
} },
}, },
methods: { methods: {
handlerSelectSong(params) { handlerSelectSong(params) {
const data = {...this.currentPlay, ...params, isLoader: true}; const data = { ...this.currentPlay, ...params, isLoader: true };
data.currentIndex = this.songList.findIndex(el=>el.azura_id === params.azura_id); data.currentIndex = this.songList.findIndex(
this.$store.dispatch('setCurrentPlay', data); (el) => el.azura_id === params.azura_id,
console.log('handlerSelectSong') );
}, this.$store.dispatch('setCurrentPlay', data);
handlerPlaySong(params) { console.log('handlerSelectSong');
this.$store.dispatch('setCurrentPlay', params); },
console.log('handlerPlaySong') handlerPlaySong(params) {
// this.$store.dispatch('handlerPlayer', {pause: true}); this.$store.dispatch('setCurrentPlay', params);
}, console.log('handlerPlaySong');
handlerPauseSong(params) { // this.$store.dispatch('handlerPlayer', {pause: true});
this.$store.dispatch('setCurrentPlay', params); },
console.log('handlerPauseSong') handlerPauseSong(params) {
// this.$store.dispatch('handlerPlayer', {play: true}); this.$store.dispatch('setCurrentPlay', params);
}, console.log('handlerPauseSong');
removeSong(song){ // this.$store.dispatch('handlerPlayer', {play: true});
this.$emit('removeSong', song) },
}, removeSong(song) {
addPlaylist(song){ this.$emit('removeSong', song);
this.$emit('addPlaylist', song) },
}, addPlaylist(song) {
removePlaylist(song){ this.$emit('addPlaylist', song);
this.$emit('removePlaylist', song) },
} removePlaylist(song) {
} this.$emit('removePlaylist', song);
} },
},
};
</script> </script>

View File

@ -1,25 +1,29 @@
<template> <template>
<div class="support-block"> <div class="support-block">
<h2 class="h2">Поддержи нас</h2> <h2 class="h2">Поддержи нас</h2>
<div class="support-block__list"> <div class="support-block__list">
<div class="support-block__item m--one-circle"> <div class="support-block__item m--one-circle">
<div class="title">Донат</div> <div class="title">Донат</div>
Мы будем рады, если вы поддержите нас любой суммой! Все средства пойдут на дальнейшее развитие проекта Мы будем рады, если вы поддержите нас любой суммой! Все средства пойдут
</div> на дальнейшее развитие проекта
<div class="support-block__item m--two-circle"> </div>
<div class="title">Дело</div> <div class="support-block__item m--two-circle">
Если вы фотографируете, монтируете, пишете, корректируете, занимаетесь продвижением или делаете еще что-нибудь классное и думаете, что можете быть нам полезны на волонтерских началах свяжитесь с нами через форму <div class="title">Дело</div>
</div> Если вы фотографируете, монтируете, пишете, корректируете, занимаетесь
<div class="support-block__item m--three-circle"> продвижением или делаете еще что-нибудь классное и думаете, что можете
<div class="title">Развитие</div> быть нам полезны на волонтерских началах свяжитесь с нами через форму
Расскажите о нашем проекте в соцсетях! Можно поделиться любым нашим постом, видео в ютубе или рассказать о нас в своей аудитории </div>
</div> <div class="support-block__item m--three-circle">
</div> <div class="title">Развитие</div>
</div> Расскажите о нашем проекте в соцсетях! Можно поделиться любым нашим
постом, видео в ютубе или рассказать о нас в своей аудитории
</div>
</div>
</div>
</template> </template>
<script> <script>
export default { export default {
name: 'SupportBlock' name: 'SupportBlock',
} };
</script> </script>

View File

@ -1,102 +1,108 @@
<template> <template>
<div class="team"> <div class="team">
<div class="team__header"> <div class="team__header">
<h2 class="h2 team__title"> <h2 class="h2 team__title">Наша команда</h2>
Наша команда <div class="team__description">
</h2> На IT волне команда профессионалов неутомимо трудится, чтобы дарить
<div class="team__description"> слушателям самые свежие и актуальные новости из мира технологий,
На IT волне команда профессионалов неутомимо трудится, чтобы дарить слушателям самые свежие и актуальные отвечать на их вопросы и обсуждать горячие темы на IT радио.
новости из мира технологий, отвечать на их вопросы и обсуждать горячие темы на IT радио. </div>
</div> </div>
</div> <template v-if="showLoader">
<template v-if="showLoader"> <div class="loader">
<div class="loader"> <div class="spinner" />
<div class="spinner"/> Загрузка данных
Загрузка данных </div>
</div> </template>
</template> <Swiper
<Swiper v-else
v-else :slides-per-view="4"
:slides-per-view="4" :space-between="20"
:space-between="20" :modules="modules"
:modules="modules" :pagination="{
:pagination="{ el: '.team__progress',
el: '.team__progress', clickable: true,
clickable: true, type: 'progressbar',
type: 'progressbar', }"
}" :breakpoints="{
:breakpoints="{ 0: {
0: { slidesPerView: 1,
slidesPerView: 1, },
}, 450: {
450: { slidesPerView: 1.5,
slidesPerView: 1.5, },
}, 768: {
768: { slidesPerView: 2.5,
slidesPerView: 2.5, },
}, 1020: {
1020:{ slidesPerView: 3,
slidesPerView: 3, },
}, 1280: {
1280: { slidesPerView: 4,
slidesPerView: 4, },
}, }"
}" class="team__slider"
class="team__slider" >
> <SwiperSlide
<SwiperSlide class="team__item" v-for="employee in team" :key="employee.id"> class="team__item"
<div class="team__cover"> v-for="employee in team"
<img :src="`${selfUrl + employee.img_person}`" alt="user"/> :key="employee.id"
</div> >
<div class="team__name"> <div class="team__cover">
{{ employee.name }} {{ employee.last_name }} <img :src="`${selfUrl + employee.img_person}`" alt="user" />
<span>{{ employee.position }}</span> </div>
</div> <div class="team__name">
</SwiperSlide> {{ employee.name }} {{ employee.last_name }}
</Swiper> <span>{{ employee.position }}</span>
<div class="team__tools"> </div>
<div class="team__progress" ref="progressBar"> </SwiperSlide>
<span></span> </Swiper>
</div> <div class="team__tools">
<router-link :to="{name: 'about'}" class="m--link"> <div class="team__progress" ref="progressBar">
Больше о нас <span></span>
</router-link> </div>
</div> <router-link :to="{ name: 'about' }" class="m--link">
</div> Больше о нас
</router-link>
</div>
</div>
</template> </template>
<script> <script>
import 'swiper/css'; import 'swiper/css';
import {Swiper, SwiperSlide} from "swiper/vue"; import { Swiper, SwiperSlide } from 'swiper/vue';
import {Pagination, Scrollbar} from "swiper/modules"; import { Pagination, Scrollbar } from 'swiper/modules';
import {app} from "@/services"; import { app } from '@/services';
import {selfUrl} from '@/settings'; import { selfUrl } from '@/settings';
export default { export default {
name: 'team', name: 'team',
components: {Swiper, SwiperSlide}, components: { Swiper, SwiperSlide },
data() { data() {
return { return {
selfUrl, selfUrl,
team: [], team: [],
showLoader: false, showLoader: false,
modules: [Scrollbar, Pagination], modules: [Scrollbar, Pagination],
} };
}, },
created() { created() {
this.getTeams(); this.getTeams();
}, },
methods: { methods: {
getTeams() { getTeams() {
this.showLoader = true; this.showLoader = true;
app.getTeams().then((data) => { app
this.showLoader = false; .getTeams()
this.team = data; .then((data) => {
}).catch(err => { this.showLoader = false;
this.showLoader = false; this.team = data;
console.log(err) })
}) .catch((err) => {
} this.showLoader = false;
} console.log(err);
} });
},
},
};
</script> </script>

View File

@ -1,7 +1,12 @@
import { route } from 'quasar/wrappers' import { route } from 'quasar/wrappers';
import store from '@/store' import store from '@/store';
import { createRouter, createMemoryHistory, createWebHistory, createWebHashHistory } from 'vue-router' import {
import routes from './routes' createRouter,
createMemoryHistory,
createWebHistory,
createWebHashHistory,
} from 'vue-router';
import routes from './routes';
/* /*
* If not building with SSR mode, you can * If not building with SSR mode, you can
@ -13,50 +18,57 @@ import routes from './routes'
*/ */
export default route(function (/* { store, ssrContext } */) { export default route(function (/* { store, ssrContext } */) {
const createHistory = process.env.SERVER const createHistory = process.env.SERVER
? createMemoryHistory ? createMemoryHistory
: (process.env.VUE_ROUTER_MODE === 'history' ? createWebHistory : createWebHashHistory) : process.env.VUE_ROUTER_MODE === 'history'
? createWebHistory
: createWebHashHistory;
const Router = createRouter({ const Router = createRouter({
scrollBehavior(to, from, savedPosition) { scrollBehavior(to, from, savedPosition) {
if (savedPosition) { if (savedPosition) {
return savedPosition return savedPosition;
} else { } else {
//document.getElementById('app').scrollIntoView({ behavior: 'smooth' }); //document.getElementById('app').scrollIntoView({ behavior: 'smooth' });
//if (to.query.page) return; //if (to.query.page) return;
return new Promise((resolve) => { return new Promise((resolve) => {
resolve({ left: 0, top: 0 }); resolve({ left: 0, top: 0 });
}) });
} }
}, },
routes, routes,
linkActiveClass: 'is-subactive', linkActiveClass: 'is-subactive',
linkExactActiveClass: 'is-active', linkExactActiveClass: 'is-active',
// Leave this as is and make changes in quasar.conf.js instead! // Leave this as is and make changes in quasar.conf.js instead!
// quasar.conf.js -> build -> vueRouterMode // quasar.conf.js -> build -> vueRouterMode
// quasar.conf.js -> build -> publicPath // quasar.conf.js -> build -> publicPath
history: createHistory(process.env.MODE === 'ssr' ? void 0 : process.env.VUE_ROUTER_BASE) history: createHistory(
}) process.env.MODE === 'ssr' ? void 0 : process.env.VUE_ROUTER_BASE,
),
});
Router.beforeEach((to, from, next) => { Router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth) && !process.env.SERVER) { if (
if (store.state.user && store.state.user?.id) { to.matched.some((record) => record.meta.requiresAuth) &&
next(); !process.env.SERVER
} else { ) {
next({ name: 'home' }); if (store.state.user && store.state.user?.id) {
this.$store.dispatch('setShowAuthModal', true); next();
} } else {
} else { next({ name: 'home' });
next(); this.$store.dispatch('setShowAuthModal', true);
} }
}); } else {
next();
}
});
Router.afterEach((to, from) => { Router.afterEach((to, from) => {
if (to.name !== from.name && to.name === 'page404' && from.name) { if (to.name !== from.name && to.name === 'page404' && from.name) {
if (!process.env.SERVER) window.history.replaceState({}, null, from.path); if (!process.env.SERVER) window.history.replaceState({}, null, from.path);
} }
}); });
return Router return Router;
}) });

View File

@ -1,145 +1,145 @@
import home from "@/views/home.vue"; import home from '@/views/home.vue';
import rubric from "@/views/rubric.vue"; import rubric from '@/views/rubric.vue';
import playlists from "@/views/playlists.vue"; import playlists from '@/views/playlists.vue';
import support from "@/views/support.vue"; import support from '@/views/support.vue';
import contacts from "@/views/contacts.vue"; import contacts from '@/views/contacts.vue';
import podcasts from "@/views/podcasts.vue"; import podcasts from '@/views/podcasts.vue';
import about from "@/views/about.vue"; import about from '@/views/about.vue';
import profile from "@/views/profile.vue"; import profile from '@/views/profile.vue';
import playlist from "@/views/playlist.vue"; import playlist from '@/views/playlist.vue';
import playlistCreate from "@/views/playlist-edit.vue"; import playlistCreate from '@/views/playlist-edit.vue';
const routes = [ const routes = [
{ {
path: '/', path: '/',
name: 'home', name: 'home',
component: home, component: home,
meta: { meta: {
title: 'Главная', title: 'Главная',
isAuth: false isAuth: false,
},
}, },
{ },
path: '/about', {
name: 'about', path: '/about',
component: about, name: 'about',
meta: { component: about,
title: 'О нас', meta: {
isAuth: false title: 'О нас',
}, isAuth: false,
}, },
{ },
path: '/rubric', {
name: 'rubric', path: '/rubric',
component: rubric, name: 'rubric',
meta: { component: rubric,
title: 'Рубрики', meta: {
isAuth: false title: 'Рубрики',
}, isAuth: false,
}, },
{ },
path: '/playlists', {
name: 'playlists', path: '/playlists',
component: playlists, name: 'playlists',
meta: { component: playlists,
title: 'Плейлисты', meta: {
isAuth: false title: 'Плейлисты',
}, isAuth: false,
}, },
{ },
path: '/podcasts', {
name: 'podcasts', path: '/podcasts',
component: podcasts, name: 'podcasts',
meta: { component: podcasts,
title: 'Подкасты', meta: {
isAuth: false title: 'Подкасты',
}, isAuth: false,
}, },
{ },
path: '/support', {
name: 'support', path: '/support',
component: support, name: 'support',
meta: { component: support,
title: 'Поддержка', meta: {
isAuth: false title: 'Поддержка',
}, isAuth: false,
}, },
{ },
path: '/contacts', {
name: 'contacts', path: '/contacts',
component: contacts, name: 'contacts',
meta: { component: contacts,
title: 'Контакты', meta: {
isAuth: false title: 'Контакты',
}, isAuth: false,
}, },
{ },
path: '/profile', {
name: 'profile', path: '/profile',
component: profile, name: 'profile',
meta: { component: profile,
title: 'Личный кабинет', meta: {
isAuth: false title: 'Личный кабинет',
}, isAuth: false,
children: [
{
path: 'playlist/:id',
name: 'playlist',
component: playlist,
meta: {
title: 'Плейлист',
requiresAuth: true
},
props: true,
},
{
path: 'playlist-create/:id',
name: 'playlist-create',
component: playlistCreate,
meta: {
title: 'Плейлист',
requiresAuth: true
},
props: true,
},{
path: 'playlist-edit/:id',
name: 'playlist-edit',
component: playlistCreate,
meta: {
title: 'Плейлист',
requiresAuth: true
},
props: true,
},
]
}, },
children: [
// { {
// path: '/error500', path: 'playlist/:id',
// name: 'page500', name: 'playlist',
// component: () => import('@/views/Page500.vue'), component: playlist,
// meta: { meta: {
// title: 'Ошибка 500', title: 'Плейлист',
// showSidebarAuth: true, requiresAuth: true,
// }, },
// }, { props: true,
// path: '/error404', },
// name: 'error404', {
// component: () => import('@/views/Page404.vue'), path: 'playlist-create/:id',
// meta: { name: 'playlist-create',
// title: 'Ошибка 404', component: playlistCreate,
// showSidebarAuth: true, meta: {
// }, title: 'Плейлист',
// }, { requiresAuth: true,
// path: '/:catchAll(.*)*', },
// name: 'page404', props: true,
// component: () => import('@/views/Page404.vue'), },
// meta: { {
// title: 'Ошибка 404', path: 'playlist-edit/:id',
// showSidebarAuth: true, name: 'playlist-edit',
// }, component: playlistCreate,
// }, meta: {
title: 'Плейлист',
requiresAuth: true,
},
props: true,
},
],
},
// {
// path: '/error500',
// name: 'page500',
// component: () => import('@/views/Page500.vue'),
// meta: {
// title: 'Ошибка 500',
// showSidebarAuth: true,
// },
// }, {
// path: '/error404',
// name: 'error404',
// component: () => import('@/views/Page404.vue'),
// meta: {
// title: 'Ошибка 404',
// showSidebarAuth: true,
// },
// }, {
// path: '/:catchAll(.*)*',
// name: 'page404',
// component: () => import('@/views/Page404.vue'),
// meta: {
// title: 'Ошибка 404',
// showSidebarAuth: true,
// },
// },
]; ];
export default routes export default routes;

View File

@ -1,173 +1,216 @@
import {urlPath as settings} from '@/settings'; import { urlPath as settings } from '@/settings';
import {REST, RESTError} from './rest'; import { REST, RESTError } from './rest';
export default class extends REST { export default class extends REST {
static get settings() { static get settings() {
return settings; return settings;
} }
static user(params) { static user(params) {
return this._get(`user`, {}, params).then((data) => { return this._get(`user`, {}, params)
return data; .then((data) => {
}).catch((error) => { return data;
throw new RESTError(error, 'Не удалось создать пользователя'); })
}); .catch((error) => {
} throw new RESTError(error, 'Не удалось создать пользователя');
static loginUser(params) { });
return this._post(`token`, {}, params).then((data) => { }
return data; static loginUser(params) {
}).catch((error) => { return this._post(`token`, {}, params)
throw new RESTError(error, 'Не удалось создать пользователя'); .then((data) => {
}); return data;
} })
static createUser(params) { .catch((error) => {
return this._post(`user/create_user`, {}, params).then((data) => { throw new RESTError(error, 'Не удалось создать пользователя');
return data; });
}).catch((error) => { }
throw new RESTError(error, 'Не удалось создать пользователя'); static createUser(params) {
}); return this._post(`user/create_user`, {}, params)
} .then((data) => {
return data;
static updateUser(params) { })
return this._post(`user/update_user`, {}, params).then((data) => { .catch((error) => {
return data; throw new RESTError(error, 'Не удалось создать пользователя');
}).catch((error) => { });
throw new RESTError(error, 'Не удалось создать пользователя'); }
});
} static updateUser(params) {
return this._post(`user/update_user`, {}, params)
static getTeams(station, params) { .then((data) => {
return this._get(`radio/teams`, params, {}).then((data) => { return data;
return data; })
}).catch((error) => { .catch((error) => {
throw new RESTError(error, 'Ошибка при получении команды'); throw new RESTError(error, 'Не удалось создать пользователя');
}); });
} }
static getCheckFavoriteSong(id){ static getTeams(station, params) {
return this._get(`radio/song/check_is_favorite/${id}`, {}, {}).then((data) => { return this._get(`radio/teams`, params, {})
return data; .then((data) => {
}).catch((error) => { return data;
throw new RESTError(error, 'Ошибка при проверке песни'); })
}); .catch((error) => {
} throw new RESTError(error, 'Ошибка при получении команды');
static getAllSong(){ });
return this._get(`radio/song/get_all_song`, {}, {}).then((data) => { }
return data;
}).catch((error) => { static getCheckFavoriteSong(id) {
throw new RESTError(error, 'Ошибка при получениии всех песен'); return this._get(`radio/song/check_is_favorite/${id}`, {}, {})
}); .then((data) => {
} return data;
static getAudio(id){ })
return this._get(`radio/song/get_audio/${id}`, {}, {}, false, true).then((data) => { .catch((error) => {
return data; throw new RESTError(error, 'Ошибка при проверке песни');
}).catch((error) => { });
throw new RESTError(error, 'Ошибка при получениии песни'); }
}); static getAllSong() {
} return this._get(`radio/song/get_all_song`, {}, {})
static createFavoriteForUser(params){ .then((data) => {
return this._post(`radio/song/add_favorite`, {}, params).then((data) => { return data;
return data; })
}).catch((error) => { .catch((error) => {
throw new RESTError(error, 'Ошибка при получении плейлистов'); throw new RESTError(error, 'Ошибка при получениии всех песен');
}); });
} }
static getAudio(id) {
static removeFavoriteForUser(params){ return this._get(`radio/song/get_audio/${id}`, {}, {}, false, true)
return this._post(`radio/song/delete_song`, {}, params).then((data) => { .then((data) => {
return data; return data;
}).catch((error) => { })
throw new RESTError(error, 'Ошибка при получении плейлистов'); .catch((error) => {
}); throw new RESTError(error, 'Ошибка при получениии песни');
} });
}
static getFavoriteList(params){ static createFavoriteForUser(params) {
return this._get(`radio/song`, {}, params).then((data) => { return this._post(`radio/song/add_favorite`, {}, params)
return data; .then((data) => {
}).catch((error) => { return data;
throw new RESTError(error, 'Ошибка при получении плейлистов'); })
}); .catch((error) => {
} throw new RESTError(error, 'Ошибка при получении плейлистов');
static getRubriks() { });
return this._get(`radio/rubriks`, {}, {}).then((data) => { }
return data;
}).catch((error) => { static removeFavoriteForUser(params) {
throw new RESTError(error, 'Ошибка при получении рубрик'); return this._post(`radio/song/delete_song`, {}, params)
}); .then((data) => {
} return data;
static getRubrik(id) { })
return this._get(`radio/rubriks/${id}`, {}, {}).then((data) => { .catch((error) => {
return data; throw new RESTError(error, 'Ошибка при получении плейлистов');
}).catch((error) => { });
throw new RESTError(error, 'Ошибка при получении рубрик'); }
});
} static getFavoriteList(params) {
return this._get(`radio/song`, {}, params)
static removeFavorites(params) { .then((data) => {
return this._post(`radio/song/delete_song`, {}, params).then((data) => { return data;
return data; })
}).catch((error) => { .catch((error) => {
throw new RESTError(error, 'Ошибка при получении рубрик'); throw new RESTError(error, 'Ошибка при получении плейлистов');
}); });
} }
static getRubriks() {
static getPlaylists() { return this._get(`radio/rubriks`, {}, {})
return this._get(`radio/playlists`, {}, {}).then((data) => { .then((data) => {
return data; return data;
}).catch((error) => { })
throw new RESTError(error, 'Ошибка при получении плейлистов'); .catch((error) => {
}); throw new RESTError(error, 'Ошибка при получении рубрик');
} });
static getPlaylist(id) { }
return this._get(`radio/playlists/${id}`, {}, {}).then((data) => { static getRubrik(id) {
return data; return this._get(`radio/rubriks/${id}`, {}, {})
}).catch((error) => { .then((data) => {
throw new RESTError(error, 'Ошибка при получении плейлистов'); return data;
}); })
} .catch((error) => {
throw new RESTError(error, 'Ошибка при получении рубрик');
static addSongToPlaylist(params) { });
return this._post(`radio/playlists/add_to_playlist`, {}, params).then((data) => { }
return data;
}).catch((error) => { static removeFavorites(params) {
throw new RESTError(error, 'Ошибка при получении плейлистов'); return this._post(`radio/song/delete_song`, {}, params)
}); .then((data) => {
} return data;
static removeSongToPlaylist(params) { })
return this._post(`radio/playlists/delete_song_with_playlist`, {}, params).then((data) => { .catch((error) => {
return data; throw new RESTError(error, 'Ошибка при получении рубрик');
}).catch((error) => { });
throw new RESTError(error, 'Ошибка при удаления треков из плейлиста'); }
});
} static getPlaylists() {
static updatePlaylist(params) { return this._get(`radio/playlists`, {}, {})
return this._post(`radio/playlists/update_playlist`, {}, params).then((data) => { .then((data) => {
return data; return data;
}).catch((error) => { })
throw new RESTError(error, 'Ошибка при удаления треков из плейлиста'); .catch((error) => {
}); throw new RESTError(error, 'Ошибка при получении плейлистов');
} });
}
static createPlaylists() { static getPlaylist(id) {
return this._post(`radio/playlists/create_playlist`, {}, {}).then((data) => { return this._get(`radio/playlists/${id}`, {}, {})
return data; .then((data) => {
}).catch((error) => { return data;
throw new RESTError(error, 'Ошибка при получении плейлистов'); })
}); .catch((error) => {
} throw new RESTError(error, 'Ошибка при получении плейлистов');
});
}
static getNews(station, params) {
return this._get(`radio.mp3`, params, {}).then((data) => { static addSongToPlaylist(params) {
return data; return this._post(`radio/playlists/add_to_playlist`, {}, params)
}).catch((error) => { .then((data) => {
throw new RESTError(error, 'Ошибка при получении плейлистов'); return data;
}); })
} .catch((error) => {
static getProfiles(station, params) { throw new RESTError(error, 'Ошибка при получении плейлистов');
return this._get(`radio.mp3`, params, {}).then((data) => { });
return data; }
}).catch((error) => { static removeSongToPlaylist(params) {
throw new RESTError(error, 'Ошибка при получении плейлистов'); return this._post(`radio/playlists/delete_song_with_playlist`, {}, params)
}); .then((data) => {
} return data;
})
.catch((error) => {
throw new RESTError(error, 'Ошибка при удаления треков из плейлиста');
});
}
static updatePlaylist(params) {
return this._post(`radio/playlists/update_playlist`, {}, params)
.then((data) => {
return data;
})
.catch((error) => {
throw new RESTError(error, 'Ошибка при удаления треков из плейлиста');
});
}
static createPlaylists() {
return this._post(`radio/playlists/create_playlist`, {}, {})
.then((data) => {
return data;
})
.catch((error) => {
throw new RESTError(error, 'Ошибка при получении плейлистов');
});
}
static getNews(station, params) {
return this._get(`radio.mp3`, params, {})
.then((data) => {
return data;
})
.catch((error) => {
throw new RESTError(error, 'Ошибка при получении плейлистов');
});
}
static getProfiles(station, params) {
return this._get(`radio.mp3`, params, {})
.then((data) => {
return data;
})
.catch((error) => {
throw new RESTError(error, 'Ошибка при получении плейлистов');
});
}
} }

View File

@ -1,65 +1,67 @@
import {urlPathAudio as settings} from '@/settings'; import { urlPathAudio as settings, urlPathAudio } from '@/settings';
import {REST, RESTError} from './rest'; import { REST, RESTError } from './rest';
import {urlPathAudio} from "@/settings";
export default class extends REST { export default class extends REST {
static get settings() { static get settings() {
return settings; return settings;
} }
init(){ init() {
const sseBaseUri = `${settings}/api/live/nowplaying/sse`; const sseBaseUri = `${settings}/api/live/nowplaying/sse`;
const sseUriParams = new URLSearchParams({ const sseUriParams = new URLSearchParams({
cf_connect: JSON.stringify({ cf_connect: JSON.stringify({
subs: { subs: {
"station:it-radio": { recover: true }, 'station:it-radio': { recover: true },
}, },
}), }),
}); });
this.connection = new EventSource(sseBaseUri + "?" + sseUriParams.toString()); this.connection = new EventSource(
} sseBaseUri + '?' + sseUriParams.toString(),
);
removePlay(){ }
this.connection.close()
} removePlay() {
songs(){ this.connection.close();
this.connection.onmessage = (e) => { }
const jsonData = JSON.parse(e.data); songs() {
// if ("connect" in jsonData) { this.connection.onmessage = (e) => {
// const connectData = jsonData.connect; const jsonData = JSON.parse(e.data);
// // if ("connect" in jsonData) {
// if ("data" in connectData) { // const connectData = jsonData.connect;
// // Legacy SSE data //
// connectData.data.forEach((initialRow) => handleSseData(initialRow)); // if ("data" in connectData) {
// } else { // // Legacy SSE data
// // New Centrifugo time format // connectData.data.forEach((initialRow) => handleSseData(initialRow));
// if ("time" in connectData) { // } else {
// } // // New Centrifugo time format
// // if ("time" in connectData) {
// // New Centrifugo cached NowPlaying initial push. // }
// for (const subName in connectData.subs) { //
// const sub = connectData.subs[subName]; // // New Centrifugo cached NowPlaying initial push.
// if ("publications" in sub && sub.publications.length > 0) { // for (const subName in connectData.subs) {
// sub.publications.forEach((initialRow) => handleSseData(initialRow, false)); // const sub = connectData.subs[subName];
// } // if ("publications" in sub && sub.publications.length > 0) {
// } // sub.publications.forEach((initialRow) => handleSseData(initialRow, false));
// } // }
// } else if ("pub" in jsonData) { // }
// handleSseData(jsonData.pub); // }
// } // } else if ("pub" in jsonData) {
}; // handleSseData(jsonData.pub);
// }
} };
}
onHandler(event){
this.connection.onmessage = event onHandler(event) {
} this.connection.onmessage = event;
static getPlayList(station, params) { }
// return this._get(`station/${station}/playlists`, params, {}).then((data) => { static getPlayList(station, params) {
return this._get(`radio.mp3`, params, {}).then((data) => { // return this._get(`station/${station}/playlists`, params, {}).then((data) => {
return data; return this._get(`radio.mp3`, params, {})
}).catch((error) => { .then((data) => {
throw new RESTError(error, 'Ошибка при получении плейлистов'); return data;
}); })
} .catch((error) => {
throw new RESTError(error, 'Ошибка при получении плейлистов');
});
}
} }

View File

@ -1,7 +1,4 @@
import audio from './audio'; import audio from './audio';
import app from './app'; import app from './app';
export { export { audio, app };
audio,
app
};

View File

@ -4,88 +4,115 @@ import store from '@/store';
import cache from '@/utils/cache'; import cache from '@/utils/cache';
class RESTError extends Error { class RESTError extends Error {
constructor(error, message, params={}) { constructor(error, message, params = {}) {
let detail = error.response && error.response.data && (error.response.data.detail || error.response.data.error && error.response.data.error.detail); let detail =
let header = (message || error.message) + (detail ? ': ' + detail : ''); error.response &&
super(header); error.response.data &&
(error.response.data.detail ||
(error.response.data.error && error.response.data.error.detail));
let header = (message || error.message) + (detail ? ': ' + detail : '');
super(header);
this.name = this.constructor.name; this.name = this.constructor.name;
this.parent = error; this.parent = error;
this.detail = detail; this.detail = detail;
this.response = error.response; this.response = error.response;
for (let k in params) { for (let k in params) {
this[k] = params[k]; this[k] = params[k];
}
//if (this.response && (this.response.status === 401 || this.response.status === 403)) {
if (this.response && (this.response.status === 401)) {
store.dispatch('deathUser');
store.dispatch('setShowAuthModal', true);
} else {
if (typeof Error.captureStackTrace === 'function') {
Error.captureStackTrace(this, this.constructor);
} else {
this.stack = (new Error(header)).stack;
}
}
} }
//if (this.response && (this.response.status === 401 || this.response.status === 403)) {
if (this.response && this.response.status === 401) {
store.dispatch('deathUser');
store.dispatch('setShowAuthModal', true);
} else {
if (typeof Error.captureStackTrace === 'function') {
Error.captureStackTrace(this, this.constructor);
} else {
this.stack = new Error(header).stack;
}
}
}
} }
class REST { class REST {
static get settings() { static get settings() {
throw new Error('settings must be overridden'); throw new Error('settings must be overridden');
} }
static _get(url, params={}, extraParams, use_cache=false, isBlob=false) { static _get(
return this._request('get', url, params, {}, {}, extraParams, use_cache, isBlob); url,
} params = {},
static _post(url, params, data) { extraParams,
return this._request('post', url, params, data); use_cache = false,
} isBlob = false,
static _put(url, params, data) { ) {
return this._request('put', url, params, data); return this._request(
} 'get',
static _patch(url, params, data) { url,
return this._request('patch', url, params, data); params,
} {},
static _delete(url, params, data) { {},
return this._request('delete', url, params, data); extraParams,
} use_cache,
static _request(method, url, params={}, data={}, extraData={}, extraParams={}, use_cache=false, isBlob=false) { isBlob,
let cache_key = null; );
return ajax.request({ }
method, static _post(url, params, data) {
url: `${this.settings}${url ? '/' : ''}${url}/`, return this._request('post', url, params, data);
params, }
data, static _put(url, params, data) {
extraData, return this._request('put', url, params, data);
extraParams, }
headers: this._getAuthHeaders(), static _patch(url, params, data) {
responseType: this._getResponseType(isBlob), return this._request('patch', url, params, data);
}).then((response) => { }
if (cache_key) { static _delete(url, params, data) {
cache.set(cache_key, response.data); return this._request('delete', url, params, data);
} }
return response.data; static _request(
}); method,
} url,
static _getResponseType(value){ params = {},
if (value) { data = {},
return 'arraybuffer' extraData = {},
extraParams = {},
use_cache = false,
isBlob = false,
) {
let cache_key = null;
return ajax
.request({
method,
url: `${this.settings}${url ? '/' : ''}${url}/`,
params,
data,
extraData,
extraParams,
headers: this._getAuthHeaders(),
responseType: this._getResponseType(isBlob),
})
.then((response) => {
if (cache_key) {
cache.set(cache_key, response.data);
} }
return response.data;
});
}
static _getResponseType(value) {
if (value) {
return 'arraybuffer';
} }
static _getAuthHeaders() { }
if (store.state.token) { static _getAuthHeaders() {
return { 'Authorization': `Bearer ${store.state.token}` }; if (store.state.token) {
} return { Authorization: `Bearer ${store.state.token}` };
}
static _cancelToken() {
return ajax.cancelToken();
} }
}
static _cancelToken() {
return ajax.cancelToken();
}
} }
export default REST; export default REST;
export { export { RESTError, REST };
RESTError,
REST
};

View File

@ -1,53 +1,45 @@
//throw new Error('Settings module must be replaced depending on mode'); //throw new Error('Settings module must be replaced depending on mode');
const ajax = { const ajax = {
timeout: process.env.AJAX_TIMEOUT, timeout: process.env.AJAX_TIMEOUT,
responseType: process.env.AJAX_RESPONSE_TYPE, responseType: process.env.AJAX_RESPONSE_TYPE,
responseEncoding: process.env.AJAX_ENCODING responseEncoding: process.env.AJAX_ENCODING,
}; };
const cache = { const cache = {
storage: process.env.CACHE_STORAGE storage: process.env.CACHE_STORAGE,
}; };
const serviceUrl = { const serviceUrl = {
selfUrl: process.env.SERVICE_SELF_URL, selfUrl: process.env.SERVICE_SELF_URL,
url: process.env.SERVICE_URL, url: process.env.SERVICE_URL,
protocol: process.env.SERVICE_PROTOCOL, protocol: process.env.SERVICE_PROTOCOL,
port: process.env.SERVICE_PORT, port: process.env.SERVICE_PORT,
api: process.env.SERVICE_API, api: process.env.SERVICE_API,
apiAudio: process.env.SERVICE_URL_AUDIO, apiAudio: process.env.SERVICE_URL_AUDIO,
localPath: '//localhost', localPath: '//localhost',
onLocal: (process.env.SERVICE_ON_LOCAL === 'true') onLocal: process.env.SERVICE_ON_LOCAL === 'true',
} };
let urlPath = `${serviceUrl.protocol}:${serviceUrl.url}${serviceUrl.api}`; let urlPath = `${serviceUrl.protocol}:${serviceUrl.url}${serviceUrl.api}`;
let urlPathAudio = `${serviceUrl.protocol}:${serviceUrl.apiAudio}`; let urlPathAudio = `${serviceUrl.protocol}:${serviceUrl.apiAudio}`;
if (process.env.CLIENT) { if (process.env.CLIENT) {
if (serviceUrl.onLocal || window.location.hostname === 'localhost') { if (serviceUrl.onLocal || window.location.hostname === 'localhost') {
urlPath = `${serviceUrl.localPath}:${serviceUrl.port}${serviceUrl.api}`; urlPath = `${serviceUrl.localPath}:${serviceUrl.port}${serviceUrl.api}`;
} }
} }
let selfUrl = `${serviceUrl.protocol}:${serviceUrl.url}` let selfUrl = `${serviceUrl.protocol}:${serviceUrl.url}`;
let selfPath = `${serviceUrl.protocol}:${serviceUrl.selfUrl}`; let selfPath = `${serviceUrl.protocol}:${serviceUrl.selfUrl}`;
const robotsTxt = { const robotsTxt = {
filePath: '/robots.txt', filePath: '/robots.txt',
host: selfPath, host: selfPath,
policy: [ policy: [
{ {
userAgent: process.env.ROBOTS_USER_AGENT, userAgent: process.env.ROBOTS_USER_AGENT,
allow: JSON.parse(process.env.ROBOTS_ALLOW || null), allow: JSON.parse(process.env.ROBOTS_ALLOW || null),
disallow: JSON.parse(process.env.ROBOTS_DISALLOW || null), disallow: JSON.parse(process.env.ROBOTS_DISALLOW || null),
} },
] ],
}; };
export { export { selfUrl, ajax, cache, urlPath, urlPathAudio, selfPath, robotsTxt };
selfUrl,
ajax,
cache,
urlPath,
urlPathAudio,
selfPath,
robotsTxt,
};

View File

@ -1,144 +1,143 @@
import {createStore} from 'vuex' import { createStore } from 'vuex';
import VuexPersist from 'vuex-persist'; import VuexPersist from 'vuex-persist';
const vuexPersist = new VuexPersist({ const vuexPersist = new VuexPersist({
key: 'it-radio', key: 'it-radio',
//storage: window.localStorage //storage: window.localStorage
}); });
// Vue.use(Vuex); // Vue.use(Vuex);
export default createStore({ export default createStore({
state() { state() {
return { return {
token: null, token: null,
refreshToken: null, refreshToken: null,
user: null, user: null,
modal:{ modal: {
auth: false, auth: false,
changingUser: false changingUser: false,
}, },
showAuthModal: false, showAuthModal: false,
station: { station: {
id: 1 id: 1,
}, },
currentPlay: { currentPlay: {
isPlay: false, isPlay: false,
isLoader: false, isLoader: false,
live: true, live: true,
volume: 50, volume: 50,
currentIndex: null, currentIndex: null,
}, },
player: { player: {
target: null, target: null,
}, },
userFavorite: { userFavorite: {
podcast: [], podcast: [],
playlist: [], playlist: [],
songs: [] songs: [],
} },
} };
},
plugins: [vuexPersist.plugin],
mutations: {
user(state, user) {
state.user = user;
}, },
plugins: [vuexPersist.plugin], updateToken(state, tokens) {
mutations: { state.token = tokens.access;
user(state, user) { state.refreshToken = tokens.refresh;
state.user = user;
},
updateToken(state, tokens) {
state.token = tokens.access;
state.refreshToken = tokens.refresh;
},
removeToken(state) {
state.token = null;
state.refreshToken = null;
},
setCurrentPlay(state, song) {
state.currentPlay = song;
},
setModal(state, show) {
state.modal = {...state.modal, ...show}
},
setPlayer(state, params) {
state.player = {...state.player, ...params}
},
initPlayer(state) {
state.player.target = document.createElement('audio')
state.player.target.src = '';
state.player.target.preload = 'auto';
state.player.target.controls = true;
state.player.target.volume = 0.5;
console.log('initPlayer', state.player.target)
},
changePlayer(state, params) {
const awaitPlay = () => {
if (state.player.target.readyState >= 4) {
if (state.currentPlay.isPlay){
state.player.target.play();
}
state.currentPlay.isLoader = false;
state.player.target.removeEventListener('canplaythrough', awaitPlay);
} else {
awaitPlay();
}
}
state.player.target.src = params;
state.player.src = params;
console.log(state.player.target.src)
// state.currentPlay.isLoader = true;
state.player.target.addEventListener('canplaythrough', awaitPlay)
},
handlerPlayer(state, params) {
if (params.pause) {
state.currentPlay.isPlay = false;
state.player.target.pause();
}
if (params.play) {
if (state.player.target.readyState >= 3){
state.currentPlay.isPlay = true;
state.player.target.play();
}
}
if (params.volume) {
state.player.target.volume = params.volume;
}
},
setUserFavorite(state, params) {
state.userFavorite = {...state.userFavorite, ...params}
}
}, },
actions: { removeToken(state) {
setToken(context, tokens) { state.token = null;
context.commit('updateToken', tokens); state.refreshToken = null;
}, },
setUser(context, user) { setCurrentPlay(state, song) {
context.commit('user', user); state.currentPlay = song;
}, },
deathUser(context) { setModal(state, show) {
context.commit('user', {}); state.modal = { ...state.modal, ...show };
context.commit('removeToken'); },
}, setPlayer(state, params) {
setCurrentPlay(context, song) { state.player = { ...state.player, ...params };
context.commit('setCurrentPlay', song); },
}, initPlayer(state) {
setModal(context, show) { state.player.target = document.createElement('audio');
context.commit('setModal', show); state.player.target.src = '';
}, state.player.target.preload = 'auto';
setPlayer(context, params) { state.player.target.controls = true;
context.commit('setPlayer', params); state.player.target.volume = 0.5;
}, console.log('initPlayer', state.player.target);
initPlayer(context) { },
context.commit('initPlayer'); changePlayer(state, params) {
}, const awaitPlay = () => {
handlerPlayer(context, params) { if (state.player.target.readyState >= 4) {
context.commit('handlerPlayer', params); if (state.currentPlay.isPlay) {
}, state.player.target.play();
changePlayer(context, params) { }
context.commit('changePlayer', params); state.currentPlay.isLoader = false;
}, state.player.target.removeEventListener('canplaythrough', awaitPlay);
setUserFavorite(context, params) { } else {
context.commit('setUserFavorite', params); awaitPlay();
}, }
} };
state.player.target.src = params;
state.player.src = params;
console.log(state.player.target.src);
// state.currentPlay.isLoader = true;
state.player.target.addEventListener('canplaythrough', awaitPlay);
},
handlerPlayer(state, params) {
if (params.pause) {
state.currentPlay.isPlay = false;
state.player.target.pause();
}
if (params.play) {
if (state.player.target.readyState >= 3) {
state.currentPlay.isPlay = true;
state.player.target.play();
}
}
if (params.volume) {
state.player.target.volume = params.volume;
}
},
setUserFavorite(state, params) {
state.userFavorite = { ...state.userFavorite, ...params };
},
},
actions: {
setToken(context, tokens) {
context.commit('updateToken', tokens);
},
setUser(context, user) {
context.commit('user', user);
},
deathUser(context) {
context.commit('user', {});
context.commit('removeToken');
},
setCurrentPlay(context, song) {
context.commit('setCurrentPlay', song);
},
setModal(context, show) {
context.commit('setModal', show);
},
setPlayer(context, params) {
context.commit('setPlayer', params);
},
initPlayer(context) {
context.commit('initPlayer');
},
handlerPlayer(context, params) {
context.commit('handlerPlayer', params);
},
changePlayer(context, params) {
context.commit('changePlayer', params);
},
setUserFavorite(context, params) {
context.commit('setUserFavorite', params);
},
},
}); });

View File

@ -1,2 +1 @@
export function someAction (/* context */) { export function someAction(/* context */) {}
}

View File

@ -1,2 +1 @@
export function someGetter (/* state */) { export function someGetter(/* state */) {}
}

View File

@ -1,12 +1,12 @@
import state from './state' import state from './state';
import * as getters from './getters' import * as getters from './getters';
import * as mutations from './mutations' import * as mutations from './mutations';
import * as actions from './actions' import * as actions from './actions';
export default { export default {
namespaced: true, namespaced: true,
getters, getters,
mutations, mutations,
actions, actions,
state state,
} };

View File

@ -1,2 +1 @@
export function someMutation (/* state */) { export function someMutation(/* state */) {}
}

View File

@ -1,5 +1,5 @@
export default function () { export default function () {
return { return {
// //
} };
} }

View File

@ -3,88 +3,91 @@ import axios from 'axios';
import { ajax as settings } from '@/settings'; import { ajax as settings } from '@/settings';
export default class { export default class {
static get(params) { static get(params) {
return this.request(_defaults({ method: 'get' }, params)); return this.request(_defaults({ method: 'get' }, params));
}
static post(params) {
return this.request(_defaults({ method: 'post' }, params));
}
static put(params) {
return this.request(_defaults({ method: 'put' }, params));
}
static patch(params) {
return this.request(_defaults({ method: 'patch' }, params));
}
static delete(params) {
return this.request(_defaults({ method: 'delete' }, params));
}
static request(params) {
if (params.extraData) {
params.data = this.__append_extra_data(params.data, params.extraData);
delete params.extraData;
} }
static post(params) { if (params.extraParams) {
return this.request(_defaults({ method: 'post' }, params)); params.params = this.__append_extra_params(
params.params,
params.extraParams,
);
delete params.extraParams;
} }
static put(params) { /*
return this.request(_defaults({ method: 'put' }, params));
}
static patch(params) {
return this.request(_defaults({ method: 'patch' }, params));
}
static delete(params) {
return this.request(_defaults({ method: 'delete' }, params));
}
static request(params) {
if (params.extraData) {
params.data = this.__append_extra_data(params.data, params.extraData);
delete params.extraData;
}
if (params.extraParams) {
params.params = this.__append_extra_params(params.params, params.extraParams);
delete params.extraParams;
}
/*
if (params.cancel) { if (params.cancel) {
params.cancelToken = this.CancelToken(params.cancel); params.cancelToken = this.CancelToken(params.cancel);
delete params.cancel; delete params.cancel;
} }
*/ */
return axios.request(_defaults({}, params, this.settings)); return axios.request(_defaults({}, params, this.settings));
} }
/* /*
static cancelToken() { static cancelToken() {
return axios.CancelToken.source(); return axios.CancelToken.source();
} }
*/ */
static getUri(params) { static getUri(params) {
return axios.getUri(params); return axios.getUri(params);
} }
static __append_extra_data(data, extra) { static __append_extra_data(data, extra) {
data = data || {}; data = data || {};
if (process.env.CLIENT && data instanceof FormData) { if (process.env.CLIENT && data instanceof FormData) {
for (let k in extra) { for (let k in extra) {
data.append(k, extra[k]); data.append(k, extra[k]);
} }
} else if (data instanceof URLSearchParams) { } else if (data instanceof URLSearchParams) {
for (let k in extra) { for (let k in extra) {
data.append(k, extra[k]); data.append(k, extra[k]);
} }
} else if (typeof data === 'string') { } else if (typeof data === 'string') {
for (let k in extra) { for (let k in extra) {
if (data !== '') data += '&'; if (data !== '') data += '&';
data += encodeURIComponent(k) + '=' + encodeURIComponent(data[k]); data += encodeURIComponent(k) + '=' + encodeURIComponent(data[k]);
} }
} else if (typeof data === 'object') { } else if (typeof data === 'object') {
for (let k in extra) { for (let k in extra) {
data[k] = extra[k]; data[k] = extra[k];
} }
} else { } else {
throw new Error('Can\'t append extra data to this type of data'); throw new Error("Can't append extra data to this type of data");
}
return data;
} }
static __append_extra_params(data, extra) { return data;
data = data || {}; }
static __append_extra_params(data, extra) {
data = data || {};
if (data instanceof URLSearchParams) { if (data instanceof URLSearchParams) {
for (let k in extra) { for (let k in extra) {
data.append(k, extra[k]); data.append(k, extra[k]);
} }
} else if (typeof data === 'object') { } else if (typeof data === 'object') {
for (let k in extra) { for (let k in extra) {
data[k] = extra[k]; data[k] = extra[k];
} }
} else { } else {
throw new Error('Can\'t append extra params to this type of params'); throw new Error("Can't append extra params to this type of params");
}
return data;
}
static get settings() {
return settings;
} }
return data;
}
static get settings() {
return settings;
}
} }

View File

@ -2,74 +2,71 @@ import _keys from 'lodash/keys';
import { cache as settings } from '@/settings'; import { cache as settings } from '@/settings';
class Converter { class Converter {
static encode(value) { static encode(value) {
return this.__isComplex(value) ? JSON.stringify(value) : value; return this.__isComplex(value) ? JSON.stringify(value) : value;
} }
static decode(value) { static decode(value) {
return this.__isJSON(value) ? JSON.parse(value) : value; return this.__isJSON(value) ? JSON.parse(value) : value;
} }
static __isComplex(value) { static __isComplex(value) {
return (value instanceof Array || typeof value === 'object'); return value instanceof Array || typeof value === 'object';
} }
static __isJSON(value) { static __isJSON(value) {
return (typeof value === 'string' && /^(\{|\[)/.test(value)); return typeof value === 'string' && /^(\{|\[)/.test(value);
} }
} }
class TempStorage { class TempStorage {
constructor() { constructor() {
this.__data = {}; this.__data = {};
} }
getItem(key) { getItem(key) {
return this.__data[key]; return this.__data[key];
} }
setItem(key, value) { setItem(key, value) {
this.__data[key] = value; this.__data[key] = value;
} }
removeItem(key) { removeItem(key) {
delete this.__data[key]; delete this.__data[key];
} }
clear() { clear() {
this.__data = {}; this.__data = {};
} }
get length() { get length() {
return _keys(this.__data).length; return _keys(this.__data).length;
} }
} }
class Cache { class Cache {
constructor(storage) { constructor(storage) {
if (storage === 'tempStorage') { if (storage === 'tempStorage') {
this._storage = new TempStorage(); this._storage = new TempStorage();
} else { } else {
if (!(storage in window)) { if (!(storage in window)) {
throw new Error(`Storage ${storage} is not supported`); throw new Error(`Storage ${storage} is not supported`);
} }
this._storage = window[storage]; this._storage = window[storage];
}
} }
get(key) { }
return Converter.decode(this._storage.getItem(key)); get(key) {
} return Converter.decode(this._storage.getItem(key));
set(key, value) { }
this._storage.setItem(key, Converter.encode(value)); set(key, value) {
} this._storage.setItem(key, Converter.encode(value));
remove(key) { }
this._storage.removeItem(key); remove(key) {
} this._storage.removeItem(key);
clear() { }
this._storage.clear(); clear() {
} this._storage.clear();
key(ns, type, data) { }
let key = ns + ':' + type; key(ns, type, data) {
if (data) { let key = ns + ':' + type;
key += ':' + JSON.stringify(data, _keys(data).sort()); if (data) {
} key += ':' + JSON.stringify(data, _keys(data).sort());
return key;
} }
return key;
}
} }
export default new Cache(settings.storage); export default new Cache(settings.storage);

View File

@ -1,25 +1,20 @@
const helpers = { const helpers = {
range: (start, end, step = 1, toFixed = null) => { range: (start, end, step = 1, toFixed = null) => {
let arr = [] let arr = [];
while(start <= end) { while (start <= end) {
if (toFixed) if (toFixed) start = Number(start.toFixed(toFixed));
start = Number(start.toFixed(toFixed)) arr.push(start);
arr.push(start) start += step;
start += step }
} return arr;
return arr },
}, };
}
export default { export default {
install (app) { install(app) {
app.helpers = helpers app.helpers = helpers;
app.config.globalProperties.$helpers = helpers app.config.globalProperties.$helpers = helpers;
} },
} };
export { export { helpers };
helpers
}

View File

@ -1,61 +1,54 @@
<template> <template>
<div class="app__main m--error-404"> <div class="app__main m--error-404">
<div <div :class="['page404', this.user?.id ? 'auth' : null]">
:class="['page404', this.user?.id? 'auth': null]" <div :class="['container']">
> <div class="page404__block">
<div :class="['container']"> <div class="page404__info">
<div class="page404__block"> <div class="page404__info-title">404</div>
<div <div class="page404__info-subtitle">
class="page404__info" Мы не можем найти то, что вы ищете
>
<div class="page404__info-title">
404
</div>
<div class="page404__info-subtitle">
Мы не можем найти то, что вы ищете
</div>
<div class="page404__info-content">
Возможно, запрашиваемая вами страница была перенесена или удалена. Также возможно, что вы допустили небольшую опечатку при вводе адреса такое случается даже с нами, поэтому еще раз внимательно проверьте.
</div>
<div class="page404__info-bottom">
Переходите на главную страницу, там вы сможете найти много полезной информации!
</div>
<div class="page404__info-button">
<button
class="button button-blue"
@click="next()"
>
На главную
</button>
</div>
</div>
</div>
</div> </div>
<div class="page404__info-content">
Возможно, запрашиваемая вами страница была перенесена или удалена.
Также возможно, что вы допустили небольшую опечатку при вводе
адреса такое случается даже с нами, поэтому еще раз внимательно
проверьте.
</div>
<div class="page404__info-bottom">
Переходите на главную страницу, там вы сможете найти много
полезной информации!
</div>
<div class="page404__info-button">
<button class="button button-blue" @click="next()">
На главную
</button>
</div>
</div>
</div> </div>
</div>
</div> </div>
</div>
</template> </template>
<script> <script>
export default { export default {
name: 'Page404', name: 'Page404',
components: { components: {},
}, data() {
data() { return {};
return { },
} computed: {
}, user() {
computed: { return this.$store.state.user;
user() { },
return this.$store.state.user; },
}, mounted() {
}, console.log(this.user);
mounted() { },
console.log(this.user) methods: {
}, next() {
methods: { this.$router.push({ name: 'home' });
next() { },
this.$router.push({ name: 'home' }); },
} };
},
}
</script> </script>

View File

@ -1,60 +1,47 @@
<template> <template>
<div class="app__main m--error-500"> <div class="app__main m--error-500">
<div <div :class="['page500']">
:class="['page500']" <div :class="['container']">
> <div class="page500__block">
<div :class="['container']"> <div class="page500__info">
<div class="page500__block"> <div class="page500__info-title">Упс!</div>
<div <div class="page500__info-subtitle">Что то пошло не так!</div>
class="page500__info" <div class="page500__info-content">
> Мы уже знаем об этом и делаем все возможное!
<div class="page500__info-title">
Упс!
</div>
<div class="page500__info-subtitle">
Что то пошло не так!
</div>
<div class="page500__info-content">
Мы уже знаем об этом и делаем все возможное!
</div>
<div class="page500__info-bottom">
Переходите на главную страницу, там вы сможете найти много полезной информации!
</div>
<div class="page500__info-button">
<button
class="button button-blue"
@click="next()"
>
На главную
</button>
</div>
</div>
</div>
</div> </div>
<div class="page500__info-bottom">
Переходите на главную страницу, там вы сможете найти много
полезной информации!
</div>
<div class="page500__info-button">
<button class="button button-blue" @click="next()">
На главную
</button>
</div>
</div>
</div> </div>
</div>
</div> </div>
</div>
</template> </template>
<script> <script>
export default { export default {
name: 'Page404', name: 'Page404',
components: { components: {},
}, data() {
data() { return {};
return { },
} computed: {
}, user() {
computed: { return this.$store.state.user;
user() { },
return this.$store.state.user; },
}, mounted() {},
}, methods: {
mounted() { next() {
}, this.$router.push({ name: 'home' });
methods: { },
next() { },
this.$router.push({ name: 'home' }); };
}
},
}
</script> </script>

View File

@ -1,103 +1,113 @@
<template> <template>
<div class="about"> <div class="about">
<div class="app__content"> <div class="app__content">
<AppBreadcrumbs <AppBreadcrumbs
:breadcrumbs="[ :breadcrumbs="[
{ name: 'Главная', route: { name: 'home' } }, { name: 'Главная', route: { name: 'home' } },
{ name: 'О нас', route: { name: 'about' } }, { name: 'О нас', route: { name: 'about' } },
]" ]"
/> />
<div class="about__header">
<div class="about__header-top">
<div class="about__header-left">
<h1 class="h2">О нас</h1>
<div class="text about__header-description">IT-радио это не просто обычная радиостанция, мы ваши
партнеры в творчестве и современных технологиях.
</div>
</div>
<div class="about__header-right">
</div>
</div>
<div class="text about__header-bottom">
Наша миссия воплотить ваши мечты в реальность, шаг за шагом. Благодаря разнообразной команде ведущих, журналистов, разработчиков и новаторов, мы постоянно расширяем границы возможного в цифровом мире.
</div>
</div>
<div class="about__description">
<h2 class="h2">Мы здесь, чтобы открыть глаза на мир IT</h2>
<div class="about__description-info">
<div class="text about__description-item m--left">
IT-радио это уникальный проект, который объединяет в себе самых ярких представителей IT-индустрии, а также экспертов из различных областей, чтобы поделиться своими знаниями и опытом с широкой аудиторией.
</div>
<div class="text about__description-item">
Мы команда, которая верит в силу теплой улыбки и дружеской беседы.
</div>
</div>
</div>
<video class="about__video" playsinline="" autoplay="" loop="" muted="">
<source src="@/assets/videos/about.mp4" type="video/mp4">
</video>
<div class="about__description">
<div class="about__description-info">
<div class="text about__description-item m--left">
Основанное с целью переосмыслить радио через призму современного и инновационного подхода, мы стали больше, чем просто радиостанцией, мы сообщество родственных душ, которые разделяют страсть к артистизму, развитию и инновациям.
</div>
<div class="text about__description-item">
Каждое шоу на IT-радио включает в себя актуальные темы, новости, обзоры, интервью с экспертами и многое другое.
</div>
</div>
</div>
</div>
<div class="about__gallery">
<div class="about__gallery-item m--gallery-item-one">
</div>
<div class="about__gallery-item m--gallery-item-two">
</div>
<div class="about__gallery-item m--gallery-item-three">
</div>
</div>
<Team/>
<div class="app__content">
<div class="about__history">
<div class="about__history-header">
<h2 class="h2 about__history-title">История радиостанции</h2>
<div class="title about__history-date">Дата</div>
</div>
<div class="about__history-list">
<div class="about__history-item">
<div class="title m--white about__history-title">Событие кратко 1</div>
<div class="about__history-date">Ноябрь 2023</div>
</div>
<div class="about__history-item">
<div class="title m--white about__history-title">Событие кратко 2</div>
<div class="about__history-date">Ноябрь 2023</div>
</div>
<div class="about__history-item">
<div class="title m--white about__history-title">Событие кратко 3</div>
<div class="about__history-date">Ноябрь 2023</div>
</div>
<div class="about__history-item">
<div class="title m--white about__history-title">Событие кратко 4</div>
<div class="about__history-date">Ноябрь 2023</div>
</div>
</div>
</div>
<SupportBlock/>
</div>
</div>
<div class="about__header">
<div class="about__header-top">
<div class="about__header-left">
<h1 class="h2">О нас</h1>
<div class="text about__header-description">
IT-радио это не просто обычная радиостанция, мы ваши партнеры в
творчестве и современных технологиях.
</div>
</div>
<div class="about__header-right"></div>
</div>
<div class="text about__header-bottom">
Наша миссия воплотить ваши мечты в реальность, шаг за шагом.
Благодаря разнообразной команде ведущих, журналистов, разработчиков и
новаторов, мы постоянно расширяем границы возможного в цифровом мире.
</div>
</div>
<div class="about__description">
<h2 class="h2">Мы здесь, чтобы открыть глаза на мир IT</h2>
<div class="about__description-info">
<div class="text about__description-item m--left">
IT-радио это уникальный проект, который объединяет в себе самых
ярких представителей IT-индустрии, а также экспертов из различных
областей, чтобы поделиться своими знаниями и опытом с широкой
аудиторией.
</div>
<div class="text about__description-item">
Мы команда, которая верит в силу теплой улыбки и дружеской беседы.
</div>
</div>
</div>
<video class="about__video" playsinline="" autoplay="" loop="" muted="">
<source src="@/assets/videos/about.mp4" type="video/mp4" />
</video>
<div class="about__description">
<div class="about__description-info">
<div class="text about__description-item m--left">
Основанное с целью переосмыслить радио через призму современного и
инновационного подхода, мы стали больше, чем просто радиостанцией,
мы сообщество родственных душ, которые разделяют страсть к
артистизму, развитию и инновациям.
</div>
<div class="text about__description-item">
Каждое шоу на IT-радио включает в себя актуальные темы, новости,
обзоры, интервью с экспертами и многое другое.
</div>
</div>
</div>
</div>
<div class="about__gallery">
<div class="about__gallery-item m--gallery-item-one"></div>
<div class="about__gallery-item m--gallery-item-two"></div>
<div class="about__gallery-item m--gallery-item-three"></div>
</div>
<Team />
<div class="app__content">
<div class="about__history">
<div class="about__history-header">
<h2 class="h2 about__history-title">История радиостанции</h2>
<div class="title about__history-date">Дата</div>
</div>
<div class="about__history-list">
<div class="about__history-item">
<div class="title m--white about__history-title">
Событие кратко 1
</div>
<div class="about__history-date">Ноябрь 2023</div>
</div>
<div class="about__history-item">
<div class="title m--white about__history-title">
Событие кратко 2
</div>
<div class="about__history-date">Ноябрь 2023</div>
</div>
<div class="about__history-item">
<div class="title m--white about__history-title">
Событие кратко 3
</div>
<div class="about__history-date">Ноябрь 2023</div>
</div>
<div class="about__history-item">
<div class="title m--white about__history-title">
Событие кратко 4
</div>
<div class="about__history-date">Ноябрь 2023</div>
</div>
</div>
</div>
<SupportBlock />
</div>
</div>
</template> </template>
<script> <script>
import AppBreadcrumbs from "@/components/app-breadcrumbs.vue"; import AppBreadcrumbs from '@/components/app-breadcrumbs.vue';
import Team from "@/components/team.vue"; import Team from '@/components/team.vue';
import SupportBlock from "@/components/support-block.vue"; import SupportBlock from '@/components/support-block.vue';
export default { export default {
name: 'about', name: 'about',
components: {SupportBlock, Team, AppBreadcrumbs} components: { SupportBlock, Team, AppBreadcrumbs },
} };
</script> </script>

View File

@ -1,112 +1,131 @@
<template> <template>
<div class="app__content contacts"> <div class="app__content contacts">
<AppBreadcrumbs <AppBreadcrumbs
:breadcrumbs="[ :breadcrumbs="[
{ name: 'Главная', route: { name: 'home' } }, { name: 'Главная', route: { name: 'home' } },
{ name: 'Контакты', route: { name: 'contacts' } }, { name: 'Контакты', route: { name: 'contacts' } },
]" ]"
/> />
<h1 class="h2">Контакты</h1> <h1 class="h2">Контакты</h1>
<div class="contacts__content"> <div class="contacts__content">
<div class="contacts__info"> <div class="contacts__info">
<div class="text contacts__item"> <div class="text contacts__item">
<span class="title">Телефон</span> <span class="title">Телефон</span>
+7 (900) 000-00-00 +7 (900) 000-00-00
</div> </div>
<div class="text contacts__item"> <div class="text contacts__item">
<span class="title">Почта</span> <span class="title">Почта</span>
it-radio@info.org it-radio@info.org
</div> </div>
<div class="text contacts__item"> <div class="text contacts__item">
<span class="title">Адрес</span> <span class="title">Адрес</span>
г. Челябинск, Адрес г. Челябинск, Адрес
</div> </div>
<div class="text contacts__item"> <div class="text contacts__item">
<span class="title">Соц. сети</span> <span class="title">Соц. сети</span>
<div class="contacts__social"> <div class="contacts__social">
<div class="contacts__social m--telegram"></div> <div class="contacts__social m--telegram"></div>
<div class="contacts__social m--vk"></div> <div class="contacts__social m--vk"></div>
</div> </div>
</div> </div>
</div> </div>
<div class="contacts__map"> <div class="contacts__map">
<div class="contacts__map-frame" style="position:relative;overflow:hidden;"><a href="https://yandex.ru/maps/56/chelyabinsk/?utm_medium=mapframe&utm_source=maps" style="color:#eee;font-size:12px;position:absolute;top:0px;">Челябинск</a><a href="https://yandex.ru/maps/geo/chelyabinsk/53159527/?ll=61.421984%2C55.159071&utm_medium=mapframe&utm_source=maps&z=14.04" style="color:#eee;font-size:12px;position:absolute;top:14px;">Челябинск Яндекс Карты</a><iframe src="https://yandex.ru/map-widget/v1/?ll=61.421984%2C55.159071&mode=poi&poi%5Bpoint%5D=61.399655%2C55.160475&poi%5Buri%5D=ymapsbm1%3A%2F%2Fgeo%3Fdata%3DCgg1MzE1OTUyNxIg0KDQvtGB0YHQuNGPLCDQp9C10LvRj9Cx0LjQvdGB0LoiCg04nHVCFb2jXEI%2C&z=14.04" width="100%" height="100%" frameborder="1" allowfullscreen="true" style="position:relative;"></iframe></div> </div> <div
<FormKit class="contacts__map-frame"
v-model="formData" style="position: relative; overflow: hidden"
type="form" >
data-loading="showLoaderSending" <a
form-class="$reset contacts__form form" href="https://yandex.ru/maps/56/chelyabinsk/?utm_medium=mapframe&utm_source=maps"
submit-label="Отправить" style="color: #eee; font-size: 12px; position: absolute; top: 0px"
:disabled="showLoaderSending" >Челябинск</a
:loading="showLoaderSending ? true : undefined" ><a
:submit-attrs="{ href="https://yandex.ru/maps/geo/chelyabinsk/53159527/?ll=61.421984%2C55.159071&utm_medium=mapframe&utm_source=maps&z=14.04"
inputClass: '$reset button m--white m--arrow m--w-100', style="color: #eee; font-size: 12px; position: absolute; top: 14px"
wrapperClass: '$reset registration__form-submit form__submit', >Челябинск Яндекс Карты</a
outerClass: '$reset', ><iframe
}" src="https://yandex.ru/map-widget/v1/?ll=61.421984%2C55.159071&mode=poi&poi%5Bpoint%5D=61.399655%2C55.160475&poi%5Buri%5D=ymapsbm1%3A%2F%2Fgeo%3Fdata%3DCgg1MzE1OTUyNxIg0KDQvtGB0YHQuNGPLCDQp9C10LvRj9Cx0LjQvdGB0LoiCg04nHVCFb2jXEI%2C&z=14.04"
@submit="submitHandler" width="100%"
@click-outside="$emit('hideModal')" height="100%"
> frameborder="1"
<div class="title">Напишите нам</div> allowfullscreen="true"
<FormKitSchema :schema="schema"/> style="position: relative"
</FormKit> ></iframe>
</div> </div>
<SupportBlock/> </div>
</div> <FormKit
v-model="formData"
type="form"
data-loading="showLoaderSending"
form-class="$reset contacts__form form"
submit-label="Отправить"
:disabled="showLoaderSending"
:loading="showLoaderSending ? true : undefined"
:submit-attrs="{
inputClass: '$reset button m--white m--arrow m--w-100',
wrapperClass: '$reset registration__form-submit form__submit',
outerClass: '$reset',
}"
@submit="submitHandler"
@click-outside="$emit('hideModal')"
>
<div class="title">Напишите нам</div>
<FormKitSchema :schema="schema" />
</FormKit>
</div>
<SupportBlock />
</div>
</template> </template>
<script> <script>
import AppBreadcrumbs from "@/components/app-breadcrumbs.vue"; import AppBreadcrumbs from '@/components/app-breadcrumbs.vue';
import SupportBlock from "@/components/support-block.vue"; import SupportBlock from '@/components/support-block.vue';
export default { export default {
name: 'contacts', name: 'contacts',
components: {SupportBlock, AppBreadcrumbs}, components: { SupportBlock, AppBreadcrumbs },
data(){ data() {
return{ return {
formData: {}, formData: {},
schema: [ schema: [
{ {
$formkit: 'text', $formkit: 'text',
name: 'name', name: 'name',
label: 'ФИО', label: 'ФИО',
placeholder: 'ФИО', placeholder: 'ФИО',
validation: 'required', validation: 'required',
outerClass: 'field--required' outerClass: 'field--required',
}, },
{ {
$formkit: 'text', $formkit: 'text',
name: 'name', name: 'name',
label: 'Название организации', label: 'Название организации',
placeholder: 'Название организации', placeholder: 'Название организации',
validation: 'required', validation: 'required',
outerClass: 'field--required' outerClass: 'field--required',
}, },
{ {
$formkit: 'maska', $formkit: 'maska',
name: 'phone', name: 'phone',
maska: { mask: '+7 (###) ###-##-##' }, maska: { mask: '+7 (###) ###-##-##' },
label: 'Контактный телефон', label: 'Контактный телефон',
placeholder: '+7 (###) ###-##-##', placeholder: '+7 (###) ###-##-##',
validation: 'required', validation: 'required',
outerClass: 'field--required' outerClass: 'field--required',
}, },
{ {
$formkit: 'textarea', $formkit: 'textarea',
name: 'message', name: 'message',
label: 'Сообщение', label: 'Сообщение',
placeholder: 'Сообщение', placeholder: 'Сообщение',
validation: 'required', validation: 'required',
outerClass: 'field--required' outerClass: 'field--required',
} },
], ],
showLoaderSending: false showLoaderSending: false,
} };
}, },
methods:{ methods: {
submitHandler(){ submitHandler() {},
},
} };
}
}
</script> </script>

View File

@ -1,133 +1,140 @@
<template> <template>
<div class="home"> <div class="home">
<div class="home__meaning" ref="targetWrapper"> <div class="home__meaning" ref="targetWrapper">
<div class="app__content"> <div class="app__content">
<p class="text home__subtitle"> <p class="text home__subtitle">
Мы цифровое <span>онлайн радио.</span><br/> Мы цифровое <span>онлайн радио.</span><br />
Помогаем разобраться в том, что такое <span>IT.</span><br/> Помогаем разобраться в том, что такое <span>IT.</span><br />
Находимся в <span>Челябинске</span>, но вещаем на весь <span>Мир</span><br/> Находимся в <span>Челябинске</span>, но вещаем на весь <span>Мир</span
</p> ><br />
<h1 class="home__title" ref="targetTitle"> </p>
IT-Радио <span id="targetTitleSpan">радиостанция про сферу</span> технологий <br/> и развитие <h1 class="home__title" ref="targetTitle">
<span id="targetTitleSpan">в IT</span> IT-Радио
<!-- IT Радио --> <span id="targetTitleSpan">радиостанция про сферу</span> технологий
<!-- <span id="targetTitleSpan">радиостанция</span>--> <br />
<!-- <br/>--> и развитие
<!-- <span id="targetTitleSpan">про сферу</span> технологий<br/>--> <span id="targetTitleSpan">в IT</span>
<!-- и развитие <span id="targetTitleSpan">в IT</span><br/>--> <!-- IT Радио -->
</h1> <!-- <span id="targetTitleSpan">радиостанция</span>-->
</div> <!-- <br/>-->
<div class="home__banner" ref="target"> <!-- <span id="targetTitleSpan">про сферу</span> технологий<br/>-->
</div> <!-- и развитие <span id="targetTitleSpan">в IT</span><br/>-->
</div> </h1>
<template v-if="true"> </div>
<div class="app__content"> <div class="home__banner" ref="target"></div>
</div>
<div class="home__description"> <template v-if="true">
<div class="home__info"> <div class="app__content">
<div class="text home__info--item"> <div class="home__description">
IT-RADIO. 2023 <div class="home__info">
<span> <div class="text home__info--item">
Сегодня IT-сфера развивается настолько быстро, что следить за всеми новинками и изменениями в ней становится все сложнее.<br/><br/> Но есть способ всегда быть в курсе последних новостей и событий это IT-радио. IT-RADIO. 2023
</span> <span>
</div> Сегодня IT-сфера развивается настолько быстро, что следить за
<h2 class="h2 m--border"> всеми новинками и изменениями в ней становится все сложнее.<br /><br />
Открывая новые горизонты в мире технологий Но есть способ всегда быть в курсе последних новостей и событий
</h2> это IT-радио.
<div class="text home__info--item m--circle"> </span>
<span> </div>
IT-радио это уникальный проект, который объединяет в себе самых ярких представителей IT-индустрии, а также экспертов из различных областей, чтобы поделиться своими знаниями и опытом с широкой аудиторией.<br/><br/> <h2 class="h2 m--border">
Каждое шоу на IT-радио включает в себя актуальные темы, новости, обзоры, интервью с экспертами и многое другое. Открывая новые горизонты в мире технологий
</span> </h2>
</div> <div class="text home__info--item m--circle">
</div> <span>
<div class="home__content"> IT-радио это уникальный проект, который объединяет в себе
<div class="home__content--item m--one-circle"> самых ярких представителей IT-индустрии, а также экспертов из
<span class="title">Музыка</span> различных областей, чтобы поделиться своими знаниями и опытом с
Нам важно создать комфортную атмосферу, которая поможет сосредоточиться на задачах и улучшит широкой аудиторией.<br /><br />
продуктивность. Каждое шоу на IT-радио включает в себя актуальные темы, новости,
</div> обзоры, интервью с экспертами и многое другое.
<div class="home__content--item m--two-circle"> </span>
<span class="title">Подкасты</span> </div>
Возможность задать вопросы профессионалам из разных областей IT </div>
</div> <div class="home__content">
<div class="home__content--item m--three-circle"> <div class="home__content--item m--one-circle">
<span class="title">Новости</span> <span class="title">Музыка</span>
Обзоры последних новинок и изменений в IT-индустрии Нам важно создать комфортную атмосферу, которая поможет
</div> сосредоточиться на задачах и улучшит продуктивность.
</div> </div>
</div> <div class="home__content--item m--two-circle">
</div> <span class="title">Подкасты</span>
<Team/> Возможность задать вопросы профессионалам из разных областей IT
<div class="app__content"> </div>
<RubricBlock/> <div class="home__content--item m--three-circle">
</div> <span class="title">Новости</span>
<div class="home__social"> Обзоры последних новинок и изменений в IT-индустрии
<div class="home__social--tools"> </div>
<div class="home__social--description"> </div>
<h2 class="h2 m--white">Соц сети</h2> </div>
<div class="text"> </div>
Следите за обновлениями и новыми постами на IT Radio, чтобы быть в курсе последних новостей <Team />
и <div class="app__content">
событий в мире IT, а также следить за анонсами и обновлениями! <RubricBlock />
</div> </div>
</div> <div class="home__social">
<div class="home__social--btns"> <div class="home__social--tools">
<button class="button m--blur">Telegram</button> <div class="home__social--description">
<button class="button m--blur">VKontakte</button> <h2 class="h2 m--white">Соц сети</h2>
<button class="button m--blur">Instagram</button> <div class="text">
<button class="button m--blur">YouTube</button> Следите за обновлениями и новыми постами на IT Radio, чтобы быть в
</div> курсе последних новостей и событий в мире IT, а также следить за
</div> анонсами и обновлениями!
</div> </div>
<div class="app__content"> </div>
<blog/> <div class="home__social--btns">
</div> <button class="button m--blur">Telegram</button>
</template> <button class="button m--blur">VKontakte</button>
</div> <button class="button m--blur">Instagram</button>
<button class="button m--blur">YouTube</button>
</div>
</div>
</div>
<div class="app__content">
<blog />
</div>
</template>
</div>
</template> </template>
<script> <script>
import {gsap} from "gsap"; import { gsap } from 'gsap';
import {ScrollTrigger} from "gsap/ScrollTrigger"; import { ScrollTrigger } from 'gsap/ScrollTrigger';
import Team from "@/components/team.vue"; import Team from '@/components/team.vue';
import RubricBlock from "components/rubric-block.vue"; import RubricBlock from 'components/rubric-block.vue';
import Blog from "components/blog.vue"; import Blog from 'components/blog.vue';
export default { export default {
name: 'home', name: 'home',
components: {Blog, RubricBlock, Team}, components: { Blog, RubricBlock, Team },
created() { created() {},
}, mounted() {
mounted() { this.initScene();
this.initScene(); },
}, methods: {
methods: { initScene() {
initScene() { gsap.registerPlugin(ScrollTrigger);
gsap.registerPlugin(ScrollTrigger); gsap.to(this.$refs.target, {
gsap.to(this.$refs.target, { scale: 1,
scale: 1, scrollTrigger: {
scrollTrigger: { trigger: this.$refs.targetWrapper,
trigger: this.$refs.targetWrapper, scrub: true,
scrub: true, start: 0,
start: 0, end: 600,
end: 600, pin: true,
pin: true, },
}, });
}, gsap.to(this.$refs.targetTitle, {
); color: 'transparent',
gsap.to(this.$refs.targetTitle, { backgroundImage:
color: 'transparent', 'linear-gradient(91.17deg, #C6F1F7 -4.01%, #F983E9 36.14%, #B877FF 77.44%, #C2E9CD 106.11%)',
backgroundImage: 'linear-gradient(91.17deg, #C6F1F7 -4.01%, #F983E9 36.14%, #B877FF 77.44%, #C2E9CD 106.11%)', scrollTrigger: {
scrollTrigger: { trigger: this.$refs.targetWrapper,
trigger: this.$refs.targetWrapper, scrub: true,
scrub: true, start: 0,
start: 0, end: 600,
end: 600, },
}, });
}, },
); },
} };
}
}
</script> </script>

View File

@ -1,179 +1,203 @@
<template> <template>
<div class="playlist-edit"> <div class="playlist-edit">
<AppBreadcrumbs <AppBreadcrumbs
:breadcrumbs="[ :breadcrumbs="[
{ name: 'Главная', route: { name: 'home' } }, { name: 'Главная', route: { name: 'home' } },
{ name: 'Личный кабинет', route: { name: 'profile' } }, { name: 'Личный кабинет', route: { name: 'profile' } },
$route.name==='playlist-create'? $route.name === 'playlist-create'
{ name: 'Добавление плейлиста', route: { name: 'playlist-create' } }: ? { name: 'Добавление плейлиста', route: { name: 'playlist-create' } }
{ name: 'Редактирование плейлиста', route: { name: 'playlist-edit' } }, : {
]"/> name: 'Редактирование плейлиста',
<h1 class="h2 playlist__title m--margin">{{ $route.name === 'playlist-create' ? 'Новый плейлист' : playlist.name }}</h1> route: { name: 'playlist-edit' },
<button class="playlist-edit__upload" @click="handlerUploadCover">Добавить обложку</button> },
<div class="field__input m--hidden"> ]"
<input />
id="cover" <h1 class="h2 playlist__title m--margin">
ref="coverInput" {{ $route.name === 'playlist-create' ? 'Новый плейлист' : playlist.name }}
accept=".jpg,.png,.svg" </h1>
class="input" <button class="playlist-edit__upload" @click="handlerUploadCover">
type="file" Добавить обложку
name="logo" </button>
> <div class="field__input m--hidden">
</div> <input
<FormKit id="cover"
v-model="playlist.name" ref="coverInput"
type="text" accept=".jpg,.png,.svg"
outer-class="playlist-edit__search" class="input"
inner-class="m--search" type="file"
placeholder="Название плейлиста" name="logo"
></FormKit> />
<div class="playlist-edit__list"> </div>
<div class="playlist-edit__item"> <FormKit
<div class="playlist-edit__title">Поиск по каталогу</div> v-model="playlist.name"
<template v-if="showLoaderSongs"> type="text"
<div class="loader"> outer-class="playlist-edit__search"
<div class="spinner"/> inner-class="m--search"
Загрузка данных placeholder="Название плейлиста"
</div> ></FormKit>
</template> <div class="playlist-edit__list">
<SongList <div class="playlist-edit__item">
v-else-if="songsFiltered.length>0" <div class="playlist-edit__title">Поиск по каталогу</div>
:songList="songsFiltered" <template v-if="showLoaderSongs">
class="m--column" <div class="loader">
@addPlaylist="addPlaylist" <div class="spinner" />
/> Загрузка данных
<div v-else>Каталог музыки пуст!</div> </div>
</div> </template>
<div class="playlist-edit__item"> <SongList
<div class="playlist-edit__title">Добавленные треки</div> v-else-if="songsFiltered.length > 0"
<template v-if="showLoaderPlaylist"> :songList="songsFiltered"
<div class="loader"> class="m--column"
<div class="spinner"/> @addPlaylist="addPlaylist"
Загрузка данных />
</div> <div v-else>Каталог музыки пуст!</div>
</template> </div>
<SongList <div class="playlist-edit__item">
v-else-if="playlist.song?.length>0" <div class="playlist-edit__title">Добавленные треки</div>
:songList="playlist.song" <template v-if="showLoaderPlaylist">
class="m--column" <div class="loader">
:songAlreadyAdd="true" <div class="spinner" />
@removePlaylist="removePlaylist" Загрузка данных
/> </div>
<div v-else>Добавьте музыку в плейлист!</div> </template>
</div> <SongList
</div> v-else-if="playlist.song?.length > 0"
</div> :songList="playlist.song"
class="m--column"
:songAlreadyAdd="true"
@removePlaylist="removePlaylist"
/>
<div v-else>Добавьте музыку в плейлист!</div>
</div>
</div>
</div>
</template> </template>
<script> <script>
import {app} from "@/services"; import { app } from '@/services';
import AppBreadcrumbs from "@/components/app-breadcrumbs.vue"; import AppBreadcrumbs from '@/components/app-breadcrumbs.vue';
import SongList from "@/components/song-list.vue"; import SongList from '@/components/song-list.vue';
export default { export default {
name: 'playlist-edit', name: 'playlist-edit',
components: {SongList, AppBreadcrumbs}, components: { SongList, AppBreadcrumbs },
data() { data() {
return { return {
playlist: {}, playlist: {},
songs: [], songs: [],
showLoaderSongs: false, showLoaderSongs: false,
showLoaderPlaylist: false, showLoaderPlaylist: false,
} };
}, },
created() { created() {
this.getAllSong(); this.getAllSong();
this.getPlaylist(); this.getPlaylist();
}, },
computed: { computed: {
songsFiltered() { songsFiltered() {
return this.songs.filter(song => { return this.songs.filter((song) => {
const alreadyAdd = this.playlist.song.find(item => item.azura_id === song.azura_id) const alreadyAdd = this.playlist.song.find(
return !alreadyAdd (item) => item.azura_id === song.azura_id,
}) );
} return !alreadyAdd;
}, });
methods: { },
getPlaylist() { },
this.showLoaderPlaylist = true; methods: {
app.getPlaylist(this.$route.params.id).then(res => { getPlaylist() {
this.showLoaderPlaylist = false; this.showLoaderPlaylist = true;
this.playlist = res; app
}).catch(err => { .getPlaylist(this.$route.params.id)
this.showLoaderPlaylist = false; .then((res) => {
console.error(err) this.showLoaderPlaylist = false;
}) this.playlist = res;
}, })
getAllSong() { .catch((err) => {
this.showLoaderSongs = true; this.showLoaderPlaylist = false;
app.getAllSong().then(res => { console.error(err);
this.showLoaderSongs = false; });
this.songs = res; },
}).catch(err => { getAllSong() {
this.showLoaderSongs = false; this.showLoaderSongs = true;
console.error(err) app
}) .getAllSong()
}, .then((res) => {
addPlaylist(song) { this.showLoaderSongs = false;
console.log(song) this.songs = res;
const params = { })
playlist_id: this.$route.params.id, .catch((err) => {
...song this.showLoaderSongs = false;
} console.error(err);
this.showLoaderSongs = true; });
this.showLoaderPlaylist = true; },
app.addSongToPlaylist(params).then(() => { addPlaylist(song) {
this.showLoaderPlaylist = false; console.log(song);
this.showLoaderSongs = false; const params = {
this.getPlaylist(); playlist_id: this.$route.params.id,
}).catch(err => { ...song,
this.showLoaderPlaylist = false; };
this.showLoaderSongs = false; this.showLoaderSongs = true;
console.error(err) this.showLoaderPlaylist = true;
}) app
}, .addSongToPlaylist(params)
removePlaylist(song) { .then(() => {
const params = { this.showLoaderPlaylist = false;
playlist_id: this.$route.params.id, this.showLoaderSongs = false;
azura_id: song.azura_id this.getPlaylist();
} })
this.showLoaderSongs = true; .catch((err) => {
this.showLoaderPlaylist = true; this.showLoaderPlaylist = false;
app.removeSongToPlaylist(params).then(() => { this.showLoaderSongs = false;
this.showLoaderPlaylist = false; console.error(err);
this.showLoaderSongs = false; });
this.getPlaylist(); },
}).catch(err => { removePlaylist(song) {
this.showLoaderPlaylist = false; const params = {
this.showLoaderSongs = false; playlist_id: this.$route.params.id,
console.error(err) azura_id: song.azura_id,
}) };
}, this.showLoaderSongs = true;
handlerUploadCover(){ this.showLoaderPlaylist = true;
let logoInput = this.$refs.coverInput; app
let click = new MouseEvent('click'); .removeSongToPlaylist(params)
.then(() => {
logoInput.onchange = this.uploadCover; this.showLoaderPlaylist = false;
logoInput.dispatchEvent(click); this.showLoaderSongs = false;
}, this.getPlaylist();
uploadCover(event){ })
let file = event.target.files ? event.target.files[0] : null .catch((err) => {
if (file) { this.showLoaderPlaylist = false;
const data = new FormData(); this.showLoaderSongs = false;
data.append('playlist_art', file); console.error(err);
data.append('playlist_id', this.$route.params.id); });
app.updatePlaylist(data).then((res) => { },
this.showLoaderPlaylist = false; handlerUploadCover() {
this.showLoaderSongs = false; let logoInput = this.$refs.coverInput;
this.playlist = res; let click = new MouseEvent('click');
}).catch(err => {
this.showLoaderPlaylist = false; logoInput.onchange = this.uploadCover;
this.showLoaderSongs = false; logoInput.dispatchEvent(click);
console.error(err) },
}) uploadCover(event) {
} let file = event.target.files ? event.target.files[0] : null;
} if (file) {
} const data = new FormData();
} data.append('playlist_art', file);
data.append('playlist_id', this.$route.params.id);
app
.updatePlaylist(data)
.then((res) => {
this.showLoaderPlaylist = false;
this.showLoaderSongs = false;
this.playlist = res;
})
.catch((err) => {
this.showLoaderPlaylist = false;
this.showLoaderSongs = false;
console.error(err);
});
}
},
},
};
</script> </script>

View File

@ -1,55 +1,63 @@
<template> <template>
<div class="playlist"> <div class="playlist">
<template v-if="showLoaderPlaylist"> <template v-if="showLoaderPlaylist">
<div class="loader"> <div class="loader">
<div class="spinner"/> <div class="spinner" />
Загрузка данных Загрузка данных
</div> </div>
</template> </template>
<template v-else> <template v-else>
<div class="playlist__header"> <div class="playlist__header">
<div class="playlist__back" @click="handlerBack"></div> <div class="playlist__back" @click="handlerBack"></div>
<div class="h2 playlist__title">{{ playlist.name }}</div> <div class="h2 playlist__title">{{ playlist.name }}</div>
<div class="playlist__edit" @click="next({name: 'playlist-edit', params:{id:this.playlist.id}})"></div> <div
</div> class="playlist__edit"
<SongList :songList="playlist.song" :songAlreadyAdd="true"/> @click="
</template> next({ name: 'playlist-edit', params: { id: this.playlist.id } })
</div> "
></div>
</div>
<SongList :songList="playlist.song" :songAlreadyAdd="true" />
</template>
</div>
</template> </template>
<script> <script>
import {app} from "@/services"; import { app } from '@/services';
import SongList from "@/components/song-list.vue"; import SongList from '@/components/song-list.vue';
export default { export default {
name: 'playlist', name: 'playlist',
components: {SongList}, components: { SongList },
data() { data() {
return { return {
showLoaderPlaylist: false, showLoaderPlaylist: false,
playlist: {} playlist: {},
} };
}, },
created() { created() {
this.getPlaylist(); this.getPlaylist();
}, },
methods: { methods: {
getPlaylist() { getPlaylist() {
this.showLoaderPlaylist = true; this.showLoaderPlaylist = true;
app.getPlaylist(this.$route.params.id).then(res => { app
this.showLoaderPlaylist = false; .getPlaylist(this.$route.params.id)
this.playlist = res; .then((res) => {
}).catch(err => { this.showLoaderPlaylist = false;
this.showLoaderPlaylist = false; this.playlist = res;
console.error(err) })
}) .catch((err) => {
}, this.showLoaderPlaylist = false;
handlerBack() { console.error(err);
this.$router.go(-1); });
}, },
next(params) { handlerBack() {
this.$router.push(params); this.$router.go(-1);
} },
} next(params) {
} this.$router.push(params);
},
},
};
</script> </script>

View File

@ -1,109 +1,109 @@
<template> <template>
<div class="app__content playlists"> <div class="app__content playlists">
<AppBreadcrumbs <AppBreadcrumbs
:breadcrumbs="[ :breadcrumbs="[
{ name: 'Главная', route: { name: 'home' } }, { name: 'Главная', route: { name: 'home' } },
{ name: 'Плейлист', route: { name: 'playlists' } }, { name: 'Плейлист', route: { name: 'playlists' } },
]" ]"
/> />
<div class="playlists__content"> <div class="playlists__content">
<h1 class="h2">Плейлист</h1> <h1 class="h2">Плейлист</h1>
<div class="playlists__tabs tabs m--btns"> <div class="playlists__tabs tabs m--btns">
<button <button
v-for="item in tabsItems" v-for="item in tabsItems"
:key="`tab-${item.name}`" :key="`tab-${item.name}`"
class="button" class="button"
:class="currentTabsItem === item.name && 'is-active'" :class="currentTabsItem === item.name && 'is-active'"
@click.prevent="changeTab(item.name)" @click.prevent="changeTab(item.name)"
> >
{{ item.label }} {{ item.label }}
</button> </button>
</div> </div>
<div class="playlists__list"> <div class="playlists__list">
<div class="playlists__item"> <div class="playlists__item">
<div class="title m--white playlists__time">09:00</div> <div class="title m--white playlists__time">09:00</div>
<div class="text playlists__param">Исполнитель</div> <div class="text playlists__param">Исполнитель</div>
<div class="text playlists__param m--long">Название трека</div> <div class="text playlists__param m--long">Название трека</div>
</div>
<div class="playlists__item">
<div class="title m--white playlists__time">09:00</div>
<div class="text playlists__param">Исполнитель</div>
<div class="text playlists__param m--long">Название трека</div>
</div>
<div class="playlists__item">
<div class="title m--white playlists__time">09:00</div>
<div class="text playlists__param">Исполнитель</div>
<div class="text playlists__param m--long">Название трека</div>
</div>
<div class="playlists__item">
<div class="title m--white playlists__time">09:00</div>
<div class="text playlists__param">Исполнитель</div>
<div class="text playlists__param m--long">Название трека</div>
</div>
<div class="playlists__item">
<div class="title m--white playlists__time">09:00</div>
<div class="text playlists__param">Исполнитель</div>
<div class="text playlists__param m--long">Название трека</div>
</div>
</div>
<Pagination :total="37" :limit="5" :currentPage="currentPage || 1" />
</div> </div>
<div class="playlists__item">
<div class="title m--white playlists__time">09:00</div>
<div class="text playlists__param">Исполнитель</div>
<div class="text playlists__param m--long">Название трека</div>
</div>
<div class="playlists__item">
<div class="title m--white playlists__time">09:00</div>
<div class="text playlists__param">Исполнитель</div>
<div class="text playlists__param m--long">Название трека</div>
</div>
<div class="playlists__item">
<div class="title m--white playlists__time">09:00</div>
<div class="text playlists__param">Исполнитель</div>
<div class="text playlists__param m--long">Название трека</div>
</div>
<div class="playlists__item">
<div class="title m--white playlists__time">09:00</div>
<div class="text playlists__param">Исполнитель</div>
<div class="text playlists__param m--long">Название трека</div>
</div>
</div>
<Pagination :total="37" :limit="5" :currentPage="currentPage || 1" />
</div> </div>
</div>
</template> </template>
<script> <script>
import AppBreadcrumbs from "@/components/app-breadcrumbs.vue"; import AppBreadcrumbs from '@/components/app-breadcrumbs.vue';
import Pagination from "@/components/pagination.vue"; import Pagination from '@/components/pagination.vue';
// import { audio } from "@/services"; // import { audio } from "@/services";
export default { export default {
name: 'playlists', name: 'playlists',
components: {Pagination, AppBreadcrumbs}, components: { Pagination, AppBreadcrumbs },
data(){ data() {
return{ return {
currentTabsItem: 'today', currentTabsItem: 'today',
currentPage: 1, currentPage: 1,
tabsItems:[ tabsItems: [
{ {
label: 'Вчера', label: 'Вчера',
name: 'yesterday' name: 'yesterday',
}, },
{ {
label: 'Сегодня', label: 'Сегодня',
name: 'today' name: 'today',
}, },
{ {
label: 'Завтра', label: 'Завтра',
name: 'tomorrow' name: 'tomorrow',
}, },
], ],
station: this.$store.state.station station: this.$store.state.station,
} };
},
watch: {
'$route.query.page': {
handler(from) {
this.currentPage = Number(from);
},
}, },
watch:{ },
'$route.query.page': { created() {
handler(from) { // this.getPlayList();
this.currentPage = Number(from); },
}, methods: {
} // getPlayList(){
// audio.getPlayList(this.station.id).then(res => {
// let groups = res
// // this.$store.dispatch('setMeta', {});
// // this.$store.dispatch('fetchDataByKey', { data: groups, key: 'groups' });
// // this.showLoaderSending.groups = false;
// }).catch(err => {
// // this.showLoaderSending.groups = false;
// console.error(err)
// })
// },
changeTab(tab) {
this.currentTabsItem = tab;
}, },
created() { },
// this.getPlayList(); };
},
methods:{
// getPlayList(){
// audio.getPlayList(this.station.id).then(res => {
// let groups = res
// // this.$store.dispatch('setMeta', {});
// // this.$store.dispatch('fetchDataByKey', { data: groups, key: 'groups' });
// // this.showLoaderSending.groups = false;
// }).catch(err => {
// // this.showLoaderSending.groups = false;
// console.error(err)
// })
// },
changeTab(tab){
this.currentTabsItem = tab;
}
}
}
</script> </script>

View File

@ -1,11 +1,9 @@
<template> <template>
<div> <div></div>
</div>
</template> </template>
<script> <script>
export default { export default {
name: 'podcasts' name: 'podcasts',
} };
</script> </script>

View File

@ -1,171 +1,198 @@
<template> <template>
<div class="app__content profile"> <div class="app__content profile">
<template v-if="$route.name !== 'playlist-edit' && $route.name !== 'playlist-create'"> <template
<AppBreadcrumbs v-if="
:breadcrumbs="[ $route.name !== 'playlist-edit' && $route.name !== 'playlist-create'
{ name: 'Главная', route: { name: 'home' } }, "
{ name: 'Личный кабинет', route: { name: 'profile' } }, >
]" <AppBreadcrumbs
/> :breadcrumbs="[
<h1 class="h2 profile__title">{{ user.email }}</h1> { name: 'Главная', route: { name: 'home' } },
<button class="button m--text-link" @click="showRecovery">Редактировать профиль</button> { name: 'Личный кабинет', route: { name: 'profile' } },
<div class="profile__tabs tabs m--btns"> ]"
<button />
v-for="item in tabsItems" <h1 class="h2 profile__title">{{ user.email }}</h1>
:key="`tab-${item.name}`" <button class="button m--text-link" @click="showRecovery">
class="button" Редактировать профиль
:class="currentTabsItem === item.name && 'is-active'" </button>
@click.prevent="changeTab(item.name)" <div class="profile__tabs tabs m--btns">
> <button
{{ item.label }} v-for="item in tabsItems"
</button> :key="`tab-${item.name}`"
</div> class="button"
</template> :class="currentTabsItem === item.name && 'is-active'"
<template v-if="$route.name === 'profile'"> @click.prevent="changeTab(item.name)"
<template v-if="currentTabsItem==='music'"> >
<template v-if="showLoaderSong"> {{ item.label }}
<div class="loader"> </button>
<div class="spinner"/> </div>
Загрузка данных </template>
</div> <template v-if="$route.name === 'profile'">
</template> <template v-if="currentTabsItem === 'music'">
<SongList v-else :songList="userFavorite.songs" @removeSong="removeFavorites"/> <template v-if="showLoaderSong">
</template> <div class="loader">
<template v-if="currentTabsItem==='playlists'"> <div class="spinner" />
<template v-if="showLoaderPlaylist"> Загрузка данных
<div class="loader"> </div>
<div class="spinner"/> </template>
Загрузка данных <SongList
</div> v-else
</template> :songList="userFavorite.songs"
<PlaylistRoster @removeSong="removeFavorites"
v-else />
:list="userFavorite.playlist" </template>
@createPlaylist="createPlayList" <template v-if="currentTabsItem === 'playlists'">
/> <template v-if="showLoaderPlaylist">
</template> <div class="loader">
</template> <div class="spinner" />
<routerView v-else/> Загрузка данных
</div> </div>
</template>
<PlaylistRoster
v-else
:list="userFavorite.playlist"
@createPlaylist="createPlayList"
/>
</template>
</template>
<routerView v-else />
</div>
</template> </template>
<script> <script>
import AppBreadcrumbs from "@/components/app-breadcrumbs.vue"; import AppBreadcrumbs from '@/components/app-breadcrumbs.vue';
import SongList from "@/components/song-list.vue"; import SongList from '@/components/song-list.vue';
import {app} from "@/services"; import { app } from '@/services';
import PlaylistRoster from "@/components/playlist-roster.vue"; import PlaylistRoster from '@/components/playlist-roster.vue';
export default { export default {
name: 'profile', name: 'profile',
components: {PlaylistRoster, SongList, AppBreadcrumbs}, components: { PlaylistRoster, SongList, AppBreadcrumbs },
data() { data() {
return { return {
currentTabsItem: 'music', currentTabsItem: 'music',
tabsItems: [ tabsItems: [
{ {
label: 'Музыка', label: 'Музыка',
name: 'music' name: 'music',
}, },
{ {
label: 'Подкасты', label: 'Подкасты',
name: 'podcasts' name: 'podcasts',
}, },
{ {
label: 'Плейлисты', label: 'Плейлисты',
name: 'playlists' name: 'playlists',
}, },
], ],
showLoaderSong: false, showLoaderSong: false,
showLoaderPlaylist: false, showLoaderPlaylist: false,
showLoaderPodcast: true, showLoaderPodcast: true,
} };
}, },
computed: { computed: {
user() { user() {
return this.$store.state.user; return this.$store.state.user;
}, },
userFavorite() { userFavorite() {
return this.$store.state.userFavorite return this.$store.state.userFavorite;
} },
}, },
watch: { watch: {
'$route': { $route: {
immediate: true, immediate: true,
handler(to, from) { handler(to, from) {
if (!from && to?.hash && to?.name==='"profile"'){ if (!from && to?.hash && to?.name === '"profile"') {
console.log('1') console.log('1');
this.currentTabsItem = to?.hash.replace('#', '') || 'music'; this.currentTabsItem = to?.hash.replace('#', '') || 'music';
} }
if (to?.hash !== from?.hash && to?.name === from?.name || !from?.name && !from?.hash){ if (
console.log('2') (to?.hash !== from?.hash && to?.name === from?.name) ||
if (to.hash) { (!from?.name && !from?.hash)
this.currentTabsItem = to?.hash.replace('#', '') || 'music'; ) {
} else { console.log('2');
this.currentTabsItem = 'music'; if (to.hash) {
} this.currentTabsItem = to?.hash.replace('#', '') || 'music';
} } else {
else { this.currentTabsItem = 'music';
console.log('3') }
if (to?.name === 'playlist') { } else {
this.currentTabsItem = 'playlists' console.log('3');
} if (to?.name === 'playlist') {
} this.currentTabsItem = 'playlists';
}, }
}, }
}, },
created() { },
this.getSongList(); },
this.getPlaylists(); created() {
}, this.getSongList();
methods: { this.getPlaylists();
getSongList() { },
this.showLoaderSong = true; methods: {
app.getFavoriteList().then(res => { getSongList() {
this.showLoaderSong = false; this.showLoaderSong = true;
this.$store.dispatch('setUserFavorite', {songs: res}); app
}).catch(err => { .getFavoriteList()
this.showLoaderSong = false; .then((res) => {
console.error(err) this.showLoaderSong = false;
}) this.$store.dispatch('setUserFavorite', { songs: res });
}, })
changeTab(tab) { .catch((err) => {
this.currentTabsItem = tab; this.showLoaderSong = false;
if (this.$route.name === 'profile') { console.error(err);
this.$router.push({name: this.$route.name, hash: `#${tab}`}); });
} else { },
this.$router.push({name: 'profile', hash: `#${tab}`}); changeTab(tab) {
} this.currentTabsItem = tab;
}, if (this.$route.name === 'profile') {
removeFavorites(song) { this.$router.push({ name: this.$route.name, hash: `#${tab}` });
this.showLoaderSong = true; } else {
app.removeFavorites(song).then(() => { this.$router.push({ name: 'profile', hash: `#${tab}` });
this.showLoaderSong = false; }
this.getSongList(); },
}).catch(err => { removeFavorites(song) {
this.showLoaderSong = false; this.showLoaderSong = true;
console.error(err) app
}) .removeFavorites(song)
}, .then(() => {
showRecovery() { this.showLoaderSong = false;
this.$store.dispatch('setModal', {changingUser: true}); this.getSongList();
}, })
getPlaylists() { .catch((err) => {
this.showLoaderPlaylist = true; this.showLoaderSong = false;
app.getPlaylists().then(res => { console.error(err);
this.showLoaderPlaylist = false; });
this.$store.dispatch('setUserFavorite', {playlist: res}); },
}).catch(err => { showRecovery() {
this.showLoaderPlaylist = false; this.$store.dispatch('setModal', { changingUser: true });
console.error(err) },
}) getPlaylists() {
}, this.showLoaderPlaylist = true;
createPlayList() { app
app.createPlaylists().then(res=>{ .getPlaylists()
this.$router.push({name: 'playlist-create', params: {id: res.id}}); .then((res) => {
}).catch(err=>{ this.showLoaderPlaylist = false;
console.error(err) this.$store.dispatch('setUserFavorite', { playlist: res });
}) })
} .catch((err) => {
} this.showLoaderPlaylist = false;
} console.error(err);
});
},
createPlayList() {
app
.createPlaylists()
.then((res) => {
this.$router.push({
name: 'playlist-create',
params: { id: res.id },
});
})
.catch((err) => {
console.error(err);
});
},
},
};
</script> </script>

View File

@ -1,21 +1,21 @@
<template> <template>
<div class="app__content rubric"> <div class="app__content rubric">
<AppBreadcrumbs <AppBreadcrumbs
:breadcrumbs="[ :breadcrumbs="[
{ name: 'Главная', route: { name: 'home' } }, { name: 'Главная', route: { name: 'home' } },
{ name: 'Рубрики', route: { name: 'rubric' } }, { name: 'Рубрики', route: { name: 'rubric' } },
]" ]"
/> />
<RubricBlock/> <RubricBlock />
</div> </div>
</template> </template>
<script> <script>
import RubricBlock from "@/components/rubric-block.vue"; import RubricBlock from '@/components/rubric-block.vue';
import AppBreadcrumbs from "@/components/app-breadcrumbs.vue"; import AppBreadcrumbs from '@/components/app-breadcrumbs.vue';
export default { export default {
name: 'rubric', name: 'rubric',
components: {AppBreadcrumbs, RubricBlock} components: { AppBreadcrumbs, RubricBlock },
} };
</script> </script>

View File

@ -1,11 +1,9 @@
<template> <template>
<div> <div></div>
</div>
</template> </template>
<script> <script>
export default { export default {
name: 'support' name: 'support',
} };
</script> </script>