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
@ -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' } }
: {} : {},
] ],
] ],
} };
} };

4575
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,9 +79,10 @@ 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')
.use(ESLintPlugin, [{ extensions: ['js', 'vue'] }]);
// chain.plugin('normal-module-replacement').use( // chain.plugin('normal-module-replacement').use(
// new webpack.NormalModuleReplacementPlugin(/settings$/, function(resource) { // new webpack.NormalModuleReplacementPlugin(/settings$/, function(resource) {
// resource.request = resource.request.replace(/settings$/, `settings/${process.env.NODE_ENV}`); // resource.request = resource.request.replace(/settings$/, `settings/${process.env.NODE_ENV}`);
@ -91,7 +93,8 @@ module.exports = configure(function (ctx) {
// 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,9 +102,10 @@ 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
.rule('videos')
.test(/\.(mp4|webm|mov)(\?.*)?$/) .test(/\.(mp4|webm|mov)(\?.*)?$/)
.type('javascript/auto') .type('javascript/auto')
.use('url-loader') .use('url-loader')
@ -109,25 +113,25 @@ module.exports = configure(function (ctx) {
.options({ .options({
esModule: false, esModule: false,
limit: 32768, limit: 32768,
name: `assets/media/[name].[hash:8].[ext]` 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,30 +1,37 @@
<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> </div>
<Player/> <Player />
<AppFooter/> <AppFooter />
</div> </div>
<Authentication/> <Authentication />
<ChangingUser/> <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: { components: {
ChangingUser, ChangingUser,
Player, Player,
@ -44,29 +51,29 @@ export default {
return this.$store.state.user; return this.$store.state.user;
}, },
showErrorPage404() { showErrorPage404() {
return false return false;
// return this.$store.state.showErrorPage?.response?.status === 404; // return this.$store.state.showErrorPage?.response?.status === 404;
}, },
showErrorPage500() { showErrorPage500() {
return false return false;
// return this.$store.state.showErrorPage?.response?.status === 500; // return this.$store.state.showErrorPage?.response?.status === 500;
}, },
currentPlay() { currentPlay() {
return this.$store.state.currentPlay return this.$store.state.currentPlay;
}, },
}, },
watch: {}, watch: {},
created() { created() {
this.$store.dispatch('setCurrentPlay', {...this.currentPlay, isPlay: false}); this.$store.dispatch('setCurrentPlay', {
...this.currentPlay,
isPlay: false,
});
}, },
mounted() { mounted() {},
}, methods: {},
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,21 +1,21 @@
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 = { const confFormKit = {
@ -36,7 +36,7 @@ export default boot(async ({ app, router }) => {
fieldset: '$reset field__fieldset', fieldset: '$reset field__fieldset',
options: '$reset field__options', options: '$reset field__options',
option: '$reset field__option', option: '$reset field__option',
decorator: '$reset field__decorator' decorator: '$reset field__decorator',
}, },
}, },
messages: { messages: {
@ -56,7 +56,7 @@ export default boot(async ({ app, router }) => {
// return `${name} должна быть в прошлом.`; // return `${name} должна быть в прошлом.`;
// }, // },
// }, // },
} },
}, },
inputs: { inputs: {
// datepicker: createInput(datePickerInput, { // datepicker: createInput(datePickerInput, {
@ -73,11 +73,9 @@ export default boot(async ({ app, router }) => {
}), }),
toggle: createInput(toggle, { toggle: createInput(toggle, {
props: ['placeholder', 'disabled', 'readonly'], props: ['placeholder', 'disabled', 'readonly'],
emits: ['toggle'] emits: ['toggle'],
}), }),
}, },
}; };
app.use(plugin, defaultConfig(confFormKit)); 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

@ -8,11 +8,7 @@
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"
class="breadcrumbs__item-link"
@click="navigate"
>
{{ item.name }} {{ item.name }}
</a> </a>
</div> </div>
@ -26,8 +22,10 @@ export default {
props: { props: {
breadcrumbs: { breadcrumbs: {
type: Array, type: Array,
default() { return []; } default() {
return [];
},
},
}, },
}
}; };
</script> </script>

View File

@ -4,7 +4,9 @@
<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">
Написать
</button>
</div> </div>
</div> </div>
<div class="footer__bottom"> <div class="footer__bottom">
@ -29,29 +31,19 @@
:key="key" :key="key"
:class="['footer__menu-item', item.class]" :class="['footer__menu-item', item.class]"
> >
<router-link <router-link :to="item.link" class="footer__menu-link">
:to="item.link"
class="footer__menu-link"
>
{{ item.title }} {{ item.title }}
</router-link> </router-link>
</li> </li>
</ul> </ul>
<ul class="footer__connection"> <ul class="footer__connection">
<li class="footer__menu-item" <li class="footer__menu-item">
> <router-link to="#" class="m--underline">
<router-link
to="#"
class="m--underline"
>
it@radio.org it@radio.org
</router-link> </router-link>
</li> </li>
<li class="footer__menu-item"> <li class="footer__menu-item">
<router-link <router-link to="#" class="m--underline">
to="#"
class="m--underline"
>
+7 (900) 000-01-12 +7 (900) 000-01-12
</router-link> </router-link>
</li> </li>
@ -70,57 +62,57 @@ export default {
{ {
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

@ -2,14 +2,14 @@
<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"
@ -23,8 +23,20 @@
> >
{{ 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"
class="button"
:class="[item.icon, showAuthentication && 'm--active']"
@click="handlerClick(item.action)"
>
{{ item.title }}
</button>
<button
v-else
class="header__menu-icon"
:class="[item.icon]"
@click="handlerClick(item.action)"
></button>
</li> </li>
</ul> </ul>
<div class="header__burger" @click="handlerShowMenu"> <div class="header__burger" @click="handlerShowMenu">
@ -38,39 +50,39 @@
<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', name: 'rubric',
role: 'all', role: 'all',
title: 'Рубрики' title: 'Рубрики',
}, },
{ {
name: 'playlists', name: 'playlists',
role: 'all', role: 'all',
title: 'Плейлист' title: 'Плейлист',
}, },
{ {
name: 'podcasts', name: 'podcasts',
role: 'all', role: 'all',
title: 'Подкасты' title: 'Подкасты',
}, },
{ {
name: 'support', name: 'support',
role: 'all', role: 'all',
title: 'Поддержка' title: 'Поддержка',
}, },
{ {
name: 'contacts', name: 'contacts',
role: 'all', role: 'all',
title: 'Контакты' title: 'Контакты',
}, },
{ {
name: 'home', name: 'home',
@ -78,70 +90,70 @@ export default {
action: 'login', action: 'login',
icon: 'm--arrow', icon: 'm--arrow',
title: 'Войти', title: 'Войти',
class: 'header__btn' class: 'header__btn',
}, },
{ {
name: 'profile', name: 'profile',
role: 'auth', role: 'auth',
icon: 'm--profile', icon: 'm--profile',
action: 'profile', action: 'profile',
class:'m--tools' class: 'm--tools',
}, },
{ {
name: 'exit', name: 'exit',
role: 'auth', role: 'auth',
icon: 'm--exit', icon: 'm--exit',
action: 'exit', action: 'exit',
class:'m--tools' class: 'm--tools',
}, },
], ],
showMenu: true, showMenu: true,
} };
}, },
watch:{ watch: {
'$route':{ $route: {
handler(to){ handler(to) {
if (this.showMenu){ if (this.showMenu) {
this.showMenu = false; this.showMenu = false;
} }
}
}
}, },
computed:{ },
},
computed: {
user() { user() {
return this.$store.state.user; return this.$store.state.user;
}, },
menu(){ menu() {
return this.menuList.filter(item=>{ return this.menuList.filter((item) => {
if (item.role==='all') return true if (item.role === 'all') return true;
if (item.role==='auth' && this.user?.id) return !!this.user?.id if (item.role === 'auth' && this.user?.id) return !!this.user?.id;
if (item.role==='login' && !this.user?.id) return !this.user?.id if (item.role === 'login' && !this.user?.id) return !this.user?.id;
return false return false;
}) });
}, },
showAuthentication(){ showAuthentication() {
return this.$store.state.showAuthModal return this.$store.state.showAuthModal;
}, },
}, },
methods:{ methods: {
handlerClick(methods){ handlerClick(methods) {
if (methods==='login'){ if (methods === 'login') {
this.$store.dispatch('setModal', {auth: true}); this.$store.dispatch('setModal', { auth: true });
} }
if (methods==='profile'){ if (methods === 'profile') {
this.next('profile') this.next('profile');
} }
if(methods==='exit'){ if (methods === 'exit') {
this.$store.dispatch('deathUser'); this.$store.dispatch('deathUser');
this.next('home') this.next('home');
} }
}, },
next(name){ next(name) {
this.$router.push({name}) this.$router.push({ name });
}, },
handlerShowMenu(){ handlerShowMenu() {
this.showMenu = !this.showMenu; this.showMenu = !this.showMenu;
} },
} },
} };
</script> </script>

View File

@ -9,12 +9,12 @@
<div class="blog__list"> <div class="blog__list">
<div class="blog__item" v-for="article in articles" :key="article.id"> <div class="blog__item" v-for="article in articles" :key="article.id">
<div class="blog__item-header"> <div class="blog__item-header">
<div class="blog__item-title">{{article.title}}</div> <div class="blog__item-title">{{ article.title }}</div>
<button class="button m--circle blog__item-btn"></button> <button class="button m--circle blog__item-btn"></button>
</div> </div>
<div class="blog__info"> <div class="blog__info">
<div class="blog__info-item">Читать {{article.time}} минуты</div> <div class="blog__info-item">Читать {{ article.time }} минуты</div>
<div class="blog__info-item">{{article.data}}</div> <div class="blog__info-item">{{ article.data }}</div>
</div> </div>
</div> </div>
</div> </div>
@ -25,35 +25,37 @@
<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', time: '2',
data: '21 октября' data: '21 октября',
}, },
{ {
id: 3, id: 3,
title:'Как кибербезопасность становится ключевым фактором успеха в IT', title:
'Как кибербезопасность становится ключевым фактором успеха в IT',
time: '2', time: '2',
data: '21 октября' data: '21 октября',
}, },
{ {
id: 4, id: 4,
title:'5 советов по выбору правильной технологии для вашего проекта', title: '5 советов по выбору правильной технологии для вашего проекта',
time: '2', time: '2',
data: '21 октября' data: '21 октября',
} },
] ],
} };
} },
} };
</script> </script>

View File

@ -10,7 +10,7 @@
type="text" type="text"
:placeholder="placeholder" :placeholder="placeholder"
@maska="handleMaska" @maska="handleMaska"
> />
</template> </template>
<script setup> <script setup>
@ -18,8 +18,8 @@ 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;
@ -30,6 +30,6 @@ const readonly = props.context.readonly || false;
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

