Commit ae467204 authored by 郭铭瑶's avatar 郭铭瑶 🤘

初步完成

parent b19df767
{
"presets": [
["env", {
"modules": false,
"useBuiltIns": "entry",
"targets": {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}],
"stage-2"
],
"plugins": [
"transform-vue-jsx",
"transform-runtime",
["import", {
"libraryName": "view-design",
"libraryDirectory": "src/components"
}]
]
}
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
/build/
/config/
/dist/
/*.js
// https://eslint.org/docs/user-guide/configuring
module.exports = {
root: true,
parserOptions: {
parser: 'babel-eslint'
},
env: {
browser: true,
},
// https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
// consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules.
extends: ['plugin:vue/essential'],
// required to lint *.vue files
plugins: [
'vue'
],
// add your custom rules here
rules: {
// allow debugger during development
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
"indent": [
"error",
2
],
'linebreak-style': 'off',
"quotes": [
"error",
"single",
],
"semi": [
"error",
"never",
],
"no-console": 0,
}
}
.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": {}
}
}
# national-dashboard
# dashboard
全国稻田、渔业数据大屏
\ No newline at end of file
> A Vue.js project
## Build Setup
``` bash
# install dependencies
npm install
# serve with hot reload at localhost:8080
npm run dev
# build for production with minification
npm run build
# build for production and view the bundle analyzer report
npm run build --report
```
For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader).
// 用于打包时在dist目录中输出electron.js和package.json
const fs = require('fs')
const path = require('path')
class BuildElectronPlugin {
apply(compiler) {
compiler.plugin('emit', (compilation, callback) => {
const filename = path.join(__dirname, '../electron.js')
const outFilename = (filename.split('/')).pop()
new Promise((resolve, reject) => {
fs.readFile(filename, (err, data) => {
if (err) {
reject(err)
} else {
resolve(data)
}
})
}).then(res => {
const jsonText = `{"main": "${outFilename}"}`
compilation.assets[outFilename.toString()] = {
source () {
return res;
},
size () {
return fs.statSync(filename).size;
}
}
compilation.assets['package.json'] = {
source () {
return jsonText
},
size () {
return jsonText.length
}
}
})
callback();
});
}
}
module.exports = BuildElectronPlugin;
'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
}
}
// generate loader string to be used with extract text plugin
function generateLoaders (loader, loaderOptions) {
const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]
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,
publicPath: '../../',
fallback: 'vue-style-loader'
})
} else {
return ['vue-style-loader'].concat(loaders)
}
}
/**
* 下面的stylus配置便于可全局使用stylus定义的变量
*/
const stylusOptions = {
import: [
path.join(__dirname, '../src/assets/css/variables.styl')
],
path: [
path.join(__dirname, '../src/assets'),
path.join(__dirname, '../')
]
}
// 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', stylusOptions),
styl: generateLoaders('stylus', stylusOptions)
}
}
// 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)
}
const createLintingRule = () => ({
test: /\.(js|vue)$/,
loader: 'eslint-loader',
enforce: 'pre',
include: [resolve('src'), resolve('test')],
options: {
formatter: require('eslint-friendly-formatter'),
emitWarning: !config.dev.showEslintErrorsInOverlay
}
})
module.exports = {
context: path.resolve(__dirname, '../'),
entry: {
app: ['babel-polyfill', './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'),
'#': resolve('static'),
}
},
module: {
rules: [
...(config.dev.useEslint ? [createLintingRule()] : []),
{
test: /\.vue$/,
loader: 'vue-loader',
options: vueLoaderConfig
},
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
},
{
test: /view-design.src.*?js$/,
loader: 'babel-loader',
},
{
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]')
}
},
{
test: /\.styl(us)?$/,
use: [
'vue-style-loader',
'css-loader',
'stylus-loader'
]
}
]
},
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 BuildElectronPlugin = require('./build-electron-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: [
// new BuildElectronPlugin(),
// 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: 'localhost', // 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-
// Use Eslint Loader?
// If true, your code will be linted during bundling and
// linting errors and warnings will be shown in the console.
useEslint: true,
// If true, eslint errors and warnings will also be shown in the error overlay
// in the browser.
showEslintErrorsInOverlay: false,
/**
* 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"'
}
const {app, BrowserWindow} = require('electron')
const url = require('url')
const path = require('path')
let win
function createWindow() {
// const file = 'index.html'
win = new BrowserWindow({})
win.maximize()
win.setResizable(false)
// win.loadURL(url.format({
// pathname: path.join(__dirname, file),
// protocol: 'file:',
// slashes: true,
// }))
// win.webContents.openDevTools()
win.loadFile('./index.html')
win.on('closed', () => {
win = null
})
}
app.on('ready', createWindow)
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
if (win = null) {
createWindow()
}
})
<!DOCTYPE html>
<html id="html">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
<title>全国专题</title>
<style>
html {
font-size: 1.6vh;
}
</style>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
This diff is collapsed.
{
"name": "national-dashboard",
"version": "1.0.0",
"description": "A Vue.js project",
"author": "yaominguo <missgmy@yahoo.com>",
"private": true,
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"start": "npm run dev",
"electron": "electron electron.js",
"lint": "eslint --fix --ext .js,.vue src",
"build": "node build/build.js",
"build:mac": "node build/build.js && electron-packager ./dist dashboard --platform=mas --electron-version=6.1.0 --overwrite",
"build:win": "node build/build.js && electron-packager ./dist dashboard --platform=win32 --electron-version=6.1.0 --overwrite"
},
"dependencies": {
"animate.css": "^3.7.2",
"axios": "^0.19.0",
"babel-polyfill": "^6.26.0",
"countup.js": "^2.0.4",
"echarts": "^4.4.0",
"odometer": "^0.4.8",
"qs": "^6.9.1",
"view-design": "^4.0.2",
"vue": "^2.5.2",
"vue-countup-v2": "^4.0.0",
"vue-odometer": "^1.0.2",
"vue-router": "^3.0.1",
"vue-seamless-scroll": "^1.1.17"
},
"devDependencies": {
"autoprefixer": "^7.1.2",
"babel-core": "^6.22.1",
"babel-eslint": "^8.2.1",
"babel-helper-vue-jsx-merge-props": "^2.0.3",
"babel-loader": "^7.1.1",
"babel-plugin-import": "^1.12.2",
"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",
"electron": "^3.0.11",
"electron-packager": "^13.0.0",
"eslint": "^4.15.0",
"eslint-friendly-formatter": "^3.0.0",
"eslint-loader": "^1.7.1",
"eslint-plugin-vue": "^4.0.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",
"rimraf": "^2.6.0",
"semver": "^5.3.0",
"shelljs": "^0.7.6",
"stylus": "^0.54.7",
"stylus-loader": "^3.0.2",
"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">
<!-- <transition name="custom-classes-transition" enter-active-class="animated fadeIn" leave-active-class="animated fadeOut"> -->
<router-view :key="$route.fullPath"/>
<!-- </transition> -->
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
routes: ['home', 'industry', 'special', 'production', 'trade', 'fish', 'disease', 'enterprise', 'flow'],
cur: 0,
timer: null,
timeOuter: null,
seconds: 1000 * 10
}
},
// mounted() {
// // this.$router.push({
// // name: this.routes[this.cur]
// // })
// // this.setTimer()
// // document.body.addEventListener('mousemove', this.removeTimer)
// },
// beforeDestroy() {
// clearInterval(this.timer)
// },
// methods: {
// setTimer() {
// this.timer = setInterval(() => {
// this.cur += 1
// if (this.cur >= this.routes.length) {
// this.cur = 0
// }
// this.$router.push({
// name: this.routes[this.cur]
// })
// }, this.seconds)
// },
// removeTimer() {
// clearTimeout(this.timeOuter)
// clearInterval(this.timer)
// this.timer = null
// this.timeOuter = setTimeout(this.setTimer, this.seconds / 10)
// },
// },
// watch: {
// $route(to, from) {
// if (to.name && this.cur != this.routes.indexOf(to.name)) {
// this.cur = this.routes.indexOf(to.name)
// }
// // if (to.name === 'home') {
// // clearInterval(this.timer)
// // clearTimeout(this.timeOuter)
// // this.timer = null
// // this.cur = 0
// // } else {
// // this.cur = this.routes.indexOf(to.name)
// // }
// }
// }
}
</script>
<style lang="stylus">
@import './assets/css/variables.styl'
@import './assets/css/reset.styl'
@font-face
font-family DIN
src url(./assets/font/DIN-Medium.otf)
@font-face
font-family Microsoft YaHei UI
src url(./assets/font/Microsoft-YaHei-UI-Bold.ttf)
@font-face
font-family Pangmenzhengdao
src url(./assets/font/pangmenzhengdao.ttf)
html, body
background-color #000 !important
width 100%
height 100%
user-select none
#app
font-family DIN, 'Avenir', Helvetica, Arial, sans-serif
-webkit-font-smoothing antialiased
-moz-osx-font-smoothing grayscale
width 100%
height 100%
font-size 1rem
overflow: hidden
color $fontColor
/* 设置滚动条的样式 */
::-webkit-scrollbar {
width: 0.5rem;
}
// /* 滚动槽 */
// ::-webkit-scrollbar-track {
// -webkit-box-shadow: inset006pxrgba(0,0,0,0.3);
// /* border-radius: 10px; */
// }
/* 滚动条滑块 */
::-webkit-scrollbar-thumb {
/* border-radius: 10px; */
background:rgba(91, 213, 255, 0.2)
-webkit-box-shadow:inset006pxrgba(0,0,0,0.5);
}
::-webkit-scrollbar-thumb:window-inactive {
background:rgba(91, 213, 255, 0.2)
}
</style>
$color-main = #5BD5FF
#app
.ivu-select-selection
.ivu-select-dropdown
font-size 0.8rem
background-color rgba(0,0,0,0.2)
border-radius 0
border 0.1rem solid $color-main
color $color-main
padding 0
.ivu-select-arrow
color $color-main
.ivu-select-selected-value
font-size 0.8rem
.ivu-select-item
.ivu-dropdown-item
font-size 0.8rem !important
text-align center
color $color-main
&:hover
&.ivu-select-item-selected
color #fff
background $color-main
$font-yahei = Microsoft YaHei UI, 'Avenir', Helvetica, Arial, sans-serif
$font-pang = Pangmenzhengdao, 'Avenir', Helvetica, Arial, sans-serif
$font-din = DIN, 'Avenir', Helvetica, Arial, sans-serif
$color-map(opacity = 0.3)
rgba(91, 213, 255, opacity)
$color-green = #71C012
$gd-layout()
width 100%
height 100%
background-size cover
background-position center
background-color #061627
position relative
display grid
grid-gap 1rem
padding 1rem
$fontColor = #2c3e50
$edgeColor = #2ee4f5
$cardBg = rgba(19, 78, 115, 0.4)
$cardBorder = 0.1rem solid #1c425f
$cardFontColor = #0eb2ee
import MonitorBrief from './monitor-brief.vue'
export default (Vue) => {
Vue.component('m-brief', MonitorBrief)
}
<template>
<div class="brief-container">
<span class="label">{{label}}</span>
<m-count class="count" :value="value"/>
<span>{{unit}}</span>
</div>
</template>
<script>
export default {
name: 'MonitorBrief',
props: {
label: {
type: String,
default: '',
},
count: {
type: Number,
default: 0,
},
unit: {
type: String,
default: '',
}
},
computed: {
value() {
return this.count
}
}
}
</script>
<style lang="stylus" scoped>
.brief-container
display inline-block
color #fff
font-size 0.8rem
.label
color $cardFontColor
margin-right 0.5rem
.count
font-size 1.4rem
font-weight bold
</style>
import MonitorCard from './monitor-card.vue'
export default (Vue) => {
Vue.component('m-card', MonitorCard)
}
<template>
<div class="monitor-card">
<div v-if="mode == 1" class="card-wrapper">
<div class="card-title">
<span class="s"/>
<span class="m"/>
<p>{{title}}</p>
<span class="m"/>
<span class="s"/>
</div>
<div class="edge left-top"/>
<div class="edge right-top"/>
<div class="edge left-bottom"/>
<div class="edge right-bottom"/>
<div class="edge shadow left"/>
<div class="edge shadow right"/>
<slot />
</div>
<div v-else-if="mode == 2" class="map-card-wrapper">
<div class="card-title">{{title}}</div>
<div class="card-content">
<div class="edge left-bottom"/>
<div class="edge right-bottom"/>
<slot />
</div>
</div>
</div>
</template>
<script>
export default {
name: 'MonitorCard',
props: {
title: {
type: String,
default: '标题',
},
mode: {
type: [String, Number],
default: '1',
}
}
}
</script>
<style lang="stylus" scoped>
$edgeWidth = 0
$size()
height 100%
width 100%
.monitor-card
$size()
.card-wrapper
$size()
background $cardBg
// border $cardBorder
box-shadow inset 0 0 0.8rem rgba(100,200,255,0.5)
padding 0.5rem 1rem
position relative
>.card-title
display flex
align-items center
color $cardFontColor
border-bottom $cardBorder
padding-bottom 0.5rem
font-size 1.2rem
font-weight 460
p
margin 0 0.5rem
span
display inline-block
background $edgeColor
margin 0 0.1rem
&.s
width 0.2rem
height 1rem
opacity 0.5
&.m
width 0.3rem
height 1.2rem
>.edge
position absolute
width 1rem
height 1rem
border: 0.12rem solid $edgeColor
&.left-top
border-right-color transparent
border-bottom-color transparent
top $edgeWidth
left $edgeWidth
&.right-top
border-left-color transparent
border-bottom-color transparent
top $edgeWidth
right $edgeWidth
&.left-bottom
border-right-color transparent
border-top-color transparent
bottom $edgeWidth
left $edgeWidth
&.right-bottom
border-left-color transparent
border-top-color transparent
bottom $edgeWidth
right $edgeWidth
&.shadow
background $edgeColor
height 24%
width 0.1rem
border none
top 0
bottom 0
margin auto
&.left
left 0
box-shadow 1px 0px 6px 1px $edgeColor
&.right
right 0
box-shadow -1px 0px 6px 1px $edgeColor
.map-card-wrapper
$size()
.card-title
color #fff
font-size 1.4rem
font-family $font-pang
.card-content
background $color-map(0.1)
border-top 0.12rem solid $edgeColor
height calc(100% - 2rem)
position relative
>.edge
position absolute
width 1rem
height 1rem
border: 0.12rem solid $edgeColor
&.left-bottom
border-right-color transparent
border-top-color transparent
bottom $edgeWidth
left $edgeWidth
&.right-bottom
border-left-color transparent
border-top-color transparent
bottom $edgeWidth
right $edgeWidth
</style>
import MonitorChart from './monitor-chart.vue'
export default (Vue) => {
Vue.component('m-chart', MonitorChart)
}
<template>
<div class="chart" ref="chart"/>
</template>
<script>
export default {
name: 'CommonChart',
props: {
data: {
type: Array,
default() {
return []
},
},
showLegend: {
type: Boolean,
default: true,
},
options: {
type: Object,
default() {
return {
colors: null,
grid: {},
legend: {},
tooltip: {},
xAxis: {},
yAxis: {},
}
}
},
},
mounted() {
if (this.data.length > 0) {
this.$nextTick(this.init)
}
},
methods: {
init() {
const chart = this.$echarts.init(this.$refs.chart)
chart.setOption(this.config)
}
},
computed: {
config() {
const options = {}
const colors = this.options.colors || ['#21640D', '#2F8B14', '#71C012', '#FFCE34', '#F47C1F']
options.grid = Object.assign(this.defaultOptions.grid, this.options.grid)
options.tooltip = Object.assign(this.defaultOptions.tooltip, this.options.tooltip)
if(this.showLegend) {
options.legend = Object.assign(this.defaultOptions.legend, this.options.legend)
if (this.options.series.type === 'pie') {
options.color = this.options.color || colors
options.series = [this.options.series]
options.series[0].data = options.legend.data = this.data
return options
}
options.legend.data = this.data.map(item => item.name)
}
options.xAxis = Object.assign(this.defaultOptions.xAxis, this.options.xAxis)
options.yAxis = Object.assign(this.defaultOptions.yAxis, this.options.yAxis)
options.series = this.data.map((item, index) => {
let color = colors[index]
let shadow = {}
if (Array.isArray(color)) { // 如果颜色是数组则渐变
const shadowColor = color[0] || '#0076FF'
color = new this.$echarts.graphic.LinearGradient(0, 0, 0, 1, [
{offset: 0, color: color[0]},
{offset: 1, color: color[1]}
])
shadow = {
shadowColor: shadowColor,
shadowBlur: 6,
}
}
const result = {
name: item.name,
barWidth: '50%',
itemStyle: { color, ...shadow },
data: item.data || []
}
if (this.options.series) {
return Object.assign(result, this.options.series)
}
return result
})
return options
},
defaultOptions() {
return {
grid: {
top: '25%',
left: '3%',
right: '3%',
bottom: '5px',
width: 'auto',
height: 'auto',
containLabel: true,
},
legend: {
top: '5%',
left: '6%',
width: '100%',
data: [],
itemWidth: 15,
textStyle: {
color: '#ccc',
fontSize: this.fontSize,
},
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
xAxis: {
type: 'category',
data: [],
axisLabel: {
textStyle: {
color: '#ccc',
},
fontSize: this.fontSize,
},
axisLine: {
lineStyle: {
color: 'rgba(91,213,255,0.3)'
}
},
splitLine: {
show: true,
lineStyle: {
color: 'rgba(91,213,255,0.3)'
}
}
},
yAxis: {
nameTextStyle: {
color: '#fff',
fontSize: this.fontSize,
},
type: 'value',
splitLine: {
show: true,
lineStyle: {
color: 'rgba(91,213,255,0.3)'
}
},
axisLabel: {
textStyle: {
color: '#ccc',
},
fontSize: this.fontSize,
},
axisLine: {
lineStyle: {
color: 'rgba(91,213,255,0.3)'
}
},
},
}
},
fontSize() {
// return Math.floor(window.innerWidth / 100) - 1
return Math.floor(screen.height * 1.48 / 100)
},
},
watch: {
data(cur, past) {
if (cur && cur !== past && cur.length > 0) {
this.init()
}
}
},
}
</script>
<style lang="stylus" scoped>
.chart
height 100%
width 100%
</style>
import MonitorCount from './monitor-count.vue'
export default (Vue) => {
Vue.component('m-count', MonitorCount)
}
<template>
<ICountUp
:delay="delay"
:endVal="value"
:options="config"
@ready="onReady"
/>
</template>
<script>
import ICountUp from 'vue-countup-v2'
export default {
name: 'MonitorCount',
components: {
ICountUp,
},
props: {
delay: {
type: Number,
default: 500,
},
value: {
type: Number,
default: 0,
},
decimal: { // 默认保留2位小数点
type: Number,
default: 2,
},
options: {
type: Object,
default() {
return {
useEasing: true,
useGrouping: true,
separator: ',',
decimal: '.',
prefix: '',
suffix: '',
}
}
},
autoUpdate: {
type: Boolean,
default: false,
},
updateDuration: {
type: Number,
default: 1,
},
},
computed: {
config() {
return Object.assign(this.options, {decimalPlaces: this.decimal})
}
},
methods: {
onReady(instance, countup) {
if (!this.autoUpdate) return
setTimeout(() => {
instance.reset()
instance.update(instance.endVal)
}, 1000 * 60 * this.updateDuration)
},
}
}
</script>
import MonitorFlip from './monitor-flip.vue'
export default (Vue) => {
Vue.component('m-flip', MonitorFlip)
}
<template>
<IOdometer
class="monitor-flip"
:value="num"
/>
</template>
<script>
import IOdometer from 'vue-odometer'
export default {
name: 'MonitorFlip',
components: {
IOdometer,
},
props: {
value: {
type: Number,
default: 0,
},
},
data() {
return {
num: 0,
}
},
mounted() {
this.$nextTick(() => {
this.num = this.value
})
},
}
</script>
<style lang="stylus" scoped>
.monitor-flip
font-family $font-din
</style>
<style lang="stylus">
@import 'odometer/themes/odometer-theme-default.css'
.monitor-flip
.odometer-digit
background linear-gradient($color-map() 47%, transparent 50%, $color-map() 53%)
margin-right 0.4rem
padding 0 0.4rem
.odometer-digit-inner
padding 0 0.4rem
</style>
import MonitorProgress from './monitor-progress'
export default (Vue) => {
Vue.component('m-progress', MonitorProgress)
}
<template>
<div class="monitor-progress" :style="style">
<div class="progress-container" :style="containerStyle">
<div class="progress-bar"/>
<div class="progress-bg" :style="bgStyle"/>
</div>
<b v-if="!hideInfo" class="progress-info" :style="infoStyle">
<m-count :value="percent"/>%
</b>
</div>
</template>
<script>
export default {
name: 'MonitorProgress',
props: {
percent: {
type: Number,
default: 0,
},
color: {
type: String | Array,
default: '#0176fe',
},
size: {
type: Number,
default: 14,
},
'hide-info': {
type: Boolean,
default: false,
},
'text-inside': {
type: Boolean,
default: false,
}
},
computed: {
style() {
const size = Math.round(this.size / 10)
const result = {
padding: `${(size / 5).toFixed(1)}rem ${(size / 4.5).toFixed(1)}rem`,
}
if (!this.hideInfo && !this.textInside) {
result.width = '85%'
} else {
if (this.percent >= 95) {
result.width = '85%'
} else {
result.width = '100%'
}
}
return result
},
containerStyle() {
return {
height: `${(this.size / 10).toFixed(1)}rem`,
width: `${this.percent >= 100 ? 100 : this.percent}%`,
}
},
bgStyle() {
if ('string' === typeof this.color) {
return {
background: this.color
}
} else {
return {
background: `linear-gradient(90deg, ${this.color[0]}, ${this.color[1]})`
}
}
},
infoStyle() {
let info = {
left: '102%'
}
if (this.textInside && this.percent < 95) {
info = {
left: `${this.percent + 1}%`,
}
}
return {
...info,
fontSize: `${(this.size * 0.7 / 10).toFixed(1)}rem`,
color: 'string' === typeof this.color ? this.color : this.color[1],
}
},
}
}
</script>
<style lang="stylus" scoped>
$radius = 2rem
.monitor-progress
position relative
border-radius $radius
background rgba(0,0,0,0.18)
box-shadow inset 0 0 0.2rem 0 #000
.progress-container
width 0
position relative
border-radius $radius
transition width 2s ease
div
position: absolute
top 0
left 0
width 100%
height 100%
border-radius $radius
&.progress-bar
z-index 1
opacity 0.2
background-size 17rem
background-image repeating-linear-gradient(45deg, #fff, #fff 0.8rem, transparent 0.8rem, transparent 1.2rem)
animation rolling 20s linear infinite running
.progress-info
display flex
align-items center
justify-content center
position absolute
left 0
top 0
height 100%
transition left 2s ease
text-shadow 0 0 0.6rem rgba(255,255,255,0.5)
@keyframes rolling
to
background-position-x 17rem
</style>
// 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 'babel-polyfill'
import Vue from 'vue'
import App from './App'
import router from './router'
import echarts from 'echarts'
import {Button, Divider, Progress, Select, Option, Circle, Icon, Dropdown, DropdownMenu, DropdownItem} from 'view-design'
import animate from 'animate.css'
import ajax from '@/server/ajax'
import api from '@/server/api'
import MonitorCard from '@/components/MonitorCard'
import MonitorChart from '@/components/MonitorChart'
import MonitorCount from '@/components/MonitorCount'
import MonitorFlip from '@/components/MonitorFlip'
import MonitorBrief from '@/components/MonitorBrief'
import MonitorProgress from '@/components/MonitorProgress'
import 'view-design/dist/styles/iview.css'
Vue.config.productionTip = false
Vue.prototype.$echarts = echarts
Vue.prototype.$ajax = ajax
Vue.prototype.$api = api
Vue.use(animate)
Vue.use(MonitorCard)
Vue.use(MonitorCount)
Vue.use(MonitorFlip)
Vue.use(MonitorBrief)
Vue.use(MonitorProgress)
Vue.use(MonitorChart)
Vue.component('Button', Button)
Vue.component('Divider', Divider)
Vue.component('Progress', Progress)
Vue.component('Select', Select)
Vue.component('Option', Option)
Vue.component('i-circle', Circle)
Vue.component('Icon', Icon)
Vue.component('Dropdown', Dropdown)
Vue.component('DropdownMenu', DropdownMenu)
Vue.component('DropdownItem', DropdownItem)
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
import Vue from 'vue'
import Router from 'vue-router'
const ChinaFarming = () => import('@/views/china-farming')
const ChinaFishing = () => import('@/views/china-fishing')
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
redirect: '/farming'
},
{
path: '/farming',
name: 'farming',
component: ChinaFarming
},
{
path: '/fishing',
name: 'fishing',
component: ChinaFishing
},
]
})
import axios from 'axios'
import qs from 'qs'
import api from './api'
const Axios = axios.create({
baseURL: api.BASE_URL,
timeout: 50000,
})
Axios.interceptors.request.use(config => {
// 启动loading,添加token
// config.headers.Authorization = token
return config
}, error => {
return Promise.reject(error)
})
Axios.interceptors.response.use(response => {
// TODO 返回的数据status判断错误操作等……
return response.data
}, error => {
return Promise.resolve(error.response)
})
export default {
post(url, data) {
return Axios({
method: 'POST',
url,
data: qs.stringify(data),
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
}
}).then(res => res)
},
get(url, params) {
return Axios({
method: 'GET',
url,
params, // get 请求时带的参数
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': 'application/json;charset=UTF-8',
}
}).then(res => res)
}
}
let IMG_URL = ''
let FILE_URL = ''
switch (process.env.NODE_ENV) {
case 'production':
IMG_URL = 'http://10.221.1.181:8080/dist/static/'
FILE_URL = '/dist/static/'
break
default:
IMG_URL = 'http://localhost:8080/static/'
FILE_URL = '/static/'
};
export default {
BASE_URL: 'http://sunmonster.vicp.cc:41318/pudong/',
IMG_URL,
FILE_URL,
GET_SMART_INFO: '/api/discoverInfo',
GET_SMART_DETAIL: '/api/discoverDetail',
GET_TS_LIST: '/api/findUnCaseTsList',
GET_BX_LIST: '/api/findUnCaseBxList',
GET_COMPANY_CYCLE: '/api/findCycle',
GET_CREDIT_HIGH: '/api/findCreditHigh',
GET_CREDIT_MIDDLE: '/api/findCreditMiddle',
GET_CREDIT_LOW: '/api/findCreditLow',
}
/** 公共方法 */
export default {
/**
* 在深层数据结构中取值(为了替代类似 res && res.data && res.data.content这种写法)
* @param {Object} obj [必填-需要取值的目标对象(例:res)]
* @param {String} path [必填-数据结构路径(例:'data.content')]
* @param {Any} defaultValue [可选-如果取不到值则默认返回该值]
*/
confirm(obj, path, defaultValue = null) {
if (!obj || typeof(obj) != 'object' || !path || typeof(path) != 'string') return
const reducer = (accumulator, currentValue) =>
(accumulator && accumulator[currentValue]) ?
accumulator[currentValue] :
defaultValue
path = path.split('.')
return path.reduce(reducer, obj)
},
/**
* ----- 柯里化版本 (为了不再重复输入obj这个参数) -----
* 在深层数据结构中取值(为了替代类似 res && res.data && res.data.content这种写法)
* @param {Object} obj [必填-需要取值的目标对象(例:res)]
*/
confirm_currying(obj) {
if (!obj || typeof(obj) != 'object') return
return (path, defaultValue = null) => {
if (!path || typeof(path) != 'string') return
const reducer = (accumulator, currentValue) =>
(accumulator && accumulator[currentValue]) ?
accumulator[currentValue] :
defaultValue
path = path.split('.')
return path.reduce(reducer, obj)
}
},
/**
* 判断一维数组中是否存在某个值
* @param {String} value 需要校验的字符串
* @param {Array} validList 被查找的一维数组
* @return {Boolean} 是否存在的结果
*/
oneOf(value, validList) {
for (let i = 0; i < validList.length; i++) {
if (value === validList[i]) {
return true
}
}
return false
},
/**
* 转换为金钱格式(千分位且保留两位小数)
* @param {Number | String} num [需转换的数字或字符串]
*/
toMoney(num) {
if (!num) {
return 0.00
}
num = this.toFloat(num).toFixed(2)
const arr = num.toString().split('.')
let int = (arr[0] || 0).toString(),
result = ''
while (int.length > 3) {
result = ',' + int.slice(-3) + result
int = int.slice(0, int.length - 3)
}
if (int) {
result = int + result
}
return `${result}.${arr[1]}`
},
/**
* 手机号码校验
* @param {String} num [需校验的手机号码]
*/
checkPhone(num) {
if (!num) return false
const filter = /^1[3-9][0-9]{9}$/
return filter.test(num)
},
/**
* 固定电话号码校验
* @param {String} num [需校验的固话]
*/
checkTel(num) {
if (!num) return false
const filter = /^(?:0[1-9][0-9]{1,2}-)?[2-8][0-9]{6,7}$/
return filter.test(num)
},
/**
* 身份证号码校验
* @param {String} num [需校验的身份证号码]
*/
checkID(num) {
if (!num) return false
const filter = /(^\d{15}$)|(^\d{17}([0-9]|X)$)/
return filter.test(num)
},
/**
* 数字校验(整数或者小数)
* @param {String} num [需校验的数字]
*/
checkNumber(num) {
if (!num && num != 0) return false
const filter = /^[0-9]+\.{0,1}[0-9]{0,2}$/
return filter.test(num)
},
/**
* 邮编校验(整数或者小数)
* @param {String} num [需校验的数字]
*/
checkZipCode(num) {
if (!num && num != 0) return false
const filter = /^[0-9]{6}$/
return filter.test(num)
},
/**
* 文本校验(只能为中文、英文、数字组合,不允许其他特殊符号)
* @param {String} txt [需校验的文本]
*/
checkContent(txt) {
const filter = /^[\u4E00-\u9FA5A-Za-z0-9]+$/
return filter.test(txt)
},
/**
* 密码校验(6位以上数字字母的组合)
* @param {String} txt [需校验的文本]
*/
checkPassword(num) {
if (!num && num != 0) return false
const filter = /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,}$/
return filter.test(num)
},
/**
* 获取URL执行参数值
* @param {String} variable 地址参数名
* @return false 未找到;
*/
getQueryVariable(variable) {
var query = window.location.search.substring(1)
var vars = query.split('&')
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split('=')
if (pair[0] == variable) {
return pair[1]
}
}
},
/**
* 获取当前年
*
*/
getCurrentYear() {
var date = new Date
return date.getFullYear()
},
/**
* 接收带时分秒的时间格式,返回去掉时分秒的时间格式
* @param {String} val
*/
strTime(val) {
if (val === undefined || val == null) return
val = val.toString()
if (val == null || val == '') {
return ''
} else {
return val.slice(0, val.indexOf(' '))
}
},
/**
* 判断传入参数的类型,以字符串的形式返回
* @obj:数据
**/
dataType(obj) {
if (obj === null) return 'Null'
if (obj === undefined) return 'Undefined'
return Object.prototype.toString.call(obj).slice(8, -1)
},
/**
* 处理对象参数值,排除对象参数值为”“、null、undefined,并返回一个新对象
**/
dealObjectValue(obj) {
var param = {}
if (obj === null || obj === undefined || obj === '') return param
for (var key in obj) {
if (this.dataType(obj[key]) === 'Object') {
param[key] = dealObjectValue(obj[key])
} else if (obj[key] !== null && obj[key] !== undefined && obj[key] !== '') {
param[key] = obj[key]
}
}
return param
},
/**
* 判断是否是ie并返回版本号
*/
IEVersion() {
const userAgent = navigator.userAgent //取得浏览器的userAgent字符串
const isIE = userAgent.indexOf('compatible') > -1 && userAgent.indexOf('MSIE') > -1 //判断是否IE<11浏览器
const isEdge = userAgent.indexOf('Edge') > -1 && !isIE //判断是否IE的Edge浏览器
const isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf('rv:11.0') > -1
if(isIE) {
const reIE = new RegExp('MSIE (\\d+\\.\\d+);')
reIE.test(userAgent)
const fIEVersion = parseFloat(RegExp['$1'])
if(fIEVersion == 7) {
return 7
} else if(fIEVersion == 8) {
return 8
} else if(fIEVersion == 9) {
return 9
} else if(fIEVersion == 10) {
return 10
} else {
return 6//IE版本<=7
}
} else if(isEdge) {
return 'edge'//edge
} else if(isIE11) {
return 11 //IE11
}else{
return -1//不是ie浏览器
}
},
/**
* 输入数字转换成大写字母,比如 输入 0 输出 'A'
* @param {Number} num 输入的数字
*/
numToLetter(num) {
if (!num && num != 0) return null
return (Number(num) + 10).toString(36).toUpperCase()
}
}
This diff is collapsed.
<template>
<div id="container" :style="`background-image: url(${require('@/assets/images/stars-bg.png')})`">
<ChinaMap ref="map" :data="mapData" @select="handleMapSelect"/>
<ThemeTitle style="width: 130%;margin-left:10%;">全国稻田综合种养驾驶舱</ThemeTitle>
<div class="year-select">
<Dropdown>
<p>
主显示
<span class="year">
2018
<Icon type="md-arrow-dropdown"></Icon>
</span>
</p>
<DropdownMenu slot="list">
<DropdownItem>2018</DropdownItem>
<DropdownItem>2017</DropdownItem>
</DropdownMenu>
</Dropdown>
<Dropdown>
<p>
对比
<span class="year">
2017
<Icon type="md-arrow-dropdown"></Icon>
</span>
</p>
<DropdownMenu slot="list">
<DropdownItem>2018</DropdownItem>
<DropdownItem>2017</DropdownItem>
</DropdownMenu>
</Dropdown>
</div>
<div class="area">
<p>全国稻田综合种养面积</p>
<b v-if="area"><m-flip :value="area"/></b>
<span>公顷</span>
<div>
<p>淡水养殖产量<b><m-count :value="waterProduction" :decimal="0"/></b></p>
<p>稻田产量<b><m-count :value="farmProduction" :decimal="0"/></b></p>
</div>
</div>
<div class="box1">
<m-card mode="2" :title="`${curCardIndex ? mapData[curCardIndex].name : '全国'}历年数据对比`">
<div class="data-wrapper">
<div>
<p><span/>历年稻田综合种养面积变化(公顷)</p>
<m-chart :options="options1" :data="data1" :showLegend="false"/>
</div>
<div>
<p><span/>历年稻田综合种养产量变化(吨)</p>
<m-chart :options="options2" :data="data2"/>
</div>
<div>
<p><span/>历年稻田综合种养整体变化情况(吨/公顷)</p>
<m-chart :options="options3" :data="data3"/>
</div>
</div>
</m-card>
</div>
<div class="box2">
<m-card mode="2" title="各地区稻田综合种养情况">
<area-card ref="areaCard" @select="handleCardSelect" :list="mapData"/>
</m-card>
</div>
</div>
</template>
<script>
import ThemeTitle from './components/title'
import ChinaMap from './components/map'
import AreaCard from './components/area-card'
export default {
name: 'ChinaFarming',
components: {
ThemeTitle,
ChinaMap,
AreaCard,
},
data() {
return {
curCardIndex: null,
area: 0,
waterProduction: 0,
farmProduction: 0,
mapData: [],
options1: {
colors: [['#1FECFF', '#0076FF']],
grid: {
top: '5%',
bottom: '15%',
},
xAxis: {
data: ['2017', '2018']
},
series: {
type: 'bar',
barWidth: '20%',
}
},
data1: [],
options2: {
colors: [['#FAD961', '#F76B1C'], ['#B4EC51', '#429321'], ['#1FECFF', '#0076FF']],
grid: {
top: '15%',
bottom: '10%',
},
legend: {
left: '60%',
top: '-2%',
itemWidth: 10,
itemHeight: 10,
},
xAxis: {
data: ['2017', '2018'],
},
series: {
type: 'bar',
barGap: 0,
barWidth: '20%',
}
},
data2: [],
options3: {
colors: [['#FAD961', '#F76B1C'], ['#B4EC51', '#429321'], ['#1FECFF', '#0076FF']],
grid: {
top: '15%',
bottom: '10%',
},
legend: {
left: '45%',
top: '-2%',
itemWidth: 10,
itemHeight: 10,
},
xAxis: {
data: ['2017', '2018'],
},
series: {
type: 'bar',
barGap: 0,
barWidth: '20%',
}
},
data3: [],
}
},
mounted() {
setTimeout(() => {
this.area = 2028262
this.waterProduction = 29598384
this.farmProduction = 2333269
this.mapData = [
{ name: '北京', value: 177, area: 100, water: 0, farm: 25962},
{ name: '天津', value: 42, area: 100, water: 638, farm: 27227},
{ name: '河北', value: 102, area: 100, water: 3783, farm: 1523},
{ name: '山西', value: 81, area: 100, water: 3783, farm: 1523},
{ name: '内蒙古', value: 17, area: 100, water: 3783, farm: 1523},
{ name: '辽宁', value: 67, area: 100, water: 3783, farm: 1523},
{ name: '吉林', value: 182, area: 100, water: 3783, farm: 1523},
{ name: '黑龙江', value: 100, area: 100, water: 3783, farm: 1523},
{ name: '上海', value: 24, area: 256897, water: 219, farm: 94293},
{ name: '江苏', value: 299, area: 100, water: 249994, farm: 325294},
{ name: '浙江', value: 114, area: 100, water: 3783, farm: 1523},
{ name: '安徽', value: 29, area: 100, water: 3783, farm: 1523},
{ name: '福建', value: 316, area: 100, water: 3783, farm: 1523},
{ name: '江西', value: 91, area: 100, water: 3783, farm: 1523},
{ name: '山东', value: 19, area: 100, water: 3783, farm: 1523},
{ name: '河南', value: 137, area: 100, water: 3783, farm: 1523},
{ name: '湖北', value: 26, area: 100, water: 690722, farm: 440298},
{ name: '湖南', value: 114, area: 100, water: 3783, farm: 1523},
{ name: '重庆', value: 91, area: 100, water: 3783, farm: 1523},
{ name: '四川', value: 25, area: 100, water: 3783, farm: 1523},
{ name: '贵州', value: 62, area: 100, water: 3783, farm: 1523},
{ name: '云南', value: 83, area: 100, water: 3783, farm: 1523},
{ name: '西藏', value: 9, area: 100, water: 3783, farm: 1523},
{ name: '陕西', value: 80, area: 100, water: 3783, farm: 1523},
{ name: '甘肃', value: 256, area: 100, water: 3783, farm: 1523},
{ name: '青海', value: 10, area: 100, water: 3783, farm: 1523},
{ name: '宁夏', value: 18, area: 100, water: 3783, farm: 1523},
{ name: '新疆', value: 67, area: 100, water: 3783, farm: 1523},
{ name: '广东', value: 123, area: 100, water: 1674, farm: 2817456},
{ name: '广西', value: 59, area: 100, water: 3783, farm: 1523},
{ name: '海南', value: 14, area: 100, water: 3783, farm: 366861},
]
this.data1 = [{data: [12345, 22345]}]
this.data2 = [{name: '稻田', data: [12345, 13345]}, {name:'淡水养殖', data:[22345, 23345]}]
this.data3 = [{name: '稻田', data: [12345, 13345]}, {name:'淡水养殖', data:[22345, 23345]}, {name: '面积', data: [12345,12345]}]
}, 1000)
},
methods: {
handleMapSelect(name) {
this.curCardIndex = this.mapData.findIndex(item => item.name == name)
this.setChartData()
this.$refs.areaCard.handleSelect(this.curCardIndex)
},
handleCardSelect(index) {
if (this.curCardIndex == index) return
this.curCardIndex = index
this.setChartData()
if (!index) {
this.$refs.map.setRegions(index)
return
}
this.$refs.map.setRegions(this.mapData[index].name)
},
setChartData() {
if (!this.curCardIndex) {
this.data1 = [{data: [12345, 22345]}]
this.data2 = [{name: '稻田', data: [12345, 13345]}, {name:'淡水养殖', data:[22345, 23345]}]
this.data3 = [{name: '稻田', data: [12345, 13345]}, {name:'淡水养殖', data:[22345, 23345]}, {name: '面积', data: [12345,12345]}]
return
}
const data = this.mapData[this.curCardIndex]
this.data1 = [{data: [data.area, data.area]}]
this.data2 = [{name: '稻田', data: [data.farm, data.farm]}, {name:'淡水养殖', data:[data.water, data.water]}]
this.data3 = [{name: '稻田', data: [data.farm, data.farm]}, {name:'淡水养殖', data:[data.water, data.water]}, {name: '面积', data: [data.area,data.area]}]
},
},
}
</script>
<style lang="stylus" scoped>
#container
$gd-layout()
grid-template-areas \
'. . box1'\
'. . box1'\
'box2 box2 box2'
grid-template-rows 1fr 1fr 1fr
grid-template-columns 1fr 1.5fr 1fr
grid-gap 0
.box1
grid-area box1
.box2
grid-area box2
.area
width 42%
font-size 1.8rem
color $color-map(1)
position absolute
top 10%
left 0
right 0
text-align center
>div
display flex
justify-content space-around
margin-top 1rem
p
font-size 1.4rem
b
color $color-map(1)
font-size 1.8rem
font-family $font-din
margin 0 0.5rem
p
color #fff
font-family $font-pang
b
font-size 3rem
>span
font-family $font-pang
.data-wrapper
display flex
flex-direction column
height 100%
padding 1rem
>div
height 33%
margin-bottom 0.5rem
>p
color $color-map(0.8)
display flex
align-items center
>span
display inline-block
width 0.4rem
height 1rem
margin-right 0.5rem
background $color-map(0.8)
.year-select
position absolute
z-index 100
top 0
right 1rem
color #fff
>div
margin-left 0.5rem
.year
color $color-map(1)
cursor pointer
font-size 1.6rem
font-weight bold
</style>
This diff is collapsed.
<template>
<div id="map" :style="`background-image: url(${require('@/assets/images/stars-bg.png')})`"/>
</template>
<script>
import china from 'echarts/map/json/china.json'
export default {
name: 'ChinaMap',
mounted() {
this.$nextTick(() => {
var mapName = 'china'
this.$echarts.registerMap('china',china)
var data = [
{ name: '北京', value: 177 },
{ name: '天津', value: 42 },
{ name: '河北', value: 102 },
{ name: '山西', value: 81 },
{ name: '内蒙古', value: 47 },
{ name: '辽宁', value: 67 },
{ name: '吉林', value: 82 },
{ name: '黑龙江', value: 66 },
{ name: '上海', value: 24 },
{ name: '江苏', value: 92 },
{ name: '浙江', value: 114 },
{ name: '安徽', value: 109 },
{ name: '福建', value: 116 },
{ name: '江西', value: 91 },
{ name: '山东', value: 119 },
{ name: '河南', value: 137 },
{ name: '湖北', value: 116 },
{ name: '湖南', value: 114 },
{ name: '重庆', value: 91 },
{ name: '四川', value: 125 },
{ name: '贵州', value: 62 },
{ name: '云南', value: 83 },
{ name: '西藏', value: 9 },
{ name: '陕西', value: 80 },
{ name: '甘肃', value: 56 },
{ name: '青海', value: 10 },
{ name: '宁夏', value: 18 },
{ name: '新疆', value: 67 },
{ name: '广东', value: 123 },
{ name: '广西', value: 59 },
{ name: '海南', value: 14 }
]
var geoCoordMap = {}
/*获取地图数据*/
let myChart = this.$echarts.init(document.getElementById('map'))
// myChart.showLoading();
var mapFeatures = this.$echarts.getMap(mapName).geoJson.features
// myChart.hideLoading();
mapFeatures.forEach(function(v) {
// 地区名称
var name = v.properties.name
// 地区经纬度
geoCoordMap[name] = v.properties.cp
})
var max = 480,
min = 9 // todo
var maxSize4Pin = 100,
minSize4Pin = 20
var convertData = function(data) {
var res = []
for (var i = 0; i < data.length; i++) {
var geoCoord = geoCoordMap[data[i].name]
if (geoCoord) {
res.push({
name: data[i].name,
value: geoCoord.concat(data[i].value)
})
}
}
return res
}
var option = {
// legend: {
// orient: 'vertical',
// y: 'bottom',
// x: 'right',
// data: ['credit_pm2.5'],
// textStyle: {
// color: '#fff'
// }
// },
// visualMap: {
// show: true,
// min: 0,
// max: 200,
// left: 400,
// bottom: 200,
// text: ['高', '低'], // 文本,默认为数值文本
// calculable: true,
// seriesIndex: [1],
// inRange: {
// color: ['#3B5077', '#031525'] // 蓝黑
// // color: ['#ffc0cb', '#800080'] // 红紫
// // color: ['#3C3B3F', '#605C3C'] // 黑绿
// // color: ['#0f0c29', '#302b63', '#24243e'] // 黑紫黑
// // color: ['#23074d', '#cc5333'] // 紫红
// // color: ['#00467F', '#A5CC82'] // 蓝绿
// // color: ['#1488CC', '#2B32B2'] // 浅蓝
// // color: ['#00467F', '#A5CC82'] // 蓝绿
// // color: ['#00467F', '#A5CC82'] // 蓝绿
// // color: ['#00467F', '#A5CC82'] // 蓝绿
// // color: ['#00467F', '#A5CC82'] // 蓝绿
// }
// },
/*工具按钮组*/
// toolbox: {
// show: true,
// orient: 'vertical',
// left: 'right',
// top: 'center',
// feature: {
// dataView: {
// readOnly: false
// },
// restore: {},
// saveAsImage: {}
// }
// },
geo: {
show: true,
map: mapName,
label: {
normal: {
show: false
},
emphasis: {
show: false
}
},
roam: true,
itemStyle: {
normal: {
areaColor: '#031525',
borderColor: '#3B5077'
},
emphasis: {
areaColor: '#2B91B7'
}
}
},
series: [
// {
// name: '散点',
// type: 'scatter',
// coordinateSystem: 'geo',
// data: convertData(data),
// symbolSize: function(val) {
// return val[2] / 10
// },
// label: {
// normal: {
// formatter: '{b}',
// position: 'right',
// show: true
// },
// emphasis: {
// show: true
// }
// },
// itemStyle: {
// normal: {
// color: '#05C3F9'
// }
// }
// },
{
type: 'map',
map: mapName,
geoIndex: 0,
aspectScale: 0.75, //长宽比
showLegendSymbol: false, // 存在legend时显示
label: {
normal: {
show: true
},
emphasis: {
show: false,
textStyle: {
color: '#fff'
}
}
},
roam: true,
itemStyle: {
normal: {
areaColor: '#031525',
borderColor: '#3B5077'
},
emphasis: {
areaColor: '#2B91B7'
}
},
animation: false,
data: data
},
{
name: '点',
type: 'scatter',
coordinateSystem: 'geo',
symbol: 'pin', //气泡
symbolSize: function(val) {
var a = (maxSize4Pin - minSize4Pin) / (max - min)
var b = minSize4Pin - a * min
b = maxSize4Pin - a * max
return a * val[2] + b
},
label: {
normal: {
show: true,
textStyle: {
color: '#fff',
fontSize: 9
}
}
},
itemStyle: {
normal: {
color: '#F62157' //标志颜色
}
},
zlevel: 6,
data: convertData(data)
},
// {
// name: 'Top 5',
// type: 'effectScatter',
// coordinateSystem: 'geo',
// data: convertData(
// data
// .sort(function(a, b) {
// return b.value - a.value
// })
// .slice(0, 5)
// ),
// symbolSize: function(val) {
// return val[2] / 10
// },
// showEffectOn: 'render',
// rippleEffect: {
// brushType: 'stroke'
// },
// hoverAnimation: true,
// label: {
// normal: {
// formatter: '{b}',
// position: 'right',
// show: true
// }
// },
// itemStyle: {
// normal: {
// color: 'yellow',
// shadowBlur: 10,
// shadowColor: 'yellow'
// }
// },
// zlevel: 1
// }
]
}
myChart.setOption(option)
})
}
}
</script>
<style lang="stylus" scoped>
#map
width 100%
height 100%
background-size cover
</style>
<template>
<div class="area-list">
<template v-if="list && list.length > 0">
<div v-for="(item, index) in list" :key="item.name">
<div :class="`area-card ${index === curIndex ? 'on' : ''}`" @click="handleSelect(index)">
<i-circle :trail-color="switchColor(item.value).trail" :stroke-color="switchColor(item.value).stroke" :percent="item.value" :size="size">
<span style="font-size:0.8rem">{{item.value | pipe}}</span>
</i-circle>
<div>
<p>{{item.name}}</p>
<p v-if="item.output"><b><m-count :value="item.output"/></b><i>万元</i></p>
<p v-if="item.area"><b><m-count :value="item.area" :decimal="0"/></b><i>公顷</i></p>
<p v-if="item.water || item.farm"><b><m-count :value="item.water" :decimal="0"/></b> / <b><m-count :value="item.farm" :decimal="0"/></b><i></i></p>
</div>
</div>
</div>
</template>
</div>
</template>
<script>
export default {
name: 'AreaCard',
props: {
list: {
type: Array,
default() {
return []
}
}
},
data() {
return {
curIndex: null,
}
},
methods: {
handleSelect(i) {
if (this.curIndex === i) {
this.curIndex = null
} else {
this.curIndex = i
}
this.$emit('select', this.curIndex)
},
switchColor(val) {
if (val <= 20) {
return {
stroke: '#DBF6FF',
trail: '#85CDFF',
}
} else if (val <= 35) {
return {
stroke: '#5BD5FF',
trail: '#0076FF',
}
} else if (val <= 50) {
return {
stroke: '#8ED617',
trail: '#3F772F',
}
} else if (val <= 65) {
return {
stroke: '#FFCE34',
trail: '#E06536',
}
} else if (val <= 80) {
return {
stroke: '#FF6161',
trail: '#A02929',
}
} else if (val <= 100) {
return {
stroke: '#8623EB',
trail: '#C691FF',
}
} else {
return {
stroke: '#8623EB',
trail: '#C691FF',
}
}
}
},
filters: {
pipe(val) {
const result = val > 100 ? 100 : val
return `${result}%`
}
},
computed: {
size() {
return Math.floor(window.innerWidth / 100) * 2.5
},
},
}
</script>
<style lang="stylus" scoped>
.area-list
width 100%
display flex
flex-wrap wrap
padding 0.5rem 0.5rem 0
>div
width 12.5%
.area-card
display flex
align-items center
width 100%
padding 0.5rem 0
cursor pointer
border 0.1rem solid transparent
&.on
border-color $color-map(0.5)
box-shadow 0 0 1rem 0.1rem $color-map(1)
>div
color #ccc
margin-left 0.5rem
p
line-height 1
font-size 0.9rem
span
color $color-map(0.8)
i
font-size 0.8rem
</style>
<template>
<div class="map-wrapper">
<div id="map" ref="map"/>
<div v-if="data.length > 0" class="visualmap">
<p>{{visualLabel[0]}}</p>
<div class="bar" />
<p>{{visualLabel[1]}}</p>
</div>
</div>
</template>
<script>
import china from 'echarts/map/json/china.json'
const mapData = [
{ name: '北京', value: 177 },
{ name: '天津', value: 42 },
{ name: '河北', value: 102 },
{ name: '山西', value: 81 },
{ name: '内蒙古', value: 17 },
{ name: '辽宁', value: 67 },
{ name: '吉林', value: 182 },
{ name: '黑龙江', value: 100 },
{ name: '上海', value: 24 },
{ name: '江苏', value: 299 },
{ name: '浙江', value: 114 },
{ name: '安徽', value: 29 },
{ name: '福建', value: 316 },
{ name: '江西', value: 91 },
{ name: '山东', value: 19 },
{ name: '河南', value: 137 },
{ name: '湖北', value: 26 },
{ name: '湖南', value: 114 },
{ name: '重庆', value: 91 },
{ name: '四川', value: 25 },
{ name: '贵州', value: 62 },
{ name: '云南', value: 83 },
{ name: '西藏', value: 9 },
{ name: '陕西', value: 80 },
{ name: '甘肃', value: 256 },
{ name: '青海', value: 10 },
{ name: '宁夏', value: 18 },
{ name: '新疆', value: 67 },
{ name: '广东', value: 123 },
{ name: '广西', value: 59 },
{ name: '海南', value: 14 }
]
export default {
name: 'ChinaMap',
props: {
data: {
type: Array,
default() {
return []
}
},
visualLabel: {
type: Array,
default() {
return ['高', '低']
}
},
visualFormatter: {
type: [String, Function],
// default: '{b}<br/>综合种养产量:{c}'
default() {
return (e) => {
const {data} = e
return `
<h3>${data.name}</h3>
<p>养殖面积:${data.area}(公顷)</p>
<p>淡水养殖产量:${data.water}(吨)</p>
<p>稻田产量:${data.farm}(吨)</p>
`
}
}
},
visualConfig: {
type: Object,
default() {
return {}
}
},
},
data() {
return {
map: null,
mapName: 'china',
config: {
geo: {
map: 'china',
left: '5%',
top: '5%',
label: {
normal: {
show: false,
},
emphasis: {
color: '#fff',
}
},
itemStyle: {
normal: {
areaColor: 'rgba(0, 191, 255, 0.1)',
borderColor: 'rgba(0, 191, 255, 0.6)',
borderWidth: 0.4,
},
emphasis: {
areaColor: '#5ad4ff',
color: '#fff'
}
},
regions: [],
},
series: []
}
}
},
mounted() {
this.$nextTick(this.initMap)
},
methods: {
initMap() {
// 初始化echarts
this.$echarts.registerMap(this.mapName, china)
this.map = this.$echarts.init(this.$refs.map)
this.map.setOption(this.config)
this.addEvent()
},
addEvent() {
// 监听地图点击事件
this.map.on('click', (ev) => {
const {name} = ev.data
this.setRegions(name)
this.$emit('select', name)
})
},
setRegions(name) {
if (!name) {
this.config.geo.regions = []
this.map.setOption(this.config)
return
}
let regions = [{
name,
selected: true,
itemStyle: {
areaColor: '#5ad4ff',
color: 'red',
shadowColor: 'rgba(0, 0, 0, 1)',
shadowBlur: 10,
shadowOffsetY: 10,
shadowOffsetX: -5,
}
}]
if (this.config.geo.regions.length > 0 && this.config.geo.regions[0].name == name) {
regions = []
}
this.config.geo.regions = regions
this.map.setOption(this.config)
},
},
watch: {
data(cur, past) {
if (cur && cur !== past && cur.length > 0) {
this.config.series.push({
type: 'map',
map: this.mapName,
geoIndex: 0,
data: this.data,
})
this.config.tooltip = {
trigger: 'item',
formatter: this.visualFormatter,
}
this.config.visualMap = Object.assign({
show: false,
inRange: {
opacity: 0.5,
color: ['rgba(91, 213, 255, 0.1)', 'rgba(91, 213, 255, 0.6)']
}
}, this.visualConfig)
this.map.setOption(this.config)
}
}
}
}
</script>
<style lang="stylus" scoped>
.map-wrapper
width 100%
height 100%
position absolute
#map
width 100%
height 100%
.visualmap
color #fff
position absolute
top 50%
left 5%
text-align center
.bar
width 2rem
height 6rem
background linear-gradient(to bottom, rgba(91, 213, 255, 0.6), rgba(91, 213, 255, 0.1))
</style>
<template>
<div id="title" ref="title">
<img :src="bgImg"/>
<p><slot /></p>
</div>
</template>
<script>
const titleBg1 = require('@/assets/images/title-bg.png')
const titleBg2 = require('@/assets/images/title-bg2.png')
export default {
name: 'ThemeTitle',
data() {
return {
bgImg: titleBg1,
}
},
mounted() {
const width = this.$refs.title && this.$refs.title.style.width
if (width && Number(width.split('%')[0]) >= 90) {
this.bgImg = titleBg2
}
},
}
</script>
<style lang="stylus" scoped>
#title
display flex
align-items center
justify-content center
position relative
min-width 60%
margin 0 auto
height 4.2rem
cursor pointer
>img
position absolute
width 100%
height 100%
top 0
left 0
>p
font-family $font-pang
font-size 2.5rem
background-clip text
-webkit-background-clip text
color #1efbff
-webkit-text-fill-color transparent
background-image linear-gradient(to right, #1efbff, #0094ff)
</style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment