[
  {
    "path": ".babelrc",
    "content": "{\n  \"presets\": [\n    [\"@babel/preset-env\", {\n      \"modules\": false,\n      \"targets\": {\n        \"browsers\": [\"> 1%\", \"last 2 versions\", \"not ie <= 8\"]\n      },\n      \"useBuiltIns\": \"entry\"\n    }],\n    \"@babel/preset-react\"\n  ],\n  \"plugins\": [\n    \"@babel/plugin-transform-runtime\",\n    // Stage 2\n    [\"@babel/plugin-proposal-decorators\", { \"legacy\": true }],\n    \"@babel/plugin-proposal-function-sent\",\n    \"@babel/plugin-proposal-export-namespace-from\",\n    \"@babel/plugin-proposal-numeric-separator\",\n    \"@babel/plugin-proposal-throw-expressions\",\n    // Stage 3\n    \"@babel/plugin-syntax-dynamic-import\",\n    \"@babel/plugin-syntax-import-meta\",\n    [\"@babel/plugin-proposal-class-properties\", { \"loose\": false }],\n    \"@babel/plugin-proposal-json-strings\",\n    [\"import\", { \"libraryName\": \"antd-mobile\" ,\"style\": true}]\n  ]\n}"
  },
  {
    "path": ".gitignore",
    "content": "dist\nnode_modules\n.idea"
  },
  {
    "path": ".postcssrc.js",
    "content": "module.exports = {\n  \"plugins\": {\n    \"postcss-import\": {},\n    \"postcss-url\": {},\n    // to edit target browsers: use \"browserslist\" field in package.json\n    \"autoprefixer\": {}\n  }\n}"
  },
  {
    "path": "README.md",
    "content": "# react-mobile-qqMusic\n# 技术栈\n 1. react\n 2. react-router\n 3. react-redux\n 4. es6\n 5. axios\n 6. webpack\n# 关于项目 \n## 1.安装依赖包\n```\n  yarn\n```\n## 2.启动服务\n### 开发者\n```\nnpm run dev \n```\n## 3.编译\n```\nnpm run build \n```\n\n# 已实现功能\n## Tab-我的\n![Tab-我的](https://segmentfault.com/img/bVVCk9?w=660&h=1174)\n## Tab-音乐馆\n![Tab-音乐馆](https://segmentfault.com/img/bVVClw?w=662&h=1182)\n## Tab-发现\n![Tab-发现](https://segmentfault.com/img/bVVClz?w=660&h=1174)\n## 侧滑栏\n![Tab-侧滑栏](https://segmentfault.com/img/bVVClH?w=660&h=1176)\n## 播放列表\n![Tab-播放列表](https://segmentfault.com/img/bVVCmT?w=660&h=1174)\n## 播放器\n![Tab-播放器1](https://segmentfault.com/img/bVVClM?w=662&h=1170)\n![Tab-播放器2](https://segmentfault.com/img/bVVCl4?w=664&h=1174)\n## 歌曲搜索\n![Tab-歌曲搜索1](https://segmentfault.com/img/bVVCl7?w=662&h=1174)\n![Tab-歌曲搜索2](https://segmentfault.com/img/bVVCmi?w=654&h=1174)\n## 歌单管理\n![Tab-歌单管理1](https://segmentfault.com/img/bVVCmA?w=660&h=1180)\n![Tab-歌单管理2](https://segmentfault.com/img/bVVCmM?w=660&h=1176)\n# 项目总结\n整个项目采用了React这个框架来构建，之前我都是用Vue用做开发的。正好借此机会做一个小小的对比，纯是个人使用的心得体会。如果你也有一些不一样的心得交流的话，欢迎交流。\n \n 1. React相比Vue给我感受最深的就是他的优雅的组件化，用起来是非常爽，谁用谁知道，引用即可使用。而Vue在这块相对来说就要弱一点，引用了组件之后还要注册一下。\n 2. Vue在双向数据绑定的体验上要优于React的，React采用的是Flux的单向数据流动。这在实现一些需要双向数据交互的功能上，Vue是占有优势的。\n 3. Vue相比React更加轻量级。Vue只需要引用一个Vue.js即可使用，而React则要引用React.js、React-dom.js、babel.js(用于转换jsx的语法)。\n 4. Vue在上手程度上要优于React。Vue学习成本很低，另外官方有比较完善的中文文档。而React官方则只有英文文档，另外学习成本也比较高。我见到网上某人喷只会Vue的是前端小白，我对这种人只能报以呵呵。简单本身是没有错误，一个东西能以简单的方式解决难道不好吗？关于这个中文文档居然还有人喷那些喜欢用Vue的是不是英文能力差，我就再报以呵呵一笑。本身拥有中文文档就是一个优势，结果还成了被喷的地方。首先，并不是所有人的英文能力都跟某些嘴炮大神那么牛逼的。其次，就算是英文能力牛逼的人，你敢说你阅读中文的能力会比你阅读英文能力差？\n 5. 我个人感觉Vue的全家桶（不包括Vue）使用起来，我个人感觉是要比React的全家桶（不包括React）使用起来舒服的。\n 6. 虽然Vue在一些细节上要比React好，但是不能觉得React就比Vue差。这种想法是错误。特别是大型应用上，使用React项目维护起来肯定是要比Vue要好的。当然这不代表Vue不能构建大型应用。\n 7. React在社区生态建设上是比Vue好很多的，而且后面站着FaceBook。不怕遇到问题没人可以帮你解决的情况，而Vue的话就要稍微担心一下。\n\n> 最后强调一下：React和Vue都是非常棒的前端框架，建议大家都去学习一下。采用React或者是Vue还是要结合业务场景和现实情况做选择的。单纯说React还是Vue好，我个人觉得都是耍流氓。\n\n \n"
  },
  {
    "path": "build/build.js",
    "content": "'use strict'\nrequire('./check-versions')()\n\nprocess.env.NODE_ENV = 'production'\n\nconst ora = require('ora')\nconst rm = require('rimraf')\nconst path = require('path')\nconst chalk = require('chalk')\nconst webpack = require('webpack')\nconst config = require('../config')\nconst webpackConfig = require('./webpack.prod.conf')\n\nconst spinner = ora('building for production...')\nspinner.start()\n\nrm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {\n  if (err) throw err\n  webpack(webpackConfig, (err, stats) => {\n    spinner.stop()\n    if (err) throw err\n    process.stdout.write(stats.toString({\n      colors: true,\n      modules: false,\n      children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.\n      chunks: false,\n      chunkModules: false\n    }) + '\\n\\n')\n\n    if (stats.hasErrors()) {\n      console.log(chalk.red('  Build failed with errors.\\n'))\n      process.exit(1)\n    }\n\n    console.log(chalk.cyan('  Build complete.\\n'))\n    console.log(chalk.yellow(\n      '  Tip: built files are meant to be served over an HTTP server.\\n' +\n      '  Opening index.html over file:// won\\'t work.\\n'\n    ))\n  })\n})\n"
  },
  {
    "path": "build/check-versions.js",
    "content": "'use strict'\nconst chalk = require('chalk')\nconst semver = require('semver')\nconst packageConfig = require('../package.json')\nconst shell = require('shelljs')\n\nfunction exec (cmd) {\n  return require('child_process').execSync(cmd).toString().trim()\n}\n\nconst versionRequirements = [\n  {\n    name: 'node',\n    currentVersion: semver.clean(process.version),\n    versionRequirement: packageConfig.engines.node\n  }\n]\n\nif (shell.which('npm')) {\n  versionRequirements.push({\n    name: 'npm',\n    currentVersion: exec('npm --version'),\n    versionRequirement: packageConfig.engines.npm\n  })\n}\n\nmodule.exports = function () {\n  const warnings = []\n\n  for (let i = 0; i < versionRequirements.length; i++) {\n    const mod = versionRequirements[i]\n\n    if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {\n      warnings.push(mod.name + ': ' +\n        chalk.red(mod.currentVersion) + ' should be ' +\n        chalk.green(mod.versionRequirement)\n      )\n    }\n  }\n\n  if (warnings.length) {\n    console.log('')\n    console.log(chalk.yellow('To use this template, you must update following to modules:'))\n    console.log()\n\n    for (let i = 0; i < warnings.length; i++) {\n      const warning = warnings[i]\n      console.log('  ' + warning)\n    }\n\n    console.log()\n    process.exit(1)\n  }\n}\n"
  },
  {
    "path": "build/utils.js",
    "content": "'use strict'\nconst path = require('path')\nconst config = require('../config')\nconst MiniCssExtractPlugin = require(\"mini-css-extract-plugin\")\nconst packageConfig = require('../package.json')\nconst theme=require('../theme')\n\nconst devMode = process.env.NODE_ENV !== 'production'\n\nexports.assetsPath = function (_path) {\n  const assetsSubDirectory = process.env.NODE_ENV === 'production'\n    ? config.build.assetsSubDirectory\n    : config.dev.assetsSubDirectory\n\n  return path.posix.join(assetsSubDirectory, _path)\n}\n\nexports.cssLoaders = function (options) {\n  options = options || {}\n\n  const cssLoader = {\n    loader: 'css-loader',\n    options: {\n      sourceMap: options.sourceMap\n    }\n  }\n\n  const postcssLoader = {\n    loader: 'postcss-loader',\n    options: {\n      sourceMap: options.sourceMap\n    }\n  }\n\n  const styleLoader={\n    loader:devMode ? 'style-loader' : MiniCssExtractPlugin.loader,\n  }\n  // generate loader string to be used with extract text plugin\n  function generateLoaders (loader, loaderOptions) {\n    const loaders = options.usePostCSS ? [styleLoader,cssLoader, postcssLoader] : [styleLoader,cssLoader]\n\n    if (loader) {\n      loaders.push({\n        loader: loader + '-loader',\n        options: Object.assign({}, loaderOptions, {\n          sourceMap: options.sourceMap\n        })\n      })\n    }\n\n    return loaders;\n  }\n\n  // https://vue-loader.vuejs.org/en/configurations/extract-css.html\n  return {\n    css: generateLoaders(),\n    less: generateLoaders('less',{modifyVars:theme}),\n    scss: generateLoaders('sass')\n  }\n}\n\n// Generate loaders for standalone style files (outside of .vue)\nexports.styleLoaders = function (options) {\n  const output = []\n  const loaders = exports.cssLoaders(options)\n\n  for (const extension in loaders) {\n    const loader = loaders[extension]\n    output.push({\n      test: new RegExp('\\\\.' + extension + '$'),\n      use: loader\n    })\n  }\n  return output\n}\n\n\nexports.createNotifierCallback = () => {\n  const notifier = require('node-notifier')\n\n  return (severity, errors) => {\n    if (severity !== 'error') return\n\n    const error = errors[0]\n    const filename = error.file && error.file.split('!').pop()\n\n    notifier.notify({\n      title: packageConfig.name,\n      message: severity + ': ' + error.name,\n      subtitle: filename || '',\n      icon: path.join(__dirname, 'logo.png')\n    })\n  }\n}\n"
  },
  {
    "path": "build/webpack.base.conf.js",
    "content": "'use strict'\nconst path = require('path')\nconst utils = require('./utils')\nconst config = require('../config')\n\nfunction resolve (dir) {\n  return path.join(__dirname, '..', dir)\n}\n\n\n\nmodule.exports = {\n  context: path.resolve(__dirname, '../'),\n  entry: {\n    app: './src/main.js'\n  },\n  output: {\n    path: config.build.assetsRoot,\n    filename: '[name].js',\n    publicPath: process.env.NODE_ENV === 'production'\n      ? config.build.assetsPublicPath\n      : config.dev.assetsPublicPath\n  },\n  resolve: {\n    alias:{\n      '@':path.join(__dirname,'../src')\n    },\n    extensions: ['.js', '.jsx', '.json']\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.(js|jsx)$/,\n        loader: 'babel-loader',\n        exclude:/node_modules/\n      },\n      {\n        test: /\\.(png|jpe?g|gif|svg)(\\?.*)?$/,\n        loader: 'url-loader',\n        options: {\n          limit: 10000,\n          name: utils.assetsPath('img/[name].[hash:7].[ext]')\n        }\n      },\n      {\n        test: /\\.(mp4|webm|ogg|mp3|wav|flac|aac)(\\?.*)?$/,\n        loader: 'url-loader',\n        options: {\n          limit: 10000,\n          name: utils.assetsPath('media/[name].[hash:7].[ext]')\n        }\n      },\n      {\n        test: /\\.(woff2?|eot|ttf|otf)(\\?.*)?$/,\n        loader: 'url-loader',\n        options: {\n          limit: 10000,\n          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')\n        }\n      }\n    ]\n  },\n  node: {\n    // prevent webpack from injecting useless setImmediate polyfill because Vue\n    // source contains it (although only uses it if it's native).\n    setImmediate: false,\n    // prevent webpack from injecting mocks to Node native modules\n    // that does not make sense for the client\n    dgram: 'empty',\n    fs: 'empty',\n    net: 'empty',\n    tls: 'empty',\n    child_process: 'empty'\n  }\n}\n"
  },
  {
    "path": "build/webpack.dev.conf.js",
    "content": "'use strict'\nconst utils = require('./utils')\nconst webpack = require('webpack')\nconst config = require('../config')\nconst merge = require('webpack-merge')\nconst path = require('path')\nconst baseWebpackConfig = require('./webpack.base.conf')\nconst CopyWebpackPlugin = require('copy-webpack-plugin')\nconst HtmlWebpackPlugin = require('html-webpack-plugin')\nconst FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')\nconst portfinder = require('portfinder')\n\nconst HOST = process.env.HOST\nconst PORT = process.env.PORT && Number(process.env.PORT)\n\nconst devWebpackConfig = merge(baseWebpackConfig, {\n  module: {\n    rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })\n  },\n  mode: config.dev.mode,\n  // cheap-module-eval-source-map is faster for development\n  devtool: config.dev.devtool,\n\n  // these devServer options should be customized in /config/index.js\n  devServer: {\n    clientLogLevel: 'warning',\n    historyApiFallback: {\n      rewrites: [\n        { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },\n      ],\n    },\n    hot: true,\n    contentBase: false, // since we use CopyWebpackPlugin.\n    compress: true,\n    host: HOST || config.dev.host,\n    port: PORT || config.dev.port,\n    open: config.dev.autoOpenBrowser,\n    overlay: config.dev.errorOverlay\n      ? { warnings: false, errors: true }\n      : false,\n    publicPath: config.dev.assetsPublicPath,\n    proxy: config.dev.proxyTable,\n    quiet: true, // necessary for FriendlyErrorsPlugin\n    watchOptions: {\n      poll: config.dev.poll,\n    }\n  },\n  plugins: [\n    new webpack.HotModuleReplacementPlugin(),\n    // https://github.com/ampedandwired/html-webpack-plugin\n    new HtmlWebpackPlugin({\n      filename: 'index.html',\n      template: 'index.html',\n      inject: true\n    }),\n    // copy custom static assets\n    new CopyWebpackPlugin([\n      {\n        from: path.resolve(__dirname, '../static'),\n        to: config.dev.assetsSubDirectory,\n        ignore: ['.*']\n      }\n    ])\n  ]\n})\n\nmodule.exports = new Promise((resolve, reject) => {\n  portfinder.basePort = process.env.PORT || config.dev.port\n  portfinder.getPort((err, port) => {\n    if (err) {\n      reject(err)\n    } else {\n      // publish the new Port, necessary for e2e tests\n      process.env.PORT = port\n      // add port to devServer config\n      devWebpackConfig.devServer.port = port\n\n      // Add FriendlyErrorsPlugin\n      devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({\n        compilationSuccessInfo: {\n          messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],\n        },\n        onErrors: config.dev.notifyOnErrors\n        ? utils.createNotifierCallback()\n        : undefined\n      }))\n\n      resolve(devWebpackConfig)\n    }\n  })\n})\n"
  },
  {
    "path": "build/webpack.prod.conf.js",
    "content": "'use strict'\nconst path = require('path')\nconst utils = require('./utils')\nconst webpack = require('webpack')\nconst config = require('../config')\nconst merge = require('webpack-merge')\nconst baseWebpackConfig = require('./webpack.base.conf')\nconst CopyWebpackPlugin = require('copy-webpack-plugin')\nconst HtmlWebpackPlugin = require('html-webpack-plugin')\nconst MiniCssExtractPlugin = require(\"mini-css-extract-plugin\")\nconst OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')\nconst UglifyJsPlugin = require('uglifyjs-webpack-plugin')\nconst CleanWebpackPlugin = require('clean-webpack-plugin');\n\n\n\n\nconst webpackConfig = merge(baseWebpackConfig, {\n  module: {\n    rules: utils.styleLoaders({\n      sourceMap: config.build.productionSourceMap,\n      usePostCSS: true\n    })\n  },\n  mode: config.build.mode,\n  devtool: config.build.productionSourceMap ? config.build.devtool : false,\n  output: {\n    path: config.build.assetsRoot,\n    filename: utils.assetsPath('js/[name].[chunkhash].js'),\n    chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')\n  },\n  optimization:{\n    splitChunks:{\n      chunks: 'all',\n      minSize: 30000,\n      minChunks: 1,\n      maxAsyncRequests: 5,\n      maxInitialRequests: 3,\n      automaticNameDelimiter: '~',\n      name: true,\n      cacheGroups: {\n        vendors: {\n          test: /[\\\\/]node_modules[\\\\/]/,\n          chunks: 'initial',\n          reuseExistingChunk:true,\n          priority: -10\n        }\n      }\n    },\n    runtimeChunk: {\n      name: 'runtime'\n    },\n    minimizer:[ \n      new OptimizeCSSAssetsPlugin({\n        cssProcessorOptions: config.build.productionSourceMap\n          ? { safe: true, map: { inline: false } }\n          : { safe: true }\n      }),\n      new UglifyJsPlugin({\n        uglifyOptions: {\n          compress: {\n            warnings: false\n          }\n        },\n        cache:true,\n        parallel: true,\n        sourceMap: config.build.productionSourceMap \n      }),\n    ]\n  },\n  plugins: [\n    new CleanWebpackPlugin(),\n    // extract css into its own file\n    new MiniCssExtractPlugin({\n      filename: utils.assetsPath('css/[name].[contenthash].css'),\n      chunkFilename: utils.assetsPath('css/[id].css')\n    }),\n   \n    // generate dist index.html with correct asset hash for caching.\n    // you can customize output by editing /index.html\n    // see https://github.com/ampedandwired/html-webpack-plugin\n    new HtmlWebpackPlugin({\n      filename: config.build.index,\n      template: 'index.html',\n      inject: true,\n      minify: {\n        removeComments: true,\n        collapseWhitespace: true,\n        removeAttributeQuotes: true\n        // more options:\n        // https://github.com/kangax/html-minifier#options-quick-reference\n      },\n      // necessary to consistently work with multiple chunks via CommonsChunkPlugin\n      chunksSortMode: 'dependency'\n    }),\n    // keep module.id stable when vendor modules does not change\n    new webpack.HashedModuleIdsPlugin(),\n\n    // copy custom static assets\n    new CopyWebpackPlugin([\n      {\n        from: path.resolve(__dirname, '../static'),\n        to: config.build.assetsSubDirectory,\n        ignore: ['.*']\n      }\n    ])\n  ]\n})\n\nif (config.build.productionGzip) {\n  const CompressionWebpackPlugin = require('compression-webpack-plugin')\n\n  webpackConfig.plugins.push(\n    new CompressionWebpackPlugin({\n      asset: '[path].gz[query]',\n      algorithm: 'gzip',\n      test: new RegExp(\n        '\\\\.(' +\n        config.build.productionGzipExtensions.join('|') +\n        ')$'\n      ),\n      threshold: 10240,\n      minRatio: 0.8\n    })\n  )\n}\n\nif (config.build.bundleAnalyzerReport) {\n  const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin\n  webpackConfig.plugins.push(new BundleAnalyzerPlugin())\n}\n\nmodule.exports = webpackConfig\n"
  },
  {
    "path": "config/dev.env.js",
    "content": "'use strict'\nconst merge = require('webpack-merge')\nconst prodEnv = require('./prod.env')\n\nmodule.exports = merge(prodEnv, {\n  NODE_ENV: '\"development\"'\n})\n"
  },
  {
    "path": "config/index.js",
    "content": "'use strict'\n// Template version: 1.3.1\n// see http://vuejs-templates.github.io/webpack for documentation.\n\nconst path = require('path')\n\nmodule.exports = {\n  dev: {\n\n    // Paths\n    assetsSubDirectory: 'static',\n    assetsPublicPath: '/',\n    proxyTable: {\n      '/api':'http://localhost:3000'\n    },\n\n    // Various Dev Server settings\n    host: 'localhost', // can be overwritten by process.env.HOST\n    port: 8000, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined\n    autoOpenBrowser: false,\n    errorOverlay: true,\n    notifyOnErrors: true,\n    poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-\n\n    //https://webpack.js.org/concepts/mode/#mode-development\n    mode:'development',\n    \n    /**\n     * Source Maps\n     */\n\n    // https://webpack.js.org/configuration/devtool/#development\n    devtool: 'cheap-module-eval-source-map',\n\n    // If you have problems debugging vue-files in devtools,\n    // set this to false - it *may* help\n    // https://vue-loader.vuejs.org/en/options.html#cachebusting\n    cacheBusting: true,\n\n    cssSourceMap: true\n  },\n\n  build: {\n    // Template for index.html\n    index: path.resolve(__dirname, '../dist/index.html'),\n\n    // Paths\n    assetsRoot: path.resolve(__dirname, '../dist'),\n    assetsSubDirectory: 'static',\n    assetsPublicPath: '/',\n\n    //https://webpack.js.org/concepts/mode/#mode-production\n    mode:'production',\n\n    /**\n     * Source Maps\n     */\n\n    productionSourceMap: true,\n    // https://webpack.js.org/configuration/devtool/#production\n    devtool: '#source-map',\n\n    // Gzip off by default as many popular static hosts such as\n    // Surge or Netlify already gzip all static assets for you.\n    // Before setting to `true`, make sure to:\n    // npm install --save-dev compression-webpack-plugin\n    productionGzip: false,\n    productionGzipExtensions: ['js', 'css'],\n\n    // Run the build command with an extra argument to\n    // View the bundle analyzer report after build finishes:\n    // `npm run build --report`\n    // Set to `true` or `false` to always turn it on or off\n    bundleAnalyzerReport: process.env.npm_config_report\n  }\n}\n"
  },
  {
    "path": "config/prod.env.js",
    "content": "'use strict'\nmodule.exports = {\n  NODE_ENV: '\"production\"'\n}\n"
  },
  {
    "path": "index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n    <link rel=\"shortcut icon\" href=\"//y.qq.com/favicon.ico?max_age=2592000\">\n    <title>仿QQ音乐 - 中国最新最全免费正版高品质音乐平台！</title>\n</head>\n<body>\n    <div id=\"app\"></div>\n</body>\n</html>"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"sword\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n    \"dev\": \"node_modules/.bin/webpack-dev-server --inline --progress --config build/webpack.dev.conf.js\",\n    \"build\": \"node build/build.js\",\n    \"clean\": \"rm -rf ./dist\"\n  },\n  \"author\": \"wuming\",\n  \"license\": \"ISC\",\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.3.4\",\n    \"@babel/plugin-proposal-class-properties\": \"^7.3.4\",\n    \"@babel/plugin-proposal-decorators\": \"^7.3.0\",\n    \"@babel/plugin-proposal-export-namespace-from\": \"^7.2.0\",\n    \"@babel/plugin-proposal-function-sent\": \"^7.2.0\",\n    \"@babel/plugin-proposal-json-strings\": \"^7.2.0\",\n    \"@babel/plugin-proposal-numeric-separator\": \"^7.2.0\",\n    \"@babel/plugin-proposal-throw-expressions\": \"^7.2.0\",\n    \"@babel/plugin-syntax-dynamic-import\": \"^7.2.0\",\n    \"@babel/plugin-syntax-import-meta\": \"^7.2.0\",\n    \"@babel/plugin-transform-async-to-generator\": \"^7.3.4\",\n    \"@babel/plugin-transform-runtime\": \"^7.3.4\",\n    \"@babel/polyfill\": \"^7.2.5\",\n    \"@babel/preset-env\": \"^7.3.4\",\n    \"@babel/preset-react\": \"^7.0.0\",\n    \"@babel/preset-stage-2\": \"^7.0.0\",\n    \"@babel/runtime\": \"^7.3.4\",\n    \"autoprefixer\": \"^7.1.2\",\n    \"babel-loader\": \"^8.0.5\",\n    \"babel-plugin-import\": \"^1.11.0\",\n    \"clean-webpack-plugin\": \"^0.1.16\",\n    \"copy-webpack-plugin\": \"^5.0.0\",\n    \"css-loader\": \"^0.28.4\",\n    \"file-loader\": \"^3.0.1\",\n    \"friendly-errors-webpack-plugin\": \"^1.7.0\",\n    \"html-webpack-plugin\": \"^3.2.0\",\n    \"image-webpack-loader\": \"^3.3.1\",\n    \"less\": \"^2.7.2\",\n    \"less-loader\": \"^4.0.5\",\n    \"mini-css-extract-plugin\": \"^0.5.0\",\n    \"node-notifier\": \"^5.4.0\",\n    \"node-sass\": \"^4.11.0\",\n    \"optimize-css-assets-webpack-plugin\": \"^5.0.1\",\n    \"ora\": \"^3.2.0\",\n    \"postcss-import\": \"^12.0.1\",\n    \"postcss-loader\": \"^3.0.0\",\n    \"postcss-pxtorem\": \"^4.0.1\",\n    \"postcss-url\": \"^8.0.0\",\n    \"react-transition-group\": \"^2.2.0\",\n    \"sass-loader\": \"^7.1.0\",\n    \"shelljs\": \"^0.8.3\",\n    \"style-loader\": \"^0.18.2\",\n    \"svg-sprite-loader\": \"^0.3.1\",\n    \"uglifyjs-webpack-plugin\": \"^2.1.2\",\n    \"url-loader\": \"^1.1.2\",\n    \"webpack\": \"^4.29.6\",\n    \"webpack-bundle-analyzer\": \"^2.13.1\",\n    \"webpack-cli\": \"^3.2.3\",\n    \"webpack-dev-server\": \"^3.2.1\",\n    \"webpack-merge\": \"^4.2.1\"\n  },\n  \"dependencies\": {\n    \"antd-mobile\": \"^2.2.9\",\n    \"axios\": \"^0.16.2\",\n    \"lodash\": \"^4.17.11\",\n    \"qs\": \"^6.6.0\",\n    \"rc-form\": \"^2.4.3\",\n    \"react\": \"^16.8.4\",\n    \"react-dom\": \"^16.8.4\",\n    \"react-loadable\": \"^5.5.0\",\n    \"react-redux\": \"^6.0.1\",\n    \"react-router\": \"^4.3.1\",\n    \"react-router-dom\": \"^4.3.1\",\n    \"redux\": \"^4.0.1\",\n    \"redux-thunk\": \"^2.3.0\"\n  },\n  \"engines\": {\n    \"node\": \">= 6.0.0\",\n    \"npm\": \">= 3.0.0\"\n  }\n}\n"
  },
  {
    "path": "src/App.js",
    "content": "import React from 'react';\nimport {Router} from 'react-router-dom';\nimport {Switch, Route ,Redirect} from 'react-router';\nimport {history,routes} from '@/router';\n\n\n\nfunction getRouterByRoutes(routes){\n  const renderedRoutesList = [];\n  const renderRoutes = (routes,parentPath)=>{\n    Array.isArray(routes)&&routes.forEach((route)=>{\n      const {path,redirect,children,layout,component} = route;\n      if(redirect){\n        renderedRoutesList.push(<Redirect key={`${parentPath}${path}`} exact from={path} to={`${parentPath}${redirect}`}/>)\n      }\n      if(component){\n        renderedRoutesList.push(\n          layout?<Route \n            key={`${parentPath}${path}`} \n            exact path={`${parentPath}${path}`}\n            render={(props)=>React.createElement(layout,props,React.createElement(component,props))} />:\n          <Route \n              key={`${parentPath}${path}`} \n              exact \n              path={`${parentPath}${path}`} \n              component={component}/>)\n      }\n      if(Array.isArray(children)&&children.length>0){\n        renderRoutes(children,path)\n      }\n    });\n  }  \n  renderRoutes(routes,'')\n  return renderedRoutesList;\n \n}\nclass App extends React.PureComponent{\n  render(){\n    return (\n      <Router history={history}>\n        <Switch>\n          {getRouterByRoutes(routes)}\n        </Switch>\n      </Router>\n    )\n  }\n}\nexport default App;"
  },
  {
    "path": "src/api/index.js",
    "content": "import {keys} from 'lodash'\nimport http from '@/utils/http'\nimport API_URL from './url';\n\nfunction mapUrlObjToFuncObj(urlObj){\n  const API = {};\n  keys(urlObj).forEach((key)=>{\n    const item = urlObj[key]; \n    API[key]=function(params){\n      return http[item.method](item.url,params,item.option);\n    }\n  });\n  return API;\n}\n\nfunction mapUrlObjToStrObj(urlObj){\n  const Url = {};\n  keys(urlObj).forEach((key)=>{\n    const item = urlObj[key];\n    Url[key]=item.url;\n  });\n  return Url;\n}\n\nexport const API = mapUrlObjToFuncObj(API_URL);\nexport const URL = mapUrlObjToStrObj(API_URL);\n   "
  },
  {
    "path": "src/api/url.js",
    "content": "\nimport Qs from 'qs'\nexport default {\n  //获取音乐播放链接\n  getMusicUrl:{\n    method:'get',\n    url:'https://api.mlwei.com/music/api/?key=523077333&cache=0&type=song'\n  },\n  //获取音乐歌词\n  getMusicLyric:{\n    method:'get',\n    url:'https://api.mlwei.com/music/api/?key=523077333&cache=0&type=lrc'\n  },\n  //查询音乐\n  queryMusic:{\n    method:'get',\n    url:'https://api.mlwei.com/music/api/?key=523077333&cache=0&type=so'\n  }\n}"
  },
  {
    "path": "src/components/Bandstand/index.js",
    "content": "import React from 'react';\nimport {bindActionCreators} from 'redux';\nimport classnames from 'classnames';\nimport Control from '@/components/Control';\nimport MusicList from '@/components/MusicList';\nimport * as actions from '@/store/actions';\nimport { connect } from 'react-redux';\nimport { Toast } from 'antd-mobile';\nimport {API} from '@/api';\nimport playImg from '@/assets/icon-music-play.png';\nimport pauseImg from '@/assets/icon-music-pause.png';\nimport playListImg from '@/assets/icon-play-list.png';\nimport \"./style.scss\";\n\n@connect(\n    (state)=>state.global,\n    (dispatch)=>bindActionCreators(actions,dispatch)\n)\nclass Bandstand extends React.Component {\n    state={\n        isMusicListShow: false,\n        isControlShow: false,\n        currentMusicUrl: '',\n        currentSeconds:0,\n        totalSeconds:0\n    }\n    //改变播放状态\n    changePlayState=()=>{\n        const {changePlayStatus,isPlay,musicList} = this.props;\n        if (musicList.length > 0) {\n            changePlayStatus(!isPlay);\n            if (!isPlay) {\n                this.qqmusicAudio.play();\n            } else {\n                this.qqmusicAudio.pause();\n            }\n        } else {\n            Toast.info('暂无可播放的音乐', 1);\n        }\n    }\n    //根据歌曲id获取音乐url\n    getMusicById(id, callback) {\n        API.getMusicUrl({\n            id\n        }).then((data)=>{\n            if (typeof callback === 'function') {\n                callback(data);\n            }\n        })\n    }\n    consoleSwitch=()=>{\n        this.setState({\n            isControlShow: !this.state.isControlShow\n        });\n    }\n    changeCurrentTime=(seconds)=>{\n        this.setState({\n            currentSeconds:seconds\n        });\n        this.qqmusicAudio.currentTime=seconds;\n    }\n    musicListSwitch=()=>{\n        const {musicList} = this.props;\n        const {isMusicListShow} = this.state;\n        if (musicList.length > 0||isMusicListShow) {\n            this.setState({\n                isMusicListShow: !isMusicListShow\n            });\n        } else {\n            Toast.info('暂无可播放的音乐', 1);\n        }\n    }\n    componentDidMount(){\n        const {musicList,currentMusic,changePlayStatus,playSpecificMusicByMid,addAndChangeMusic} = this.props;\n        this.getMusicById('000cwwze4FkFj4',(data)=>{\n            addAndChangeMusic(data,false);\n        });\n        this.qqmusicAudio.oncanplay=()=>{\n            this.qqmusicAudio&&this.setState({\n                totalSeconds:this.qqmusicAudio.duration\n            });\n        };\n        this.qqmusicAudio.ontimeupdate=()=>{\n            this.qqmusicAudio&&this.setState({\n                currentSeconds:this.qqmusicAudio.currentTime\n            });\n        };\n        this.qqmusicAudio.onended=()=>{\n            if (musicList.length ===  1) {\n                changePlayStatus(false)\n            } else  {\n                const currentIndex = musicList.findIndex((music)=>music.mid===currentMusic.mid)\n                if(currentIndex<musicList.length-1){\n                    playSpecificMusicByMid(currentIndex+1);\n                }else{\n                    playSpecificMusicByMid(0);                \n                }\n            }\n        };\n    }\n    componentDidUpdate() {\n        const {isPlay} = this.props;\n        if(isPlay){\n            this.qqmusicAudio.play();\n        }else{\n            this.qqmusicAudio.pause();                \n        }\n    }\n    render() {\n        const {currentMusic={},isPlay,musicList} = this.props;\n        const {title,author,pic,url} = currentMusic;\n        return (\n            <div className=\"qqmusic-home-footer border-top\">\n                <div className=\"left\">\n                    <img className={classnames('avatar',isPlay ? 'active' : '')} src={pic} onClick={this.consoleSwitch} />\n                </div>\n                <div className=\"center\" onClick={this.consoleSwitch}>\n                    <h4 className=\"song\">{title}</h4>\n                    <p className=\"singer\">{author}</p>\n                </div>\n                <p className={musicList.length === 0 ? 'no-music show' : 'no-music'}>QQ音乐 听我想听的歌</p>\n                <div className=\"right\">\n                    <audio ref={(audio)=>this.qqmusicAudio=audio} src={url} ></audio>\n                    <img className=\"qqmusic-play-switch\" src={isPlay ? pauseImg : playImg} onClick={this.changePlayState} />\n                    <img className=\"qqmusic-play-list\" src={playListImg} onClick={this.musicListSwitch} />\n                </div>\n                <Control changeCurrentTime={this.changeCurrentTime} currentSeconds={this.state.currentSeconds} totalSeconds={this.state.totalSeconds} isControlShow={this.state.isControlShow} changePlayState={this.changePlayState} consoleSwitch={this.consoleSwitch}></Control>\n                <MusicList isMusicListShow={this.state.isMusicListShow} musicListSwitch={this.musicListSwitch}></MusicList>\n            </div>\n        )\n    }\n}\nexport default Bandstand;"
  },
  {
    "path": "src/components/Bandstand/style.scss",
    "content": ".qqmusic-home-footer {\n    position: relative;\n    display: flex;\n    align-items: center;\n    height: 65px;\n    background: #fff;\n    .left {\n        .avatar {\n            width: 50px;\n            height: 50px;\n            border-radius: 50%;\n            margin-left: 10px;\n            &.active {\n                animation:animationRotate 10s linear infinite;\n            }\n        }\n    }\n    .center {\n        padding-left: 15px;\n        max-width: 200px;\n        .song {\n            font-size: 17px;\n            color: #000;\n            font-weight: 400;\n            overflow: hidden;\n            white-space: nowrap;\n            text-overflow: ellipsis;\n        }\n        .singer {\n            font-size: 13px;\n            color: #6F6F6F;\n            margin-top: 5px;\n        }\n    }\n    .no-music{\n        display: none;\n        position: absolute;\n        top:0;\n        left: 0;\n        right: 100px;\n        bottom: 0;\n        padding-left: 15px;\n        line-height: 65px;\n        font-size: 15px;\n        background-color: #fff;\n        color: #373737;\n        &.show{\n            display: block;\n        }\n    }\n    .right {\n        flex: 1;\n        text-align: right;\n        .qqmusic-play-switch {\n            width: 35px;\n            height: 35px;\n            margin-right: 20px;\n        }\n        .qqmusic-play-list {\n            width: 30px;\n            height: 35px;\n            margin-right: 15px;\n        }\n    }\n}\n\n//  动画\n@keyframes animationRotate {\n    from {\n        transform: rotate(0);\n    }\n    to {\n        transform: rotate(360deg);\n    }\n}"
  },
  {
    "path": "src/components/Control/index.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport {bindActionCreators} from 'redux';\nimport classnames from 'classnames';\nimport { Carousel } from 'antd-mobile';\nimport * as actions from '@/store/actions';\nimport utils from '@/utils';\nimport './style.scss';\nimport { API } from '@/api';\n@connect(\n    (state)=>state.global,\n    (dispatch)=>bindActionCreators(actions,dispatch)\n)\nclass Control extends React.Component {\n    state={\n        oldSongId:'',\n        lyricArray: [],\n        currentLyricIndex:0\n    }\n    static getDerivedStateFromProps(nextProps,prevState){\n        const {lyricArray,currentLyricIndex} = prevState;\n        const {currentSeconds} = nextProps;\n        const newLyricIndex = lyricArray.findIndex((item)=>Math.abs(item.seconds-currentSeconds)<0.2);\n        return {\n            currentLyricIndex:newLyricIndex >-1?newLyricIndex:currentLyricIndex\n        }\n    }\n    //播放上一首\n    prevMusic=()=>{\n        const {musicList,currentMusic={},playSpecificMusicByMid} = this.props;\n        const currentIndex = musicList.findIndex((music)=>music.mid===currentMusic.mid);\n        let nextMusic ;\n        if (currentIndex > 0) {\n            nextMusic = musicList[currentIndex - 1];\n        } else {\n            nextMusic = musicList[musicList.length-1];\n        }\n        playSpecificMusicByMid(nextMusic.mid);\n    }\n    //播放下一首\n    nextMusic=()=>{\n        const {musicList,currentMusic={},playSpecificMusicByMid} = this.props;\n        const currentIndex = musicList.findIndex((music)=>music.mid===currentMusic.mid);\n        let nextMusic ;\n        if (currentIndex < musicList.length - 1) {\n            nextMusic = musicList[currentIndex + 1];\n        } else {\n            nextMusic = musicList[0];\n        }\n        playSpecificMusicByMid(nextMusic.mid);\n\n    }\n    changePlayProgress=(event)=>{\n        const {totalSeconds} = this.props;\n        let left = event.changedTouches[0].clientX - this.refs.progressParent.offsetLeft - event.target.offsetWidth / 2;\n        let maxLeft = this.refs.progressParent.offsetWidth;\n        let minLeft = 0;\n        if (left < minLeft) {\n            left = minLeft;\n        }\n        if (left > maxLeft) {\n            left = maxLeft;\n        }\n        this.props.changeCurrentTime(left / maxLeft * totalSeconds);\n    }\n    componentDidUpdate(){\n        const {currentMusic={}} = this.props;\n        const {oldSongId,currentLyricIndex} =this.state;\n        const {mid} = currentMusic;\n        if(mid&&oldSongId!==mid){\n            API.getMusicLyric({\n                id:mid\n            }).then((response)=>{\n                this.setState({\n                    oldSongId:mid,\n                    lyricArray:response.split('\\n').map((item)=>{\n                        const matchTimestamp = item.match(/\\[.+\\]/)[0];\n                        return {\n                            seconds:isNaN(utils.parseStrToSeconds(matchTimestamp))?0:utils.parseStrToSeconds(matchTimestamp),\n                            text:item.split('').filter((char)=>matchTimestamp.indexOf(char)<0).join('')\n                        }\n                    }).filter((item)=>item.text.length>0)\n                });\n            });\n        }\n        this.lyricDom.scrollTop=currentLyricIndex*40;\n    }\n    render() {\n        const {lyricArray,currentLyricIndex} = this.state;\n        const {currentMusic={},isPlay,changePlayState,currentSeconds,totalSeconds,isControlShow,consoleSwitch} = this.props;\n        const {title,author,pic} = currentMusic;\n        return (\n            <div className={classnames('qqmusic-control',isControlShow ? 'show' : '')}>\n                <div className=\"qqmusic-control-content\">\n                    <div className=\"qqmusic-control-top\">\n                        <img className=\"icon-control-down\" src={require(\"@/assets/icon-control-down.png\")} onClick={consoleSwitch} />\n                        <p className=\"music-name\">{title}</p>\n                    </div>\n                    <div className={classnames('qqmusic-control-middle',isPlay ? 'active' : '')}>\n                        <Carousel autoplay={false}>\n                            {\n                                [\n                                    (\n                                        <div key=\"1\" className=\"carousel-one\">\n                                            <p className=\"music-signer\">{author}</p>\n                                            <img className=\"music-cover\" src={pic} />\n                                        </div>\n\n                                    ),\n                                    (\n                                        <div key=\"2\" className=\"carousel-two\" style={{scrollMarginTop:currentLyricIndex*40}}>\n                                            <ul ref={(dom)=>this.lyricDom=dom}  className=\"lyricList\">\n                                                {\n                                                    lyricArray.map((item, index) => {\n                                                        return (\n                                                            <li className={currentLyricIndex===index?\"lyric active\":\"lyric\"} key={index}>{item.text}</li>\n                                                        )\n                                                    })\n                                                }\n                                            </ul>\n\n                                        </div>\n                                    )\n                                ]\n                            }\n                        </Carousel>\n\n                    </div>\n                    <div className=\"qqmusic-control-bottom\">\n                        <div className=\"qqmusic-control-progress\">\n                            <span className=\"currentPlayTime\">{utils.formatSeconds(currentSeconds)}</span>\n                            <div ref=\"progressParent\" className=\"progress-wrapper\">\n                                <div className=\"progress-inner\" style={{ width: currentSeconds / totalSeconds * 200 + \"px\" }}></div>\n                                <span className=\"progress-btn\" onTouchMove={this.changePlayProgress.bind(this)} style={{ transform: `translateX(${currentSeconds / totalSeconds * 200 - 7}px)` }}></span>\n                            </div>\n                            <span className=\"totalPlayTime\">{utils.formatSeconds(totalSeconds)}</span>\n                        </div>\n                        <div className=\"qqmusic-control-btns\">\n                            <img className=\"prev\" src={require(\"@/assets/icon-music-prev.png\")} onClick={this.prevMusic} />\n                            <img className=\"status\" src={isPlay ? require(\"@/assets/icon-control-pause.png\") : require(\"@/assets/icon-control-play.png\")} onClick={changePlayState} />\n                            <img className=\"next\" src={require(\"@/assets/icon-music-next.png\")} onClick={this.nextMusic} />\n                        </div>\n                    </div>\n                </div>\n                <div className=\"qqmusic-control-bg\" style={{ backgroundImage: `url(${pic}` }}></div>\n                <div className=\"qqmusic-control-bg-mask\"></div>\n            </div>\n        )\n    }\n}\nexport default Control;"
  },
  {
    "path": "src/components/Control/style.scss",
    "content": ".qqmusic-control {\n    position: fixed;\n    top: 0;\n    left: 0;\n    width: 100%;\n    height: 100%;\n    transform: translateY(100%);\n    transition: transform 0.1s ease-out;\n    background-color: #fff;\n    &.show {\n        transform: translateY(0);\n        z-index: 1;\n        .qqmusic-control-content {\n            display: flex;\n            flex-direction: column;\n            position: absolute;\n            top: 0;\n            bottom: 0;\n            left: 0;\n            right: 0;\n            z-index: 3;\n            overflow: auto;\n            .qqmusic-control-top {\n                position: relative;\n                flex: 0 0 50px;\n                .icon-control-down {\n                    position: absolute;\n                    left: 15px;\n                    top: 10px;\n                    width: 25px;\n                }\n                .music-name {\n                    text-align: center;\n                    font-size: 20px;\n                    color: #fff;\n                    padding-top: 15px;\n                }\n            }\n            .qqmusic-control-middle {\n                text-align: center;\n                flex: 1;\n                .slider-list{\n                    min-height: 370px !important;\n                }\n                .carousel-one {\n                    .music-signer {\n                        text-align: center;\n                        font-size: 16px;\n                        color: #fff;\n                        padding-top: 15px;\n                    }\n                    .music-signer:before {\n                        content: '';\n                        display: inline-block;\n                        width: 20px;\n                        border-top: 1px solid #fff;\n                        vertical-align: 6px;\n                        margin-right: 10px;\n                    }\n                    .music-signer:after {\n                        content: '';\n                        display: inline-block;\n                        width: 20px;\n                        border-top: 1px solid #fff;\n                        vertical-align: 6px;\n                        margin-left: 10px;\n                    }\n                    .music-cover {\n                        width: 210px;\n                        height: 210px;\n                        border-radius: 50%;\n                        margin-top: 60px;\n                    }\n                }\n                .carousel-two {\n                    position: relative;\n                    height: 100%;\n                    box-sizing: border-box;\n                    padding-top: 10px;\n                    .lyricList {\n                        overflow: auto;\n                        height: 315px;\n                        box-sizing: border-box;\n                        padding-top: 130px;\n                        .lyric {\n                            color: #8a8a8a;\n                            font-size: 13px;\n                            text-align: center;\n                            line-height: 40px;\n                            &.active {\n                                color: #31c37c;\n                            }\n                        }\n                    }\n                }\n                &.active {\n                    .music-cover {\n                        animation: animationRotate 10s linear infinite;\n                    }\n                }\n            }\n            .qqmusic-control-bottom {\n                flex: 0 0 200px;\n                box-sizing: border-box;\n                padding-bottom: 20px;\n                .qqmusic-control-progress {\n                    position: relative;\n                    margin-top: 15px;\n                    text-align: center;\n                    .currentPlayTime,\n                    .totalPlayTime {\n                        position: absolute;\n                        color: #8a8a8a;\n                        font-size: 12px;\n                    }\n                    .currentPlayTime {\n                        left: 25px;\n                        top: 7px;\n                    }\n                    .totalPlayTime {\n                        right: 25px;\n                        top: 7px;\n                    }\n                    .progress-wrapper {\n                        position: relative;\n                        display: inline-block;\n                        width: 200px;\n                        height: 1px;\n                        background-color: #e6e6e6;\n                        .progress-inner {\n                            height: 1px;\n                            background-color: #31c37c;\n                        }\n                        .progress-btn {\n                            position: absolute;\n                            top: -8px;\n                            left: 0;\n                            width: 15px;\n                            height: 15px;\n                            border-radius: 50%;\n                            background-color: #31c37c;\n                        }\n                    }\n                }\n                .qqmusic-control-btns {\n                    display: flex;\n                    height: 90px;\n                    align-items: center;\n                    justify-content: center;\n                    margin-top: 25px;\n                    .status {\n                        width: 70px;\n                        height: 70px;\n                        margin: 0 15px;\n                    }\n                    .prev,\n                    .next {\n                        width: 40px;\n                        height: 40px;\n                    }\n                }\n            }\n        }\n        .qqmusic-control-bg {\n            position: absolute;\n            top: 0;\n            bottom: 0;\n            left: 0;\n            right: 0;\n            background-size: cover;\n            background-position: bottom center;\n            z-index: 1;\n            -webkit-filter: blur(15px);\n            -webkit-transform: scale(1.15);\n        }\n        .qqmusic-control-bg-mask {\n            position: absolute;\n            top: 0;\n            left: 0;\n            right: 0;\n            bottom: 0;\n            background: #000;\n            z-index: 2;\n            opacity: 0.6;\n        }\n    }\n}\n\n//  动画\n@keyframes animationRotate {\n    from {\n        transform: rotate(0);\n    }\n    to {\n        transform: rotate(360deg);\n    }\n}"
  },
  {
    "path": "src/components/Header/index.js",
    "content": "import React from 'react';\nimport { NavLink } from 'react-router-dom';\nimport { Popover, Toast } from 'antd-mobile';\nimport './style.scss';\nimport Slider from '@/components/Slider';\nimport Search from '@/components/Search';\nconst Item = Popover.Item;\nclass Header extends React.Component {\n    state = {\n        docked: false,\n        search: false,\n        popover:false\n    }\n    openChange=()=>{\n        const {docked} = this.state;\n        this.setState({\n            docked: !docked\n        });\n    }\n    searchChange=()=>{ \n        const {search} = this.state;\n        this.setState({\n            search: !search\n        });\n    }\n    popoverChange=(visible)=>{\n        this.setState({\n            popover:visible\n        });\n    }\n    popoverSelect=(options)=>{\n        if(options.key===\"1\"){\n            Toast.offline('听歌识曲功能未开放', 1);\n        }else if(options.key===\"2\"){\n            Toast.offline('扫一扫功能未开放', 1);\n        }\n        this.setState({\n            popover:false\n        });\n    }\n    render(){\n        const {popover,docked,search} = this.state;\n        const {className} = this.props;\n        return (\n            <div className={className}>\n                <div className=\"qqmusic-header\">\n                    <div className=\"top\">\n                        <i className=\"icon-left\" onClick={this.openChange}></i>\n                        <NavLink className=\"qqmusic-tab\" activeClassName=\"qqmusic-tab-active\" to=\"/myCenter\" replace>我的</NavLink>\n                        <NavLink className=\"qqmusic-tab\" activeClassName=\"qqmusic-tab-active\" to=\"/musicClub\" replace>音乐馆</NavLink>\n                        <NavLink className=\"qqmusic-tab\" activeClassName=\"qqmusic-tab-active\" to=\"/discovery\" replace>发现</NavLink>\n                        <Popover mask style={{left:0,right:0}}\n                            visible={popover}\n                            overlay={[\n                                (<Item key=\"1\" value=\"scan\"><img className=\"popover-item-img\" src={require('@/assets/icon-popover-discriminate.png')}/><font className=\"popover-item-text\">听歌识曲</font></Item>),\n                                (<Item key=\"2\" value=\"sweep\"><img className=\"popover-item-img\" src={require('@/assets/icon-popover-sweep.png')}/><font className=\"popover-item-text\">扫一扫</font></Item>),\n                            ]}\n                            onVisibleChange={this.popoverChange}\n                            onSelect={this.popoverSelect}\n                        ><i className=\"icon-right\" onClick={this.popoverChange.bind(this,true)}></i></Popover>\n                    </div>\n                    <div className=\"bottom\" onTouchStart={this.searchChange}>\n                        <div className=\"search\">\n                            <i className=\"search-icon\"></i>\n                            <span className=\"text\">搜索</span>\n                        </div>\n                    </div>\n                </div>\n                <Slider docked={docked} openChange={this.openChange}></Slider>\n                <Search search={search} searchChange={this.searchChange}></Search>\n            </div>\n        );\n    }\n}\nexport default Header;"
  },
  {
    "path": "src/components/Header/style.scss",
    "content": "// 头部\n$headerFontColor:#dbf3e8;\n$headerMainBackgroundColor:#31c37c;\n$headerSearchBackgroundColor:#2AAA73;\n@mixin flexCenter () {\n    display: flex;\n    align-items: center;\n    justify-content: center;\n}\n\n.qqmusic-header {\n    background-color: $headerMainBackgroundColor;\n    .top {\n        position: relative;\n        @include flexCenter();\n        height: 40px;\n        .qqmusic-tab {\n            font-size: 20px;\n            color: $headerFontColor;\n            padding: 0 10px;\n            font-weight: 300;\n        }\n        .qqmusic-tab-active {\n            font-weight: 700;\n        }\n        .icon-left {\n            position: absolute;\n            left: 12px;\n            top: 3px;\n            width: 28px;\n            height: 35px;\n            background: url('../../assets/icon-menu-list.png');\n            background-size: 28px 35px;\n        }\n        .icon-right {\n            position: absolute;\n            right: 12px;\n            top: 6px;\n            width: 28px;\n            height: 28px;\n            background: url('../../assets/icon-menu-add.png');\n            background-size: 28px 28px;\n        }\n    }\n    .bottom {\n        padding: 7px 10px;\n        .search {\n            @include flexCenter();            \n            height: 30px;\n            width: 100%;\n            background-color: $headerSearchBackgroundColor;\n            border-radius: 5px;\n        }\n        .text {\n            margin-left: 5px;\n            font-size: 17px;\n            font-style: normal;\n            color: $headerFontColor;\n            font-weight: 300;            \n        }\n        .search-icon {\n            display: inline-block;\n            background: url('../../assets/icon-search-default.png');\n            height: 18px;\n            width: 18px;\n            background-size: 18px 18px;\n        }\n    }\n}\n.popover-item-img{\n    width: 20px;\n    height: 20px;\n}\n.popover-item-text{\n    padding-left: 10px;\n    font-size: 17px;\n    vertical-align: 4px;\n}"
  },
  {
    "path": "src/components/Loading/index.js",
    "content": "import React from 'react';\nimport './style.scss';\n\nexport default function loading() {\n  return (\n    <div className=\"comp-loading\">\n      <div className=\"item-1\"></div>\n      <div className=\"item-2\"></div>\n      <div className=\"item-3\"></div>\n      <div className=\"item-4\"></div>\n      <div className=\"item-5\"></div>\n    </div>\n  )  \n}\n"
  },
  {
    "path": "src/components/Loading/style.scss",
    "content": "\n@import '@/scss/variable.scss';\n.comp-loading {\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  height: 100vh;\n  overflow: hidden;\n  animation-delay: 1s;\n  .item-1 {\n    width: 20px;\n    height: 20px;\n    border-radius: 50%;\n    background-color: $primary-color;\n    margin: 7px;\n    display: flex;\n    justify-content: center;\n    align-items: center;\n  }\n  @keyframes scale {\n    0% {\n      transform: scale(1);\n    }\n    50%,\n      75% {\n      transform: scale(2.5);\n    }\n    78%, 100% {\n      opacity: 0;\n    }\n  }\n  .item-1:before {\n    content: '';\n    width: 20px;\n    height: 20px;\n    border-radius: 50%;\n    background-color: $primary-color;\n    opacity: 0.7;\n    animation: scale 2s infinite cubic-bezier(0, 0, 0.49, 1.02);\n    animation-delay: 200ms;\n    transition: 0.5s all ease;\n    transform: scale(1);\n  }\n  \n  .item-2 {\n    width: 20px;\n    height: 20px;\n    border-radius: 50%;\n    background-color: $primary-color;\n    margin: 7px;\n    display: flex;\n    justify-content: center;\n    align-items: center;\n  }\n  @keyframes scale {\n    0% {\n      transform: scale(1);\n    }\n    50%,\n      75% {\n      transform: scale(2.5);\n    }\n    78%, 100% {\n      opacity: 0;\n    }\n  }\n  .item-2:before {\n    content: '';\n    width: 20px;\n    height: 20px;\n    border-radius: 50%;\n    background-color: $primary-color;\n    opacity: 0.7;\n    animation: scale 2s infinite cubic-bezier(0, 0, 0.49, 1.02);\n    animation-delay: 400ms;\n    transition: 0.5s all ease;\n    transform: scale(1);\n  }\n  \n  .item-3 {\n    width: 20px;\n    height: 20px;\n    border-radius: 50%;\n    background-color: $primary-color;\n    margin: 7px;\n    display: flex;\n    justify-content: center;\n    align-items: center;\n  }\n  @keyframes scale {\n    0% {\n      transform: scale(1);\n    }\n    50%,\n      75% {\n      transform: scale(2.5);\n    }\n    78%, 100% {\n      opacity: 0;\n    }\n  }\n  .item-3:before {\n    content: '';\n    width: 20px;\n    height: 20px;\n    border-radius: 50%;\n    background-color: $primary-color;\n    opacity: 0.7;\n    animation: scale 2s infinite cubic-bezier(0, 0, 0.49, 1.02);\n    animation-delay: 600ms;\n    transition: 0.5s all ease;\n    transform: scale(1);\n  }\n  \n  .item-4 {\n    width: 20px;\n    height: 20px;\n    border-radius: 50%;\n    background-color: $primary-color;\n    margin: 7px;\n    display: flex;\n    justify-content: center;\n    align-items: center;\n  }\n  @keyframes scale {\n    0% {\n      transform: scale(1);\n    }\n    50%,\n      75% {\n      transform: scale(2.5);\n    }\n    78%, 100% {\n      opacity: 0;\n    }\n  }\n  .item-4:before {\n    content: '';\n    width: 20px;\n    height: 20px;\n    border-radius: 50%;\n    background-color: $primary-color;\n    opacity: 0.7;\n    animation: scale 2s infinite cubic-bezier(0, 0, 0.49, 1.02);\n    animation-delay: 800ms;\n    transition: 0.5s all ease;\n    transform: scale(1);\n  }\n  \n  .item-5 {\n    width: 20px;\n    height: 20px;\n    border-radius: 50%;\n    background-color: $primary-color;\n    margin: 7px;\n    display: flex;\n    justify-content: center;\n    align-items: center;\n  }\n  @keyframes scale {\n    0% {\n      transform: scale(1);\n    }\n    50%,\n      75% {\n      transform: scale(2.5);\n    }\n    78%, 100% {\n      opacity: 0;\n    }\n  }\n  .item-5:before {\n    content: '';\n    width: 20px;\n    height: 20px;\n    border-radius: 50%;\n    background-color: $primary-color;\n    opacity: 0.7;\n    animation: scale 2s infinite cubic-bezier(0, 0, 0.49, 1.02);\n    animation-delay: 1000ms;\n    transition: 0.5s all ease;\n    transform: scale(1);\n  }\n}"
  },
  {
    "path": "src/components/MusicList/index.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport {bindActionCreators} from 'redux';\nimport classnames from 'classnames';\nimport * as actions from '@/store/actions';\nimport './style.scss';\n\n@connect(\n    (state)=>state.global,\n    (dispatch)=>bindActionCreators(actions,dispatch)\n)\nclass MusicList extends React.Component{\n    playSpecificMusic(music){\n        const {mid} = music;\n        const {playSpecificMusicByMid} = this.props\n        playSpecificMusicByMid(mid);                         \n    }\n    clearMusicList=()=>{\n        const {clearMusicList} = this.props;\n        clearMusicList();\n    }\n    removeMusicFromList(music){\n        const {mid} = music;\n        const {removeMusicFromList} = this.props\n        removeMusicFromList(mid);                                \n    }\n    componentWillReceiveProps(nextProps) {\n        if(nextProps.musicList.length===0){\n             this.props.musicListSwitch();                                          \n        }            \n    }        \n    render(){\n        const {currentMusic,mid,musicList,isMusicListShow,musicListSwitch} = this.props;\n        return (\n            <div className={classnames('qqmusic-music-list-wrapper',isMusicListShow?'show':'')}>\n                <div className=\"qqmusic-music-list-content\">\n                   <div className=\"top border-bottom\">\n                       <h4 className=\"title\">播放列表</h4>\n                       <img className=\"clear-list\" src={require(\"@/assets/icon-list-clear.png\")} onClick={this.clearMusicList}/>\n                   </div>\n                   <div className=\"middle\">\n                       <ul className=\"music-list\">\n                           {\n                             musicList.map((item)=>{\n                                return (\n                                    <li className=\"music-item border-bottom\" style={{color:item.mid===currentMusic.mid?\"#31c37c\":\"#fff\"}} key={item.mid}>\n                                        <span onClick={this.playSpecificMusic.bind(this,item)}>{item.title} - {item.author}</span>\n                                        <img className=\"tag\" style={{display:item.mid===mid?'inline-block':'none'}} src={require('@/assets/icon-music-playing.png')}/>\n                                        <img className=\"delete\" src={require(\"@/assets/icon-record-close.png\")} onClick={this.removeMusicFromList.bind(this,item)}/>\n                                    </li>\n                                );\n                             })\n                           }\n                       </ul>\n                   </div>\n                   <div className=\"bottom\" onClick={musicListSwitch}>关闭</div>\n                </div>\n                <div className=\"qqmusic-music-list-bg\" onClick={musicListSwitch}></div>\n            </div>\n        )\n    }\n}\nexport default MusicList;"
  },
  {
    "path": "src/components/MusicList/style.scss",
    "content": ".qqmusic-music-list-wrapper{\n    .qqmusic-music-list-bg{\n        position: fixed;\n        top:0;\n        right:0;\n        bottom: 0;\n        left:0;\n        background: rgba( 0,0,0,0.4);\n        opacity: 0;\n        z-index: -1;\n        transition: opacity 0.14s linear;\n    }\n    .qqmusic-music-list-content{\n        display: flex;\n        flex-direction: column;\n        position: fixed;\n        left:0;\n        bottom:0;\n        width: 100%;\n        height: 60%;\n        z-index: 2;              \n        background-color:rgba(31,37,47,0.9);\n        transform: translateY(100%);\n        transition:  transform 0.14s linear;  \n        .top{\n            position: relative;\n            flex:0 0 50px;\n            .title{\n                font-size: 17px;\n                color: #fff;\n                font-weight: 300;\n                line-height: 50px;\n                padding-left: 15px;\n            }\n            .clear-list{\n                position: absolute;\n                top: 15px;\n                right: 25px;\n                width: 20px;\n            }\n        }\n        .middle{\n            flex: 1;\n            overflow: auto;\n            .music-list{\n                .music-item{\n                    position: relative;\n                    height: 40px;\n                    line-height: 40px;\n                    padding: 0 15px;\n                    font-size: 15px;\n                    .tag{\n                        margin-left: 30px;\n                        height: 15px;\n                    }\n                    .delete{\n                        position: absolute;\n                        height: 15px;\n                        right: 15px;\n                        top: 14px;\n                    }\n                }\n            }\n        }\n        .bottom{\n            color: #fff;\n            font-size: 16px;\n            text-align: center;\n            flex:0 0 50px;\n            line-height: 50px;\n        }   \n    }\n    &.show{\n        position: fixed;\n        top:0;\n        right: 0;\n        bottom: 0;\n        left:0;\n        z-index: 3;\n        .qqmusic-music-list-bg{\n            opacity: 1;\n            z-index: 1;\n        }\n        .qqmusic-music-list-content{\n            transform: translateY(0);  \n        }\n    }\n}"
  },
  {
    "path": "src/components/NewSongMenu/index.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport {bindActionCreators} from 'redux';\nimport classnames from 'classnames';\nimport * as actions from '@/store/actions';\nimport {NoticeBar,Toast} from 'antd-mobile';\nimport './style.scss';\n@connect(\n    (state)=>state.global,\n    (dispatch)=>bindActionCreators(actions,dispatch)\n)\nclass NewSongMenu extends React.Component{\n    state={\n        totalCount:0,\n        isErrorShow:false\n    }\n    comeback=()=>{\n        this.setState({\n            totalCount:0\n        });\n        this.inputText.value=\"\";\n        this.props.newSongMenuShowSwitch();\n    }\n    changeStrLength=()=>{\n        if(this.inputText.value.length<=20){\n            this.setState({\n                totalCount:this.inputText.value.length\n            });\n        }else{\n            this.inputText.value=this.inputText.value.substring(0,20);\n            this.setState({\n                isErrorShow:true\n            });\n            setTimeout(()=>{\n                this.setState({\n                isErrorShow:false\n            });\n            },1200);\n        }\n    }\n    saveSongMenu=()=>{\n        const {addSongMenu,songMenuArray} = this.props;\n        const isCanAdd=!songMenuArray.some((item)=>{\n            return item===this.inputText.value\n        });\n        if(isCanAdd){\n            addSongMenu(this.inputText.value)\n            this.comeback();\n        }else{\n            Toast.fail('该歌单已存在', 1);\n        }\n    }\n    render(){\n        const {isNewSongMenuShow} = this.props;\n        const {totalCount,isErrorShow} = this.state;\n        return(\n            <div className={classnames('qqmusic-new-songmenu',isNewSongMenuShow?'show':'')}>\n                <div className=\"new-songmenu-header\">\n                    <img className=\"icon-arrow-left\" src={require(\"@/assets/icon-arrow-left.png\")} onClick={this.comeback} />\n                    <p className=\"title\">新建歌单</p>\n                    <span className=\"save\" onClick={this.saveSongMenu}>保存</span>\n                </div>\n                <div className=\"new-songmenu-body\">\n                    <input ref={(input)=>this.inputText=input} className=\"input-text\" type=\"text\" placeholder=\"请输入内容\" onInput={this.changeStrLength}/>\n                    <p className=\"total-count\">{20-totalCount}</p>\n                    <NoticeBar className={isErrorShow?'error-notice show':'error-notice'} mode=\"closable\" icon={null}>！最多输入20个字</NoticeBar>\n                </div>                \n            </div>\n        );\n    }\n}\nexport default NewSongMenu;"
  },
  {
    "path": "src/components/NewSongMenu/style.scss",
    "content": ".qqmusic-new-songmenu{\n    position: fixed;\n    top:0;\n    left: 0;\n    width: 100%;\n    height: 100%;\n    transform: translateY(100%);\n    transition: transform 0.1s linear;\n    background-color: #f5f5f9;\n    z-index: 2;\n    &.show{\n        transform: translateY(0);\n    }\n    .new-songmenu-header{\n        background: #31c37c;\n        height: 40px;\n        position: relative;\n        .icon-arrow-left{\n            position: absolute;\n            left: 15px;\n            top: 10px;\n            height: 20px;\n        }    \n        .title{\n            color: #fff;\n        }\n        .save{\n            position: absolute;\n            right: 15px;\n            top:0;\n            color: #fff;            \n        }\n    }\n    .new-songmenu-body{\n        .input-text{\n            width: 100%;\n            height: 30px;\n            padding-left: 10px;\n            font-size: 14px;\n            background-color: #fff;\n            vertical-align: top;  \n            color: #31c37c;\n            text-shadow: -1px 0px 0px #373737;\n            -webkit-text-fill-color: transparent;          \n        }\n        .total-count{\n            text-align: right;\n            padding-right: 10px;\n            font-size: 14px;\n            line-height: 16px;\n            color: #00a1d6;\n        }\n        .error-notice{\n            position: fixed;\n            left: 0;\n            top:0;\n            width: 100%;\n            background-color: #d81e06;\n            color: #eee;\n            text-align: left;\n            display: none;\n            &.show{\n                display: block;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/components/Search/index.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport {bindActionCreators} from 'redux';\nimport classnames from 'classnames';\nimport { Toast } from 'antd-mobile';\nimport * as actions from '@/store/actions';\nimport { API } from '@/api';\n\n\n\nimport './style.scss';\n@connect(\n    (state)=>state.global,\n    (dispatch)=>bindActionCreators(actions,dispatch)\n)\nclass Search extends React.Component {\n    state = {\n        recordList: [],\n        songList: [],\n        pageNo: 1,\n        totalCount: 0,\n        isCanGet: true,\n        isSearch: true,\n        isRemindDivShow:true\n    }\n    comeback=()=>{\n        document.getElementsByClassName('input-text')[0].value = '';\n        this.setState({\n            songList: [],\n            pageNo: 1,\n            totalCount: 0,\n            isRemindDivShow:true\n        });\n        this.props.searchChange.bind(this)();\n    }\n    //监听键盘事件\n    keyboardListener=(event)=>{\n        if (event.keyCode === 13) {\n            this.setState({\n                isRemindDivShow:false\n            });\n            this.addSearchRecord(document.getElementsByClassName('input-text')[0].value);\n            this.getSearhListAjax();\n        }\n    }\n    //搜索数据\n    getSearhListAjax=(event)=>{\n        const {isSearch,pageNo,isCanGet,songList} = this.state;\n        this.setState({\n            isRemindDivShow:false\n        });\n        this.addSearchRecord(document.getElementsByClassName('input-text')[0].value);\n        let searchText = document.getElementsByClassName('input-text')[0].value;\n        let offset = pageNo * 20;\n        if (isCanGet) {\n            this.setState({\n                isCanGet: false,\n            });\n            if (isSearch) {\n                this.setState({\n                    songList: []\n                });\n            }\n            API.queryMusic({\n                nu:offset,\n                id:searchText\n            }).then((response)=>{\n                const {Code,Body,songnum} = response;\n                if(Code==='OK'){\n                    this.setState({\n                        isCanGet: true,\n                        totalCount: songnum,\n                        songList: isSearch ? Body : songList.concat(Body),\n                        isSearch: true\n                    }); \n                }else{\n                    Toast.fail('查询失败');\n                }\n               \n            })\n        }\n    }\n    //下拉加载\n    getMoreSearchList=(event)=>{\n        const {totalCount,songList,isCanGet,pageNo} = this.state;\n        const scrollHeight = event.target.scrollHeight;\n        const scrollTop = event.target.scrollTop;\n        const clientHeight = event.target.clientHeight;\n        if (scrollHeight - scrollTop - clientHeight < 10) {\n            if (totalCount > songList.length) {\n                if (isCanGet) {\n                    this.setState({\n                        pageNo: pageNo + 1,\n                        isSearch: false\n                    }, function () {\n                        this.getSearhListAjax();\n                    });\n                }\n            }\n        }\n    }\n    clearInput=()=>{\n        document.getElementsByClassName('input-text')[0].value = '';\n        this.setState({\n            songList: [],\n            pageNo: 1,\n            totalCount: 0,\n            isRemindDivShow:true\n        });\n    }\n    //快捷搜索\n    fastSearch(searchText){\n        document.getElementsByClassName('input-text')[0].value = searchText;\n        this.setState({\n            isRemindDivShow:false\n        });\n        this.addSearchRecord(searchText);\n        this.getSearhListAjax();\n    }\n    //添加搜索记录\n    addSearchRecord(recordStr) {\n        const {recordList} = this.state;       \n        const isCanAdd = !recordList.some((item) => {\n            return item === recordStr;\n        });\n        if (isCanAdd&&recordStr!=='') { \n            recordList.unshift(recordStr);\n        }\n        this.setState({\n            recordList:[].concat(recordList)\n        });\n        localStorage[\"yqq_search_history\"] = recordList.join(\",\");\n    }\n    //移除记录\n    removeRecord(record) {\n        const {recordList} = this.state;\n        const newRecordList = recordList.filter((item) => {\n            return record !== item;\n        });\n        this.setState({\n            recordList:newRecordList\n        });\n        localStorage[\"yqq_search_history\"] = newRecordListv.join(\",\");        \n    }\n    //清楚历史记录\n    clearRecord=()=>{\n        localStorage[\"yqq_search_history\"]=\"\";\n        this.setState({\n            recordList:[]\n        });\n    }\n    //往播放列表中添加音乐\n    addMusic(musicItem) {\n        const {addAndChangeMusic} = this.props;\n        addAndChangeMusic(musicItem,true);\n        this.comeback();\n    }\n    componentDidMount() {\n        if (localStorage[\"yqq_search_history\"]) {\n            this.setState({\n                recordList: localStorage[\"yqq_search_history\"].split(\",\")\n            });\n        }\n\n    }\n    render() {\n        const {songList,isCanGet,recordList,isRemindDivShow} = this.state;\n        const {search} = this.props;\n        const searchTextList=[\"邓紫棋\",\"全孝盛\",\"张靓颖\",\"周杰伦\",\"薛之谦\",\"林俊杰\"]\n        return (\n            <div className={classnames('qqmusic-search-wrapper',search ? 'show' :'')} >\n                <div className=\"qqmusic-search-top\">\n                    <img ref='inputText' className=\"icon-arrow-left\" src={require(\"@/assets/icon-arrow-left.png\")} onClick={this.comeback} />\n                    <input className=\"input-text\" type=\"text\" placeholder=\"支持音乐搜索\" onKeyUp={this.keyboardListener} />\n                    <span className=\"icon-input-clear\" onClick={this.clearInput}></span>\n                    <span className=\"btn-search\" onClick={this.getSearhListAjax}>搜索</span>\n                </div>\n                <div className=\"qqmusic-search-bottom\" onScroll={this.getMoreSearchList}>\n                    <div className=\"remind-mask\" style={{display:isRemindDivShow?'block':'none'}}>\n                        <div className=\"search-text-list-wrapper\">\n                            <h4 className=\"title-hot-search\">热门搜索</h4>\n                            <ul className=\"search-text-list\">\n                                {\n                                    searchTextList.map((item,index)=>{\n                                        return (\n                                            <li className=\"search-text-item\" onClick={this.fastSearch.bind(this,item)} key={index}>{item}</li>                                            \n                                        );\n                                    })\n                                }\n                            </ul>\n                        </div>\n                        <h4 style={{display:recordList.length>0?'block':'none'}} className=\"title-search-history border-bottom\">搜索历史<span className=\"cleanRecord\" onClick={this.clearRecord}>清空历史</span></h4>\n                        <ul className=\"record-list\">\n                            {\n                                recordList.map((item,index) => {\n                                    return (\n                                        <li className=\"record-item border-bottom\" key={index}>\n                                            <span className=\"icon-recent\"></span>\n                                            <p onClick={this.fastSearch.bind(this,item)}>{item}</p>\n                                            <span className=\"icon-close\" onClick={this.removeRecord.bind(this, item)}></span>\n                                        </li>\n                                    )\n                                })\n                            }\n                        </ul>\n                    </div>\n                    <ul className=\"qqmusic-search-list\">\n                        {\n                            songList.map((item, index) => {\n                                return (\n                                    <li className=\"qqmusic-search-list-item border-bottom\" key={index} onClick={this.addMusic.bind(this, item)}>\n                                        <div className=\"left\">\n                                            <h4 className=\"title\">{item.title}</h4>\n                                            <p className=\"singer\">{item.author}</p>\n                                            <p className=\"intro\">{item.album}</p>\n                                        </div>\n                                        <div className=\"right\">\n                                            <img className=\"cover\" alt={item.album} src={item.pic}/>\n                                        </div>\n                                    </li>\n                                )\n                            })\n                        }\n                        <li className=\"hint\" style={isCanGet ? { display: 'none' } : {}}>正在加载更多...</li>\n                    </ul>\n                </div>\n            </div>\n        )\n    }\n}\nexport default Search;"
  },
  {
    "path": "src/components/Search/style.scss",
    "content": ".qqmusic-search-wrapper {\n    position: relative;\n    display: flex;\n    flex-direction: column;\n    position: fixed;\n    top: 0;\n    left: 0;\n    right: 0;\n    bottom: 0;\n    z-index: 1;\n    background: #f5f5f9;\n    transform: translateY(100%);\n    transition: transform 0.2s ease-out;\n    &.show {\n        transform: translateY(0);\n    }\n    .qqmusic-search-top {\n        position: relative;\n        background: #31c37c;\n        \n        box-sizing: border-box;\n        padding: 10px 80px 10px 40px;\n        .icon-arrow-left {\n            position: absolute;\n            top: 10px;\n            left: 10px;\n            width: 20px;\n            height: 20px;\n        }\n        .input-text {\n            width: 100%;\n            background: #31c37c;\n            color: #dbf3e8;\n            font-size: 15px;\n        }\n        .input-text::placeholder {\n            color: #dbf3e8;\n            opacity: 0.6;\n        }\n        .icon-input-clear {\n            position: absolute;\n            right: 50px;\n            top: 7px;\n            background: url(\"../../assets/icon-input-clear.png\");\n            background-size: cover;\n            width: 25px;\n            height: 25px;\n        }\n        .btn-search {\n            position: absolute;\n            display: inline-block;\n            right: 10px;\n            top: 10px;\n            color: #dbf3e8;\n        }\n    }\n    .qqmusic-search-bottom {\n        flex: 1;\n        overflow: scroll;\n        .qqmusic-search-list {\n            background: #fff;\n            .qqmusic-search-list-item {\n                display: flex;\n                padding: 5px 15px;\n                .left{\n                    flex: 1;\n                    .title {\n                        font-size: 15px;\n                        font-weight: 500;\n                    }\n                    .singer {\n                        font-size: 13px;\n                        padding: 5px 0;\n                        color: #707070;\n                    }\n                    .intro {\n                        font-size: 11px;\n                        line-height: 14px;\n                        color: #bfbfbf;\n                    }\n                }\n                .right{\n                    width: 60px;\n                    .cover{\n                        width: 100%;\n                        \n                    }\n                }\n               \n            }\n            .hint {\n                text-align: center;\n                line-height: 31px;\n                font-size: 15px;\n                background-color: #f5f5f9;\n            }\n        }\n    }\n    .remind-mask {\n        position: absolute;\n        top:40px;\n        right:0;\n        bottom: 0;\n        left: 0;\n        .search-text-list-wrapper{\n            padding: 15px;\n            background: #fff;\n            .title-hot-search{\n                color: #8a8a8a;\n                padding: 15px 0;\n                font-weight: 400;\n                font-size: 15px;\n            }\n            .search-text-list{\n                .search-text-item{\n                    display: inline-block;\n                    border-radius: 40px;\n                    border: 1px solid #515151;\n                    color: #373737;\n                    height: 30px;\n                    line-height: 30px;\n                    padding: 0 10px;\n                    margin: 5px;\n                }\n            }\n        }\n        .title-search-history{\n            position: relative;\n            color: #8a8a8a;\n            padding: 15px 0 15px 15px;\n            font-weight: 400;\n            font-size: 15px;\n            background-color: #fff;\n            .clean-record{\n                position: absolute;\n                right: 15px;\n                top: 15px;\n                color: #31c37c;\n            }\n        }\n        .record-list {\n            .record-item {\n                position: relative;\n                background: #fff;\n                height: 45px;\n                line-height: 45px;\n                padding-left: 60px;\n                .icon-recent {\n                    position: absolute;\n                    left: 15px;\n                    top: 7px;\n                    background: url(\"../../assets/icon-record-recent.png\") no-repeat;\n                    background-size: cover;\n                    width: 26px;\n                    height: 26px;\n                }\n                .icon-close {\n                    position: absolute;\n                    right: 15px;\n                    top: 12px;\n                    background: url(\"../../assets/icon-record-close.png\") no-repeat;\n                    background-size: cover;\n                    width: 21px;\n                    height: 21px;\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/components/Slider/index.js",
    "content": "import React from 'react';\nimport classnames from 'classnames';\nimport {Switch } from 'antd-mobile';\nimport { createForm } from 'rc-form';\nimport './style.scss';\nclass Slider extends React.Component {\n    state={\n        wifi:false,\n        timingClose:true\n    }\n    switchChange(type,checked){\n        console.log(type+\":\"+checked);\n    }\n    render() {\n        const {docked} = this.props;\n        let SwitchExample = (props) => {\n            const { getFieldProps } = props.form;\n            return (\n                <Switch className='qqmusic-slider-body-item-extra' platform='ios' type={props.type}\n                {...getFieldProps('Switch',{\n                  initialValue: false,\n                  valuePropName: 'checked',\n                })}    \n                onClick={(checked) => { this.switchChange(props.type,checked); }}          \n              />\n            )\n        };\n        SwitchExample = createForm()(SwitchExample);\n        const headerSliderList = [\n            {\n                imgSrc: require('@/assets/icon-slider-message.png'),\n                title: '升级为VIP',\n                text: '畅享音乐特权'\n            },\n            {\n                imgSrc: require('@/assets/icon-slider-skin.png'),\n                title: '个性化中心',\n                text: '默认主题'\n            },\n            {\n                imgSrc: require('@/assets/icon-slider-vip.png'),\n                title: '消息中心',\n                text: ''\n            }\n        ];\n        const bodySliderList = [\n            {\n                text:'仅Wi-Fi联网',\n                extra:<SwitchExample type={'仅Wi-Fi联网'}/>\n            },\n            {\n                text:'定时关闭',\n                extra:<SwitchExample type={'定时关闭'}/>\n            },\n            {\n                text:'免流量服务',\n                extra:null\n            },\n            {\n                text:'微云音乐网盘',\n                extra:null                \n            },\n            {\n                text:'传歌到手机',\n                extra:null                \n            },\n            {\n                text:'QPlay与车载音乐',\n                extra:null                \n            },\n            {\n                text:'清理占用空间',\n                extra:null                \n            },\n            {\n                text:'免费WIFI',\n                extra:null                \n            },\n            {\n                text:'帮助与反馈',\n                extra:null                \n            },\n            {\n                text:'关于QQ音乐',\n                extra:null                \n            }\n        ];\n        return (\n            <div>\n                <div className={classnames('qqmusic-slider',docked ? 'open' : '')}>\n                    <div className=\"qqmusic-slider-header border-bottom\">\n                        {\n                            headerSliderList.map(function (item, index) {\n                                return (\n                                    <div className=\"qqmusic-slider-header-Item\" key={index}>\n                                        <img className=\"qqmusic-slider-header-Item-img\" src={item.imgSrc} />\n                                        <h4 className=\"qqmusic-slider-header-Item-title\">{item.title}</h4>\n                                        <p className=\"qqmusic-slider-header-Item-text\">{item.text}</p>\n                                    </div>\n                                )\n                            })\n                        }\n                    </div>\n                    <ul className=\"qqmusic-slider-body\">\n                        {\n                            bodySliderList.map(function (item, index) {\n                                return (\n                                    <li className='qqmusic-slider-body-item' key={index}>\n                                        <font className='qqmusic-slider-body-item-text'>{item.text}</font>{item.extra}\n                                    </li>\n                                )\n                            })\n                        }\n                    </ul>\n                    <div className=\"qqmusic-slider-footer border-top\">\n                        <div className=\"qqmusic-slider-footer-left\">\n                            <i className=\"qqmusic-slider-footer-icon\"></i>\n                            <span className=\"qqmusic-slider-footer-text\">设置</span>\n                        </div>\n                        <div className=\"qqmusic-slider-footer-right\">\n                            <i className=\"qqmusic-slider-footer-icon\"></i>\n                            <span className=\"qqmusic-slider-footer-text\">退出登录/关闭</span>\n                        </div>\n                    </div>\n                </div>\n                <div className={classnames('qqmusic-slider-bg',docked ? 'open' : '')} onTouchStart={this.props.openChange}></div>\n            </div>\n        )\n    }\n}\n\nexport default Slider;\n"
  },
  {
    "path": "src/components/Slider/style.scss",
    "content": "// 菜单浮层\n.qqmusic-slider-bg {\n    position: fixed;\n    left: 0;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    background-color: rgba(0, 0, 0, 0.7);\n    z-index: 2016;\n    display: none;\n    &.open {\n        display: block;\n    }\n}\n\n.qqmusic-slider {\n    display: flex;\n    flex-direction: column;\n    position: fixed;\n    left: 0;\n    top: 0;\n    bottom: 0;\n    width: 80%;\n    box-sizing: border-box;\n    padding: 0 15px;\n    background-color: #fff;\n    transform: translateX(-100%);\n    transition: transform 0.3s ease-out;\n    z-index: 2017;\n    &.open {\n        transform: translateX(0);\n    }\n    .qqmusic-slider-header {\n        display: flex;\n        flex: 0 0 125px;\n        padding-bottom: 20px;\n        .qqmusic-slider-header-Item {\n            flex: 1;\n            text-align: center;\n            .qqmusic-slider-header-Item-img {\n                width: 35px;\n                height: 35px;\n                margin: 20px 0;\n            }\n            .qqmusic-slider-header-Item-title {\n                font-size: 14px;\n                font-weight: 400;\n            }\n            .qqmusic-slider-header-Item-text {\n                font-size: 11px;\n                font-weight: 300;\n                margin: 5px 0;\n                color: #c7c7c7;\n            }\n        }\n    }\n    .qqmusic-slider-body {\n        flex: 1;\n        -webkit-overflow-scrolling: touch;\n        overflow: auto;\n        .qqmusic-slider-body-item{\n            position: relative;\n            height: 45px;\n            .qqmusic-slider-body-item-text{\n                display: block;\n                font-size: 14px;\n                line-height: 45px;\n            }\n            .qqmusic-slider-body-item-extra{\n                position: absolute;\n                right: 10px;\n                top:5px;\n            }\n        } \n    }\n    .qqmusic-slider-footer {\n        display: flex;\n        flex: 0 0 50px;\n        .qqmusic-slider-footer-left,.qqmusic-slider-footer-right{\n            flex: 1;\n            display: flex;\n            align-items: center;\n        }\n        .qqmusic-slider-footer-left{\n             .qqmusic-slider-footer-icon  {\n                display: inline-block;\n                width: 20px;\n                height: 20px;\n                background: url('../../assets/icon-slider-setting.png');\n                background-size: 20px, 20px;            \n             }       \n        }\n        .qqmusic-slider-footer-right{\n            justify-content: flex-end;                                                            \n            .qqmusic-slider-footer-icon  {\n                display: inline-block;\n                width: 15px;\n                height: 15px;\n                background: url('../../assets/icon-slider-exit.png');\n                background-size: 15px, 15px;            \n             }        \n        }\n\n        .qqmusic-slider-footer-text {\n            margin-left:5px;\n            font-size: 14px;\n            line-height: 25px;\n        }\n    }\n}\n"
  },
  {
    "path": "src/components/SongMenu/index.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport {bindActionCreators} from 'redux';\nimport classnames from 'classnames';\nimport addImg from '@/assets/icon-songmenu-add.png';\nimport NewSongMenu from '@/components/NewSongMenu';\nimport SongMenuMangement from  '@/components/SongMenuMangement';\nimport * as actions from '@/store/actions';\nimport './style.scss';\n@connect(\n    (state)=>state.global,\n    (dispatch)=>bindActionCreators(actions,dispatch)\n)\nclass SongMenu extends React.Component {\n    state={\n        isNewSongMenuShow:false,\n        isSongMenuMangementShow:false,\n        activeTab:1\n    }\n    newSongMenuShowSwitch=()=>{\n        const {isNewSongMenuShow} = this.state;\n        this.setState({\n            isNewSongMenuShow:!isNewSongMenuShow\n        });\n    }\n    songMenuMangementShowSwitch=()=>{\n        const {isSongMenuMangementShow} = this.state;\n        this.setState({\n            isSongMenuMangementShow:!isSongMenuMangementShow\n        });\n    }\n    tabChange(tabIndex){\n        this.setState({\n            activeTab:tabIndex\n        });\n    }   \n    render() {\n        const {activeTab,isNewSongMenuShow,isSongMenuMangementShow} = this.state;\n        const {songMenuArray} = this.props;\n        return (\n            <div className=\"qqmusic-mycenter-bottom\">\n                <div className=\"qqmusic-mycenter-tabs\">\n                    <span className={classnames('qqmusic-mycenter-tab',activeTab===1?'active':'')} onClick={this.tabChange.bind(this,1)} >自建歌单</span>\n                    |\n                    <span className={classnames('qqmusic-mycenter-tab',activeTab===2?'active':'')} onClick={this.tabChange.bind(this,2)}>收藏歌单</span>\n                    <i style={activeTab===2?{display:'none'}:{}} className=\"add-songmenu\" onClick={this.newSongMenuShowSwitch}/>\n                    <i  className=\"songmenu-manage\" onClick={this.songMenuMangementShowSwitch}></i>\n                </div>\n                <div className=\"qqmusic-mycenter-tab-content-one\" style={activeTab!==1?{display:'none'}:{}}>\n                    <ul className=\"songmenu-array\" style={songMenuArray.length>0?{display:'block'}:{display:'none'}}>\n                        {\n                            songMenuArray.map((item,index)=>{\n                                return (\n                                    <li className=\"songmenu-item\" key={index}>\n                                        <div className=\"left\">\n                                            <img className=\"logo\" src={require(\"@/assets/icon-qqmusic-logo.png\")}/>\n                                        </div>\n                                        <div className=\"right\">\n                                            <p className=\"name\">{item}</p>\n                                            <p className=\"num border-bottom\">0首</p>\n                                            <span className=\"icon-right\"></span>\n                                        </div>                                        \n                                    </li>\n                                )\n                            })\n                        }\n                    </ul>\n                    <div className=\"add-songmenu-wrapper\" style={{display:songMenuArray.length>0?'none':'flex'}} onClick={this.newSongMenuShowSwitch}>\n                        <div className=\"add-songmenu-wrapper-left\">\n                            <img className=\"add-songmenu-img\" src={addImg}/>\n                        </div>\n                        <div className=\"add-songmenu-wrapper-right\">\n                            <p className=\"add-songmenu-text border-bottom\">新建歌单</p>\n                        </div>\n                    </div>\n                </div>\n                <div className=\"qqmusic-mycenter-tab-content-two\" style={activeTab!==2?{display:'none'}:{}}>\n                    <p className=\"no-collected-songmenu\">没有收藏的歌单</p>\n                </div>\n                <NewSongMenu isNewSongMenuShow={isNewSongMenuShow} newSongMenuShowSwitch={this.newSongMenuShowSwitch} ></NewSongMenu>\n                <SongMenuMangement isSongMenuMangementShow={isSongMenuMangementShow} songMenuMangementShowSwitch={this.songMenuMangementShowSwitch}></SongMenuMangement>\n            </div>\n        );\n    }\n}\nexport default SongMenu;"
  },
  {
    "path": "src/components/SongMenu/style.scss",
    "content": ".qqmusic-mycenter-bottom {\n    text-align: center;\n    margin-top: 5px;\n    background: #fff;\n    line-height: 40px;\n    color: #8a8a8a;\n    .qqmusic-mycenter-tabs {\n        position: relative;\n        .qqmusic-mycenter-tab {\n            padding: 0 10px;\n            &.active {\n                color: #000;\n            }\n        }\n        .add-songmenu {\n            position: absolute;\n            right: 40px;\n            top: 11px;\n            display: inline-block;\n            height: 20px;\n            width: 20px;\n            background: url('../../assets/icon-songmenu-add.png');\n            background-size: 20px 20px;\n        }\n        .songmenu-manage {\n            position: absolute;\n            right: 10px;\n            top: 12px;\n            display: inline-block;\n            height: 20px;\n            width: 20px;\n            background: url('../../assets/icon-songmenu.png');\n            background-size: 20px 20px;\n            .no-collected-songMenu {\n                font-size: 15px;\n                text-align: center;\n                color: #cdcdcd;\n            }\n        }\n    }\n    .qqmusic-mycenter-tab-content-one {\n        background: #fff;\n        min-height: 90px;\n        .songmenu-array {\n            .songmenu-item {\n                display: flex;\n                height: 60px;\n                margin-top: 1px;\n                .left {\n                    flex: 0 0 60px;\n                    background: #e6e6e6;\n                    display: flex;\n                    align-items: center;\n                    justify-content: center;\n                    .logo {\n                        width: 25px;\n                        height: 25px;\n                    }\n                }\n                .right {\n                    position: relative;\n                    flex: 1;\n                    padding-left: 10px;\n                    .name,\n                    .num {\n                        font-size: 15px;\n                        line-height: 30px;\n                        text-align: left;\n                        padding-left: 15px;\n                    }\n                    .icon-right {\n                        position: absolute;\n                        top: 22px;\n                        right: 15px;\n                        background: url(\"../../assets/icon-easy-right.png\");\n                        background-size: cover;\n                        height: 17px;\n                        width: 17px;\n                    }\n                }\n            }\n        }\n        .add-songmenu-wrapper {\n            display: flex;\n            height: 60px;\n            .add-songmenu-wrapper-left {\n                flex: 0 0 60px;\n                background: #e6e6e6;\n                display: flex;\n                align-items: center;\n                justify-content: center;\n                .add-songmenu-img {\n                    width: 30px;\n                    height: 30px;\n                }\n            }\n            .add-songmenu-wrapper-right {\n                flex: 1;\n                .add-songmenu-text {\n                    line-height: 60px;\n                    text-align: left;\n                    margin-left: 10px;\n                }\n            }\n        }\n    }\n    .qqmusic-mycenter-tab-content-two {\n        background: #fff;\n        min-height: 60px;\n    }\n}"
  },
  {
    "path": "src/components/SongMenuMangement/index.js",
    "content": "import React from 'react';\nimport { connect } from 'react-redux';\nimport {bindActionCreators} from 'redux';\nimport {Checkbox} from 'antd-mobile';\nimport * as actions from '@/store/actions';\nimport './style.scss';\nconst CheckboxItem = Checkbox.CheckboxItem;\n@connect(\n    (state)=>state.global,\n    (dispatch)=>bindActionCreators(actions,dispatch)\n)\nclass SongMenuMangement extends React.Component{\n    state={\n        selectedList:[]\n    }\n    comeback=()=>{\n        this.props.songMenuMangementShowSwitch();\n    }\n    changeSelectedList(text){\n        const isCanAdd=!this.state.selectedList.some((item)=>{\n            return text===item;\n        });\n        let selectedList=this.state.selectedList;\n        if(isCanAdd){\n            selectedList.push(text);\n        }else{\n            selectedList=selectedList.filter((item)=>{\n                    return text!==item;\n                })\n        }\n        this.setState({\n                selectedList\n            });\n    }\n    removeSongMenu=()=>{\n        const {selectedList} = this.state;\n        const {removeSongMenu} = this.props;\n        removeSongMenu(selectedList);\n    }\n    render(){\n        const {songMenuArray,isSongMenuMangementShow} = this.props;\n        return (\n            <div className={isSongMenuMangementShow?\"qqmusic-songmenu-mangement show\":\"qqmusic-songmenu-mangement\"}>\n                <div className=\"songmenu-mangement-header\">\n                    <img className=\"icon-arrow-left\" src={require(\"@/assets/icon-arrow-left.png\")} onClick={this.comeback.bind(this)} />\n                    <p className=\"title\">管理自建歌单</p>\n                </div>\n                <div className=\"songmenu-mangement-body\">\n                    <ul className=\"songmenu-array\">\n                        {\n                            songMenuArray.map((item,index)=>{\n                                return (\n                                    <li className=\"songmenu-item\" key={index}>\n                                        <div className=\"left\">\n                                        <CheckboxItem className=\"checkBox\"  onChange={this.changeSelectedList.bind(this,item)}></CheckboxItem>\n                                        </div>\n                                        <div className=\"middle border-bottom\">\n                                            <img className=\"logo\" src={require(\"@/assets/icon-qqmusic-logo.png\")}/>\n                                        </div>\n                                        <div className=\"right border-bottom\">\n                                            <p className=\"name\">{item}</p>\n                                            <p className=\"num\">0首</p>\n                                        </div>                                        \n                                    </li>\n                                )\n                            })\n                        }\n                    </ul>\n                </div>\n                <div className=\"songmenu-mangement-footer\">\n                    <div className=\"delete-wrapper\">\n                        <img className=\"delete\" onClick={this.removeSongMenu} src={require(\"@/assets/icon-songmenu-delete.png\")}/>                                          \n                    </div>\n                    <p className=\"text-wrapper\">\n                        <span className=\"text\" onClick={this.removeSongMenu}>删除</span>\n                    </p>\n                </div>\n            </div>\n        )\n    }\n}\nexport default SongMenuMangement;"
  },
  {
    "path": "src/components/SongMenuMangement/style.scss",
    "content": ".qqmusic-songmenu-mangement{\n    display: flex;\n    flex-direction: column;\n    position: fixed;\n    top:0;\n    left: 0;\n    width: 100%;\n    height: 100%;\n    transform: translateX(100%);\n    transition: transform 0.1s linear;\n    background-color: #f5f5f9;\n    z-index: 2;\n    &.show{\n        transform: translateX(0);\n    }\n    .songmenu-mangement-header{\n        background: #31c37c;\n        height:0 0 40px;\n        position: relative;\n        .icon-arrow-left{\n            position: absolute;\n            left: 15px;\n            top:10px;\n            height: 20px;\n        }    \n        .title{\n            color: #fff;\n        }\n    }\n    .songmenu-mangement-body{\n        flex: 1;\n        overflow: auto;\n        .songmenu-array{\n            .songmenu-item{\n                display: flex;\n                height: 60px; \n                margin-top: 4px;  \n                background-color: #fff;\n                .left{\n                    flex: 0 0 50px;\n                    display: flex;\n                    align-items: center;\n                    justify-content: center;\n                    .checkBox{\n                        height: 100%;\n                        .am-checkbox.am-checkbox-checked .am-checkbox-inner{\n                            border: 1px solid #31c37c;\n                            background-color: #31c37c;\n                        }\n                        .am-checkbox.am-checkbox-checked .am-checkbox-inner:after{\n                            border-color: #fff;\n                        }\n                    }\n                }         \n                .middle{\n                    flex:0 0 60px;\n                    background: #e6e6e6;\n                    display: flex;\n                    align-items: center;\n                    justify-content: center;\n                    .logo{\n                        width: 25px;\n                        height:25px;\n                    }\n                } \n                .right{\n                    position: relative;\n                    flex: 1;\n                    .name,.num{\n                        padding-left: 10px;\n                        font-size: 15px;\n                        line-height: 30px;\n                        text-align: left;\n                        padding-left: 15px;\n                    }\n                }           \n            }   \n        }\n    }\n    .songmenu-mangement-footer{\n        flex: 0 0 75px;\n        background: #fff;\n        text-align: center;\n        line-height: 25px;\n        box-sizing: border-box;\n        padding-top: 10px;\n        .delete-wrapper{\n            .delete{\n                width: 25px;\n            }\n        }\n        .text-wrapper{\n            text-align: center;\n            .text{\n                font-size: 14px;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/constant/music.js",
    "content": "//播放或暂停音乐\nexport const CHANGE_MUSIC_STATUS=\"CHANGE_MUSIC_STATUS\";\n//添加音乐到播放列表\nexport const ADD_MUSIC=\"ADD_MUSIC\";\n//更改当前音乐\nexport const CHANGE_CURRENT_MUSIC=\"CHANGE_CURRENT_MUSIC\";\n//添加并更改当前音乐\nexport const ADD_AND_CHANGE_MUSIC=\"ADD_AND_CHANGE_MUSIC\";\n//根据下标播放指定歌曲\nexport const PLAY_MUSIC_BY_INDEX=\"PLAY_MUSIC_BY_INDEX\";\n//清空播放列表\nexport const CLEAR_MUSIC_LIST=\"CLEAR_MUSIC_LIST\";\n//移除指定的音乐\nexport const REMOVE_MUSIC_FROM_LIST=\"REMOVE_MUSIC_FROM_LIST\";\n//添加歌单\nexport const ADD_SONG_LIST=\"ADD_SONG_LIST\";\n//删除歌单\nexport const REMOVE_SONG_LIST=\"REMOVE_SONG_LIST\";"
  },
  {
    "path": "src/layouts/MainLayout/index.js",
    "content": "import React from 'react';\nimport Header from '@/components/Header';\nimport Bandstand from '@/components/Bandstand';\nimport './style.scss';\nclass MainLayout extends React.Component {\n    render() {\n        const {children} = this.props;\n        return (\n            <div className=\"qqmusic-home\">\n                <Header className=\"qqmusic-home-header\" />                                                             \n                    {children}\n                <Bandstand/>\n            </div>\n        );\n    }\n}\nexport default MainLayout;"
  },
  {
    "path": "src/layouts/MainLayout/style.scss",
    "content": ".qqmusic-home{\n    display: flex;\n    flex-direction: column;\n    height: 100%;\n}\n.qqmusic-home-body{\n    flex: 1;\n    overflow: scroll;\n}"
  },
  {
    "path": "src/main.js",
    "content": "/**\n * Created by wuming on 2017/7/11.\n */\n// import '@/utils/antm-viewport.min';\nimport '@/scss/reset.scss';\nimport React from 'react';\nimport { render } from 'react-dom';\nimport { Provider } from 'react-redux';\nimport App from './App';\nimport configureStore from '@/store';\nimport '@babel/polyfill';\nconst store = configureStore();\nrender(\n    <Provider store={store}>\n        <App/>\n    </Provider>,\n    document.getElementById(\"app\")\n);"
  },
  {
    "path": "src/pages/Discovery/index.js",
    "content": "import React from 'react';\nimport './style.scss';\nclass Discovery extends React.Component {\n    render() {\n        const discoveryListOne = [\n            {\n                text: '乐见大牌：GAI说唱惊喜轰炸，PGON爆理想型',\n                music: '天干物燥-GAI',\n                image: '/static/images/news-cover-one.jpeg',\n                author: '乐见大牌',\n                read: 3820\n            },\n            {\n                text: '有些男女之情，比爱情更让人羡慕',\n                music: '富士山下-陈奕迅',\n                image: '/static/images/news-cover-two.jpg',\n                author: '淘漉音乐',\n                read: 8230\n            },\n            {\n                text: '评论志|最怕回忆突然锋利，翻滚不息',\n                music: '突然好想你-五月天',\n                image: '/static/images/news-cover-three.jpg',\n                author: '大冲音像店',\n                read: 5761\n            }\n        ];\n        const discoveryListTwo = [\n            {\n                text: 'S.H.E：十年女团，十年回忆',\n                music: 'S.H.E | 十年女团，十年回忆-微音',\n                image: '/static/images/discovery-she.jpg',\n                author: '微音',\n                read: 3555\n            },\n            {\n                text: '张韶涵：好久不见，回来就好',\n                music: '复仇时刻-张韶涵/我是赞助商派来的',\n                image: '/static/images/discovery-zhangshaohan.jpeg',\n                author: '淘漉音乐',\n                read: 4223\n            },\n            {\n                text: 'LOL背景音乐集锦：电子盛宴，自带BUFF',\n                music: 'Time Leaper-Hinkik',\n                image: '/static/images/discovery-ali.jpeg',\n                author: '醉心琳琅',\n                read: 9405\n            }\n        ];\n        const topicList = [\n            {\n                image: '/static/images/topic-lizongsheng.jpeg',\n                title: '#又见·李宗盛',\n                text: '戳到了心坎的一句歌词'\n            },\n            {\n                image: '/static/images/topic-linyoujia.jpg',\n                title: '#又见·林宥嘉',\n                text: '曾在哪首歌里泪流不止？'\n            },\n            {\n                image: '/static/images/topic-chenyixun.jpeg',\n                title: '#又见·陈奕迅',\n                text: '循环播放最多次的一首歌'\n            },\n            {\n                image: '/static/images/topic-tianfuzhen.jpeg',\n                title: '#又见·田馥甄',\n                text: '因为哪首歌爱上她的？'\n            }\n        ];\n        return (\n            <div className=\"qqmusic-home-body\">\n                <ul className=\"qqmusic-discovery-list\">\n                    {\n                        discoveryListOne.map(function (item,index) {\n                            return (\n                                <li className=\"qqmusic-discovery-item\" key={index}>\n                                    <div className=\"qqmusic-discovery-item-left\">\n                                        <p className=\"text\">{item.text}</p>\n                                        <p className=\"music\"><img className=\"music-image\" src={require('@/assets/icon-music-black.png')} />{item.music}</p>\n                                        <p className=\"extra\">{item.author} 阅读 {item.read}</p>\n                                    </div>\n                                    <div className=\"qqmusic-discovery-item-right\">\n                                        <img className=\"image\" src={item.image} />\n                                    </div>\n                                </li>\n                            );\n                        })\n                    }\n                </ul>\n                <div className=\"qqmusic-discovery-carousel\">\n                    <div className=\"top\"><span className=\"tag\">发现·话题</span></div>\n                    <div className=\"bottom\">\n                        <ul className=\"list\">\n                            {\n                                topicList.map(function (item,index) {\n                                    return (\n                                        <li className=\"item\" key={index}>\n                                            <img className=\"image\" src={item.image} />\n                                            <div className=\"mask\">\n                                                <h4 className=\"title\">{item.title}</h4>\n                                                <p className=\"text\">{item.text}</p>\n                                            </div>\n                                        </li>\n                                    );\n                                })\n                            }\n                        </ul>\n                    </div>\n                </div>\n                <ul className=\"qqmusic-discovery-list\" style={{marginBottom:'0.3rem'}}>\n                    {\n                        discoveryListTwo.map(function (item,index) {\n                            return (\n                                <li className=\"qqmusic-discovery-item\" key={index}>\n                                    <div className=\"qqmusic-discovery-item-left\">\n                                        <p className=\"text\">{item.text}</p>\n                                        <p className=\"music\"><img className=\"music-image\" src={require('@/assets/icon-music-black.png')} />{item.music}</p>\n                                        <p className=\"extra\">{item.author} 阅读 {item.read}</p>\n                                    </div>\n                                    <div className=\"qqmusic-discovery-item-right\">\n                                        <img className=\"image\" src={item.image} />\n                                    </div>\n                                </li>\n                            );\n                        })\n                    }\n                </ul>\n            </div>\n        )\n    }\n}\nexport default Discovery;"
  },
  {
    "path": "src/pages/Discovery/style.scss",
    "content": ".qqmusic-discovery-item {\n    display: flex;\n    padding: 15px 0 0 15px;\n    .qqmusic-discovery-item-left {\n        flex: 1;\n        padding-right: 10px;\n        overflow: hidden;\n        .text {\n            margin-top: 15px;\n            font-size: 19px;\n        }\n        .music {\n            margin-top: 10px;\n            font-size: 13px;\n            white-space:nowrap;\n            overflow:hidden; \n            text-overflow:ellipsis;\n            .music-image {\n                width: 21px;\n                height: 21px;\n                margin-right: 5px;\n                vertical-align: -5px;\n            }\n        }\n        .extra {\n            font-size: 13px;\n            margin-top: 10px;\n            color: #6F6F6F;\n        }\n    }\n    .qqmusic-discovery-item-right {\n        flex: 0 0 110px;\n        height: 110px;\n        overflow: hidden;\n        .image {\n            width: 110px;\n        }\n    }\n}\n.qqmusic-discovery-carousel{\n    margin-top: 15px;\n    .top{\n        .tag{\n            font-size: 11px;\n            background: #000;\n            color: #fff;\n            padding: 1px 2px;\n            margin-left: 15px;\n        }\n    }\n    .bottom{\n        margin-top: 4px;\n        height: 99px;\n        overflow-y: hidden;\n        .list{\n            padding-left: 12px;\n            white-space:nowrap;\n            overflow: auto;\n            -webkit-overflow-scrolling: touch;\n            .item{\n                display: inline-block;\n                position: relative;\n                margin-left: 3px;\n                .image{\n                    width: 168px;\n                    height: 100px;\n                }\n                .mask{\n                    position: absolute;\n                    top:0;\n                    left:0;\n                    width: 168px;\n                    height: 100px;\n                    background: rgba(0,0,0,0.4);\n                    .title{\n                        margin-top: 40px;\n                        color: #fff;\n                        text-align: center;\n                        font-size: 21px;\n                    }\n                    .text{\n                        margin-top: 5px;\n                        color: #ccc;\n                        text-align: center;\n                        font-size: 14px;\n                    }\n                }\n            }\n        }\n    }\n    \n}"
  },
  {
    "path": "src/pages/MusicClub/index.js",
    "content": "import React from 'react';\nimport { Carousel, Grid } from 'antd-mobile';\nimport './style.scss';\nclass MusicClub extends React.Component {\n    render() {\n        const imgList = [\n            \"/static/images/carousel-cover-one.jpg\",\n            \"/static/images/carousel-cover-two.jpg\",\n            \"/static/images/carousel-cover-three.jpg\",\n            \"/static/images/carousel-cover-four.jpg\",\n            \"/static/images/carousel-cover-five.jpg\",\n            \"/static/images/carousel-cover-six.jpg\",\n            \"/static/images/carousel-cover-seven.jpg\",\n            \"/static/images/carousel-cover-eight.jpg\"\n        ];\n        const menuList = [\n            {\n                icon: require('@/assets/icon-grid-singer.png'),\n                text: '歌手'\n            },\n            {\n                icon: require('@/assets/icon-grid-rank.png'),\n                text: '排行'\n            },\n            {\n                icon: require('@/assets/icon-grid-radio.png'),\n                text: '电台'\n            },\n            {\n                icon: require('@/assets/icon-grid-categories.png'),\n                text: '分类歌单'\n            },\n            {\n                icon: require('@/assets/icon-grid-video.png'),\n                text: '视频MV'\n            },\n            {\n                icon: require('@/assets/icon-grid-album.png'),\n                text: '数字专辑'\n            },\n        ];\n\n        const songMenuArray = [\n            {\n                image: '/static/images/songmenu-one.jpeg',\n                text: '浮游时光 | 品一杯慢情调的韩系布鲁斯',\n                amount: '15.7万'\n            },\n            {\n                image: '/static/images/songmenu-two.jpeg',\n                text: '达人周末 | 那些能激起中二病的动漫燃曲',\n                amount: '65.7万'\n            },\n            {\n                image: '/static/images/songmenu-three.jpeg',\n                text: '99位唱见歌手 ：一人一首代表曲',\n                amount: '272.2万'\n            },\n            {\n                image: '/static/images/songmenu-four.jpeg',\n                text: '独立民谣 | 从大不列颠群岛吹来怡然清风',\n                amount: '39.5万'\n            },\n            {\n                image: '/static/images/songmenu-five.jpeg',\n                text: '《王者荣耀》风骚走位必备BGM',\n                amount: '1319.1万'\n            },\n            {\n                image: '/static/images/songmenu-six.jpeg',\n                text: '你一定听过却死活叫不上歌名的灵魂级配乐',\n                amount: '162.5万'\n            }\n        ]\n        return (\n            <div className=\"qqmusic-home-body\">\n                <Carousel\n                    className=\"slideshow-list\"\n                    infinite\n                    autoplay={true}\n                    autoplayInterval={2000}\n                >\n                    {imgList.map((item, index) => {\n                        return (\n                            <a key={index} className=\"slideshow-item-link\" href=\"javascript:;\">\n                                <img className=\"slideshow-item-img\" src={item} />\n                            </a>\n                        );\n                    })\n                    }\n                </Carousel>\n                <Grid\n                    className=\"qqmusic-grid-list\"\n                    data={menuList}\n                    columnNum={3}\n                    hasLine={false}\n                    renderItem={\n                        dataItem => (\n                            <div className=\"qqmusic-grid-item\">\n                                <img className=\"qqmusic-grid-item-icon\" src={dataItem.icon} />\n                                <span className=\"qqmusic-grid-item-text\" >{dataItem.text}</span>\n                            </div>\n                        )\n                    }\n                />\n                <div className=\"qqmusic-songMenu-recommend\">\n                    <p className=\"title\">歌单推荐<i className=\"icon-circle-right\"></i></p>\n                    <Grid\n                        className=\"qqmusic-recommend-list\"\n                        data={songMenuArray}\n                        columnNum={3}\n                        hasLine={false}\n                        renderItem={\n                            (dataItem, index) => {\n                                return (\n                                    <div className=\"qqmusic-recommend-item\" style={{marginLeft:index%3===1?'0.06rem':'',marginRight:index%3===1?'0.06rem':''}}>\n                                        <div className=\"qqmusic-recommend-item-image-wrapper\">\n                                            <img className=\"image\" src={dataItem.image} />\n                                            <span className=\"amount\">{dataItem.amount}</span>\n                                            <img className=\"link-to-musicList-detail\" src={require('@/assets/icon-music-link.png')}/>\n                                        </div>\n                                        <p className=\"text\" >{dataItem.text}</p>\n                                    </div>\n                                )\n                            }\n                        }\n                    />\n                </div>\n            </div>\n        )\n    }\n}\nexport default MusicClub"
  },
  {
    "path": "src/pages/MusicClub/style.scss",
    "content": ".qqmusic-home-body {\n    background: #fff;\n    .slideshow-list {\n        min-height: 154px;\n        .slideshow-item-link {\n            display: block;\n        }\n        .slideshow-item-img {\n            width: 100%;\n        }\n    }\n    .qqmusic-grid-list {\n        margin-top: 16px;\n        .am-flexbox {\n            height: 60px !important;\n            .qqmusic-grid-item {\n                display: flex;\n                align-items: center;\n                padding-left: 15px;\n                height: 60px;\n                .qqmusic-grid-item-icon {\n                    width: 24px;\n                    height: 24px;\n                }\n                .qqmusic-grid-item-text {\n                    padding-left: 10px;\n                    font-size: 15px;\n                }\n            }\n        }\n    }\n    .qqmusic-songMenu-recommend {\n        margin: 15px 0;\n        .title {\n            position: relative;\n            text-align: center;\n            font-size: 18px;\n            letter-spacing: 5px;\n            .icon-circle-right {\n                display: inline-block;\n                width: 26px;\n                height: 26px;\n                position: absolute;\n                right: 15px;\n                top: -3px;\n                background: url('../../assets/icon-circle-right.png');\n                background-size: 26px 26px;\n            }\n        }\n        .qqmusic-recommend-list {\n            margin-top: 15px;\n            .am-flexbox {\n                height: 165px !important;\n                .qqmusic-recommend-item {\n                    .qqmusic-recommend-item-image-wrapper {\n                        position: relative;\n                        width: 100%;\n                        height: 125px;\n                       .image{\n                            width: 100%;\n                            height: 100%;\n                        }\n                        .amount{\n                            position: absolute;\n                            left: 10px;\n                            bottom: 5px;\n                            font-size: 12px;\n                            color: #fff;\n                        }\n                        .amount:before{\n                            content: '';\n                            display:inline-block;\n                            width: 12px;\n                            height: 12px;\n                            margin-right: 5px;\n                            background-image: url('../../assets/icon-music-amount.png');\n                            background-size: 12px 12px;\n                        }\n                        .link-to-musicList-detail{\n                            position: absolute;\n                            right: 5px;\n                            bottom: 5px;\n                            width: 25px;\n                            height: 25px;\n                        }\n                    }\n                    .text{\n                        padding: 4px 2px;\n                        font-size: 11px;\n                        line-height: 16px;\n                        text-align: left;\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/pages/MyCenter/index.js",
    "content": "import React from 'react';\nimport { Grid } from 'antd-mobile';\nimport './style.scss';\nimport auditionImg from '@/assets/icon-user-audition.png';\nimport dredgeImg from '@/assets/icon-user-dredge.png';\nimport rankImg from '@/assets/icon-user-rank.png';\nimport SongMenu from '@/components/SongMenu';\nclass mycenter extends React.Component {\n    render() {\n        const girdList = [\n            {\n                text: '本地歌曲',\n                imgSrc: require('@/assets/icon-grid-music.png')\n            },\n            {\n                text: '下载歌曲',\n                imgSrc: require('@/assets/icon-grid-download.png')\n            },\n            {\n                text: '最近播放',\n                imgSrc: require('@/assets/icon-grid-recent.png')\n            },\n            {\n                text: '我喜欢',\n                imgSrc: require('@/assets/icon-grid-favorite.png')\n            },\n            {\n                text: '下载MV',\n                imgSrc: require('@/assets/icon-grid-mv.png')\n            },\n            {\n                text: '已购音乐',\n                imgSrc: require('@/assets/icon-grid-buy.png')\n            }\n        ]\n        return (\n            <div className=\"qqmusic-home-body\">\n                <div className=\"qqmusic-mycenter-top\">\n                    <div className=\"qqmusic-mycenter-user\">\n                        <div className=\"qqmusic-mycenter-user-module\">\n                            <div className=\"qqmusic-mycenter-user-audition\">\n                                <img className=\"icon\" src={auditionImg} />\n                                <span className=\"text\">0分钟</span>\n                            </div>\n                            <img className=\"qqmusic-mycenter-user-photo\" src=\"https://wx.qlogo.cn/mmopen/LHU7CmulIEWaZgu4PRWXOScvVCC5npYoPvBFVLMXldibtQ1BRVMJy4RaHXliabaqJSazgI8QTuF9g2X7l9iafOvfX27vcHl2ksA/0\" />\n                            <div className=\"qqmusic-mycenter-user-dredge\">\n                                <img className=\"icon\" src={dredgeImg} />\n                                <span className=\"text\">开通</span>\n                            </div>\n                        </div>\n                        <div className=\"qqmusic-mycenter-user-module\">\n                            <span className=\"userName\">椰子油</span>\n                        </div>\n                        <div className=\"qqmusic-mycenter-user-module\">\n                            <img className=\"qqmusic-mycenter-user-rank\" src={rankImg} />\n                        </div>\n                    </div>\n                    <Grid\n                        className=\"qqmusic-mycenter-grid\"\n                        data={girdList}\n                        columnNum={3}\n                        hasLine={false}\n                        renderItem={\n                            item => (\n                                <div className=\"qqmusic-mycenter-grid-item\">\n                                    <img className=\"image\" src={item.imgSrc} />\n                                    <p className=\"text\">{item.text}</p>\n                                </div>\n                            )\n                        }\n                    />\n                    <div className=\"qqmusic-mycenter-middle\">\n                        <div className=\"qqmusic-mycenter-station\">\n                            <div className=\"qqmusic-mycenter-station-left\">\n                                <img className=\"station-image\" src=\"/static/images/broadcasting-station-specific.jpeg\" />\n                            </div>\n                            <div className=\"qqmusic-mycenter-station-right\">\n                                <h4 className=\"station-title\">个性电台</h4>\n                                <p className=\"station-text\">偶遇身边好音乐</p>\n                            </div>\n                        </div>\n                        <div className=\"qqmusic-mycenter-station\">\n                            <div className=\"qqmusic-mycenter-station-left\">\n                                <img className=\"station-image\" src=\"/static/images/broadcasting-station-run.jpeg\" />\n                            </div>\n                            <div className=\"qqmusic-mycenter-station-right border-top\">\n                                <h4 className=\"station-title\">跑步电台</h4>\n                                <p className=\"station-text\">QQ音乐 x Nike，让运动乐在其中</p>\n                            </div>\n                        </div>\n                    </div>\n                    <SongMenu />\n                </div>\n            </div>\n        )\n    }\n}\nexport default mycenter;"
  },
  {
    "path": "src/pages/MyCenter/style.scss",
    "content": ".qqmusic-home-body {\n    .qqmusic-mycenter-top {\n        padding: 5px 0 20px;\n        background: #f5f5f9;\n        .qqmusic-mycenter-user {\n            background: #fff;\n            padding-bottom: 5px;\n            .qqmusic-mycenter-user-module {\n                text-align: center;\n                padding-top: 5px;\n                .qqmusic-mycenter-user-audition,\n                .qqmusic-mycenter-user-dredge {\n                    display: inline-block;\n                    border: 1px solid #8a8a8a;\n                    text-align: center;\n                    width: 80px;\n                    height: 25px;\n                    border-radius: 15px;\n                    .text {\n                        padding-left: 4px;\n                        font-size: 14px;\n                        color: #cdcdcd;\n                    }\n                    .icon {\n                        width: 24px;\n                        height: 24px;\n                        vertical-align: -5px;\n                    }\n                }\n                .qqmusic-mycenter-user-photo {\n                    width: 50px;\n                    height: 50px;\n                    border-radius: 50%;\n                    vertical-align: middle;\n                    margin: 0 15px;\n                }\n                .userName:before,\n                .userName:after {\n                    content: \"\";\n                    display: inline-block;\n                    height: 1px;\n                    width: 40px;\n                    border-top: 1px solid #2c2c2c;\n                    vertical-align: middle;\n                }\n                .userName:before {\n                    margin-right: 5px;\n                }\n                .userName::after {\n                    margin-left: 5px;\n                }\n                .qqmusic-mycenter-user-rank {\n                    height: 19px;\n                    width: 19px;\n                }\n            }\n        }\n        .qqmusic-mycenter-grid {\n            .am-flexbox {\n                height: 75px !important;\n                .qqmusic-mycenter-grid-item {\n                    .image {\n                        width: 35px;\n                        height: 35px;\n                    }\n                    .text {\n                        text-align: center;\n                        font-size: 15px;\n                        padding-top: 5px;\n                    }\n                }\n            }\n        }\n    }\n    .qqmusic-mycenter-middle {\n        margin-top: 5px;\n        background: #fff;\n        .qqmusic-mycenter-station {\n            display: flex;\n            height: 55px;\n            .qqmusic-mycenter-station-left {\n                flex: 0 0 65px;\n                .station-image {\n                    width: 55px;\n                    height: 55px;\n                }\n            }\n            .qqmusic-mycenter-station-right {\n                flex: 1;\n                display: flex;\n                justify-content: center;\n                flex-direction: column;\n                .station-title {\n                    font-size: 16px;\n                    font-weight: 400;\n                }\n                .station-text {\n                    padding-top: 5px;\n                    font-size: 13px;\n                    color: #cacaca;\n                    font-weight: 300;\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/router/index.js",
    "content": "import Loadable from 'react-loadable';\nimport createBrowserHistory from 'history/createBrowserHistory';\nimport MainLayout from '@/layouts/MainLayout';\nimport Loading from '@/components/Loading';\n\n\nconst Discovery = Loadable({loader: () => import('@/pages/Discovery'),loading: Loading});\nconst MusicClub = Loadable({loader: () => import('@/pages/MusicClub'),loading: Loading});\nconst MyCenter = Loadable({loader: () => import('@/pages/MyCenter'),loading: Loading});\n\nexport const history = createBrowserHistory();\n\nexport const routes = [\n  {\n    path:'/',\n    redirect:'/myCenter'\n  },\n  {\n    path:'/myCenter',\n    layout:MainLayout,\n    component:MyCenter\n  },\n  {\n    path:'/musicClub',\n    layout:MainLayout,\n    component:MusicClub\n  },\n  {\n    path:'/discovery',\n    layout:MainLayout,\n    component:Discovery\n  },\n]"
  },
  {
    "path": "src/scss/reset.scss",
    "content": "*{\n  margin: 0;\n  padding: 0;\n}\nhtml,body{\n  height: 100%;\n}\nli{\n  list-style: none;\n}\na{\n  text-decoration: none;\n}\ninput{\n  border: none;\n  outline:none;        \n}\n#app{\n  height: 100%;\n}\n.border-bottom{\n  position: relative;\n}\n.border-bottom:after {  \n  height: 1px;  \n  content: '';  \n  width: 100%;  \n  border-top: 1px solid #c7c7c7;  \n  position: absolute;  \n  bottom: -1px;  \n  right: 0;  \n  transform: scaleY(0.5);  \n  -webkit-transform: scaleY(0.5);   \n}  \n.border-top{\n  position: relative;\n}\n.border-top:after {  \n  height: 1px;  \n  content: '';  \n  width: 100%;  \n  border-top: 1px solid #c7c7c7;  \n  position: absolute;  \n  top: -1px;  \n  right: 0;  \n  transform: scaleY(0.5);  \n  -webkit-transform: scaleY(0.5);   \n}  "
  },
  {
    "path": "src/scss/variable.scss",
    "content": "$primary-color:#31c37c;\n$text-color-secondary:rgba(0,0,0,.45);\n$screen-xl: 1200px;\n$screen-sm: 576px;\n$screen-xs: 480px;"
  },
  {
    "path": "src/store/actionTypes.js",
    "content": "//播放或暂停音乐\nexport const CHANGE_MUSIC_STATUS=\"CHANGE_MUSIC_STATUS\";\n//添加音乐到播放列表\nexport const ADD_MUSIC=\"ADD_MUSIC\";\n//更改当前音乐\nexport const CHANGE_CURRENT_MUSIC=\"CHANGE_CURRENT_MUSIC\";\n//添加并更改当前音乐\nexport const ADD_AND_CHANGE_MUSIC=\"ADD_AND_CHANGE_MUSIC\";\n//播放指定歌曲\nexport const PLAY_SPECIFIC_MUSIC_BY_MID=\"PLAY_SPECIFIC_MUSIC_BY_MID\";\n//清空播放列表\nexport const CLEAR_MUSIC_LIST=\"CLEAR_MUSIC_LIST\";\n//移除指定的音乐\nexport const REMOVE_MUSIC_FROM_LIST=\"REMOVE_MUSIC_FROM_LIST\";\n//添加歌单\nexport const ADD_SONG_LIST=\"ADD_SONG_LIST\";\n//删除歌单\nexport const REMOVE_SONG_LIST=\"REMOVE_SONG_LIST\";"
  },
  {
    "path": "src/store/actions.js",
    "content": "import * as actionTypes from './actionTypes';\n//添加音乐\nexport const addMusic=(data,callback)=> async (dispatch,getState,{API})=>{\n  dispatch({\n    type: actionTypes.ADD_MUSIC,\n    payload:data\n  });\n  callback();\n}\n//播放或暂停音乐\nexport const changePlayStatus=(data)=> async (dispatch,getState,{API})=>{\n  dispatch({\n    type: actionTypes.CHANGE_MUSIC_STATUS,\n    payload:data\n  });\n}\n//更改音乐\nexport const changeCurrentMusic=(data)=> async (dispatch,getState,{API})=>{\n  dispatch({\n    type: actionTypes.CHANGE_CURRENT_MUSIC,\n    payload:data\n  });\n}\n//添加并更改当前音乐\nexport const addAndChangeMusic=(data,isPlay)=> async (dispatch,getState,{API})=>{\n  dispatch({\n    type: actionTypes.ADD_AND_CHANGE_MUSIC,\n    payload:{\n      data,\n      isPlay\n    }\n  });\n}\n//播放指定音乐\nexport const playSpecificMusicByMid=(data)=> async (dispatch,getState,{API})=>{\n  dispatch({\n    type: actionTypes.PLAY_SPECIFIC_MUSIC_BY_MID,\n    payload:data\n  });\n}\n//清除播放列表\nexport const clearMusicList=()=> async (dispatch,getState,{API})=>{\n  dispatch({\n    type: actionTypes.CLEAR_MUSIC_LIST\n  });\n}\n//将音乐从播放列表中移除\nexport const removeMusicFromList=(data)=> async (dispatch,getState,{API})=>{\n  dispatch({\n    type: actionTypes.REMOVE_MUSIC_FROM_LIST,\n    payload:data\n  });\n}\n//添加歌单\nexport const addSongMenu=(data)=> async (dispatch,getState,{API})=>{\n  dispatch({\n    type: actionTypes.ADD_SONG_LIST,\n    payload:data\n  });\n}\n//删除歌单\nexport const removeSongMenu=(data)=> async (dispatch,getState,{API})=>{\n  dispatch({\n    type: actionTypes.REMOVE_SONG_LIST,\n    payload:data\n  });\n}"
  },
  {
    "path": "src/store/index.js",
    "content": "import { createStore,combineReducers, applyMiddleware, compose } from 'redux';\nimport thunk from 'redux-thunk';\nimport {API} from '@/api';\nimport global from './reducer';\nconst rootReducer = combineReducers({\n  global\n})\nexport default function configureStore(initialState) {\n    const store = createStore(\n        rootReducer,\n        initialState,\n        compose(\n            applyMiddleware(thunk.withExtraArgument({API})),\n            window.devToolsExtension ? window.devToolsExtension() : f => f\n        )\n    );\n    return store;\n};"
  },
  {
    "path": "src/store/reducer.js",
    "content": "import * as actionTypes from './actionTypes';\nconst initialState = {\n    currentMusic: {},\n    isPlay: false,\n    isCurrentMusicChange: false,\n    musicList: [],\n    songMenuArray:[]\n};\nfunction isMusicExist(musicData,array) {\n   return array.some((item)=>{\n        return item.mid === musicData.mid;\n    });\n}\nfunction isSongMenuExist(name,array){\n    return array.some((item)=>{\n        return item===name;\n    });\n}\n\nexport default function music(state = initialState, action) {\n  const {currentMusic,musicList,songMenuArray} = state;\n  const {type,payload} = action;\n  switch (type) {\n      case actionTypes.ADD_MUSIC:\n          if (!isMusicExist(payload,musicList)) {\n              musicList.unshift(payload)\n              return Object.assign({}, state, {\n                  musicList\n              });\n          } else {\n              return state;\n          }\n      case actionTypes.CHANGE_CURRENT_MUSIC:\n          return Object.assign({}, state, {\n              currentMusic: payload,\n              isCurrentMusicChange: true\n          });\n      case actionTypes.CHANGE_MUSIC_STATUS:\n          return Object.assign({}, state, {\n              isPlay: payload,\n              isCurrentMusicChange: false\n          });\n      case actionTypes.ADD_AND_CHANGE_MUSIC:\n          if (!isMusicExist(payload.data,musicList)) {\n              musicList.unshift(payload.data)\n          }\n          return Object.assign({}, state, {\n              musicList,\n              currentMusic: payload.data,\n              isCurrentMusicChange: true,\n              isPlay: payload.isPlay\n          });\n      case actionTypes.PLAY_SPECIFIC_MUSIC_BY_MID:\n          return Object.assign({}, state, {\n              currentMusic: musicList.find((music)=>music.mid===payload),\n              isCurrentMusicChange: true,\n              isPlay: true\n          });\n      case actionTypes.CLEAR_MUSIC_LIST:\n          return Object.assign({}, state, {\n              currentMusic: {},\n              isCurrentMusicChange: false,\n              musicList: [],\n              isPlay: false\n          });\n      case actionTypes.REMOVE_MUSIC_FROM_LIST:\n          const newMusicList = musicList.filter((music)=>music.mid!==payload); \n          if (payload !== currentMusic.mid) {\n              return Object.assign({}, state, {\n                  isCurrentMusicChange: false,\n                  musicList: newMusicList\n              });\n          } else {\n              return Object.assign({}, state, {\n                      isCurrentMusicChange: newMusicList.length>0?true:false,\n                      isPlay:newMusicList.length>0?true:false,\n                      currentMusic:musicList.length>0?newMusicList[0]:{},\n                      musicList:newMusicList\n                  });\n          } \n      case actionTypes.ADD_SONG_LIST:\n          if(!isSongMenuExist(payload,songMenuArray)){\n              songMenuArray.unshift(payload);\n              return Object.assign({},state,{\n                  songMenuArray\n              });\n          }else{\n              return state;\n          }\n      case actionTypes.REMOVE_SONG_LIST:\n          let newSongMenuArray=songMenuArray.filter((item)=>{\n              return !isSongMenuExist(item,payload);\n          });\n          return Object.assign({},state,{\n              songMenuArray:newSongMenuArray\n          });\n      default:\n          return state;\n  }\n}"
  },
  {
    "path": "src/utils/http.js",
    "content": "import axios from 'axios';\nimport {Toast} from 'antd-mobile';\nconst instance=axios.create({\n  //超时时间\n  timeout:3000,\n  //响应前处理\n  transformResponse:(responseData)=>{\n    return responseData;\n  }\n})\n//响应拦截\ninstance.interceptors.response.use(function (response) {\n  const {status,data,statusText,headers}=response;\n  if(status===200){\n    return headers['content-type']==='application/json'?JSON.parse(data):data;  \n  }else if(status===401){\n    //跳转登录\n  }else{\n    Toast.fail(`${status}-${statusText}`);\n    return response;  \n  }\n}, function (error) {\n  // 对响应错误做点什么\n  return Promise.reject(error);\n});\nexport default {\n  get:(url,params,option)=>{\n    return instance.get(url,Object.assign({},option,{params}));\n  },\n  post:(url,params,option)=>{\n    return instance.post(url,params,option); \n  },\n  delete:(url,params,option)=>{\n    return instance.delete(url,Object.assign({},option,{params}));\n  }\n}"
  },
  {
    "path": "src/utils/index.js",
    "content": "export default  {\n    //格式化数字位数\n    \"fix\":function(num, length){\n       return ('' + num).length < length ? ((new Array(length + 1)).join('0') + num).slice(-length) : '' + num;\n    },\n    //根据秒转换成分:秒的形式\n    \"formatSeconds\":function(seconds){\n       var minute=Math.floor(seconds/60);\n       var second=Math.round(seconds-minute*60);\n       return this.fix(minute,2)+\":\"+this.fix(second,2);\n    },\n    //根据字符串解析时间\n    \"parseStrToSeconds\":function(timeStr){\n       timeStr=timeStr.replace(/\\[|\\]/,\"\");\n       var timeArray=timeStr.split(\":\"); \n       return parseInt(timeArray[0])*60+parseFloat(timeArray[1]);\n    },\n    //解析歌词\n    \"parseLyric\":function(text){\n        var lyricList=text.split(\"\\n\");\n        var timeReg=/\\[[0-9]{2}:[0-9]*\\.[0-9]*\\]/;\n        var array=[];\n        for(var i=0;i<lyricList.length;i++){\n            if(lyricList[i]!=\"\"){\n               var seconds=this.parseStrToSeconds(lyricList[i].match(timeReg)[0]);\n               var text=lyricList[i].replace(timeReg,\"\");\n               array.push( {\n                   \"seconds\":seconds,\n                   \"text\":text\n               });\n            }\n        }\n        return array;\n    }\n}"
  },
  {
    "path": "theme.js",
    "content": "module.exports={\n  \"brand-primary\":\"#31c37c\"\n}"
  }
]