@ -7,36 +7,33 @@
: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() { data() {
return { return {
placeholder: this.context.placeholder || '', placeholder: this.context.placeholder || '',
disabled: this.context.disabled || false, disabled: this.context.disabled || false,
readonly: this.context.readonly || false, readonly: this.context.readonly || false,
} };
}, },
methods: { methods: {
change() { change() {
this.context.node.input(!this.context._value); this.context.node.input(!this.context._value);
} },
} },
} };
</script> </script>

View File

@ -8,11 +8,7 @@
:clickToClose="false" :clickToClose="false"
@click-outside="close()" @click-outside="close()"
> >
<button <button class="button modal__close" @click="close"></button>
class="button modal__close"
@click="close"
>
</button>
<div class="authentication"> <div class="authentication">
<div class="authentication__tabs tabs"> <div class="authentication__tabs tabs">
<button <button
@ -42,7 +38,7 @@
@submit="submitHandler" @submit="submitHandler"
@click-outside="close" @click-outside="close"
> >
<FormKitSchema :schema="loginForm"/> <FormKitSchema :schema="loginForm" />
</FormKit> </FormKit>
</template> </template>
<template v-else> <template v-else>
@ -61,7 +57,7 @@
}" }"
@submit="submitHandler" @submit="submitHandler"
> >
<FormKitSchema :schema="registerForm"/> <FormKitSchema :schema="registerForm" />
</FormKit> </FormKit>
</template> </template>
</div> </div>
@ -69,7 +65,7 @@
</template> </template>
<script> <script>
import {app} from "@/services"; import { app } from '@/services';
export default { export default {
name: 'authentication', name: 'authentication',
@ -79,11 +75,11 @@ export default {
tabsItems: [ tabsItems: [
{ {
label: 'Войти', label: 'Войти',
name: 'login' name: 'login',
}, },
{ {
label: 'Зарегистрироваться', label: 'Зарегистрироваться',
name: 'register' name: 'register',
}, },
], ],
formLogin: {}, formLogin: {},
@ -95,7 +91,7 @@ export default {
label: 'Ваша почта', label: 'Ваша почта',
placeholder: 'Ваша почта', placeholder: 'Ваша почта',
validation: 'required', validation: 'required',
outerClass: 'field--required' outerClass: 'field--required',
}, },
{ {
$formkit: 'password', $formkit: 'password',
@ -103,7 +99,7 @@ export default {
label: 'придумайте пароль', label: 'придумайте пароль',
placeholder: 'Придумайте пароль', placeholder: 'Придумайте пароль',
validation: 'required', validation: 'required',
outerClass: 'field--required' outerClass: 'field--required',
}, },
{ {
$formkit: 'password', $formkit: 'password',
@ -111,8 +107,8 @@ export default {
label: 'Повторите пароль', label: 'Повторите пароль',
placeholder: 'Повторите пароль', placeholder: 'Повторите пароль',
validation: 'required', validation: 'required',
outerClass: 'field--required' outerClass: 'field--required',
} },
], ],
loginForm: [ loginForm: [
{ {
@ -121,7 +117,7 @@ export default {
label: 'Почта', label: 'Почта',
placeholder: 'Почта', placeholder: 'Почта',
validation: 'required', validation: 'required',
outerClass: 'field--required' outerClass: 'field--required',
}, },
{ {
$formkit: 'password', $formkit: 'password',
@ -129,16 +125,16 @@ export default {
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) {
@ -146,57 +142,62 @@ export default {
}, },
submitHandler(data, node) { submitHandler(data, node) {
if (this.currentTabsItem === 'login') { if (this.currentTabsItem === 'login') {
app.loginUser(this.formLogin).then(res => { app
.loginUser(this.formLogin)
.then((res) => {
this.$store.dispatch('setToken', res); this.$store.dispatch('setToken', res);
app.user().then(user => { app
.user()
.then((user) => {
this.$store.dispatch('setUser', user); this.$store.dispatch('setUser', user);
this.close(); this.close();
this.next('profile'); this.next('profile');
}).catch(err => {
console.log(err)
}) })
}).catch(err => { .catch((err) => {
node.setErrors( console.log(err);
[err.detail], });
err.error
)
}) })
.catch((err) => {
node.setErrors([err.detail], err.error);
});
} else { } else {
if (this.formRegistration.password === this.formRegistration.repeatPassword) { if (
app.createUser(this.formRegistration).then(res => { this.formRegistration.password ===
this.formRegistration.repeatPassword
) {
app
.createUser(this.formRegistration)
.then((res) => {
this.$store.dispatch('setToken', res); this.$store.dispatch('setToken', res);
app.user().then(user => { app
.user()
.then((user) => {
this.$store.dispatch('setUser', user); this.$store.dispatch('setUser', user);
this.close(); this.close();
this.next('profile'); this.next('profile');
}).catch(err => {
console.log(err)
}) })
}).catch(err => { .catch((err) => {
node.setErrors( console.log(err);
[err.detail], });
err.error
)
console.log(err)
}) })
.catch((err) => {
node.setErrors([err.detail], err.error);
console.log(err);
});
} else { } else {
node.setErrors( node.setErrors(['Пароли не совпадают'], {
['Пароли не совпадают'],
{
password: '', password: '',
repeatPassword: '', repeatPassword: '',
} });
)
} }
} }
}, },
close() { close() {
this.$store.dispatch('setModal', {auth: false}); this.$store.dispatch('setModal', { auth: false });
}, },
next(name) { next(name) {
this.$router.push({name}); this.$router.push({ name });
} },
} },
} };
</script> </script>

View File

@ -10,36 +10,36 @@
> >
<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> <button class="button m--fit-content m--white m--arrow" v-if="user?.id">
Написать
</button>
</template> </template>
</vue-final-modal> </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',
@ -48,21 +48,21 @@ export default {
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() {
@ -73,25 +73,28 @@ export default {
}, },
}, },
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
.getRubrik(this.selectRubric)
.then((data) => {
this.showLoader = false; this.showLoader = false;
this.rubrik = data[0]; this.rubrik = data[0];
}).catch(err => {
this.showLoader = false;
console.log(err)
}) })
.catch((err) => {
this.showLoader = false;
console.log(err);
});
}, },
} },
} };
</script> </script>

View File

