Commit e2541923 by yangchao

update

1 parent 52152996
Showing with 4218 additions and 0 deletions
{
"presets": [
["env", {
"modules": false,
"targets": {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}],
"stage-2"
],
"plugins": ["transform-vue-jsx", "transform-runtime"]
}
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 4
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
.DS_Store
node_modules/
/dist/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
// https://github.com/michael-ciniawsky/postcss-load-config
module.exports = {
"plugins": {
"postcss-import": {},
"postcss-url": {},
// to edit target browsers: use "browserslist" field in package.json
"autoprefixer": {}
}
}
'use strict'
require('./check-versions')()
process.env.NODE_ENV = 'production'
const ora = require('ora')
const rm = require('rimraf')
const path = require('path')
const chalk = require('chalk')
const webpack = require('webpack')
const config = require('../config')
const webpackConfig = require('./webpack.prod.conf')
const spinner = ora('building for production...')
spinner.start()
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
if (err) throw err
webpack(webpackConfig, (err, stats) => {
spinner.stop()
if (err) throw err
process.stdout.write(stats.toString({
colors: true,
modules: false,
children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
chunks: false,
chunkModules: false
}) + '\n\n')
if (stats.hasErrors()) {
console.log(chalk.red(' Build failed with errors.\n'))
process.exit(1)
}
console.log(chalk.cyan(' Build complete.\n'))
console.log(chalk.yellow(
' Tip: built files are meant to be served over an HTTP server.\n' +
' Opening index.html over file:// won\'t work.\n'
))
})
})
'use strict'
const chalk = require('chalk')
const semver = require('semver')
const packageConfig = require('../package.json')
const shell = require('shelljs')
function exec (cmd) {
return require('child_process').execSync(cmd).toString().trim()
}
const versionRequirements = [
{
name: 'node',
currentVersion: semver.clean(process.version),
versionRequirement: packageConfig.engines.node
}
]
if (shell.which('npm')) {
versionRequirements.push({
name: 'npm',
currentVersion: exec('npm --version'),
versionRequirement: packageConfig.engines.npm
})
}
module.exports = function () {
const warnings = []
for (let i = 0; i < versionRequirements.length; i++) {
const mod = versionRequirements[i]
if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
warnings.push(mod.name + ': ' +
chalk.red(mod.currentVersion) + ' should be ' +
chalk.green(mod.versionRequirement)
)
}
}
if (warnings.length) {
console.log('')
console.log(chalk.yellow('To use this template, you must update following to modules:'))
console.log()
for (let i = 0; i < warnings.length; i++) {
const warning = warnings[i]
console.log(' ' + warning)
}
console.log()
process.exit(1)
}
}
'use strict'
const path = require('path')
const config = require('../config')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const packageConfig = require('../package.json')
exports.assetsPath = function (_path) {
const assetsSubDirectory = process.env.NODE_ENV === 'production'
? config.build.assetsSubDirectory
: config.dev.assetsSubDirectory
return path.posix.join(assetsSubDirectory, _path)
}
exports.cssLoaders = function (options) {
options = options || {}
const cssLoader = {
loader: 'css-loader',
options: {
sourceMap: options.sourceMap
}
}
const postcssLoader = {
loader: 'postcss-loader',
options: {
sourceMap: options.sourceMap
}
}
const px2remLoader = {
loader : 'px2rem-loader',
options : {
remUnit : 75
}
}
// generate loader string to be used with extract text plugin
function generateLoaders (loader, loaderOptions) {
const loaders = options.usePostCSS ? [cssLoader, postcssLoader,px2remLoader] : [cssLoader,px2remLoader]
if (loader) {
loaders.push({
loader: loader + '-loader',
options: Object.assign({}, loaderOptions, {
sourceMap: options.sourceMap
})
})
}
// Extract CSS when that option is specified
// (which is the case during production build)
if (options.extract) {
return ExtractTextPlugin.extract({
use: loaders,
fallback: 'vue-style-loader'
})
} else {
return ['vue-style-loader'].concat(loaders)
}
}
// https://vue-loader.vuejs.org/en/configurations/extract-css.html
return {
css: generateLoaders(),
postcss: generateLoaders(),
less: generateLoaders('less'),
sass: generateLoaders('sass', { indentedSyntax: true }),
scss: generateLoaders('sass'),
stylus: generateLoaders('stylus'),
styl: generateLoaders('stylus')
}
}
// Generate loaders for standalone style files (outside of .vue)
exports.styleLoaders = function (options) {
const output = []
const loaders = exports.cssLoaders(options)
for (const extension in loaders) {
const loader = loaders[extension]
output.push({
test: new RegExp('\\.' + extension + '$'),
use: loader
})
}
return output
}
exports.createNotifierCallback = () => {
const notifier = require('node-notifier')
return (severity, errors) => {
if (severity !== 'error') return
const error = errors[0]
const filename = error.file && error.file.split('!').pop()
notifier.notify({
title: packageConfig.name,
message: severity + ': ' + error.name,
subtitle: filename || '',
icon: path.join(__dirname, 'logo.png')
})
}
}
'use strict'
const utils = require('./utils')
const config = require('../config')
const isProduction = process.env.NODE_ENV === 'production'
const sourceMapEnabled = isProduction
? config.build.productionSourceMap
: config.dev.cssSourceMap
module.exports = {
loaders: utils.cssLoaders({
sourceMap: sourceMapEnabled,
extract: isProduction
}),
cssSourceMap: sourceMapEnabled,
cacheBusting: config.dev.cacheBusting,
transformToRequire: {
video: ['src', 'poster'],
source: 'src',
img: 'src',
image: 'xlink:href'
}
}
'use strict'
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')
function resolve (dir) {
return path.join(__dirname, '..', dir)
}
module.exports = {
context: path.resolve(__dirname, '../'),
entry: {
app: './src/main.js'
},
output: {
path: config.build.assetsRoot,
filename: '[name].js',
publicPath: process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath
: config.dev.assetsPublicPath
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
}
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: vueLoaderConfig
},
{
test: /\.scss$/,
loaders: ["style", "css", "sass","style-loader!css-loader!less-loader"]
},
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('media/[name].[hash:7].[ext]')
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
}
}
]
},
node: {
// prevent webpack from injecting useless setImmediate polyfill because Vue
// source contains it (although only uses it if it's native).
setImmediate: false,
// prevent webpack from injecting mocks to Node native modules
// that does not make sense for the client
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty'
}
}
'use strict'
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const path = require('path')
const baseWebpackConfig = require('./webpack.base.conf')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
const portfinder = require('portfinder')
const HOST = process.env.HOST
const PORT = process.env.PORT && Number(process.env.PORT)
const devWebpackConfig = merge(baseWebpackConfig, {
module: {
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
},
// cheap-module-eval-source-map is faster for development
devtool: config.dev.devtool,
// these devServer options should be customized in /config/index.js
devServer: {
clientLogLevel: 'warning',
historyApiFallback: {
rewrites: [
{ from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
],
},
hot: true,
contentBase: false, // since we use CopyWebpackPlugin.
compress: true,
host: HOST || config.dev.host,
port: PORT || config.dev.port,
open: config.dev.autoOpenBrowser,
overlay: config.dev.errorOverlay
? { warnings: false, errors: true }
: false,
publicPath: config.dev.assetsPublicPath,
proxy: config.dev.proxyTable,
quiet: true, // necessary for FriendlyErrorsPlugin
watchOptions: {
poll: config.dev.poll,
}
},
plugins: [
new webpack.DefinePlugin({
'process.env': require('../config/dev.env')
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
new webpack.NoEmitOnErrorsPlugin(),
// https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: true
}),
// copy custom static assets
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: config.dev.assetsSubDirectory,
ignore: ['.*']
}
])
]
})
module.exports = new Promise((resolve, reject) => {
portfinder.basePort = process.env.PORT || config.dev.port
portfinder.getPort((err, port) => {
if (err) {
reject(err)
} else {
// publish the new Port, necessary for e2e tests
process.env.PORT = port
// add port to devServer config
devWebpackConfig.devServer.port = port
// Add FriendlyErrorsPlugin
devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
compilationSuccessInfo: {
messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
},
onErrors: config.dev.notifyOnErrors
? utils.createNotifierCallback()
: undefined
}))
resolve(devWebpackConfig)
}
})
})
'use strict'
const path = require('path')
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const env = require('../config/prod.env')
const webpackConfig = merge(baseWebpackConfig, {
module: {
rules: utils.styleLoaders({
sourceMap: config.build.productionSourceMap,
extract: true,
usePostCSS: true
})
},
devtool: config.build.productionSourceMap ? config.build.devtool : false,
output: {
path: config.build.assetsRoot,
filename: utils.assetsPath('js/[name].[chunkhash].js'),
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
},
plugins: [
// http://vuejs.github.io/vue-loader/en/workflow/production.html
new webpack.DefinePlugin({
'process.env': env
}),
new UglifyJsPlugin({
uglifyOptions: {
compress: {
warnings: false
}
},
sourceMap: config.build.productionSourceMap,
parallel: true
}),
// extract css into its own file
new ExtractTextPlugin({
filename: utils.assetsPath('css/[name].[contenthash].css'),
// Setting the following option to `false` will not extract CSS from codesplit chunks.
// Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
// It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`,
// increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
allChunks: true,
}),
// Compress extracted CSS. We are using this plugin so that possible
// duplicated CSS from different components can be deduped.
new OptimizeCSSPlugin({
cssProcessorOptions: config.build.productionSourceMap
? { safe: true, map: { inline: false } }
: { safe: true }
}),
// generate dist index.html with correct asset hash for caching.
// you can customize output by editing /index.html
// see https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: config.build.index,
template: 'index.html',
inject: true,
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
// more options:
// https://github.com/kangax/html-minifier#options-quick-reference
},
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
chunksSortMode: 'dependency'
}),
// keep module.id stable when vendor modules does not change
new webpack.HashedModuleIdsPlugin(),
// enable scope hoisting
new webpack.optimize.ModuleConcatenationPlugin(),
// split vendor js into its own file
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks (module) {
// any required modules inside node_modules are extracted to vendor
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(
path.join(__dirname, '../node_modules')
) === 0
)
}
}),
// extract webpack runtime and module manifest to its own file in order to
// prevent vendor hash from being updated whenever app bundle is updated
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
minChunks: Infinity
}),
// This instance extracts shared chunks from code splitted chunks and bundles them
// in a separate chunk, similar to the vendor chunk
// see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
new webpack.optimize.CommonsChunkPlugin({
name: 'app',
async: 'vendor-async',
children: true,
minChunks: 3
}),
// copy custom static assets
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: config.build.assetsSubDirectory,
ignore: ['.*']
}
])
]
})
if (config.build.productionGzip) {
const CompressionWebpackPlugin = require('compression-webpack-plugin')
webpackConfig.plugins.push(
new CompressionWebpackPlugin({
asset: '[path].gz[query]',
algorithm: 'gzip',
test: new RegExp(
'\\.(' +
config.build.productionGzipExtensions.join('|') +
')$'
),
threshold: 10240,
minRatio: 0.8
})
)
}
if (config.build.bundleAnalyzerReport) {
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}
module.exports = webpackConfig
'use strict'
const merge = require('webpack-merge')
const prodEnv = require('./prod.env')
module.exports = merge(prodEnv, {
NODE_ENV: '"development"'
})
'use strict'
// Template version: 1.3.1
// see http://vuejs-templates.github.io/webpack for documentation.
const path = require('path')
module.exports = {
dev: {
// Paths
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {},
// Various Dev Server settings
host: '0.0.0.0', // can be overwritten by process.env.HOST
port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
autoOpenBrowser: false,
errorOverlay: true,
notifyOnErrors: true,
poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
/**
* Source Maps
*/
// https://webpack.js.org/configuration/devtool/#development
devtool: 'cheap-module-eval-source-map',
// If you have problems debugging vue-files in devtools,
// set this to false - it *may* help
// https://vue-loader.vuejs.org/en/options.html#cachebusting
cacheBusting: true,
cssSourceMap: true
},
build: {
// Template for index.html
index: path.resolve(__dirname, '../dist/index.html'),
// Paths
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'static',
assetsPublicPath: '/',
/**
* Source Maps
*/
productionSourceMap: true,
// https://webpack.js.org/configuration/devtool/#production
devtool: '#source-map',
// Gzip off by default as many popular static hosts such as
// Surge or Netlify already gzip all static assets for you.
// Before setting to `true`, make sure to:
// npm install --save-dev compression-webpack-plugin
productionGzip: false,
productionGzipExtensions: ['js', 'css'],
// Run the build command with an extra argument to
// View the bundle analyzer report after build finishes:
// `npm run build --report`
// Set to `true` or `false` to always turn it on or off
bundleAnalyzerReport: process.env.npm_config_report
}
}
'use strict'
module.exports = {
NODE_ENV: '"production"'
}
No preview for this file type
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
<meta name="viewport" content="width=device-width,initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<meta name="apple-mobile-web-app-title" content="">
<meta name="apple-mobile-web-app-capable" content="yes"/>
<meta name="apple-mobile-web-app-status-bar-style" content="black"/>
<meta name="apple-itunes-app" content="app-id=myAppStoreID, affiliate-data=myAffiliateData, app-argument=myURL">
<meta name="format-detection" content="telphone=no, email=no"/>
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache">
<meta http-equiv="Expires" content="0">
<title>脑力中国</title>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
This diff could not be displayed because it is too large.
{
"name": "wisdom",
"version": "1.0.0",
"description": "A Vue.js project",
"author": "yangchao <408986770@qq.com>",
"private": true,
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js --host 10.4.2.105",
"start": "npm run dev",
"build": "node build/build.js"
},
"dependencies": {
"axios": "^0.18.0",
"less": "^3.9.0",
"less-loader": "^4.1.0",
"lib-flexible": "^0.3.2",
"vue": "^2.5.2",
"vue-router": "^3.0.1",
"vuex": "^3.1.0"
},
"devDependencies": {
"autoprefixer": "^7.1.2",
"babel-core": "^6.22.1",
"babel-helper-vue-jsx-merge-props": "^2.0.3",
"babel-loader": "^7.1.1",
"babel-plugin-syntax-jsx": "^6.18.0",
"babel-plugin-transform-runtime": "^6.22.0",
"babel-plugin-transform-vue-jsx": "^3.5.0",
"babel-preset-env": "^1.3.2",
"babel-preset-stage-2": "^6.22.0",
"chalk": "^2.0.1",
"copy-webpack-plugin": "^4.0.1",
"css-loader": "^0.28.0",
"extract-text-webpack-plugin": "^3.0.0",
"file-loader": "^1.1.4",
"friendly-errors-webpack-plugin": "^1.6.1",
"html-webpack-plugin": "^2.30.1",
"node-notifier": "^5.1.2",
"optimize-css-assets-webpack-plugin": "^3.2.0",
"ora": "^1.2.0",
"portfinder": "^1.0.13",
"postcss-import": "^11.0.0",
"postcss-loader": "^2.0.8",
"postcss-url": "^7.2.1",
"px2rem-loader": "^0.1.9",
"rimraf": "^2.6.0",
"semver": "^5.3.0",
"shelljs": "^0.7.6",
"uglifyjs-webpack-plugin": "^1.1.1",
"url-loader": "^0.5.8",
"vue-loader": "^13.3.0",
"vue-style-loader": "^3.0.1",
"vue-template-compiler": "^2.5.2",
"webpack": "^3.6.0",
"webpack-bundle-analyzer": "^2.9.0",
"webpack-dev-server": "^2.9.1",
"webpack-merge": "^4.1.0"
},
"engines": {
"node": ">= 6.0.0",
"npm": ">= 3.0.0"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
}
<template>
<div id="app">
<router-view/>
</div>
</template>
<script>
import {mapActions} from 'vuex'
export default {
name: 'App',
methods: {
...mapActions({
getCategoryList: 'dispatchGetCategoryList',
getQuestionList: 'dispatchGetQuestionList',
getSpecialList: 'dispatchSpecialList',
getHotKeys: 'dispatchGetHotKeys'
})
},
created(){
this.getCategoryList();
this.getQuestionList();
this.getSpecialList();
this.getHotKeys();
}
}
</script>
<style>
@import "./stylesheets/reset.css";
@import "./stylesheets/app.css";
</style>
import request from '../utils/request'
//文章列表
export function getArticleList (data) {
return request({
url : 'colleges/supportArticle/list' ,
data
})
}
//文章详情
export function getArticleDetails (data) {
return request({
url : 'colleges/supportArticle/detail' ,
data
})
}
\ No newline at end of file
import request from '../utils/request'
//分类列表
export function getCategoryList (data) {
return request({
url : 'colleges/supportCategory/list' ,
data
})
}
import request from '../utils/request'
export function collectUserInfo (data) {
return request({
url : 'Colleges/Contacts/submit' ,
data
})
}
import request from '../utils/request'
//关键字
export function getKeywords (data) {
return request({
url : 'colleges/supportCategory/keywords' ,
data
})
}
\ No newline at end of file
import request from '../utils/request'
//获取问答列表
export function queryQuestionList (data) {
return request({
url : 'colleges/supportPlateAnswer/list' ,
data
})
}
\ No newline at end of file
import request from '../utils/request'
//专题列表
export function querySpecialList (data) {
return request({
url : 'colleges/supportPlateSpecial/list' ,
data
})
}
.mask{
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0,0,0,.5);
z-index: 99;
}
.title{
font-size: 32px;
color: #000;
font-weight: 600;
}
.content{
position: fixed;
top: 0;
bottom: 0;
right: 0;
left: 170px;
background-color: #fff;
z-index: 100;
transition: all .3s linear;
transform: translateX(100%);
&.active{
transform: translateX(0);
}
}
.hd{
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
padding: 24px 30px;
border-bottom: 1px solid #E8E8E8; /*no*/
.app-logo{
width: 280px;
height: 70px;
margin-left: 30px;
}
.icon-group{
width: 46px;
height: 46px;
}
}
.main-bd{
position: absolute;
left: 0;
right: 0;
top: 130px;
bottom: 0;
padding: 12px 30px 12px 60px;
overflow: auto;
.input-box{
display: flex;
align-items: center;
margin: 12px 0 20px;
.input{
flex: 1;
display: block;
padding: 14px 20px;
font-size: 30px;
color: #333;
border:1px solid #C6C6C6;/*no*/
border-radius:8px;
background-color: #F9F9F9;
}
.search-btn{
margin-left: 12px;
display: block;
font-size: 30px;/*px*/
color: #666;
min-width: 80px;
}
}
.hot-keys{
position: relative;
overflow: hidden;
.keys{
float: left;
display: block;
margin-left: 20px;
font-size: 20px;
color: #3091FE;
}
&.after{
content: '';
clear: both;
zoom: 1;
}
}
.item{
margin: 40px auto;
.top{
display: flex;
align-items: center;
.icon-arrow{
width: 20px;
height: 14px;
margin-left: 20px;
transition: all .2s linear;
&.rotate{
transform: rotate(180deg);
}
}
}
.sub-menu{
padding: 30px 0 0;
overflow: hidden;
.item-menu{
float: left;
font-size: 32px;
color: #666;
margin-right: 60px;
}
}
}
}
\ No newline at end of file
<template>
<div class='drawer-box' v-if="showDrawer">
<div class="mask" @click="toggleDrawerStatus"></div>
<div class="content" :class="{ active : animate }">
<div class="hd">
<img class="app-logo" src="http://static.ledouya.com/Flu7n1DcDv45J4qNSj9snKHmdTs2" @click="handleBack">
<img class="icon-group" src="../../assets/images/icon-close.png" @click="toggleDrawerStatus">
</div>
<div class="main-bd">
<div class="search-box">
<div class="title">首页</div>
<div class="input-box">
<input class="input" type="text" v-model="keywords" placeholder="请输入你想搜索的">
<a class="search-btn" href="javascript:;" @click="handleSearchBtnClick">搜索</a>
</div>
<div class="hot-keys">
<a class="keys" href="javascript:;" v-for="(item,index) in hotKeys" @click="handleKeyItemClick(item)">{{ item }}</a>
</div>
</div>
<!---->
<div class="cate-list" v-if="cateList[0].children">
<div class="item" v-for="(item,index) in cateList[0].children" :key="index">
<div class="top" @click.stop="toggleCateItem(index)">
<div class="title">{{ item.name }}</div>
<img class="icon-arrow" :class="{ rotate : !item.is_edit }" src="../../assets/images/arrow.png" alt="">
</div>
<div class="sub-menu" v-if="item.children" v-show="item.is_edit ">
<div class="item-menu" v-for="(target,idx) in item.children" @click.stop="handleCateClick(target)">{{ target.name }}</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapGetters , mapMutations } from 'vuex'
export default{
data(){
return{
keywords : '' ,
animate : false
}
},
computed : {
...mapGetters({
hotKeys : 'getHotKeys' ,
showDrawer : 'getDrawerStatus' ,
cateList : 'getCategoryList' ,
showFormModal : 'getFormStatus'
})
},
watch : {
showDrawer : function () {
this.toggleFormStatus({ flag : false });
setTimeout(()=>{
if( this.showDrawer ) {
this.animate = true;
} else this.animate = false;
},100)
}
},
methods : {
...mapMutations([
'toggleDrawerStatus' ,
'toggleFormStatus'
]),
handleBack(){
this.toggleDrawerStatus();
this.$router.push({
path : '/'
})
},
toggleCateItem(index){
this.cateList[0].children[index].is_edit = !this.cateList[0].children[index].is_edit;
this.$store.commit('insertCategoryList',this.cateList)
},
handleSearchBtnClick(){
if( !this.keywords.trim().length ){
this.$message({
title : '温馨提示' ,
content : '请输入搜索关键字'
})
return ;
}
this.toggleDrawerStatus();
this.$router.push({
path : '/display/search?keywords=' + this.keywords
})
this.keywords = '';
},
handleKeyItemClick(item){
this.toggleDrawerStatus();
this.$router.push({
path : '/display/search?keywords=' + item
})
this.keywords = '';
},
handleCateClick(e){
this.toggleDrawerStatus();
this.$router.push({
path : `/display/${e.id}?cateName=${e.name}`
})
this.keywords = '';
}
}
}
</script>
<style scoped lang="less">
@import "./index.less";
</style>
\ No newline at end of file
.mask{
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0,0,0,.5);
z-index: 3;
}
.content{
position: fixed;
padding-bottom: 30px;
bottom: 0;
left: 0;
right: 0;
background-color: #fff;
z-index: 9;
transition: all .3s linear;
transform: translateY(100%);
&.active{
transform: translateY(0);
}
}
.hd{
position: relative;
border-bottom: 1px solid #E8E8E8;/*no*/
.title{
padding: 30px;
font-size: 32px;/*px*/
text-align: center;
color: #999;
}
.icon-close{
position: absolute;
width: 46px;
height: 46px;
right: 30px;
top: 30px;
}
}
.bd{
padding: 30px;
position: relative;
text-align: center;
.text{
font-size: 30px;/*px*/
color: #333;
}
.tel-link{
display: block;
margin-top: 10px;
font-size: 40px;
color: #3091FE;
}
&:after{
content: '';
display: block;
position: absolute;
left: 30px;
right: 30px;
bottom: 0;
background-color: #E8E8E8;
height: 1px; /*no*/
}
}
.tips{
padding: 30px 24px 10px;
font-size: 30px;/*px*/
color: #333;
}
.form-box{
padding: 30px 24px;
.input{
padding: 24px 30px;
border : 1px solid #c6c6c6; /*no*/
width: 100%;
font-size: 30px;/*px*/
margin-bottom: 30px;
}
}
.submit-btn{
margin: 50px 24px 0;
background-color: #3091FE;
text-align: center;
color: #fff;
font-size: 32px;
padding: 25px 30px;
}
\ No newline at end of file
<template>
<div class='form-wrapper' v-show="showFormModal">
<div class="mask" @click.stop="toggleFormStatus( { flag : false })"></div>
<div class="content" :class="{ active : animate }">
<div class="hd">
<div class="title">开店咨询</div>
<img class="icon-close" src="../../assets/images/icon-close.png" alt="" @click.stop="toggleFormStatus( { flag : false })">
</div>
<div class="bd">
<div class="text">请拨打开店咨询热线:</div>
<a class="tel-link" href="tel:400-6865539">400-6865539</a>
</div>
<div class="tips">或者填写你的联系方式,我们会主动与你联系</div>
<div class="form-box">
<input type="text" class="input" placeholder="姓名" v-model="name">
<input type="tel" class="input" placeholder="手机号码" v-model="phone" maxlength="11">
<input type="text" class="input" placeholder="公司名称(选填)" v-model="company">
</div>
<div class="submit-btn" @click="handleSubmitBtnClick">提交信息</div>
</div>
<Loading :loading="loading"></Loading>
</div>
</template>
<script>
import { mapGetters , mapMutations } from 'vuex'
import Loading from '../../components/Loading'
//api
import { collectUserInfo } from '../../api/common'
export default{
components : {
Loading
},
data(){
return{
name : '' ,
phone : '',
company : '' ,
animate : false ,
loading : false
}
},
computed : {
...mapGetters({
showFormModal : 'getFormStatus'
})
},
watch : {
showFormModal : function () {
setTimeout(()=>{
this.animate = !this.animate;
},100)
}
},
methods : {
...mapMutations([
'toggleFormStatus'
]),
handleSubmitBtnClick(){
if(!this.validate()) return;
this.loading = true;
collectUserInfo({
name : this.name ,
phone : this.phone ,
title : this.company || this.phone ,
details : this.company || this.phone
}).then(res=>{
this.loading = false;
this.toggleFormStatus( { flag : false });
if(res.error === 0 ){
this.$message({
title : '温馨提示' ,
content : res.error_reason
})
}
})
},
validate(){
if(!this.name.trim().length){
this.$message({
title : '温馨提示' ,
content : '请输入姓名'
})
return false;
}
if(!this.phone.trim().length){
this.$message({
title : '温馨提示' ,
content : '请输入联系方式'
})
return false;
}
return true;
}
}
}
</script>
<style scoped lang="less">
@import "./index.less";
</style>
\ No newline at end of file
<template>
<div class="loading" v-if="loading">
<div class="mask"></div>
<div class="loadEffect">
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
</div>
</template>
<script>
export default{
props : {
loading : {
type : Boolean ,
default : false
}
}
}
</script>
<style scoped lang="less">
.mask{
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(255,255,255,.5);
z-index: 999;
}
.loadEffect {
position: fixed;
width: 100px;
height: 100px;
top: 30%;
left: 50%;
transform: translateX(-50%);
z-index: 1000;
}
.loadEffect span {
display: inline-block;
width: 16px;
height: 16px;
border-radius: 50%;
background: #3091FE;
position: absolute;
-webkit-animation: load 1.04s ease infinite;
}
@-webkit-keyframes load {
0% {
opacity: 1;
}
100% {
opacity: 0.2;
}
}
.loadEffect span:nth-child(1) {
left: 0;
top: 50%;
margin-top: -8px;
-webkit-animation-delay: 0.13s;
}
.loadEffect span:nth-child(2) {
left: 14px;
top: 14px;
-webkit-animation-delay: 0.26s;
}
.loadEffect span:nth-child(3) {
left: 50%;
top: 0;
margin-left: -8px;
-webkit-animation-delay: 0.39s;
}
.loadEffect span:nth-child(4) {
top: 14px;
right: 14px;
-webkit-animation-delay: 0.52s;
}
.loadEffect span:nth-child(5) {
right: 0;
top: 50%;
margin-top: -8px;
-webkit-animation-delay: 0.65s;
}
.loadEffect span:nth-child(6) {
right: 14px;
bottom: 14px;
-webkit-animation-delay: 0.78s;
}
.loadEffect span:nth-child(7) {
bottom: 0;
left: 50%;
margin-left: -8px;
-webkit-animation-delay: 0.91s;
}
.loadEffect span:nth-child(8) {
bottom: 14px;
left: 14px;
-webkit-animation-delay: 1.04s;
}
</style>
\ No newline at end of file
import Vue from 'vue'
import Message from './index.vue'
const messageBox = Vue.extend(Message)
Message.install = function (options) {
if(options === undefined || options === null){
options = {
title : '标题' ,
content : '弹窗内容'
}
}else if(typeof options === 'string' || typeof options === 'number'){
options = {
title : options.title ,
content : options.content
}
}
let instance = new messageBox({
data : options
}).$mount()
document.body.appendChild(instance.$el)
Vue.nextTick(()=>{
instance.visible = true;
})
}
export default Message
\ No newline at end of file
<template>
<transition name="fade">
<div class="js_dialog" v-if="visible">
<div class="weui-mask"></div>
<div class="weui-dialog">
<div class="weui-dialog__hd">{{ title }}</div>
<div class="weui-dialog__bd">{{ content }}</div>
<div class="weui-dialog__ft">
<a href="javascript:;" class="weui-dialog__btn weui-dialog__btn_primary" @click="visible=false">确定</a>
</div>
</div>
</div>
</transition>
</template>
<script>
export default{
data(){
return{
visible : true ,
content : '' ,
title : ''
}
}
}
</script>
<style scoped lang="less">
.weui-mask {
position: fixed;
z-index: 1000;
top: 0;
right: 0;
left: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
}
.weui-dialog__hd {
padding: 40px 80px 30px;
font-size: 32px;/*px*/
}
.weui-dialog {
position: fixed;
z-index: 5000;
width: 80%;
max-width: 600px;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
background-color: #FFFFFF;
text-align: center;
border-radius: 3px;
overflow: hidden;
}
.weui-dialog__bd {
padding: 0 20px 40px;
min-height: 80px;
font-size: 28px;/*px*/
line-height: 1.3;
word-wrap: break-word;
word-break: break-all;
color: #999999;
}
.weui-dialog__ft {
position: relative;
line-height: 96px;
font-size: 32px;/*px*/
display: -webkit-box;
display: -webkit-flex;
display: flex;
.weui-dialog__btn {
display: block;
-webkit-box-flex: 1;
-webkit-flex: 1;
flex: 1;
color: #3CC51F;
text-decoration: none;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
position: relative;
&:after{
content: " ";
position: absolute;
left: 0;
top: 0;
right: 0;
height: 1px;
border-top: 1px solid #D5D5D6;
color: #D5D5D6;
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
}
}
}
</style>
\ No newline at end of file
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import 'lib-flexible/flexible'
Vue.use(ElementUI)
Vue.config.productionTip = false
//global components
import Message from './components/Message'
Vue.prototype.$message = Message.install;
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
})
module.exports = file => require('@/views/' + file + '.vue').default // vue-loader at least v13.0.0+
module.exports = file => () => import('@/views/' + file + '.vue')
import Vue from 'vue'
import Router from 'vue-router'
const _import = require('./_import_' + process.env.NODE_ENV)
Vue.use(Router)
import Layout from '../views/layout/Layout.vue'
const constantRouterMap = [
{
path: '/404', name: '404', component: _import('errorPage/404')
},
{
path: '/',
component: Layout ,
children : [
{
path : '/' ,
component : _import('home/index') ,
name : 'index' ,
},
//原点凝视
{
path : '/stareOrigin/index' ,
component : _import('stareOrigin/index') ,
name : 'stareOrigin' ,
},
{
path : '/stareOrigin/startOrigin' ,
component : _import('stareOrigin/startOrigin') ,
name : 'startOrigin' ,
},
//之子运动
{
path : '/zhiExercise/index' ,
component : _import('zhiExercise/index') ,
name : 'zhiExercise' ,
},
//随机数字
{
path : '/randomNumber/index' ,
component : _import('randomNumber/index') ,
name : 'randomNumber' ,
},
{
path : '/randomNumber/startMemory' ,
component : _import('randomNumber/startMemory') ,
name : 'startMemory' ,
},
//随机字母
{
path : '/randomLetter/index' ,
component : _import('randomLetter/index') ,
name : 'randomLetter' ,
},
{
path : '/randomLetter/startMemoryLetter' ,
component : _import('randomLetter/startMemoryLetter') ,
name : 'startMemoryLetter' ,
},
//圆周率
{
path : '/pi/index' ,
component : _import('pi/index') ,
name : 'pi' ,
}
]
},
{ path: '*', redirect: '/404' }
]
export default new Router({
routes: constantRouterMap,
mode: 'history'
})
const getters = {
nickname : state => state.app.userInfo.nickname || JSON.parse(sessionStorage.getItem('userInfo')).nickname,
routers : state => state.routers ,
subRouters : state => state.subRouters
}
export default getters
import Vue from 'vue'
import Vuex from 'vuex'
import app from './modules/app'
Vue.use(Vuex)
const state = {
baseURL : process.env.NODE_ENV === 'development' ? 'http://api.xuetang.test.ledianyun.com/' :'https://xuetang.api.ledianyun.com/' ,
}
const store = new Vuex.Store({
modules : {
app
},
state
})
export default store
import { getCategoryList } from '../../api/category'
import { queryQuestionList } from '../../api/question'
import { querySpecialList } from '../../api/special'
import { getKeywords } from '../../api/keywords'
const app = {
state : {
//分类列表
categoryList : [] ,
//问答列表
questionList : [] ,
//专题列表
specialList : [] ,
//热词列表
hotKeys : [],
//目标分类
targetCategory : {},
//form
showFormModal : false ,
//侧边栏
showDrawer : false
},
getters : {
//获取分类
getCategoryList(state){
return state.categoryList.length ? state.categoryList : JSON.parse(sessionStorage.getItem('categoryList'));
},
//选中的文章信息
getTargetCategory(state){
return state.targetCategory;
},
//获取问答
getQuestionList(state){
return state.questionList.length ? state.questionList : JSON.parse(sessionStorage.getItem('questionList'));
},
//获取专题
getSpecialList(state){
return state.specialList.length ? state.specialList : JSON.parse(sessionStorage.getItem('specialList'));
},
//获取热词
getHotKeys(state){
return state.hotKeys.length ? state.hotKeys : JSON.parse(sessionStorage.getItem('hotKeys'));
},
//获取form状态
getFormStatus(state){
return state.showFormModal;
},
//获取状态
getDrawerStatus(state){
return state.showDrawer;
}
},
mutations : {
//插入分类
insertCategoryList(state,payload){
state.categoryList = payload;
sessionStorage.setItem('categoryList',JSON.stringify(payload));
},
//插入目标文章
insertTargetCategory(state,payload){
state.targetCategory = payload;
},
//插入问答
insertQuestionList(state,payload){
state.questionList = payload;
sessionStorage.setItem('questionList',JSON.stringify(payload));
},
//插入专题
insertSpecialList(state,payload){
state.specialList = payload;
sessionStorage.setItem('specialList',JSON.stringify(payload));
},
//插入热词
insertHotKeys(state,payload){
state.hotKeys = payload;
sessionStorage.setItem('hotKeys',JSON.stringify(payload));
},
//切换状态
toggleFormStatus(state,payload){
state.showFormModal = payload.flag;
},
//切换
toggleDrawerStatus(state){
state.showDrawer = !state.showDrawer
}
},
actions : {
//异步请求分类列表
dispatchGetCategoryList({ commit }){
//加载分类
let categoryList = JSON.parse(sessionStorage.getItem('categoryList'));
if( categoryList && categoryList.length ) return;
getCategoryList().then(res=>{
if(res.data && res.data.length){
if(res.data[0].children) res.data[0].children[0].is_edit = true;
commit('insertCategoryList',res.data);
}
})
},
//异步请求问答列表
dispatchGetQuestionList({ commit }){
let questionList = JSON.parse(sessionStorage.getItem('questionList'));
if( questionList && questionList.length ) return;
queryQuestionList().then(res => {
if ( res.data && res.data.info ) {
res.data.info.map((v,index)=>{
if( index === 0 ) v.is_expand = true
else v.is_expand = false
})
commit('insertQuestionList',res.data.info)
}
})
},
//异步请求专题列表
dispatchSpecialList({ commit }){
let specialList = JSON.parse(sessionStorage.getItem('specialList'));
if( specialList && specialList.length ) return;
querySpecialList().then(res => {
if ( res.data && res.data.info ) {
commit('insertSpecialList',res.data.info)
}
})
},
//异步请求热词
dispatchGetHotKeys( { commit }){
let hotKeys = JSON.parse(sessionStorage.getItem('hotKeys'));
if( hotKeys && hotKeys.length ) return;
getKeywords().then(res=>{
if(res.data && res.data.length) {
commit('insertHotKeys',res.data);
}
})
}
}
}
export default app
\ No newline at end of file
html,body {
height: 100%;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none !important;
margin: 0;
}
#app div{
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
#app{
height: 100%;
}
.divide{
height: 10px;
background-color: #F7F7F7;
}
.content img{
max-width: 100%;
}
.content p{
line-height: 20px;
}
\ No newline at end of file
html {
font-family: "Helvetica Neue", Helvetica, STHeiTi, Arial, sans-serif;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: transparent;
font-size: 62.5%;
}
body {
margin: 0;
font-size: 1.4rem;
line-height: 1.5;
color: #333333;
background-color: white;
height: 100%;
overflow-x: hidden;
-webkit-overflow-scrolling: touch;
-webkit-tap-highlight-color: transparent;
}
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
main,
nav,
section,
summary {
display: block;
}
audio,
canvas,
progress,
video {
display: inline-block;
vertical-align: baseline;
}
audio:not([controls]) {
display: none;
height: 0;
}
[hidden],
template {
display: none;
}
svg:not(:root) {
overflow: hidden;
}
a {
background: transparent;
text-decoration: none;
-webkit-tap-highlight-color: transparent;
color: #0088cc;
}
a:active {
outline: 0;
}
a:active {
color: #006699;
}
abbr[title] {
border-bottom: 1px dotted;
}
b,
strong {
font-weight: bold;
}
dfn {
font-style: italic;
}
mark {
background: #ff0;
color: #000;
}
small {
font-size: 80%;
}
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sup {
top: -0.5em;
}
sub {
bottom: -0.25em;
}
img {
border: 0;
vertical-align: middle;
}
hr {
-moz-box-sizing: content-box;
box-sizing: content-box;
height: 0;
}
pre {
overflow: auto;
white-space: pre;
white-space: pre-wrap;
word-wrap: break-word;
}
code,
kbd,
pre,
samp {
font-family: monospace, monospace;
font-size: 1em;
}
button,
input,
optgroup,
select,
textarea {
color: inherit;
font: inherit;
margin: 0;
}
button {
overflow: visible;
}
button,
select {
text-transform: none;
}
button,
html input[type="button"],
input[type="reset"],
input[type="submit"] {
-webkit-appearance: button;
cursor: pointer;
}
button[disabled],
html input[disabled] {
cursor: default;
}
button::-moz-focus-inner,
input::-moz-focus-inner {
border: 0;
padding: 0;
}
input {
line-height: normal;
}
input[type="checkbox"],
input[type="radio"] {
box-sizing: border-box;
padding: 0;
}
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
height: auto;
}
input[type="search"] {
-webkit-appearance: textfield;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
input{
outline: 0 none;
}
fieldset {
border: 1px solid #c0c0c0;
margin: 0 2px;
padding: 0.35em 0.625em 0.75em;
}
legend {
border: 0;
padding: 0;
}
textarea {
overflow: auto;
resize: vertical;
}
optgroup {
font-weight: bold;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
td,
th {
padding: 0;
}
html,
button,
input,
select,
textarea {
font-family: "Helvetica Neue", Helvetica, STHeiTi, Arial, sans-serif;
}
h1,
h2,
h3,
h4,
h5,
h6,
p,
figure,
form,
blockquote {
margin: 0;
}
ul,
ol,
li,
dl,
dd {
margin: 0;
padding: 0;
}
ul,
ol {
list-style: none outside none;
}
h1,
h2,
h3 {
line-height: 2;
font-weight: normal;
}
h1 {
font-size: 1.8rem;
}
h2 {
font-size: 1.6rem;
}
h3 {
font-size: 1.4rem;
}
input::-moz-placeholder,
textarea::-moz-placeholder {
color: #cccccc;
}
input:-ms-input-placeholder,
textarea:-ms-input-placeholder {
color: #cccccc;
}
input::-webkit-input-placeholder,
textarea::-webkit-input-placeholder {
color: #cccccc;
}
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
\ No newline at end of file
// 请求
import axios from 'axios'
const baseURL = process.env.NODE_ENV === 'development' ? 'http://api.xuetang.test.ledianyun.com/' :'https://xuetang.api.ledianyun.com/';
// create an axios instance
const service = axios.create({
baseURL : baseURL , // api的base_url
timeout : 30000, // request timeout
method : 'post' ,
transformRequest : [function (data) {
return JSON.stringify(data)
}],
headers : {
'Content-Type' : 'application/json'
}
})
// request interceptor
service.interceptors.request.use(config => {
//console.log(config)
return config;
} , error => {
// Do something with request error
console.log(error)
return Promise.reject(error)
})
// request interceptor
service.interceptors.response.use( response => {
if( response.data.error !== 0 ){
alert( response.data['error_reason'] )
return {};
}
return response.data;
} , error => {
alert( error.message )
return Promise.reject(error)
})
export default service
\ No newline at end of file
export default function (fn,delay) {
let timer = null;
return function () {
let context = this ,
args = arguments;
clearTimeout(timer);
timer = setTimeout(function () {
fn.apply(context,args)
},delay)
}
}
<template>
<div class="page">
<div class="content">
<img src="http://static.ledouya.com/20190306/164100_1551861782775.png" alt="">
<div class="text">页面不见了!</div>
</div>
</div>
</template>
<script>
export default {}
</script>
<style scoped>
.page {
position: relative;
height: 100%;
width: 100%;
background: #D1F3FF;
}
.page .content {
position: absolute;
width: 30%;
margin: 0 auto;
text-align: center;
top: 30%;
left: 50%;
transform: translate(-50%, -30%);
}
img{
width: 120px;
}
.text{
margin-top: 10px;
font-size: 12px; /*px*/
color: #999;
}
</style>
<template>
<div class='question-box'>
<div class="title">常见问题</div>
<div class="list">
<div class="item" v-for="(item,index) in questionList" :key="index" @click.stop="toggleExpandArticle(index)">
<div class="hd">
<div class="text">{{ item.name }}</div>
<img class="icon-arrow" src="../../../assets/images/arrow-down.png" v-if="item.is_expand" >
<img class="icon-arrow" src="../../../assets/images/arrow-right.png" v-else>
</div>
<div class="article-box" v-if="item.item_list.length && item.is_expand">
<a :href="`/display/${target.category_id}/details/${target.id}`" class="article" v-for="(target,idx) in item.item_list" :key="target.id">· {{ target.title }}</a>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default{
computed : {
...mapGetters({
questionList : 'getQuestionList'
})
},
methods : {
toggleExpandArticle(index){
this.questionList[index].is_expand = !this.questionList[index].is_expand;
this.$store.commit('insertQuestionList', this.questionList )
}
}
}
</script>
<style scoped lang="less">
.question-box{
padding: 30px 24px 0;
}
.title{
position: relative;
font-size: 30px;/*px*/
color: #999;
text-align: center;
&:after,&:before{
content: '';
display: block;
position: absolute;
top: 50%;
width: 40%;
border-bottom: 1px solid #E8E8E8; /*no*/
transform: translateY(-50%);
}
&:before{
left: 0;
}
&:after{
right: 0;
}
}
.item{
position: relative;
padding-top: 30px;
padding-bottom: 30px;
.hd{
display: flex;
align-items: center;
justify-content: space-between;
.text{
font-size: 34px;/*px*/
color: #111111;
font-weight:500;
}
.icon-arrow{
width: 30px;
height: 30px;
}
}
.article-box{
padding-top: 10px;
.article{
display: block;
margin: 10px 0;
color: #3091FE;
}
}
&:after{
content: '';
display: block;
position: absolute;
height: 1px;/*no*/
background-color: #E8E8E8;
left: -30px;
right: -30px;
bottom: 0;
}
}
</style>
\ No newline at end of file
<template>
<div class='special-box'>
<div class="title">热门专题</div>
<div class="list">
<a :href="item.link" class="item" v-for="(item,index) in specialList">
<img class="icon" :src="item.picture" :title="item.name">
<h2>{{ item.name }}</h2>
</a>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default{
computed : {
...mapGetters({
specialList : 'getSpecialList'
})
},
methods : {
}
}
</script>
<style scoped lang="less">
.special-box{
padding: 30px 24px 0;
}
.title{
position: relative;
font-size: 30px;/*px*/
color: #999;
text-align: center;
&:after,&:before{
content: '';
display: block;
position: absolute;
top: 50%;
width: 40%;
border-bottom: 1px solid #E8E8E8; /*no*/
transform: translateY(-50%);
}
&:before{
left: 0;
}
&:after{
right: 0;
}
}
.list{
padding: 30px 24px 0;
overflow: hidden;
}
.item{
float: left;
text-align: center;
width: 25%;
margin-bottom: 30px;
.icon{
width: 90px;
height: 90px;
margin: 0 auto;
}
h2{
margin-top: 10px;
font-size: 30px;/*px*/
color: #666;
}
}
</style>
\ No newline at end of file
<template>
<div class='wrapper'>
<div class="title">训练工具/应用工具</div>
<div class="label">记忆类</div>
<div class="list">
<div class="item-parent" v-for="(item, index) in memory">
<div :key="index" class="item" @click="linkTo(item.path)">{{item.label}}</div>
</div>
</div>
<div class="label">速读类</div>
<div class="list">
<div class="item-parent" v-for="(item, index) in speed">
<div :key="index" class="item" @click="linkTo(item.path)">{{item.label}}</div>
</div>
</div>
<div class="label">心算类</div>
<div class="list">
<div class="item-parent" v-for="(item, index) in heartCount">
<div :key="index" class="item" @click="linkTo(item.path)">{{item.label}}</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
memory: [
{
label: '国学经典',
path: ''
},
{
label: '随机数字',
path: '/randomNumber/index'
},
{
label: '随机字母',
path: '/randomLetter/index'
},
{
label: '圆周率',
path: '/pi/index'
},
],
speed: [
{
label: '原点凝视',
path: '/stareOrigin/index'
},
{
label: '之字运动',
path: '/zhiExercise/index'
},
],
heartCount: [
{
label: '正向训练',
path: ''
},
]
}
},
methods: {
linkTo(url) {
this.$router.push({
path : url
})
}
}
}
</script>
<style lang="less">
.wrapper {
padding: 0 24px;
.title {
width: 100%;
height: 80px;
display: flex;
align-items: center;
justify-content: center;
color: #333;
font-size: 26px;
}
.label {
width: 100%;
height: 80px;
color: #111111;
font-weight: bold;
font-size: 30px;
line-height: 80px;
}
.list {
display: flex;
align-items: center;
/*justify-content: space-between;*/
flex-wrap: wrap;
}
.list .item{
width: 210px;
height: 80px;
display: flex;
align-items: center;
justify-content: center;
border: 2px solid #999;
border-radius: 8px;
color: #999;
font-size: 28px;
}
.item-parent {
width: 33.33%;
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 20px;
}
}
</style>
<template>
<div class='app-wrapper'>
<!-- <app-nav></app-nav>-->
<router-view/>
<!-- <app-footer></app-footer>-->
<!-- <Form/>-->
<!-- <Drawer/>-->
</div>
</template>
<script>
import AppNav from './components/AppNav.vue'
import AppFooter from './components/AppFooter.vue'
import Form from '../../components/Form'
import Drawer from '../../components/Drawer'
export default {
components: {
AppNav,
AppFooter,
Form,
Drawer
}
}
</script>
<style scoped lang="less">
.app-wrapper {
position: relative;
/*padding-top: 130px;*/
/*padding-bottom: 100px;*/
height: 100%;
overflow-x: hidden;
}
</style>
<template>
<div class='ft-btn' @click.stop="toggleFormStatus( { flag : true })">开店咨询</div>
</template>
<script>
import { mapMutations } from 'vuex'
export default{
methods : {
...mapMutations([
'toggleFormStatus'
])
}
}
</script>
<style scoped lang="less">
.ft-btn{
position: fixed;
left: 0;
right: 0;
bottom: 0;
font-size: 32px; /*px*/
color: #fff;
padding: 25px 30px;
text-align: center;
background-color: #3091FE;
}
</style>
\ No newline at end of file
<template>
<div class='app-nav'>
<img class="app-logo" src="http://static.ledouya.com/Flu7n1DcDv45J4qNSj9snKHmdTs2" @click="handleBack">
<img class="icon-group" src="../../../assets/images/icon-group.png" @click="toggleDrawerStatus">
</div>
</template>
<script>
import { mapMutations } from 'vuex'
export default{
methods : {
...mapMutations([
'toggleDrawerStatus'
]),
handleBack(){
this.$router.push({
path : '/'
})
}
}
}
</script>
<style scoped lang="less">
.app-nav{
position: fixed;
top: 0;
left: 0;
right: 0;
padding: 30px 24px;
display: flex;
align-items: center;
justify-content: space-between;
background-color: #fff;
z-index: 5;
}
.app-logo{
width: 280px;
height: 70px;
}
.icon-group{
width: 70px;
height: 70px;
}
</style>
\ No newline at end of file
<template>
<div class="content">
<div class="line-style">
<div class="label">圆周率</div>
</div>
<div class="line-style">
<div class="label" style="margin-top: 6px">划辅助线</div>
<div class="list">
<div class="item" :class="{active: checked == 0}" @click="change(0)">不划</div>
<div class="item" :class="{active: checked == 2}" @click="change(2)">2</div>
<div class="item" :class="{active: checked == 3}" @click="change(3)">3</div>
<div class="item" :class="{active: checked == 4}" @click="change(4)">4</div>
<div class="item" :class="{active: checked == 5}" @click="change(5)">5</div>
<div class="item" :class="{active: checked == 8}" @click="change(8)">8</div>
</div>
</div>
<div class="number-list">
<div class="number-item" v-for="(item,index) in number" :key="index" :style="{borderRightColor: item.border?'#666':''}">{{item.num}}</div>
</div>
<div class="start">记忆完成</div>
</div>
</template>
<script>
export default {
name: "index",
data() {
return {
checked: 0,
number: [
{
num: 1,
border: false
},
{
num: 4,
border: false
},
{
num: 1,
border: false
},
{
num: 5,
border: false
},
{
num: 9,
border: false
},
{
num: 2,
border: false
},
{
num: 6,
border: false
},
{
num: 5,
border: false
},
{
num: 3,
border: false
},
{
num: 5,
border: false
},
{
num: 8,
border: false
},
{
num: 9,
border: false
},
{
num: 7,
border: false
},
{
num: 9,
border: false
},
{
num: 3,
border: false
},{
num: 2,
border: false
},
{
num: 3,
border: false
},
{
num: 8,
border: false
},
{
num: 4,
border: false
},
{
num: 6,
border: false
},
{
num: 2,
border: false
},
{
num: 6,
border: false
},{
num: 4,
border: false
},
{
num: 3,
border: false
},
{
num: 3,
border: false
},
{
num: 8,
border: false
},
{
num: 3,
border: false
},
{
num: 2,
border: false
},
{
num: 7,
border: false
},
{
num: 9,
border: false
},
{
num: 5,
border: false
},
{
num: 0,
border: false
},
{
num: 2,
border: false
},
{
num: 8,
border: false
},
{
num: 8,
border: false
},
{
num: 4,
border: false
},
{
num: 1,
border: false
},
{
num: 9,
border: false
},
{
num: 7,
border: false
},
{
num: 1,
border: false
},
{
num: 6,
border: false
},
{
num: 9,
border: false
},
{
num: 3,
border: false
},
{
num: 9,
border: false
},
{
num: 9,
border: false
},
{
num: 3,
border: false
},
{
num: 7,
border: false
},
{
num: 5,
border: false
},
{
num: 1,
border: false
},
{
num: 0,
border: false
},
{
num: 5,
border: false
},
{
num: 8,
border: false
},
{
num: 2,
border: false
},
{
num: 0,
border: false
},
{
num: 9,
border: false
},
{
num: 7,
border: false
},
]
}
},
methods: {
change(val) {
if(this.checked == val) return;
this.checked = val;
this.number.forEach(v=>{
v.border = false
})
if(this.checked != 0) {
this.number.forEach((vv,ii)=>{
if((ii+1)%val == 0) {
vv.border = true;
}
})
}
}
}
}
</script>
<style scoped>
.content {
padding: 30px 24px;
}
.line-style {
display: flex;
/*align-items: center;*/
margin-top: 20px;
}
.line-style .label {
font-size: 30px;
color: #333;
width: 150px;
}
.line-style .list {
display: flex;
align-items: center;
flex-wrap: wrap;
}
.line-style .item {
height: 60px;
display: flex;
align-items: center;
justify-content: center;
border: 2px solid #666;
border-radius: 8px;
margin-left: 20px;
padding: 0 24px;
margin-bottom: 20px;
}
.line-style .active {
color: #fff;
background: #409eff;
border-color: #409eff;
}
.number-list {
display: flex;
flex-wrap: wrap;
margin-top: 20px;
}
.number-item {
width: 40px;
height: 50px;
display: flex;
align-items: center;
justify-content: center;
border-right: 2px solid transparent;
}
.start {
margin: 60px auto ;
width: 500px;
height: 80px;
border-radius: 40px;
font-size: 32px;
background: #409EFF;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
}
</style>
<template>
<div class="content">
<div class="title">随机字母设置</div>
<div class="number">记忆数量
<input type="number" placeholder="请输入记忆数量" class="input" v-model="number">
</div>
<el-button type="primary" class="start" @click="start">开始训练</el-button>
</div>
</template>
<script>
export default {
name: "index",
data() {
return {
number: 50
}
},
methods: {
start() {
this.$router.push({
path : '/randomLetter/startMemoryLetter'
})
}
}
}
</script>
<style scoped>
.content {
display: flex;
flex-direction: column;
padding-top: 48px;
align-items: center;
}
.title {
color: #1685ff;
font-size: 34px;
font-weight: bold;
margin-bottom: 50px;
}
.number {
display: flex;
align-items: center;
font-size: 30px;
}
.input {
width: 300px;
margin: 0 12px;
height: 70px;
border: 2px solid #617e99;
padding-left: 10px;
border-radius: 4px;
}
.el-input__inner {
height: 90px;
}
.start {
margin-top: 60px;
width: 500px;
height: 80px;
border-radius: 40px;
font-size: 32px;
}
</style>
<template>
<div class="content">
<div class="line-style">
<div class="label">随机字母</div>
</div>
<div class="line-style">
<div class="label" style="margin-top: 6px">划辅助线</div>
<div class="list">
<div class="item" :class="{active: checked == 0}" @click="change(0)">不划</div>
<div class="item" :class="{active: checked == 2}" @click="change(2)">2</div>
<div class="item" :class="{active: checked == 3}" @click="change(3)">3</div>
<div class="item" :class="{active: checked == 4}" @click="change(4)">4</div>
<div class="item" :class="{active: checked == 5}" @click="change(5)">5</div>
<div class="item" :class="{active: checked == 8}" @click="change(8)">8</div>
</div>
</div>
<div class="number-list">
<div class="number-item" v-for="(item,index) in number" :key="index" :style="{borderRightColor: item.border?'#666':''}">{{item.num}}</div>
</div>
<div class="start">记忆完成</div>
</div>
</template>
<script>
export default {
name: "startMemoryLetter",
data() {
return {
checked: 0,
number: [
{
num: 'g',
border: false
},
{
num: 'h',
border: false
},
{
num: 'j',
border: false
},
{
num: 'v',
border: false
},
{
num: 'd',
border: false
},
{
num: 't',
border: false
},
{
num: 's',
border: false
},
{
num: 'x',
border: false
},
{
num: 'm',
border: false
},
{
num: 'y',
border: false
},
{
num: 'w',
border: false
},
{
num: 'q',
border: false
},
{
num: 'u',
border: false
},
{
num: 'g',
border: false
},
{
num: 'b',
border: false
},{
num: 'd',
border: false
},
{
num: 'e',
border: false
},
{
num: 'p',
border: false
},
{
num: 'o',
border: false
},
{
num: 'a',
border: false
},
{
num: 'z',
border: false
},
{
num: 'c',
border: false
},{
num: 'b',
border: false
},
{
num: 'n',
border: false
},
{
num: 'l',
border: false
},
{
num: 'k',
border: false
},
{
num: 'i',
border: false
},
{
num: 'g',
border: false
},
{
num: 'r',
border: false
},
]
}
},
methods: {
change(val) {
if(this.checked == val) return;
this.checked = val;
this.number.forEach(v=>{
v.border = false
})
if(this.checked != 0) {
this.number.forEach((vv,ii)=>{
if((ii+1)%val == 0) {
vv.border = true;
}
})
}
}
}
}
</script>
<style scoped>
.content {
padding: 30px 24px;
}
.line-style {
display: flex;
/*align-items: center;*/
margin-top: 20px;
}
.line-style .label {
font-size: 30px;
color: #333;
width: 150px;
}
.line-style .list {
display: flex;
align-items: center;
flex-wrap: wrap;
}
.line-style .item {
height: 60px;
display: flex;
align-items: center;
justify-content: center;
border: 2px solid #666;
border-radius: 8px;
margin-left: 20px;
padding: 0 24px;
margin-bottom: 20px;
}
.line-style .active {
color: #fff;
background: #409eff;
border-color: #409eff;
}
.number-list {
display: flex;
flex-wrap: wrap;
margin-top: 20px;
}
.number-item {
width: 40px;
height: 50px;
display: flex;
align-items: center;
justify-content: center;
border-right: 2px solid transparent;
}
.start {
margin: 60px auto ;
width: 500px;
height: 80px;
border-radius: 40px;
font-size: 32px;
background: #409EFF;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
}
</style>
<template>
<div class="content">
<div class="title">随机数字设置</div>
<div class="number">记忆数量
<input type="number" placeholder="请输入记忆数量" class="input" v-model="number">
</div>
<el-button type="primary" class="start" @click="start">开始训练</el-button>
</div>
</template>
<script>
export default {
name: "index",
data() {
return {
number: 50
}
},
methods: {
start() {
this.$router.push({
path : '/randomNumber/startMemory'
})
}
}
}
</script>
<style scoped>
.content {
display: flex;
flex-direction: column;
padding-top: 48px;
align-items: center;
}
.title {
color: #1685ff;
font-size: 34px;
font-weight: bold;
margin-bottom: 50px;
}
.number {
display: flex;
align-items: center;
font-size: 30px;
}
.input {
width: 300px;
margin: 0 12px;
height: 70px;
border: 2px solid #617e99;
padding-left: 10px;
border-radius: 4px;
}
.el-input__inner {
height: 90px;
}
.start {
margin-top: 60px;
width: 500px;
height: 80px;
border-radius: 40px;
font-size: 32px;
}
</style>
<template>
<div class="content">
<div class="line-style">
<div class="label">随机数字</div>
</div>
<div class="line-style">
<div class="label" style="margin-top: 6px">划辅助线</div>
<div class="list">
<div class="item" :class="{active: checked == 0}" @click="change(0)">不划</div>
<div class="item" :class="{active: checked == 2}" @click="change(2)">2</div>
<div class="item" :class="{active: checked == 3}" @click="change(3)">3</div>
<div class="item" :class="{active: checked == 4}" @click="change(4)">4</div>
<div class="item" :class="{active: checked == 5}" @click="change(5)">5</div>
<div class="item" :class="{active: checked == 8}" @click="change(8)">8</div>
</div>
</div>
<div class="number-list">
<div class="number-item" v-for="(item,index) in number" :key="index" :style="{borderRightColor: item.border?'#666':''}">{{item.num}}</div>
</div>
<div class="start">记忆完成</div>
</div>
</template>
<script>
export default {
name: "startMemory",
data() {
return {
checked: 0,
number: [
{
num: 2,
border: false
},
{
num: 6,
border: false
},
{
num: 7,
border: false
},
{
num: 3,
border: false
},
{
num: 5,
border: false
},
{
num: 3,
border: false
},
{
num: 5,
border: false
},
{
num: 5,
border: false
},
{
num: 2,
border: false
},
{
num: 6,
border: false
},
{
num: 7,
border: false
},
{
num: 3,
border: false
},
{
num: 5,
border: false
},
{
num: 3,
border: false
},
{
num: 5,
border: false
},{
num: 2,
border: false
},
{
num: 6,
border: false
},
{
num: 7,
border: false
},
{
num: 3,
border: false
},
{
num: 5,
border: false
},
{
num: 3,
border: false
},
{
num: 5,
border: false
},{
num: 2,
border: false
},
{
num: 6,
border: false
},
{
num: 7,
border: false
},
{
num: 3,
border: false
},
{
num: 5,
border: false
},
{
num: 3,
border: false
},
{
num: 5,
border: false
},
]
}
},
methods: {
change(val) {
if(this.checked == val) return;
this.checked = val;
this.number.forEach(v=>{
v.border = false
})
if(this.checked != 0) {
this.number.forEach((vv,ii)=>{
if((ii+1)%val == 0) {
vv.border = true;
}
})
}
}
}
}
</script>
<style scoped>
.content {
padding: 30px 24px;
}
.line-style {
display: flex;
/*align-items: center;*/
margin-top: 20px;
}
.line-style .label {
font-size: 30px;
color: #333;
width: 150px;
}
.line-style .list {
display: flex;
align-items: center;
flex-wrap: wrap;
}
.line-style .item {
height: 60px;
display: flex;
align-items: center;
justify-content: center;
border: 2px solid #666;
border-radius: 8px;
margin-left: 20px;
padding: 0 24px;
margin-bottom: 20px;
}
.line-style .active {
color: #fff;
background: #409eff;
border-color: #409eff;
}
.number-list {
display: flex;
flex-wrap: wrap;
margin-top: 20px;
}
.number-item {
width: 40px;
height: 50px;
display: flex;
align-items: center;
justify-content: center;
border-right: 2px solid transparent;
}
.start {
margin: 60px auto ;
width: 500px;
height: 80px;
border-radius: 40px;
font-size: 32px;
background: #409EFF;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
}
</style>
<template>
<div class="content">
<div class="title">原点凝视</div>
<div class="paragraph"><span>项目意义:</span>训练视觉专注力和视觉控制的稳定性,持续性,以及抗干扰能力。</div>
<div class="paragraph"><span>训练方法:</span>端正坐姿,将屏幕与视线垂直,3分钟内尽量不要眨眼,凝视图片黑色三角
区中心,如果感觉图片在动,则表示你的注意力涣散。发生这种现象时,请迅速眨一下眼睛,调整注意力,使图片保持“静止”。
</div>
<div class="start" @click="start">开始训练</div>
</div>
</template>
<script>
export default {
name: "index",
data() {
return {
}
},
methods: {
start() {
this.$router.push({
path: '/stareOrigin/startOrigin'
})
}
}
}
</script>
<style scoped>
.content {
padding: 48px 48px 140px 48px;
}
.title {
text-align: center;
color: #000000;
font-size: 34px;
font-weight: bold;
}
.paragraph {
color: #666;
font-size: 28px;
line-height: 58px;
margin-top: 20px;
}
.paragraph span {
color: #000;
font-weight: bold;
}
.start {
width: 500px;
height: 80px;
display: flex;
align-items: center;
justify-content: center;
color: white;
background: #409eff;
border-radius: 40px;
position: fixed;
bottom: 50px;
left: 50%;
transform: translateX(-50%);
}
</style>
<template>
<div class="content">
<div class="time">{{msg}}</div>
<img class="image" src="http://static.ledouya.com/FgFDS5yGwSp3cCa4Jec9Rn9KApH4" alt="">
</div>
</template>
<script>
export default {
name: "startOrigin",
data() {
return {
msg: '3分0秒',
timer: '',
maxtime: 179
}
},
methods: {
CountDown() {
this.timer = setInterval(()=>{
if (this.maxtime >= 0) {
let minutes = Math.floor(this.maxtime / 60);
let seconds = Math.floor(this.maxtime % 60);
this.msg = minutes + "分" + seconds + "秒";
this.maxtime = this.maxtime - 1;
} else{
clearInterval(this.timer);
this.$alert('这是一段内容', '标题名称', {
confirmButtonText: '确定',
callback: action => {
this.$message({
type: 'info',
message: ''
});
}
});
}
},1000)
}
},
mounted() {
this.CountDown();
}
}
</script>
<style scoped>
.content {
display: flex;
align-items: center;
flex-direction: column;
padding-top: 48px;
}
.time {
color: #409eff;
font-size: 30px;
margin-bottom: 20px;
}
.image {
width: 90%;
}
</style>
<template>
<!--extraLinks-->
<div class="extra-box" v-if="articleList && articleList.length">
<div class="extra-title">拓展阅读</div>
<ul class="links">
<li class="link-item" v-for="(item,index) in articleList" :key="index" @click.stop="handleItemClick(item)">· {{ item.title }}</li>
</ul>
</div>
</template>
<script>
export default{
props : ['articleList'] ,
methods : {
handleItemClick(item){
this.$router.push({
path : `/display/${item.category_id}/details/${item.id}`
})
}
}
}
</script>
<style scoped lang="less">
.extra-box{
margin-top: 40px;
}
.extra-title{
font-size: 24px;/*px*/
margin-bottom: 10px;
color: #666;
padding-left: 8px;
}
.link-item {
line-height: 48px;/*px*/
display: block;
font-size: 24px;/*px*/
color: #38f;
}
</style>
\ No newline at end of file
<template>
<div class='info-box'>
<div class="breadcrumb">
<router-link :to="`/display/${details.category_id}`" class="title">{{ details.category_name }}</router-link>
<span>正文</span>
</div>
<div class="article">
<div class="art-title">{{ details.title }}</div>
<div class="time">{{ details.created_at }}</div>
<div class="content" v-html="details.content"></div>
</div>
<!--extraLinks-->
<extra></extra>
</div>
</template>
<script>
import Extra from './Extra.vue'
export default{
props : ['details'],
components : {
Extra
},
data(){
return{
}
}
}
</script>
<style scoped lang="less">
.breadcrumb{
color: #333;
font-size: 14px;
padding-bottom: 15px;
.title{
color: #38f;
&:after{
font-size: 12px;
content: "/";
display: inline-block;
color: #bbb;
margin-left: 5px;
margin-right: 5px;
}
}
}
.article{
.art-title{
color: #333;
font-size: 24px;
line-height: 45px;
margin-bottom: 20px;
}
.time{
line-height: 16px;
color: #999;
font-size: 12px;
margin-bottom: 30px
}
.content {
line-height: 1.2;
p {
margin: 5px 0;
}
}
}
</style>
\ No newline at end of file
<template>
<div class='detail-box'>
<div class="title">{{ details.title }}</div>
<div class="time">{{ details.created_at }}</div>
<div class="content" v-html="details.content"></div>
<Extra :articleList="details.recommend_detail"></Extra>
<Loading :loading-="loading"></Loading>
</div>
</template>
<script>
import { getArticleDetails } from '@/api/article'
//components
import Loading from '../../components/Loading'
import Extra from './components/Extra.vue'
export default{
components : {
Loading ,
Extra
},
data(){
return{
loading : false ,
article_id : '' ,
details : {}
}
},
watch : {
'$route' : function () {
this.article_id = this.$route.params.article_id;
this.getArticleDetails();
}
},
methods : {
//获取详情
getArticleDetails(){
this.loading = true;
getArticleDetails({
id : this.article_id
}).then(res=>{
this.loading = false;
if(res.data){
this.details = res.data;
}
})
}
},
created(){
this.article_id = this.$route.params.article_id;
this.getArticleDetails();
}
}
</script>
<style scoped lang="less">
.detail-box{
padding: 24px 30px 60px;
overflow: auto;
height: 100%;
}
.title{
font-size: 48px;/*px*/
color: #000;
}
.time{
font-size: 30px;/*px*/
color: #888;
margin-top: 16px;
margin-bottom: 30px;
}
</style>
\ No newline at end of file
<template>
<div class='list-wrapper'>
<div class="divide"></div>
<div class="hd">
<div class="title" v-if="keywords.length">搜索<span class="topic">"{{ keywords }}"</span>的相关结果</div>
<div class="title" v-if="cateName.length">{{cateName}}</div>
<div class="tab">
<div class="tab-item" :class="{ active : activeIndex === 0 }" @click="handleNavItemClick(0)">全部</div>
<div class="tab-item" :class="{ active : activeIndex === 1 }" @click="handleNavItemClick(1)">最新</div>
<div class="tab-item" :class="{ active : activeIndex === 2 }" @click="handleNavItemClick(2)">最热</div>
</div>
</div>
<template v-if="articleList.length">
<div class="bd">
<div class="article" v-for="(item,index) in articleList" :key="item.id" @click="handleArticleClick(item)">
<div class="title">{{ item.title }}</div>
<div class="ft">
<div class="time">{{ item.created_at }}</div>
<div class="num">
<img class="icon-eye" src="../../assets/images/icon-eye.png" alt="">
<div class="text">{{ item.views_num }}</div>
</div>
</div>
</div>
</div>
</template>
<template v-if="(!articleList.length) && !loading">
<div class="empty">没有找到相关结果</div>
</template>
<!--Loading-->
<Loading :loading="loading"></Loading>
</div>
</template>
<script>
import throttle from '../../utils/throttle'
//components
import Loading from '../../components/Loading'
//api
import { getArticleList } from '@/api/article'
export default{
components : {
Loading
},
data(){
return{
keywords : '' ,
cateName : '' ,
loading : false ,
element : null ,
activeIndex : 0 ,
articleList : [] ,
currentPage : 1 ,
totalPage : 1
}
},
watch : {
'$route' : function () {
if( this.$route.query.keywords ) this.keywords = this.$route.query.keywords;
else this.keywords = '';
if( this.$route.query.cateName ) this.cateName = this.$route.query.cateName;
else this.cateName = '';
this.getList(true);
}
},
methods : {
handleNavItemClick(index){
if(this.activeIndex === index) return;
this.activeIndex = index;
this.getList(true);
},
handleScrollLower(){
console.log('get more')
//距离顶部的距离
let scrollTop = this.element.scrollTop;
//可视区的高度
let windowHeight = this.element.clientHeight;
//滚动条的总高度
let scrollHeight = this.element.scrollHeight;
if( scrollHeight - scrollTop - windowHeight < 2 ){
if( this.currentPage > this.totalPage ) return;
this.getList();
}
},
getList(refresh){
this.loading = true;
if( refresh ) this.currentPage = 1;
getArticleList({
page : this.currentPage ,
page_size : 10 ,
keywords : this.keywords || '' ,
sort_type : this.activeIndex ,
category_id : this.$route.params.id || ''
}).then(res=>{
this.loading = false;
if(res.data && res.data.info){
if( refresh ) this.articleList = [];
this.articleList = [...this.articleList,...res.data.info];
this.totalPage = res.data.total_page;
this.currentPage ++;
}
})
},
handleArticleClick(e){
this.$router.push({
path : `/display/${e.category_id}/details/${e.id}`
})
}
},
created(){
if( this.$route.query.keywords ) this.keywords = this.$route.query.keywords;
if( this.$route.query.cateName ) this.cateName = this.$route.query.cateName;
this.getList();
},
mounted(){
this.element = document.querySelector('.list-wrapper')
this.element.onscroll = throttle(this.handleScrollLower,200);
},
destroyed(){
this.element.onscroll = null;
}
}
</script>
<style scoped lang="less">
@import "./stylesheets/dispaly.less";
</style>
\ No newline at end of file
.list-wrapper{
padding-bottom: 60px;
height: 100%;
overflow: auto;
}
.hd{
position: relative;
padding: 30px 24px;
.title{
font-size: 34px;
color: #666;
.topic{
color: #e00;
}
}
.tab{
display: flex;
align-items: center;
margin-top: 20px;
.tab-item{
padding: 4px 15px;
font-size: 22px;
margin-right: 20px;
color: #fff;
border-radius: 8px;
opacity: .5;
background-color: #3091FE;
&.active{
opacity: 1;
}
}
}
&:after{
content: '';
display: block;
position: absolute;
left: 30px;
right: 30px;
bottom: 0;
height: 1px; /*no*/
background-color: #E5E5E5;
}
}
.bd{
padding-left: 24px;
padding-right: 24px;
.article{
padding-top: 30px;
padding-bottom: 30px;
border-bottom: 1px solid #E5E5E5;/*no*/
.title{
font-size: 32px;
color: #333;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.ft{
margin-top: 15px;
display: flex;
align-items: center;
justify-content: space-between;
.time{
font-size: 26px;
color: #C6C6C6;
}
.num{
display: flex;
align-items: center;
.icon-eye{
width: 32px;
height: 32px;
margin-right: 10px;
}
.text{
font-size: 26px;
color: #C6C6C6;
}
}
}
}
}
.empty{
padding-top: 300px;
text-align: center;
font-size: 30px;
color: #999;
}
\ No newline at end of file
<template>
<div class="content">
<div class="title">“之”字运动</div>
<div class="paragraph"><span>项目意义:</span>训练眼球横向运动和纵向运动肌肉的力量,提高逐行阅读所必须的眼球之子运动控制能力。</div>
<div class="paragraph"><span>训练方法:</span>端正坐姿,将屏幕与视线垂直,头不转动,视点随黑球移动,在一分钟内看清黑球上3次出现的不同字符,
结束后写出正确的字符则本局训练通过。
</div>
<div class="paragraph"><span>注意事项:</span></div>
<div class="paragraph">1,本项目平时也可以脱离屏幕,单纯做眼球横向和纵向运动,头不转动,眼球最大范围地快速左右看和上下看即可;</div>
<div class="paragraph">2,若眼球有伤或正在发炎,请治疗痊愈后才进行本项目训练。训练初期有眼球酸胀感属于正常现象;</div>
<div class="speed">
黑球运动速度
<div class="item" :class="{active: speed == 1}" @click="changSpeed(1)">慢速</div>
<div class="item" :class="{active: speed == 2}" @click="changSpeed(2)">中速</div>
<div class="item" :class="{active: speed == 3}" @click="changSpeed(3)">快速</div>
</div>
<div class="start">之子运动</div>
</div>
</template>
<script>
export default {
name: "index",
data() {
return {
speed: 2
}
},
methods: {
changSpeed(val) {
this.speed = val;
}
}
}
</script>
<style scoped>
.content {
padding: 48px 48px 140px 48px;
}
.title {
text-align: center;
color: #000000;
font-size: 34px;
font-weight: bold;
}
.paragraph {
color: #666;
font-size: 28px;
line-height: 58px;
margin-top: 20px;
}
.paragraph span {
color: #000;
font-weight: bold;
}
.start {
width: 500px;
height: 80px;
display: flex;
align-items: center;
justify-content: center;
color: white;
background: #409eff;
border-radius: 40px;
/*margin: 300px auto 0;*/
position: fixed;
bottom: 50px;
left: 50%;
transform: translateX(-50%);
}
.speed {
display: flex;
align-items: center;
width: 100%;
justify-content: center;
color: #666;
margin-top: 20px;
}
.speed .item{
width: 80px;
height: 80px;
display: flex;
align-items: center;
justify-content: center;
border: 2px solid #666;
border-radius: 8px;
margin-left: 20px;
}
.speed .active {
color: #fff;
background: #409eff;
border-color: #409eff;
}
</style>
File mode changed
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!