@ -8,11 +8,7 @@
:clickToClose="false" :clickToClose="false"
@click-outside="close()" @click-outside="close()"
> >
<button <button class="button modal__close" @click="close"></button>
class="button modal__close"
@click="close"
>
</button>
<div class="modal__content"> <div class="modal__content">
<div class="modal__title">Изменение данных</div> <div class="modal__title">Изменение данных</div>
<FormKit <FormKit
@ -30,27 +26,27 @@
}" }"
@submit="submitHandler" @submit="submitHandler"
> >
<FormKitSchema :schema="userForm"/> <FormKitSchema :schema="userForm" />
</FormKit> </FormKit>
</div> </div>
</vue-final-modal> </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',
@ -58,7 +54,7 @@ export default {
label: 'Введите старый пароль', label: 'Введите старый пароль',
placeholder: 'Введите старый пароль', placeholder: 'Введите старый пароль',
validation: 'required', validation: 'required',
outerClass: 'field--required' outerClass: 'field--required',
}, },
{ {
$formkit: 'password', $formkit: 'password',
@ -66,44 +62,44 @@ export default {
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
.updateUser(this.formData)
.then((user) => {
this.showLoaderSending = false; this.showLoaderSending = false;
this.$store.dispatch('setUser', user); this.$store.dispatch('setUser', user);
}).catch(err=>{
this.showLoaderSending = false;
node.setErrors(
[err.detail],
err.error
)
}) })
.catch((err) => {
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,29 +1,37 @@
<template> <template>
<div <div v-if="total && false" class="pagination">
v-if="total && false" <router-link
class="pagination" class="pagination__btn m--prev"
> :to="{
<router-link class="pagination__btn m--prev" path: url,
:to="{ path: url, query: Object.assign({}, query, { page: goPrev }), hash: hash }" query: Object.assign({}, query, { page: goPrev }),
hash: hash,
}"
> >
</router-link> </router-link>
<ul class="pagination__list"> <ul class="pagination__list">
<li <li v-for="page in pagesArray" :key="`page-${page.value}`">
v-for="page in pagesArray"
:key="`page-${page.value}`"
>
<router-link <router-link
class="pagination__link" class="pagination__link"
:class="[page.value === currentPage && 'm--current']" :class="[page.value === currentPage && 'm--current']"
:to="{ path: url, query: Object.assign({}, query, { page: page.value }), hash: hash }" :to="{
path: url,
query: Object.assign({}, query, { page: page.value }),
hash: hash,
}"
:event="page.value ? 'click' : ''" :event="page.value ? 'click' : ''"
> >
{{ page.text }} {{ page.text }}
</router-link> </router-link>
</li> </li>
</ul> </ul>
<router-link class="pagination__btn m--next" <router-link
:to="{ path: url, query: Object.assign({}, query, { page: goForward }), hash: hash }" class="pagination__btn m--next"
:to="{
path: url,
query: Object.assign({}, query, { page: goForward }),
hash: hash,
}"
> >
</router-link> </router-link>
</div> </div>
@ -36,45 +44,45 @@ export default {
type: Number, type: Number,
default() { default() {
return 0; return 0;
} },
}, },
limit: { limit: {
type: Number, type: Number,
default() { default() {
return 10; return 10;
} },
}, },
currentPage: { currentPage: {
type: Number, type: Number,
default() { default() {
return 1; return 1;
} },
}, },
query: { query: {
type: Object, type: Object,
default() { default() {
return {}; return {};
} },
}, },
hash: { hash: {
type: String, type: String,
default() { default() {
return ''; return '';
} },
}, },
url: { url: {
type: String, type: String,
default() { default() {
return ''; return '';
} },
} },
}, },
data() { data() {
return {} return {};
}, },
computed: { computed: {
step() { step() {
return 1 return 1;
}, },
pages() { pages() {
const pagesCount = Math.ceil(this.total / this.limit); const pagesCount = Math.ceil(this.total / this.limit);
@ -83,41 +91,52 @@ export default {
pagesArray() { pagesArray() {
const count = Math.ceil(this.total / this.limit); const count = Math.ceil(this.total / this.limit);
let items = []; let items = [];
[...Array(count).keys()].map(i => i + 1).forEach(item => { [...Array(count).keys()]
.map((i) => i + 1)
.forEach((item) => {
if (count <= 4) { if (count <= 4) {
items.push({text: item, value: item}); items.push({ text: item, value: item });
} else { } else {
if (item === 1 && this.currentPage !== item && this.currentPage - 1 !== 1 && this.currentPage - 2 !== 1) { if (
items.push({text: '1', value: 1}); item === 1 &&
items.push({text: '...', value: null}); this.currentPage !== item &&
} else if (item === count && this.currentPage + 1 !== count && this.currentPage + 2 !== count) { this.currentPage - 1 !== 1 &&
items.push({text: '...', value: null}); this.currentPage - 2 !== 1
items.push({text: count, value: count}); ) {
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 { } else {
let deltaPrev = (count - this.currentPage <= 3) ? 3 : 2; let deltaPrev = count - this.currentPage <= 3 ? 3 : 2;
let deltaAfter = (this.currentPage <= 3) ? 4 - this.currentPage : 2; let deltaAfter = this.currentPage <= 3 ? 4 - this.currentPage : 2;
if (item > this.currentPage - deltaPrev && item < this.currentPage + deltaAfter) { if (
console.log(item) item > this.currentPage - deltaPrev &&
items.push({text: item, value: item}); item < this.currentPage + deltaAfter
) {
console.log(item);
items.push({ text: item, value: item });
} }
} }
} }
}); });
return items return items;
}, },
goForward() { goForward() {
return `${this.currentPage + this.step}` return `${this.currentPage + this.step}`;
}, },
goPrev() { goPrev() {
return `${this.currentPage - this.step}` return `${this.currentPage - this.step}`;
}, },
}, },
mounted() { mounted() {},
}, beforeDestroy() {},
beforeDestroy() { created() {},
},
created() {
},
methods: {}, methods: {},
}; };
</script> </script>

View File

@ -1,37 +1,51 @@
<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
v-if="loaderPlay"
type="circle"
class="player__btn m--skeleton"
/>
<template v-else> <template v-else>
<button v-if="currentPlay.isPlay" @click="handlerPause" class="button player__btn m--pause"> <button
</button> v-if="currentPlay.isPlay"
<button v-else @click="handlerPlay" class="button player__btn m--play"> @click="handlerPause"
</button> class="button player__btn m--pause"
></button>
<button
v-else
@click="handlerPlay"
class="button player__btn m--play"
></button>
</template> </template>
<div class="player__executor"> <div class="player__executor">
<q-skeleton v-if="loaderPlay" class="player__executor m--skeleton"/> <q-skeleton v-if="loaderPlay" class="player__executor m--skeleton" />
<template v-else> <template v-else>
{{ currentPlay.title || '—' }} {{ currentPlay.title || '—' }}
</template> </template>
<span> <span>
<q-skeleton v-if="loaderPlay"/> <q-skeleton v-if="loaderPlay" />
<template v-else> <template v-else>
{{ currentPlay.artist || '—' }} {{ currentPlay.artist || '—' }}
</template> </template>
</span> </span>
</div> </div>
<template v-if="user?.id"> <template v-if="user?.id">
<q-skeleton v-if="loaderPlay" class="player__favorites m--skeleton"/> <q-skeleton v-if="loaderPlay" class="player__favorites m--skeleton" />
<div v-else class="player__favorites" :class="[isFavorites&&'m--active']" @click="handlerFavorites"> <div
</div> v-else
class="player__favorites"
:class="[isFavorites && 'm--active']"
@click="handlerFavorites"
></div>
</template> </template>
<div class="player__tools"> <div class="player__tools">
<q-skeleton v-if="loaderPlay" class="player__tools m--skeleton"/> <q-skeleton v-if="loaderPlay" class="player__tools m--skeleton" />
<FormKit <FormKit
v-else v-else
v-model="isUserMusic" v-model="isUserMusic"
@ -39,26 +53,33 @@
label="Включить мою музыку" label="Включить мою музыку"
:disabled="!user?.id || userSongList.length === 0" :disabled="!user?.id || userSongList.length === 0"
/> />
<q-skeleton v-if="loaderPlay" class="player__tools m--skeleton"/> <q-skeleton v-if="loaderPlay" class="player__tools m--skeleton" />
<div v-else class="player__volume"> <div v-else class="player__volume">
<span @click="changeVolume('set')"/> <span @click="changeVolume('set')" />
<input type="range" v-model="songVolume" @change="changeVolume"> <input type="range" v-model="songVolume" @change="changeVolume" />
</div> </div>
</div> </div>
</div> </div>
<div class="player__bottom"> <div class="player__bottom">
<div class="player__time" :class="!loaderPlay&&!isUserMusic&&'m--ether'"> <div
<q-skeleton v-if="loaderPlay"/> class="player__time"
:class="!loaderPlay && !isUserMusic && 'm--ether'"
>
<q-skeleton v-if="loaderPlay" />
<template v-else-if="isUserMusic"> <template v-else-if="isUserMusic">
{{ getTime(playerInfo.currentTime) }} / {{ getTime(playerInfo.duration) }} {{ getTime(playerInfo.currentTime) }} /
</template> {{ getTime(playerInfo.duration) }}
<template v-else>
Эфир
</template> </template>
<template v-else> Эфир </template>
</div> </div>
<div class="player__progress"> <div class="player__progress">
<q-skeleton v-if="loaderPlay" height="5px"/> <q-skeleton v-if="loaderPlay" height="5px" />
<input v-else :disabled="!isUserMusic" type="range" v-model="playerInfo.progress"> <input
v-else
:disabled="!isUserMusic"
type="range"
v-model="playerInfo.progress"
/>
</div> </div>
</div> </div>
</div> </div>
@ -66,7 +87,7 @@
</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',
@ -81,29 +102,29 @@ export default {
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) {
@ -117,7 +138,7 @@ export default {
} }
}, },
}, },
'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) {
@ -125,7 +146,7 @@ export default {
} }
}, },
}, },
'isUserMusic': { isUserMusic: {
immediate: false, immediate: false,
handler() { handler() {
if (this.isUserMusic === this.currentPlay.live) { if (this.isUserMusic === this.currentPlay.live) {
@ -138,7 +159,7 @@ export default {
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();
@ -146,14 +167,24 @@ export default {
} }
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],
live: false,
});
this.getAudio(
this.userSongList[this.currentPlay.currentIndex || 0]?.azura_id,
);
if (this.player.target) { if (this.player.target) {
this.player.target.addEventListener('timeupdate', this.updateProgress) this.player.target.addEventListener('timeupdate', this.updateProgress);
} }
} }
if (!this.user?.id){ if (!this.user?.id) {
this.$store.dispatch('setCurrentPlay', {...this.currentPlay, live: true, isLoader: true, currentIndex: null}); this.$store.dispatch('setCurrentPlay', {
...this.currentPlay,
live: true,
isLoader: true,
currentIndex: null,
});
} }
}, },
methods: { methods: {
@ -166,27 +197,36 @@ export default {
this.connection.onHandler(this.getPlaying); this.connection.onHandler(this.getPlaying);
}, },
checkSongIsFavorite() { checkSongIsFavorite() {
app.getCheckFavoriteSong(this.currentPlay.azura_id || this.currentPlay.id).then(res => { app
.getCheckFavoriteSong(this.currentPlay.azura_id || this.currentPlay.id)
.then((res) => {
this.isFavorites = res.is_favorite; this.isFavorites = res.is_favorite;
}).catch(err => {
console.error(err)
}) })
.catch((err) => {
console.error(err);
});
}, },
removeFavorites(song) { removeFavorites(song) {
app.removeFavorites(song).then(() => { app
.removeFavorites(song)
.then(() => {
this.getSongList(); this.getSongList();
}).catch(err => {
this.showLoader = false;
console.error(err)
}) })
.catch((err) => {
this.showLoader = false;
console.error(err);
});
}, },
getPlaying(e) { getPlaying(e) {
const jsonData = JSON.parse(e.data) const jsonData = JSON.parse(e.data);
if (jsonData?.pub?.data) { if (jsonData?.pub?.data) {
const data = jsonData?.pub?.data; const data = jsonData?.pub?.data;
if (this.currentPlay.live) { if (this.currentPlay.live) {
if (data.np.station.listen_url !== this.player.target.src) { if (data.np.station.listen_url !== this.player.target.src) {
console.log('data.np.station.listen_url', data.np.station.listen_url) console.log(
'data.np.station.listen_url',
data.np.station.listen_url,
);
this.$store.dispatch('changePlayer', data.np.station.listen_url); this.$store.dispatch('changePlayer', data.np.station.listen_url);
const params = { const params = {
...this.currentPlay, ...this.currentPlay,
@ -194,8 +234,8 @@ export default {
azura_id: data.np.now_playing.song.id, azura_id: data.np.now_playing.song.id,
isLoader: false, isLoader: false,
live: true, live: true,
currentIndex: null currentIndex: null,
} };
delete params.unique_id; delete params.unique_id;
this.$store.dispatch('setCurrentPlay', params); this.$store.dispatch('setCurrentPlay', params);
} }
@ -205,59 +245,84 @@ export default {
updateProgress(e) { updateProgress(e) {
this.playerInfo = { this.playerInfo = {
...this.playerInfo, ...this.playerInfo,
progress: this.player.target.currentTime / this.player.target.duration * 100, progress:
currentTime: this.player.target.currentTime (this.player.target.currentTime / this.player.target.duration) * 100,
} currentTime: this.player.target.currentTime,
if (this.player.target.currentTime === this.player.target.duration){ };
if (this.player.target.currentTime === this.player.target.duration) {
let currentIndex = this.currentPlay.currentIndex + 1; let currentIndex = this.currentPlay.currentIndex + 1;
if (!this.userSongList[currentIndex]?.azura_id || currentIndex === null){ if (
!this.userSongList[currentIndex]?.azura_id ||
currentIndex === null
) {
currentIndex = 0; currentIndex = 0;
} }
this.$store.dispatch('setCurrentPlay', {...this.currentPlay, ...this.userSongList[currentIndex], currentIndex}) this.$store.dispatch('setCurrentPlay', {
...this.currentPlay,
...this.userSongList[currentIndex],
currentIndex,
});
} }
}, },
handlerPlay() { handlerPlay() {
console.log(this.currentPlay) console.log(this.currentPlay);
console.log(this.player) console.log(this.player);
this.$store.dispatch('handlerPlayer', {play: true}); this.$store.dispatch('handlerPlayer', { play: true });
}, },
handlerPause() { handlerPause() {
this.$store.dispatch('handlerPlayer', {pause: true}); this.$store.dispatch('handlerPlayer', { pause: true });
}, },
getSongList() { getSongList() {
app.getFavoriteList().then(res => { app
this.$store.dispatch('setUserFavorite', {songs: res}) .getFavoriteList()
console.log('res.length' ,res.length) .then((res) => {
if (res.length === 0){ this.$store.dispatch('setUserFavorite', { songs: res });
this.$store.dispatch('setCurrentPlay', {...this.currentPlay, live: true, isLoader: true}); console.log('res.length', res.length);
if (res.length === 0) {
this.$store.dispatch('setCurrentPlay', {
...this.currentPlay,
live: true,
isLoader: true,
});
} }
}).catch(err => {
console.error(err)
}) })
.catch((err) => {
console.error(err);
});
}, },
handlerFavorites() { handlerFavorites() {
if (this.user?.id) { if (this.user?.id) {
const params = {...this.currentPlay, azura_id: Number(this.currentPlay.id)?this.currentPlay.azura_id:this.currentPlay.id}; const params = {
...this.currentPlay,
azura_id: Number(this.currentPlay.id)
? this.currentPlay.azura_id
: this.currentPlay.id,
};
if (!this.isFavorites) { if (!this.isFavorites) {
delete params.id; delete params.id;
app.createFavoriteForUser(params).then(() => { app
.createFavoriteForUser(params)
.then(() => {
this.isFavorites = !this.isFavorites; this.isFavorites = !this.isFavorites;
this.getSongList(); this.getSongList();
}).catch(err => {
console.error(err)
}) })
.catch((err) => {
console.error(err);
});
} else { } else {
console.log(params) console.log(params);
app.removeFavorites(params).then(()=>{ app
.removeFavorites(params)
.then(() => {
this.getSongList(); this.getSongList();
}).catch(err=>{
console.error(err)
}) })
.catch((err) => {
console.error(err);
});
} }
} else { } else {
this.$emit('shopAuthentication', true) this.$emit('shopAuthentication', true);
} }
}, },
changeVolume(type) { changeVolume(type) {
let volume = this.songVolume; let volume = this.songVolume;
@ -267,52 +332,72 @@ export default {
} else { } else {
volume = this.songVolume / 100; volume = this.songVolume / 100;
} }
if (volume === 0) volume = 0.01 if (volume === 0) volume = 0.01;
this.$store.dispatch('handlerPlayer', {volume}); this.$store.dispatch('handlerPlayer', { volume });
}, },
getAudio(id) { getAudio(id) {
app.getAudio(id).then(res => { app
const blob = new Blob([res], {type: 'application/audio'}); .getAudio(id)
.then((res) => {
const blob = new Blob([res], { type: 'application/audio' });
const audioUrl = URL.createObjectURL(blob); const audioUrl = URL.createObjectURL(blob);
this.$store.dispatch('changePlayer', audioUrl); this.$store.dispatch('changePlayer', audioUrl);
this.player.target.addEventListener('timeupdate', this.updateProgress); this.player.target.addEventListener(
'timeupdate',
this.updateProgress,
);
blob.arrayBuffer().then((buffer) => {
blob.arrayBuffer().then(buffer => { var audioContext = new (window.AudioContext ||
var audioContext = new (window.AudioContext || window.webkitAudioContext)(); window.webkitAudioContext)();
audioContext.decodeAudioData(buffer, (decodedData) => { audioContext.decodeAudioData(buffer, (decodedData) => {
this.playerInfo.duration = decodedData.duration; this.playerInfo.duration = decodedData.duration;
}); });
}); });
this.$store.dispatch('setCurrentPlay', {...this.currentPlay, isLoader: false}) this.$store.dispatch('setCurrentPlay', {
}).catch(err => { ...this.currentPlay,
this.$store.dispatch('setCurrentPlay', {...this.currentPlay, isLoader: false}) isLoader: false,
console.debug(err) });
}) })
.catch((err) => {
this.$store.dispatch('setCurrentPlay', {
...this.currentPlay,
isLoader: false,
});
console.debug(err);
});
}, },
changeLive() { changeLive() {
if (this.currentPlay.live) { if (this.currentPlay.live) {
console.log('избранное') console.log('избранное');
this.playerInfo.progress = 0; this.playerInfo.progress = 0;
const params = {...this.userSongList[this.currentPlay.currentIndex || 0], live: false, isLoader: true}; const params = {
...this.userSongList[this.currentPlay.currentIndex || 0],
live: false,
isLoader: true,
};
if (!this.currentPlay.currentIndex) params.currentIndex = 0; if (!this.currentPlay.currentIndex) params.currentIndex = 0;
this.$store.dispatch('setCurrentPlay', params); this.$store.dispatch('setCurrentPlay', params);
} else { } else {
this.playerInfo.progress = 100; this.playerInfo.progress = 100;
this.$store.dispatch('setCurrentPlay', {...this.currentPlay, live: true, isLoader: true}); this.$store.dispatch('setCurrentPlay', {
console.log('поток') ...this.currentPlay,
live: true,
isLoader: true,
});
console.log('поток');
} }
}, },
getTime(value) { getTime(value) {
let minutes = Math.floor(value / 60); let minutes = Math.floor(value / 60);
let seconds = Math.round(value % 60); let seconds = Math.round(value % 60);
let paddedMinutes = minutes < 10 ? "0" + minutes : minutes; let paddedMinutes = minutes < 10 ? '0' + minutes : minutes;
let paddedSeconds = seconds < 10 ? "0" + seconds : seconds; let paddedSeconds = seconds < 10 ? '0' + seconds : seconds;
if (!paddedMinutes) paddedMinutes = '00'; if (!paddedMinutes) paddedMinutes = '00';
if (!paddedSeconds) paddedSeconds = '00'; if (!paddedSeconds) paddedSeconds = '00';
return `${paddedMinutes}:${paddedSeconds}`; return `${paddedMinutes}:${paddedSeconds}`;
}, },
} },
} };
</script> </script>

View File

@ -1,7 +1,7 @@
<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>
@ -9,19 +9,19 @@
<script> <script>
export default { export default {
name: 'playlist-item', name: 'playlist-item',
props:{ props: {
playlist:{ playlist: {
type: Object, type: Object,
default: () => {} default: () => {},
}
}, },
methods:{
editPlaylist(){
this.$emit('editPlaylist', this.playlist)
}, },
selectPlaylist(){ methods: {
this.$emit('selectPlaylist', this.playlist) editPlaylist() {
} this.$emit('editPlaylist', this.playlist);
} },
} selectPlaylist() {
this.$emit('selectPlaylist', this.playlist);
},
},
};
</script> </script>

View File

@ -15,27 +15,27 @@
</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'"
@click="next('rubric')"
>
Смотреть все
</button>
<div class="p rubric-block__description"> <div class="p rubric-block__description">
IT-радио - это уникальная платформа для обмена опытом, знаниями и обсуждения актуальных вопросов, связанных с разработкой программного обеспечения, искусственного интеллекта, интернета вещей и других направлений 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>
<div v-else class="rubric-block__list"> <div v-else class="rubric-block__list">
<div class="rubric-block__item" v-for="rubrik in rubriks" :key="`rubrik_${rubrik.id}`"> <div
<div class="title rubric-block__title">{{rubrik.name}}</div> class="rubric-block__item"
<div class="p rubric-block__description m--50">{{rubrik.title}}</div> v-for="rubrik in rubriks"
<button class="button m--arrow rubric-block__btn" @click="showModalRubric(rubrik.id)">Узнать больше</button> :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>
</div> </div>
<RubricModal :showModal="isShowModalRubric" @hideModal="hiddenModalRubric" :selectRubric="ModalTemplate"/> <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() { created() {
this.getRubriks(); this.getRubriks();
}, },
methods:{ methods: {
getRubriks() { getRubriks() {
this.showLoader = true; this.showLoader = true;
app.getRubriks().then((data) => { app
.getRubriks()
.then((data) => {
this.showLoader = false; this.showLoader = false;
this.rubriks = data; this.rubriks = data;
}).catch(err => {
this.showLoader = false;
console.log(err)
}) })
.catch((err) => {
this.showLoader = false;
console.log(err);
});
}, },
showModalRubric(key){ showModalRubric(key) {
this.ModalTemplate = key this.ModalTemplate = key;
this.isShowModalRubric = true; this.isShowModalRubric = true;
}, },
hiddenModalRubric(){ hiddenModalRubric() {
this.isShowModalRubric = false; this.isShowModalRubric = false;
}, },
next(name){ next(name) {
this.$router.push({name}) this.$router.push({ name });
} },
} },
} };
</script> </script>

View File

@ -1,27 +1,68 @@
<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"
height="28"
viewBox="0 0 33 28"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<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"
/>
<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"
/>
<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> </svg>
</div> </div>
<div> <div>
<button v-if="isPlay" @click.stop="handlerPause" class="button song-item__btn m--pause"> <button
</button> v-if="isPlay"
<button v-else @click.stop="handlerPlay" class="button song-item__btn m--play"> @click.stop="handlerPause"
</button> class="button song-item__btn m--pause"
></button>
<button
v-else
@click.stop="handlerPlay"
class="button song-item__btn m--play"
></button>
</div> </div>
<div class="song-item__info"> <div class="song-item__info">
<span>{{song.title}}</span> <span>{{ song.title }}</span>
{{song.artist}} {{ song.artist }}
</div> </div>
<div class="song-item__tools"> <div class="song-item__tools">
<button class="button song-item__btn m--small m--favorites" @click.stop="removeSong"></button> <button
<button class="button song-item__btn m--small m--add" :class="songAlreadyAddPlaylist&&'m--already'" @click.stop="songAlreadyAddPlaylist?removeToPlaylist():addPlaylist()"></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>
</div> </div>
</template> </template>
@ -29,64 +70,64 @@
<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:{
type: Boolean,
default(){
return false
}
}, },
songAlreadyAddPlaylist:{ playSong: {
type: Boolean, type: Boolean,
default(){ default() {
return false return false;
} },
},
songAlreadyAddPlaylist: {
type: Boolean,
default() {
return false;
},
}, },
}, },
watch: { watch: {
'playSong': { playSong: {
immediate: true, immediate: true,
handler() { handler() {
this.isPlay = this.playSong; this.isPlay = this.playSong;
}, },
}
}, },
data(){
return{
isPlay: this.playSong
}
}, },
methods:{ data() {
return {
isPlay: this.playSong,
};
},
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

@ -4,7 +4,9 @@
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="
song.azura_id === currentPlay.azura_id ? currentPlay.isPlay : false
"
:selectSong="song.azura_id === currentPlay.azura_id" :selectSong="song.azura_id === currentPlay.azura_id"
:songAlreadyAddPlaylist="songAlreadyAdd" :songAlreadyAddPlaylist="songAlreadyAdd"
@selectSong="handlerSelectSong" @selectSong="handlerSelectSong"
@ -18,55 +20,57 @@
</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(
(el) => el.azura_id === params.azura_id,
);
this.$store.dispatch('setCurrentPlay', data); this.$store.dispatch('setCurrentPlay', data);
console.log('handlerSelectSong') console.log('handlerSelectSong');
}, },
handlerPlaySong(params) { handlerPlaySong(params) {
this.$store.dispatch('setCurrentPlay', params); this.$store.dispatch('setCurrentPlay', params);
console.log('handlerPlaySong') console.log('handlerPlaySong');
// this.$store.dispatch('handlerPlayer', {pause: true}); // this.$store.dispatch('handlerPlayer', {pause: true});
}, },
handlerPauseSong(params) { handlerPauseSong(params) {
this.$store.dispatch('setCurrentPlay', params); this.$store.dispatch('setCurrentPlay', params);
console.log('handlerPauseSong') console.log('handlerPauseSong');
// this.$store.dispatch('handlerPlayer', {play: true}); // this.$store.dispatch('handlerPlayer', {play: true});
}, },
removeSong(song){ removeSong(song) {
this.$emit('removeSong', song) this.$emit('removeSong', song);
}, },
addPlaylist(song){ addPlaylist(song) {
this.$emit('addPlaylist', song) this.$emit('addPlaylist', song);
}, },
removePlaylist(song){ removePlaylist(song) {
this.$emit('removePlaylist', song) this.$emit('removePlaylist', song);
} },
} },
} };
</script> </script>

View File

@ -4,15 +4,19 @@
<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>
<div class="support-block__item m--two-circle"> <div class="support-block__item m--two-circle">
<div class="title">Дело</div> <div class="title">Дело</div>
Если вы фотографируете, монтируете, пишете, корректируете, занимаетесь продвижением или делаете еще что-нибудь классное и думаете, что можете быть нам полезны на волонтерских началах свяжитесь с нами через форму Если вы фотографируете, монтируете, пишете, корректируете, занимаетесь
продвижением или делаете еще что-нибудь классное и думаете, что можете
быть нам полезны на волонтерских началах свяжитесь с нами через форму
</div> </div>
<div class="support-block__item m--three-circle"> <div class="support-block__item m--three-circle">
<div class="title">Развитие</div> <div class="title">Развитие</div>
Расскажите о нашем проекте в соцсетях! Можно поделиться любым нашим постом, видео в ютубе или рассказать о нас в своей аудитории Расскажите о нашем проекте в соцсетях! Можно поделиться любым нашим
постом, видео в ютубе или рассказать о нас в своей аудитории
</div> </div>
</div> </div>
</div> </div>
@ -20,6 +24,6 @@
<script> <script>
export default { export default {
name: 'SupportBlock' name: 'SupportBlock',
} };
</script> </script>

View File

@ -1,17 +1,16 @@
<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>
Наша команда
</h2>
<div class="team__description"> <div class="team__description">
На IT волне команда профессионалов неутомимо трудится, чтобы дарить слушателям самые свежие и актуальные На 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>
@ -35,7 +34,7 @@
768: { 768: {
slidesPerView: 2.5, slidesPerView: 2.5,
}, },
1020:{ 1020: {
slidesPerView: 3, slidesPerView: 3,
}, },
1280: { 1280: {
@ -44,9 +43,13 @@
}" }"
class="team__slider" class="team__slider"
> >
<SwiperSlide class="team__item" v-for="employee in team" :key="employee.id"> <SwiperSlide
class="team__item"
v-for="employee in team"
:key="employee.id"
>
<div class="team__cover"> <div class="team__cover">
<img :src="`${selfUrl + employee.img_person}`" alt="user"/> <img :src="`${selfUrl + employee.img_person}`" alt="user" />
</div> </div>
<div class="team__name"> <div class="team__name">
{{ employee.name }} {{ employee.last_name }} {{ employee.name }} {{ employee.last_name }}
@ -58,7 +61,7 @@
<div class="team__progress" ref="progressBar"> <div class="team__progress" ref="progressBar">
<span></span> <span></span>
</div> </div>
<router-link :to="{name: 'about'}" class="m--link"> <router-link :to="{ name: 'about' }" class="m--link">
Больше о нас Больше о нас
</router-link> </router-link>
</div> </div>
@ -67,21 +70,21 @@
<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();
@ -89,14 +92,17 @@ export default {
methods: { methods: {
getTeams() { getTeams() {
this.showLoader = true; this.showLoader = true;
app.getTeams().then((data) => { app
.getTeams()
.then((data) => {
this.showLoader = false; this.showLoader = false;
this.team = data; this.team = data;
}).catch(err => {
this.showLoader = false;
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
@ -15,18 +20,20 @@ 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,
@ -36,11 +43,16 @@ export default route(function (/* { store, ssrContext } */) {
// 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 (
to.matched.some((record) => record.meta.requiresAuth) &&
!process.env.SERVER
) {
if (store.state.user && store.state.user?.id) { if (store.state.user && store.state.user?.id) {
next(); next();
} else { } else {
@ -58,5 +70,5 @@ export default route(function (/* { store, ssrContext } */) {
} }
}); });
return Router return Router;
}) });

View File

@ -1,14 +1,13 @@
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 = [
{ {
@ -17,7 +16,7 @@ const routes = [
component: home, component: home,
meta: { meta: {
title: 'Главная', title: 'Главная',
isAuth: false isAuth: false,
}, },
}, },
{ {
@ -26,7 +25,7 @@ const routes = [
component: about, component: about,
meta: { meta: {
title: 'О нас', title: 'О нас',
isAuth: false isAuth: false,
}, },
}, },
{ {
@ -35,7 +34,7 @@ const routes = [
component: rubric, component: rubric,
meta: { meta: {
title: 'Рубрики', title: 'Рубрики',
isAuth: false isAuth: false,
}, },
}, },
{ {
@ -44,7 +43,7 @@ const routes = [
component: playlists, component: playlists,
meta: { meta: {
title: 'Плейлисты', title: 'Плейлисты',
isAuth: false isAuth: false,
}, },
}, },
{ {
@ -53,7 +52,7 @@ const routes = [
component: podcasts, component: podcasts,
meta: { meta: {
title: 'Подкасты', title: 'Подкасты',
isAuth: false isAuth: false,
}, },
}, },
{ {
@ -62,7 +61,7 @@ const routes = [
component: support, component: support,
meta: { meta: {
title: 'Поддержка', title: 'Поддержка',
isAuth: false isAuth: false,
}, },
}, },
{ {
@ -71,7 +70,7 @@ const routes = [
component: contacts, component: contacts,
meta: { meta: {
title: 'Контакты', title: 'Контакты',
isAuth: false isAuth: false,
}, },
}, },
{ {
@ -80,7 +79,7 @@ const routes = [
component: profile, component: profile,
meta: { meta: {
title: 'Личный кабинет', title: 'Личный кабинет',
isAuth: false isAuth: false,
}, },
children: [ children: [
{ {
@ -89,7 +88,7 @@ const routes = [
component: playlist, component: playlist,
meta: { meta: {
title: 'Плейлист', title: 'Плейлист',
requiresAuth: true requiresAuth: true,
}, },
props: true, props: true,
}, },
@ -99,20 +98,21 @@ const routes = [
component: playlistCreate, component: playlistCreate,
meta: { meta: {
title: 'Плейлист', title: 'Плейлист',
requiresAuth: true requiresAuth: true,
}, },
props: true, props: true,
},{ },
{
path: 'playlist-edit/:id', path: 'playlist-edit/:id',
name: 'playlist-edit', name: 'playlist-edit',
component: playlistCreate, component: playlistCreate,
meta: { meta: {
title: 'Плейлист', title: 'Плейлист',
requiresAuth: true requiresAuth: true,
}, },
props: true, props: true,
}, },
] ],
}, },
// { // {
@ -142,4 +142,4 @@ const routes = [
// }, // },
]; ];
export default routes export default routes;

View File

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

View File

@ -1,28 +1,29 @@
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(){ removePlay() {
this.connection.close() this.connection.close();
} }
songs(){ songs() {
this.connection.onmessage = (e) => { this.connection.onmessage = (e) => {
const jsonData = JSON.parse(e.data); const jsonData = JSON.parse(e.data);
// if ("connect" in jsonData) { // if ("connect" in jsonData) {
@ -48,17 +49,18 @@ export default class extends REST {
// handleSseData(jsonData.pub); // handleSseData(jsonData.pub);
// } // }
}; };
} }
onHandler(event){ onHandler(event) {
this.connection.onmessage = event this.connection.onmessage = event;
} }
static getPlayList(station, params) { static getPlayList(station, params) {
// return this._get(`station/${station}/playlists`, params, {}).then((data) => { // return this._get(`station/${station}/playlists`, params, {}).then((data) => {
return this._get(`radio.mp3`, params, {}).then((data) => { return this._get(`radio.mp3`, params, {})
.then((data) => {
return data; return data;
}).catch((error) => { })
.catch((error) => {
throw new RESTError(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,8 +4,12 @@ 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 =
error.response &&
error.response.data &&
(error.response.data.detail ||
(error.response.data.error && error.response.data.error.detail));
let header = (message || error.message) + (detail ? ': ' + detail : ''); let header = (message || error.message) + (detail ? ': ' + detail : '');
super(header); super(header);
@ -18,14 +22,14 @@ class RESTError extends Error {
} }
//if (this.response && (this.response.status === 401 || this.response.status === 403)) { //if (this.response && (this.response.status === 401 || this.response.status === 403)) {
if (this.response && (this.response.status === 401)) { if (this.response && this.response.status === 401) {
store.dispatch('deathUser'); store.dispatch('deathUser');
store.dispatch('setShowAuthModal', true); store.dispatch('setShowAuthModal', true);
} else { } else {
if (typeof Error.captureStackTrace === 'function') { if (typeof Error.captureStackTrace === 'function') {
Error.captureStackTrace(this, this.constructor); Error.captureStackTrace(this, this.constructor);
} else { } else {
this.stack = (new Error(header)).stack; this.stack = new Error(header).stack;
} }
} }
} }
@ -35,8 +39,23 @@ 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 = {},
extraParams,
use_cache = false,
isBlob = false,
) {
return this._request(
'get',
url,
params,
{},
{},
extraParams,
use_cache,
isBlob,
);
} }
static _post(url, params, data) { static _post(url, params, data) {
return this._request('post', url, params, data); return this._request('post', url, params, data);
@ -50,9 +69,19 @@ class REST {
static _delete(url, params, data) { static _delete(url, params, data) {
return this._request('delete', url, params, data); return this._request('delete', url, params, data);
} }
static _request(method, url, params={}, data={}, extraData={}, extraParams={}, use_cache=false, isBlob=false) { static _request(
method,
url,
params = {},
data = {},
extraData = {},
extraParams = {},
use_cache = false,
isBlob = false,
) {
let cache_key = null; let cache_key = null;
return ajax.request({ return ajax
.request({
method, method,
url: `${this.settings}${url ? '/' : ''}${url}/`, url: `${this.settings}${url ? '/' : ''}${url}/`,
params, params,
@ -61,21 +90,22 @@ class REST {
extraParams, extraParams,
headers: this._getAuthHeaders(), headers: this._getAuthHeaders(),
responseType: this._getResponseType(isBlob), responseType: this._getResponseType(isBlob),
}).then((response) => { })
.then((response) => {
if (cache_key) { if (cache_key) {
cache.set(cache_key, response.data); cache.set(cache_key, response.data);
} }
return response.data; return response.data;
}); });
} }
static _getResponseType(value){ static _getResponseType(value) {
if (value) { if (value) {
return 'arraybuffer' return 'arraybuffer';
} }
} }
static _getAuthHeaders() { static _getAuthHeaders() {
if (store.state.token) { if (store.state.token) {
return { 'Authorization': `Bearer ${store.state.token}` }; return { Authorization: `Bearer ${store.state.token}` };
} }
} }
static _cancelToken() { static _cancelToken() {
@ -85,7 +115,4 @@ class REST {
export default REST; export default REST;
export { export { RESTError, REST };
RESTError,
REST
};

View File

@ -2,11 +2,11 @@
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 = {
@ -17,8 +17,8 @@ const serviceUrl = {
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}`;
@ -27,7 +27,7 @@ if (process.env.CLIENT) {
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 = {
@ -38,16 +38,8 @@ const robotsTxt = {
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,4 +1,4 @@
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({
@ -14,13 +14,13 @@ export default createStore({
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,
@ -35,9 +35,9 @@ export default createStore({
userFavorite: { userFavorite: {
podcast: [], podcast: [],
playlist: [], playlist: [],
songs: [] songs: [],
} },
} };
}, },
plugins: [vuexPersist.plugin], plugins: [vuexPersist.plugin],
mutations: { mutations: {
@ -56,23 +56,23 @@ export default createStore({
state.currentPlay = song; state.currentPlay = song;
}, },
setModal(state, show) { setModal(state, show) {
state.modal = {...state.modal, ...show} state.modal = { ...state.modal, ...show };
}, },
setPlayer(state, params) { setPlayer(state, params) {
state.player = {...state.player, ...params} state.player = { ...state.player, ...params };
}, },
initPlayer(state) { initPlayer(state) {
state.player.target = document.createElement('audio') state.player.target = document.createElement('audio');
state.player.target.src = ''; state.player.target.src = '';
state.player.target.preload = 'auto'; state.player.target.preload = 'auto';
state.player.target.controls = true; state.player.target.controls = true;
state.player.target.volume = 0.5; state.player.target.volume = 0.5;
console.log('initPlayer', state.player.target) console.log('initPlayer', state.player.target);
}, },
changePlayer(state, params) { changePlayer(state, params) {
const awaitPlay = () => { const awaitPlay = () => {
if (state.player.target.readyState >= 4) { if (state.player.target.readyState >= 4) {
if (state.currentPlay.isPlay){ if (state.currentPlay.isPlay) {
state.player.target.play(); state.player.target.play();
} }
state.currentPlay.isLoader = false; state.currentPlay.isLoader = false;
@ -80,14 +80,13 @@ export default createStore({
} else { } else {
awaitPlay(); awaitPlay();
} }
} };
state.player.target.src = params; state.player.target.src = params;
state.player.src = params; state.player.src = params;
console.log(state.player.target.src) console.log(state.player.target.src);
// state.currentPlay.isLoader = true; // state.currentPlay.isLoader = true;
state.player.target.addEventListener('canplaythrough', awaitPlay) state.player.target.addEventListener('canplaythrough', awaitPlay);
}, },
handlerPlayer(state, params) { handlerPlayer(state, params) {
if (params.pause) { if (params.pause) {
@ -95,7 +94,7 @@ export default createStore({
state.player.target.pause(); state.player.target.pause();
} }
if (params.play) { if (params.play) {
if (state.player.target.readyState >= 3){ if (state.player.target.readyState >= 3) {
state.currentPlay.isPlay = true; state.currentPlay.isPlay = true;
state.player.target.play(); state.player.target.play();
} }
@ -105,8 +104,8 @@ export default createStore({
} }
}, },
setUserFavorite(state, params) { setUserFavorite(state, params) {
state.userFavorite = {...state.userFavorite, ...params} state.userFavorite = { ...state.userFavorite, ...params };
} },
}, },
actions: { actions: {
setToken(context, tokens) { setToken(context, tokens) {
@ -140,5 +139,5 @@ export default createStore({
setUserFavorite(context, params) { setUserFavorite(context, params) {
context.commit('setUserFavorite', 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

@ -24,7 +24,10 @@ export default class {
delete params.extraData; delete params.extraData;
} }
if (params.extraParams) { if (params.extraParams) {
params.params = this.__append_extra_params(params.params, params.extraParams); params.params = this.__append_extra_params(
params.params,
params.extraParams,
);
delete params.extraParams; delete params.extraParams;
} }
/* /*
@ -64,7 +67,7 @@ export default class {
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; return data;
} }
@ -80,7 +83,7 @@ export default class {
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; return data;
} }

View File

@ -9,14 +9,13 @@ class Converter {
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 = {};
@ -38,7 +37,6 @@ class TempStorage {
} }
} }
class Cache { class Cache {
constructor(storage) { constructor(storage) {
if (storage === 'tempStorage') { if (storage === 'tempStorage') {
@ -71,5 +69,4 @@ class Cache {
} }
} }
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,30 +1,25 @@
<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="['container']">
<div class="page404__block"> <div class="page404__block">
<div <div class="page404__info">
class="page404__info" <div class="page404__info-title">404</div>
>
<div class="page404__info-title">
404
</div>
<div class="page404__info-subtitle"> <div class="page404__info-subtitle">
Мы не можем найти то, что вы ищете Мы не можем найти то, что вы ищете
</div> </div>
<div class="page404__info-content"> <div class="page404__info-content">
Возможно, запрашиваемая вами страница была перенесена или удалена. Также возможно, что вы допустили небольшую опечатку при вводе адреса такое случается даже с нами, поэтому еще раз внимательно проверьте. Возможно, запрашиваемая вами страница была перенесена или удалена.
Также возможно, что вы допустили небольшую опечатку при вводе
адреса такое случается даже с нами, поэтому еще раз внимательно
проверьте.
</div> </div>
<div class="page404__info-bottom"> <div class="page404__info-bottom">
Переходите на главную страницу, там вы сможете найти много полезной информации! Переходите на главную страницу, там вы сможете найти много
полезной информации!
</div> </div>
<div class="page404__info-button"> <div class="page404__info-button">
<button <button class="button button-blue" @click="next()">
class="button button-blue"
@click="next()"
>
На главную На главную
</button> </button>
</div> </div>
@ -36,13 +31,11 @@
</template> </template>
<script> <script>
export default { export default {
name: 'Page404', name: 'Page404',
components: { components: {},
},
data() { data() {
return { return {};
}
}, },
computed: { computed: {
user() { user() {
@ -50,12 +43,12 @@
}, },
}, },
mounted() { mounted() {
console.log(this.user) console.log(this.user);
}, },
methods: { methods: {
next() { next() {
this.$router.push({ name: 'home' }); this.$router.push({ name: 'home' });
}
}, },
} },
};
</script> </script>

View File

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

View File

@ -12,22 +12,27 @@
<div class="about__header-top"> <div class="about__header-top">
<div class="about__header-left"> <div class="about__header-left">
<h1 class="h2">О нас</h1> <h1 class="h2">О нас</h1>
<div class="text about__header-description">IT-радио это не просто обычная радиостанция, мы ваши <div class="text about__header-description">
партнеры в творчестве и современных технологиях. IT-радио это не просто обычная радиостанция, мы ваши партнеры в
творчестве и современных технологиях.
</div> </div>
</div> </div>
<div class="about__header-right"> <div class="about__header-right"></div>
</div>
</div> </div>
<div class="text about__header-bottom"> <div class="text about__header-bottom">
Наша миссия воплотить ваши мечты в реальность, шаг за шагом. Благодаря разнообразной команде ведущих, журналистов, разработчиков и новаторов, мы постоянно расширяем границы возможного в цифровом мире. Наша миссия воплотить ваши мечты в реальность, шаг за шагом.
Благодаря разнообразной команде ведущих, журналистов, разработчиков и
новаторов, мы постоянно расширяем границы возможного в цифровом мире.
</div> </div>
</div> </div>
<div class="about__description"> <div class="about__description">
<h2 class="h2">Мы здесь, чтобы открыть глаза на мир IT</h2> <h2 class="h2">Мы здесь, чтобы открыть глаза на мир IT</h2>
<div class="about__description-info"> <div class="about__description-info">
<div class="text about__description-item m--left"> <div class="text about__description-item m--left">
IT-радио это уникальный проект, который объединяет в себе самых ярких представителей IT-индустрии, а также экспертов из различных областей, чтобы поделиться своими знаниями и опытом с широкой аудиторией. IT-радио это уникальный проект, который объединяет в себе самых
ярких представителей IT-индустрии, а также экспертов из различных
областей, чтобы поделиться своими знаниями и опытом с широкой
аудиторией.
</div> </div>
<div class="text about__description-item"> <div class="text about__description-item">
Мы команда, которая верит в силу теплой улыбки и дружеской беседы. Мы команда, которая верит в силу теплой улыбки и дружеской беседы.
@ -35,31 +40,29 @@
</div> </div>
</div> </div>
<video class="about__video" playsinline="" autoplay="" loop="" muted=""> <video class="about__video" playsinline="" autoplay="" loop="" muted="">
<source src="@/assets/videos/about.mp4" type="video/mp4"> <source src="@/assets/videos/about.mp4" type="video/mp4" />
</video> </video>
<div class="about__description"> <div class="about__description">
<div class="about__description-info"> <div class="about__description-info">
<div class="text about__description-item m--left"> <div class="text about__description-item m--left">
Основанное с целью переосмыслить радио через призму современного и инновационного подхода, мы стали больше, чем просто радиостанцией, мы сообщество родственных душ, которые разделяют страсть к артистизму, развитию и инновациям. Основанное с целью переосмыслить радио через призму современного и
инновационного подхода, мы стали больше, чем просто радиостанцией,
мы сообщество родственных душ, которые разделяют страсть к
артистизму, развитию и инновациям.
</div> </div>
<div class="text about__description-item"> <div class="text about__description-item">
Каждое шоу на IT-радио включает в себя актуальные темы, новости, обзоры, интервью с экспертами и многое другое. Каждое шоу на IT-радио включает в себя актуальные темы, новости,
обзоры, интервью с экспертами и многое другое.
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="about__gallery"> <div class="about__gallery">
<div class="about__gallery-item m--gallery-item-one"> <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> </div>
<div class="about__gallery-item m--gallery-item-two"> <Team />
</div>
<div class="about__gallery-item m--gallery-item-three">
</div>
</div>
<Team/>
<div class="app__content"> <div class="app__content">
<div class="about__history"> <div class="about__history">
<div class="about__history-header"> <div class="about__history-header">
@ -68,36 +71,43 @@
</div> </div>
<div class="about__history-list"> <div class="about__history-list">
<div class="about__history-item"> <div class="about__history-item">
<div class="title m--white about__history-title">Событие кратко 1</div> <div class="title m--white about__history-title">
Событие кратко 1
</div>
<div class="about__history-date">Ноябрь 2023</div> <div class="about__history-date">Ноябрь 2023</div>
</div> </div>
<div class="about__history-item"> <div class="about__history-item">
<div class="title m--white about__history-title">Событие кратко 2</div> <div class="title m--white about__history-title">
Событие кратко 2
</div>
<div class="about__history-date">Ноябрь 2023</div> <div class="about__history-date">Ноябрь 2023</div>
</div> </div>
<div class="about__history-item"> <div class="about__history-item">
<div class="title m--white about__history-title">Событие кратко 3</div> <div class="title m--white about__history-title">
Событие кратко 3
</div>
<div class="about__history-date">Ноябрь 2023</div> <div class="about__history-date">Ноябрь 2023</div>
</div> </div>
<div class="about__history-item"> <div class="about__history-item">
<div class="title m--white about__history-title">Событие кратко 4</div> <div class="title m--white about__history-title">
Событие кратко 4
</div>
<div class="about__history-date">Ноябрь 2023</div> <div class="about__history-date">Ноябрь 2023</div>
</div> </div>
</div> </div>
</div> </div>
<SupportBlock/> <SupportBlock />
</div> </div>
</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

@ -30,7 +30,28 @@
</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
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>
<FormKit <FormKit
v-model="formData" v-model="formData"
type="form" type="form"
@ -48,22 +69,22 @@
@click-outside="$emit('hideModal')" @click-outside="$emit('hideModal')"
> >
<div class="title">Напишите нам</div> <div class="title">Напишите нам</div>
<FormKitSchema :schema="schema"/> <FormKitSchema :schema="schema" />
</FormKit> </FormKit>
</div> </div>
<SupportBlock/> <SupportBlock />
</div> </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: [
{ {
@ -72,7 +93,7 @@ export default {
label: 'ФИО', label: 'ФИО',
placeholder: 'ФИО', placeholder: 'ФИО',
validation: 'required', validation: 'required',
outerClass: 'field--required' outerClass: 'field--required',
}, },
{ {
$formkit: 'text', $formkit: 'text',
@ -80,7 +101,7 @@ export default {
label: 'Название организации', label: 'Название организации',
placeholder: 'Название организации', placeholder: 'Название организации',
validation: 'required', validation: 'required',
outerClass: 'field--required' outerClass: 'field--required',
}, },
{ {
$formkit: 'maska', $formkit: 'maska',
@ -89,7 +110,7 @@ export default {
label: 'Контактный телефон', label: 'Контактный телефон',
placeholder: '+7 (###) ###-##-##', placeholder: '+7 (###) ###-##-##',
validation: 'required', validation: 'required',
outerClass: 'field--required' outerClass: 'field--required',
}, },
{ {
$formkit: 'textarea', $formkit: 'textarea',
@ -97,16 +118,14 @@ export default {
label: 'Сообщение', label: 'Сообщение',
placeholder: 'Сообщение', placeholder: 'Сообщение',
validation: 'required', validation: 'required',
outerClass: 'field--required' outerClass: 'field--required',
}
],
showLoaderSending: false
}
}, },
methods:{ ],
submitHandler(){ showLoaderSending: false,
};
} },
} methods: {
} submitHandler() {},
},
};
</script> </script>

View File

@ -3,12 +3,16 @@
<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
><br />
</p> </p>
<h1 class="home__title" ref="targetTitle"> <h1 class="home__title" ref="targetTitle">
IT-Радио <span id="targetTitleSpan">радиостанция про сферу</span> технологий <br/> и развитие IT-Радио
<span id="targetTitleSpan">радиостанция про сферу</span> технологий
<br />
и развитие
<span id="targetTitleSpan">в IT</span> <span id="targetTitleSpan">в IT</span>
<!-- IT Радио --> <!-- IT Радио -->
<!-- <span id="targetTitleSpan">радиостанция</span>--> <!-- <span id="targetTitleSpan">радиостанция</span>-->
@ -17,18 +21,19 @@
<!-- и развитие <span id="targetTitleSpan">в IT</span><br/>--> <!-- и развитие <span id="targetTitleSpan">в IT</span><br/>-->
</h1> </h1>
</div> </div>
<div class="home__banner" ref="target"> <div class="home__banner" ref="target"></div>
</div>
</div> </div>
<template v-if="true"> <template v-if="true">
<div class="app__content"> <div class="app__content">
<div class="home__description"> <div class="home__description">
<div class="home__info"> <div class="home__info">
<div class="text home__info--item"> <div class="text home__info--item">
IT-RADIO. 2023 IT-RADIO. 2023
<span> <span>
Сегодня IT-сфера развивается настолько быстро, что следить за всеми новинками и изменениями в ней становится все сложнее.<br/><br/> Но есть способ всегда быть в курсе последних новостей и событий это IT-радио. Сегодня IT-сфера развивается настолько быстро, что следить за
всеми новинками и изменениями в ней становится все сложнее.<br /><br />
Но есть способ всегда быть в курсе последних новостей и событий
это IT-радио.
</span> </span>
</div> </div>
<h2 class="h2 m--border"> <h2 class="h2 m--border">
@ -36,16 +41,20 @@
</h2> </h2>
<div class="text home__info--item m--circle"> <div class="text home__info--item m--circle">
<span> <span>
IT-радио это уникальный проект, который объединяет в себе самых ярких представителей IT-индустрии, а также экспертов из различных областей, чтобы поделиться своими знаниями и опытом с широкой аудиторией.<br/><br/> IT-радио это уникальный проект, который объединяет в себе
Каждое шоу на IT-радио включает в себя актуальные темы, новости, обзоры, интервью с экспертами и многое другое. самых ярких представителей IT-индустрии, а также экспертов из
различных областей, чтобы поделиться своими знаниями и опытом с
широкой аудиторией.<br /><br />
Каждое шоу на IT-радио включает в себя актуальные темы, новости,
обзоры, интервью с экспертами и многое другое.
</span> </span>
</div> </div>
</div> </div>
<div class="home__content"> <div class="home__content">
<div class="home__content--item m--one-circle"> <div class="home__content--item m--one-circle">
<span class="title">Музыка</span> <span class="title">Музыка</span>
Нам важно создать комфортную атмосферу, которая поможет сосредоточиться на задачах и улучшит Нам важно создать комфортную атмосферу, которая поможет
продуктивность. сосредоточиться на задачах и улучшит продуктивность.
</div> </div>
<div class="home__content--item m--two-circle"> <div class="home__content--item m--two-circle">
<span class="title">Подкасты</span> <span class="title">Подкасты</span>
@ -58,18 +67,18 @@
</div> </div>
</div> </div>
</div> </div>
<Team/> <Team />
<div class="app__content"> <div class="app__content">
<RubricBlock/> <RubricBlock />
</div> </div>
<div class="home__social"> <div class="home__social">
<div class="home__social--tools"> <div class="home__social--tools">
<div class="home__social--description"> <div class="home__social--description">
<h2 class="h2 m--white">Соц сети</h2> <h2 class="h2 m--white">Соц сети</h2>
<div class="text"> <div class="text">
Следите за обновлениями и новыми постами на IT Radio, чтобы быть в курсе последних новостей Следите за обновлениями и новыми постами на IT Radio, чтобы быть в
и курсе последних новостей и событий в мире IT, а также следить за
событий в мире IT, а также следить за анонсами и обновлениями! анонсами и обновлениями!
</div> </div>
</div> </div>
<div class="home__social--btns"> <div class="home__social--btns">
@ -81,24 +90,23 @@
</div> </div>
</div> </div>
<div class="app__content"> <div class="app__content">
<blog/> <blog />
</div> </div>
</template> </template>
</div> </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();
}, },
@ -114,20 +122,19 @@ export default {
end: 600, end: 600,
pin: true, pin: true,
}, },
}, });
);
gsap.to(this.$refs.targetTitle, { gsap.to(this.$refs.targetTitle, {
color: 'transparent', color: 'transparent',
backgroundImage: '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

@ -4,12 +4,20 @@
: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> },
]"
/>
<h1 class="h2 playlist__title m--margin">
{{ $route.name === 'playlist-create' ? 'Новый плейлист' : playlist.name }}
</h1>
<button class="playlist-edit__upload" @click="handlerUploadCover">
Добавить обложку
</button>
<div class="field__input m--hidden"> <div class="field__input m--hidden">
<input <input
id="cover" id="cover"
@ -18,7 +26,7 @@
class="input" class="input"
type="file" type="file"
name="logo" name="logo"
> />
</div> </div>
<FormKit <FormKit
v-model="playlist.name" v-model="playlist.name"
@ -32,12 +40,12 @@
<div class="playlist-edit__title">Поиск по каталогу</div> <div class="playlist-edit__title">Поиск по каталогу</div>
<template v-if="showLoaderSongs"> <template v-if="showLoaderSongs">
<div class="loader"> <div class="loader">
<div class="spinner"/> <div class="spinner" />
Загрузка данных Загрузка данных
</div> </div>
</template> </template>
<SongList <SongList
v-else-if="songsFiltered.length>0" v-else-if="songsFiltered.length > 0"
:songList="songsFiltered" :songList="songsFiltered"
class="m--column" class="m--column"
@addPlaylist="addPlaylist" @addPlaylist="addPlaylist"
@ -48,12 +56,12 @@
<div class="playlist-edit__title">Добавленные треки</div> <div class="playlist-edit__title">Добавленные треки</div>
<template v-if="showLoaderPlaylist"> <template v-if="showLoaderPlaylist">
<div class="loader"> <div class="loader">
<div class="spinner"/> <div class="spinner" />
Загрузка данных Загрузка данных
</div> </div>
</template> </template>
<SongList <SongList
v-else-if="playlist.song?.length>0" v-else-if="playlist.song?.length > 0"
:songList="playlist.song" :songList="playlist.song"
class="m--column" class="m--column"
:songAlreadyAdd="true" :songAlreadyAdd="true"
@ -63,24 +71,23 @@
</div> </div>
</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();
@ -88,92 +95,109 @@ export default {
}, },
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: { methods: {
getPlaylist() { getPlaylist() {
this.showLoaderPlaylist = true; this.showLoaderPlaylist = true;
app.getPlaylist(this.$route.params.id).then(res => { app
.getPlaylist(this.$route.params.id)
.then((res) => {
this.showLoaderPlaylist = false; this.showLoaderPlaylist = false;
this.playlist = res; this.playlist = res;
}).catch(err => {
this.showLoaderPlaylist = false;
console.error(err)
}) })
.catch((err) => {
this.showLoaderPlaylist = false;
console.error(err);
});
}, },
getAllSong() { getAllSong() {
this.showLoaderSongs = true; this.showLoaderSongs = true;
app.getAllSong().then(res => { app
.getAllSong()
.then((res) => {
this.showLoaderSongs = false; this.showLoaderSongs = false;
this.songs = res; this.songs = res;
}).catch(err => {
this.showLoaderSongs = false;
console.error(err)
}) })
.catch((err) => {
this.showLoaderSongs = false;
console.error(err);
});
}, },
addPlaylist(song) { addPlaylist(song) {
console.log(song) console.log(song);
const params = { const params = {
playlist_id: this.$route.params.id, playlist_id: this.$route.params.id,
...song ...song,
} };
this.showLoaderSongs = true; this.showLoaderSongs = true;
this.showLoaderPlaylist = true; this.showLoaderPlaylist = true;
app.addSongToPlaylist(params).then(() => { app
.addSongToPlaylist(params)
.then(() => {
this.showLoaderPlaylist = false; this.showLoaderPlaylist = false;
this.showLoaderSongs = false; this.showLoaderSongs = false;
this.getPlaylist(); this.getPlaylist();
}).catch(err => { })
.catch((err) => {
this.showLoaderPlaylist = false; this.showLoaderPlaylist = false;
this.showLoaderSongs = false; this.showLoaderSongs = false;
console.error(err) console.error(err);
}) });
}, },
removePlaylist(song) { removePlaylist(song) {
const params = { const params = {
playlist_id: this.$route.params.id, playlist_id: this.$route.params.id,
azura_id: song.azura_id azura_id: song.azura_id,
} };
this.showLoaderSongs = true; this.showLoaderSongs = true;
this.showLoaderPlaylist = true; this.showLoaderPlaylist = true;
app.removeSongToPlaylist(params).then(() => { app
.removeSongToPlaylist(params)
.then(() => {
this.showLoaderPlaylist = false; this.showLoaderPlaylist = false;
this.showLoaderSongs = false; this.showLoaderSongs = false;
this.getPlaylist(); this.getPlaylist();
}).catch(err => { })
.catch((err) => {
this.showLoaderPlaylist = false; this.showLoaderPlaylist = false;
this.showLoaderSongs = false; this.showLoaderSongs = false;
console.error(err) console.error(err);
}) });
}, },
handlerUploadCover(){ handlerUploadCover() {
let logoInput = this.$refs.coverInput; let logoInput = this.$refs.coverInput;
let click = new MouseEvent('click'); let click = new MouseEvent('click');
logoInput.onchange = this.uploadCover; logoInput.onchange = this.uploadCover;
logoInput.dispatchEvent(click); logoInput.dispatchEvent(click);
}, },
uploadCover(event){ uploadCover(event) {
let file = event.target.files ? event.target.files[0] : null let file = event.target.files ? event.target.files[0] : null;
if (file) { if (file) {
const data = new FormData(); const data = new FormData();
data.append('playlist_art', file); data.append('playlist_art', file);
data.append('playlist_id', this.$route.params.id); data.append('playlist_id', this.$route.params.id);
app.updatePlaylist(data).then((res) => { app
.updatePlaylist(data)
.then((res) => {
this.showLoaderPlaylist = false; this.showLoaderPlaylist = false;
this.showLoaderSongs = false; this.showLoaderSongs = false;
this.playlist = res; this.playlist = res;
}).catch(err => { })
.catch((err) => {
this.showLoaderPlaylist = false; this.showLoaderPlaylist = false;
this.showLoaderSongs = false; this.showLoaderSongs = false;
console.error(err) console.error(err);
}) });
} }
} },
} },
} };
</script> </script>

View File

@ -2,7 +2,7 @@
<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>
@ -10,25 +10,30 @@
<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
class="playlist__edit"
@click="
next({ name: 'playlist-edit', params: { id: this.playlist.id } })
"
></div>
</div> </div>
<SongList :songList="playlist.song" :songAlreadyAdd="true"/> <SongList :songList="playlist.song" :songAlreadyAdd="true" />
</template> </template>
</div> </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();
@ -36,20 +41,23 @@ export default {
methods: { methods: {
getPlaylist() { getPlaylist() {
this.showLoaderPlaylist = true; this.showLoaderPlaylist = true;
app.getPlaylist(this.$route.params.id).then(res => { app
.getPlaylist(this.$route.params.id)
.then((res) => {
this.showLoaderPlaylist = false; this.showLoaderPlaylist = false;
this.playlist = res; this.playlist = res;
}).catch(err => {
this.showLoaderPlaylist = false;
console.error(err)
}) })
.catch((err) => {
this.showLoaderPlaylist = false;
console.error(err);
});
}, },
handlerBack() { handlerBack() {
this.$router.go(-1); this.$router.go(-1);
}, },
next(params) { next(params) {
this.$router.push(params); this.$router.push(params);
} },
} },
} };
</script> </script>

View File

@ -52,44 +52,44 @@
</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:{ watch: {
'$route.query.page': { '$route.query.page': {
handler(from) { handler(from) {
this.currentPage = Number(from); this.currentPage = Number(from);
}, },
} },
}, },
created() { created() {
// this.getPlayList(); // this.getPlayList();
}, },
methods:{ methods: {
// getPlayList(){ // getPlayList(){
// audio.getPlayList(this.station.id).then(res => { // audio.getPlayList(this.station.id).then(res => {
// let groups = res // let groups = res
@ -101,9 +101,9 @@ export default {
// console.error(err) // console.error(err)
// }) // })
// }, // },
changeTab(tab){ changeTab(tab) {
this.currentTabsItem = 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,6 +1,10 @@
<template> <template>
<div class="app__content profile"> <div class="app__content profile">
<template v-if="$route.name !== 'playlist-edit' && $route.name !== 'playlist-create'"> <template
v-if="
$route.name !== 'playlist-edit' && $route.name !== 'playlist-create'
"
>
<AppBreadcrumbs <AppBreadcrumbs
:breadcrumbs="[ :breadcrumbs="[
{ name: 'Главная', route: { name: 'home' } }, { name: 'Главная', route: { name: 'home' } },
@ -8,7 +12,9 @@
]" ]"
/> />
<h1 class="h2 profile__title">{{ user.email }}</h1> <h1 class="h2 profile__title">{{ user.email }}</h1>
<button class="button m--text-link" @click="showRecovery">Редактировать профиль</button> <button class="button m--text-link" @click="showRecovery">
Редактировать профиль
</button>
<div class="profile__tabs tabs m--btns"> <div class="profile__tabs tabs m--btns">
<button <button
v-for="item in tabsItems" v-for="item in tabsItems"
@ -22,19 +28,23 @@
</div> </div>
</template> </template>
<template v-if="$route.name === 'profile'"> <template v-if="$route.name === 'profile'">
<template v-if="currentTabsItem==='music'"> <template v-if="currentTabsItem === 'music'">
<template v-if="showLoaderSong"> <template v-if="showLoaderSong">
<div class="loader"> <div class="loader">
<div class="spinner"/> <div class="spinner" />
Загрузка данных Загрузка данных
</div> </div>
</template> </template>
<SongList v-else :songList="userFavorite.songs" @removeSong="removeFavorites"/> <SongList
v-else
:songList="userFavorite.songs"
@removeSong="removeFavorites"
/>
</template> </template>
<template v-if="currentTabsItem==='playlists'"> <template v-if="currentTabsItem === 'playlists'">
<template v-if="showLoaderPlaylist"> <template v-if="showLoaderPlaylist">
<div class="loader"> <div class="loader">
<div class="spinner"/> <div class="spinner" />
Загрузка данных Загрузка данных
</div> </div>
</template> </template>
@ -45,69 +55,71 @@
/> />
</template> </template>
</template> </template>
<routerView v-else/> <routerView v-else />
</div> </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) ||
(!from?.name && !from?.hash)
) {
console.log('2');
if (to.hash) { if (to.hash) {
this.currentTabsItem = to?.hash.replace('#', '') || 'music'; this.currentTabsItem = to?.hash.replace('#', '') || 'music';
} else { } else {
this.currentTabsItem = 'music'; this.currentTabsItem = 'music';
} }
} } else {
else { console.log('3');
console.log('3')
if (to?.name === 'playlist') { if (to?.name === 'playlist') {
this.currentTabsItem = 'playlists' this.currentTabsItem = 'playlists';
} }
} }
}, },
@ -120,52 +132,67 @@ export default {
methods: { methods: {
getSongList() { getSongList() {
this.showLoaderSong = true; this.showLoaderSong = true;
app.getFavoriteList().then(res => { app
.getFavoriteList()
.then((res) => {
this.showLoaderSong = false; this.showLoaderSong = false;
this.$store.dispatch('setUserFavorite', {songs: res}); this.$store.dispatch('setUserFavorite', { songs: res });
}).catch(err => {
this.showLoaderSong = false;
console.error(err)
}) })
.catch((err) => {
this.showLoaderSong = false;
console.error(err);
});
}, },
changeTab(tab) { changeTab(tab) {
this.currentTabsItem = tab; this.currentTabsItem = tab;
if (this.$route.name === 'profile') { if (this.$route.name === 'profile') {
this.$router.push({name: this.$route.name, hash: `#${tab}`}); this.$router.push({ name: this.$route.name, hash: `#${tab}` });
} else { } else {
this.$router.push({name: 'profile', hash: `#${tab}`}); this.$router.push({ name: 'profile', hash: `#${tab}` });
} }
}, },
removeFavorites(song) { removeFavorites(song) {
this.showLoaderSong = true; this.showLoaderSong = true;
app.removeFavorites(song).then(() => { app
.removeFavorites(song)
.then(() => {
this.showLoaderSong = false; this.showLoaderSong = false;
this.getSongList(); this.getSongList();
}).catch(err => {
this.showLoaderSong = false;
console.error(err)
}) })
.catch((err) => {
this.showLoaderSong = false;
console.error(err);
});
}, },
showRecovery() { showRecovery() {
this.$store.dispatch('setModal', {changingUser: true}); this.$store.dispatch('setModal', { changingUser: true });
}, },
getPlaylists() { getPlaylists() {
this.showLoaderPlaylist = true; this.showLoaderPlaylist = true;
app.getPlaylists().then(res => { app
.getPlaylists()
.then((res) => {
this.showLoaderPlaylist = false; this.showLoaderPlaylist = false;
this.$store.dispatch('setUserFavorite', {playlist: res}); this.$store.dispatch('setUserFavorite', { playlist: res });
}).catch(err => {
this.showLoaderPlaylist = false;
console.error(err)
}) })
.catch((err) => {
this.showLoaderPlaylist = false;
console.error(err);
});
}, },
createPlayList() { createPlayList() {
app.createPlaylists().then(res=>{ app
this.$router.push({name: 'playlist-create', params: {id: res.id}}); .createPlaylists()
}).catch(err=>{ .then((res) => {
console.error(err) this.$router.push({
name: 'playlist-create',
params: { id: res.id },
});
}) })
} .catch((err) => {
} console.error(err);
} });
},
},
};
</script> </script>

View File

@ -6,16 +6,16 @@
{ 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>