
@ -0,0 +1,18 @@ |
|||
{ |
|||
"presets": [ |
|||
["env", { |
|||
"modules": false, |
|||
"targets": { |
|||
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"] |
|||
} |
|||
}], |
|||
"stage-2" |
|||
], |
|||
"plugins": ["transform-vue-jsx", "transform-runtime"], |
|||
"env": { |
|||
"test": { |
|||
"presets": ["env", "stage-2"], |
|||
"plugins": ["transform-vue-jsx", "transform-es2015-modules-commonjs", "dynamic-import-node"] |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,9 @@ |
|||
root = true |
|||
|
|||
[*] |
|||
charset = utf-8 |
|||
indent_style = space |
|||
indent_size = 2 |
|||
end_of_line = lf |
|||
insert_final_newline = true |
|||
trim_trailing_whitespace = true |
@ -0,0 +1,5 @@ |
|||
/build/ |
|||
/config/ |
|||
/dist/ |
|||
/*.js |
|||
/test/unit/coverage/ |
@ -0,0 +1,29 @@ |
|||
// https://eslint.org/docs/user-guide/configuring
|
|||
|
|||
module.exports = { |
|||
root: true, |
|||
parserOptions: { |
|||
parser: 'babel-eslint' |
|||
}, |
|||
env: { |
|||
browser: true, |
|||
}, |
|||
extends: [ |
|||
// 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.
|
|||
'plugin:vue/essential', |
|||
// https://github.com/standard/standard/blob/master/docs/RULES-en.md
|
|||
'standard' |
|||
], |
|||
// required to lint *.vue files
|
|||
plugins: [ |
|||
'vue' |
|||
], |
|||
// add your custom rules here
|
|||
rules: { |
|||
// allow async-await
|
|||
'generator-star-spacing': 'off', |
|||
// allow debugger during development
|
|||
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' |
|||
} |
|||
} |
@ -0,0 +1,17 @@ |
|||
.DS_Store |
|||
node_modules/ |
|||
/dist/ |
|||
npm-debug.log* |
|||
yarn-debug.log* |
|||
yarn-error.log* |
|||
/test/unit/coverage/ |
|||
/test/e2e/reports/ |
|||
selenium-debug.log |
|||
|
|||
# Editor directories and files |
|||
.idea |
|||
.vscode |
|||
*.suo |
|||
*.ntvs* |
|||
*.njsproj |
|||
*.sln |
@ -0,0 +1,10 @@ |
|||
// 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": {} |
|||
} |
|||
} |
@ -0,0 +1,30 @@ |
|||
# project_kuaile_serviceh5 |
|||
|
|||
> 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 |
|||
|
|||
# run unit tests |
|||
npm run unit |
|||
|
|||
# run e2e tests |
|||
npm run e2e |
|||
|
|||
# run all tests |
|||
npm test |
|||
``` |
|||
|
|||
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). |
@ -0,0 +1,41 @@ |
|||
'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' |
|||
)) |
|||
}) |
|||
}) |
@ -0,0 +1,54 @@ |
|||
'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) |
|||
} |
|||
} |
After Width: | Height: | Size: 6.7 KiB |
@ -0,0 +1,101 @@ |
|||
'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, |
|||
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') |
|||
}) |
|||
} |
|||
} |
@ -0,0 +1,22 @@ |
|||
'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' |
|||
} |
|||
} |
@ -0,0 +1,92 @@ |
|||
'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: './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: [ |
|||
...(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: /\.(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' |
|||
} |
|||
} |
@ -0,0 +1,95 @@ |
|||
'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) |
|||
} |
|||
}) |
|||
}) |
@ -0,0 +1,149 @@ |
|||
'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 = process.env.NODE_ENV === 'testing' |
|||
? require('../config/test.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: process.env.NODE_ENV === 'testing' |
|||
? 'index.html' |
|||
: 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 |
@ -0,0 +1,7 @@ |
|||
'use strict' |
|||
const merge = require('webpack-merge') |
|||
const prodEnv = require('./prod.env') |
|||
|
|||
module.exports = merge(prodEnv, { |
|||
NODE_ENV: '"development"' |
|||
}) |
@ -0,0 +1,76 @@ |
|||
'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: false, |
|||
// 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 |
|||
} |
|||
} |
@ -0,0 +1,4 @@ |
|||
'use strict' |
|||
module.exports = { |
|||
NODE_ENV: '"production"' |
|||
} |
@ -0,0 +1,7 @@ |
|||
'use strict' |
|||
const merge = require('webpack-merge') |
|||
const devEnv = require('./dev.env') |
|||
|
|||
module.exports = merge(devEnv, { |
|||
NODE_ENV: '"testing"' |
|||
}) |
@ -0,0 +1,65 @@ |
|||
<!DOCTYPE html> |
|||
<html> |
|||
<head> |
|||
<meta charset="utf-8"> |
|||
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no,minimum-scale=1.0"> |
|||
<title></title> |
|||
<script> |
|||
if(location.href.indexOf('check.cnkicom.com') > -1){ |
|||
(function() {var _53code = document.createElement("script");_53code.src = "https://tb.53kf.com/code/code/2109215fd7c9fa4051aa17091f1d8f9d3/10";var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(_53code, s);})(); |
|||
} |
|||
</script> |
|||
|
|||
<script type="text/javascript"> |
|||
(function(doc, win) { |
|||
var userAgentInfo = navigator.userAgent; |
|||
var Agents = ["Android", "iPhone", |
|||
"SymbianOS", "Windows Phone", |
|||
"iPad", "iPod"]; |
|||
var isphone = false; |
|||
for (var v = 0; v < Agents.length; v++) { |
|||
if (userAgentInfo.indexOf(Agents[v]) > 0) { |
|||
isphone = true; |
|||
break; |
|||
} |
|||
} |
|||
if(!isphone) { |
|||
var jump_true = decodeURIComponent(location.href.split('?url=')[1]); |
|||
if(jump_true) { |
|||
location.href=jump_true; |
|||
} |
|||
} |
|||
var docEl = doc.documentElement, |
|||
resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize'; |
|||
var recalc = function() { |
|||
var width = docEl.clientWidth; |
|||
if (width < 300) { |
|||
width = 300; |
|||
} |
|||
if(width>414){ |
|||
width=414; |
|||
} |
|||
docEl.dataset.width = width |
|||
docEl.dataset.percent = 100 * (width / 750); |
|||
docEl.style.fontSize = 100 * (width / 750) + 'px'; |
|||
}; |
|||
recalc(); |
|||
if (!doc.addEventListener) return; |
|||
win.addEventListener(resizeEvt, recalc, false); |
|||
})(document, window); |
|||
</script> |
|||
</head> |
|||
<body> |
|||
<div id="app"></div> |
|||
<!-- built files will be auto injected --> |
|||
<script src="http://lib.baomitu.com/vue/2.6.10/vue.min.js"></script> |
|||
<script src="http://lib.baomitu.com/vue-resource/1.5.1/vue-resource.min.js"></script> |
|||
<script src="http://lib.baomitu.com/vue-lazyload/1.2.6/vue-lazyload.js"></script> |
|||
<script src="http://lib.baomitu.com/vue-router/3.0.2/vue-router.min.js"></script> |
|||
<script src="http://css.chachongz.com/assets_v2/js/vue-cookies.js"></script> |
|||
<script src="http://res.wx.qq.com/open/js/jweixin-1.4.0.js"></script> |
|||
|
|||
<script src="http://cdn.bootcdn.net/ajax/libs/echarts/4.1.0/echarts.min.js"></script> |
|||
<script src="http://cdn.bootcdn.net/ajax/libs/vue-echarts/4.0.2/vue-echarts.min.js"></script> |
|||
</body> |
|||
</html> |
@ -0,0 +1,86 @@ |
|||
{ |
|||
"name": "project_kuaile_serviceh5", |
|||
"version": "1.0.0", |
|||
"description": "A Vue.js project", |
|||
"author": "pengda <10266652509@qq.com>", |
|||
"private": true, |
|||
"scripts": { |
|||
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", |
|||
"start": "npm run dev", |
|||
"build": "node build/build.js" |
|||
}, |
|||
"dependencies": { |
|||
"clipboard": "^2.0.11", |
|||
"qrcode": "^1.2.0", |
|||
"qrcodejs2": "^0.0.2", |
|||
"vue": "^2.5.2", |
|||
"vue-clipboard2": "^0.1.0", |
|||
"vue-cookies": "^1.5.6", |
|||
"vue-loading-template": "^0.1.7", |
|||
"vue-resource": "^1.3.5", |
|||
"vue-router": "^2.8.0", |
|||
"vue-simple-spinner": "^1.2.10", |
|||
"vue-touch": "^2.0.0-beta.4", |
|||
"vue-wechat-title": "^2.0.4", |
|||
"vuex": "^3.1.3", |
|||
"weui": "^2.3.0", |
|||
"weui.js": "^1.2.2" |
|||
}, |
|||
"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-polyfill": "^6.26.0", |
|||
"babel-preset-env": "^1.3.2", |
|||
"babel-preset-stage-2": "^6.22.0", |
|||
"chalk": "^2.0.1", |
|||
"compression-webpack-plugin": "^1.1.11", |
|||
"copy-webpack-plugin": "^4.0.1", |
|||
"css-loader": "^0.28.0", |
|||
"es6-promise": "^4.0.5", |
|||
"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", |
|||
"jquery": "^3.3.1", |
|||
"node-notifier": "^5.1.2", |
|||
"node-sass": "^4.8.3", |
|||
"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", |
|||
"sass-loader": "^6.0.7", |
|||
"semver": "^5.3.0", |
|||
"shelljs": "^0.7.6", |
|||
"uglifyjs-webpack-plugin": "^1.1.1", |
|||
"url-loader": "^0.5.8", |
|||
"vue-lazyload": "^1.2.6", |
|||
"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.11.5", |
|||
"webpack-merge": "^4.1.0" |
|||
}, |
|||
"externals": { |
|||
"vue-echarts": "VueECharts", |
|||
"echarts": "echarts" |
|||
}, |
|||
"engines": { |
|||
"node": ">= 6.0.0", |
|||
"npm": ">= 3.0.0" |
|||
}, |
|||
"browserslist": [ |
|||
"> 1%", |
|||
"last 2 versions", |
|||
"not ie <= 8" |
|||
] |
|||
} |
@ -0,0 +1,194 @@ |
|||
<template> |
|||
<div id="app"> |
|||
<router-view :key="key" v-wechat-title="$route.meta.title"/> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'App', |
|||
computed: { |
|||
key() { |
|||
return this.$route.name !== undefined ? this.$route.name + +new Date() : this.$route + +new Date(); |
|||
} |
|||
}, |
|||
created: function () { |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
@charset "utf-8"; |
|||
html, |
|||
body, |
|||
h1, |
|||
h2, |
|||
h3, |
|||
h4, |
|||
h5, |
|||
p, |
|||
span, |
|||
a, |
|||
div, |
|||
ol, |
|||
ul, |
|||
li, |
|||
dl, |
|||
dt, |
|||
dd, |
|||
table, |
|||
tbody, |
|||
tfoot, |
|||
thead, |
|||
tr, |
|||
th, |
|||
td, |
|||
input, |
|||
textarea, |
|||
form { |
|||
margin: 0; |
|||
padding: 0; |
|||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0); |
|||
color: #404040; |
|||
} |
|||
|
|||
html { |
|||
height: 100%; |
|||
} |
|||
|
|||
body { |
|||
background-color: #f7f7f7; |
|||
-webkit-text-size-adjust: 100%; |
|||
min-width: 300px; |
|||
font: 0.13rem/2em sans-serif; |
|||
height: 100%; |
|||
} |
|||
|
|||
em, |
|||
i { |
|||
font-style: normal; |
|||
font-weight: normal; |
|||
} |
|||
|
|||
input, |
|||
textarea { |
|||
outline: none; |
|||
} |
|||
|
|||
input[type="text"], |
|||
input[type="text"], |
|||
textarea { |
|||
border-radius: 0; |
|||
-webkit-appearance: none; |
|||
} |
|||
|
|||
textarea { |
|||
border: 1px solid #ccc; |
|||
} |
|||
|
|||
ul, |
|||
ol, |
|||
li { |
|||
list-style: none; |
|||
} |
|||
|
|||
select { |
|||
background-color: #fff; |
|||
} |
|||
|
|||
#app { |
|||
background: #f7f7f7; |
|||
overflow: auto; |
|||
-webkit-overflow-scrolling: touch; |
|||
height: 100%; |
|||
} |
|||
|
|||
.fl { |
|||
float: left; |
|||
} |
|||
|
|||
.fr { |
|||
float: right; |
|||
} |
|||
|
|||
.clear:after { |
|||
display: block; |
|||
content: ''; |
|||
clear: both; |
|||
} |
|||
|
|||
.hide { |
|||
display: none; |
|||
} |
|||
|
|||
.prompt { |
|||
width: 100%; |
|||
height: 100%; |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
z-index: 110; |
|||
} |
|||
|
|||
.promptbg { |
|||
width: 100%; |
|||
height: 100%; |
|||
position: absolute; |
|||
top: 0; |
|||
left: 0; |
|||
z-index: 120; |
|||
background: #000000; |
|||
opacity: 0.3; |
|||
} |
|||
|
|||
.promptbox { |
|||
width: 70%; |
|||
margin-left: 15%; |
|||
position: absolute; |
|||
top: 30%; |
|||
left: 0; |
|||
z-index: 130; |
|||
background: #ffffff; |
|||
border-radius: 0.16rem; |
|||
} |
|||
|
|||
.promptcontent { |
|||
font-size: 0.32rem; |
|||
color: #262626; |
|||
line-height: 0.48rem; |
|||
padding: 0.3rem; |
|||
text-align: center; |
|||
border-radius: 0.16rem 0.16rem 0 0; |
|||
word-break: break-all; |
|||
} |
|||
|
|||
.promptbtn { |
|||
width: 100%; |
|||
height: 0.8rem; |
|||
border-top: 0.02rem solid #f7f7f7; |
|||
line-height: 0.8rem; |
|||
text-align: center; |
|||
font-size: 0.28rem; |
|||
color: #262626; |
|||
border-radius: 0 0 0.16rem 0.16rem; |
|||
} |
|||
|
|||
.prompt-alert{ |
|||
position: fixed; |
|||
top: 40%; |
|||
left: 50%; |
|||
transform: translate(-50%, -50%); |
|||
text-align: center; |
|||
line-height: 24px; |
|||
padding: 12px 15px; |
|||
z-index: 110; |
|||
background: #000; |
|||
opacity: 0.5; |
|||
color: #fff; |
|||
border-radius: 5px; |
|||
} |
|||
|
|||
.weui-btn { |
|||
z-index: 899; |
|||
} |
|||
</style> |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 737 B |
@ -0,0 +1,89 @@ |
|||
/*! common.css | Just for layout*/ |
|||
body * { |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
body { |
|||
padding: 0; |
|||
margin: 0; |
|||
font-family: PingFangSC-Regular, Roboto, Helvetica Neue, Helvetica, Tahoma, |
|||
Arial, PingFang SC-Light, Microsoft YaHei; |
|||
} |
|||
|
|||
body { |
|||
scrollbar-width: none; /* firefox */ |
|||
-ms-overflow-style: none; /* IE 10+ */ |
|||
overflow-x: hidden; |
|||
overflow-y: auto; |
|||
} |
|||
|
|||
::-webkit-scrollbar { |
|||
display: none; /* Chrome Safari */ |
|||
} |
|||
|
|||
button { |
|||
margin: 0; |
|||
padding: 0; |
|||
border: 1px solid transparent; |
|||
outline: none; |
|||
background-color: transparent; |
|||
} |
|||
|
|||
button:active { |
|||
opacity: 0.6; |
|||
} |
|||
|
|||
.flex-col { |
|||
display: flex; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
.flex-row { |
|||
display: flex; |
|||
flex-direction: row; |
|||
} |
|||
|
|||
.justify-start { |
|||
display: flex; |
|||
justify-content: flex-start; |
|||
} |
|||
|
|||
.justify-center { |
|||
display: flex; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.justify-end { |
|||
display: flex; |
|||
justify-content: flex-end; |
|||
} |
|||
|
|||
.justify-evenly { |
|||
display: flex; |
|||
justify-content: space-evenly; |
|||
} |
|||
|
|||
.justify-around { |
|||
display: flex; |
|||
justify-content: space-around; |
|||
} |
|||
|
|||
.justify-between { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
} |
|||
|
|||
.align-start { |
|||
display: flex; |
|||
align-items: flex-start; |
|||
} |
|||
|
|||
.align-center { |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
|
|||
.align-end { |
|||
display: flex; |
|||
align-items: flex-end; |
|||
} |
After Width: | Height: | Size: 354 B |
After Width: | Height: | Size: 693 B |
After Width: | Height: | Size: 589 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 942 B |
After Width: | Height: | Size: 503 B |
After Width: | Height: | Size: 683 B |
After Width: | Height: | Size: 699 B |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 318 B |
After Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 3.6 KiB |
@ -0,0 +1,126 @@ |
|||
<template> |
|||
<div class="h5openerror"> |
|||
<div v-wechat-title='msg'></div> |
|||
<head-title :title="title_error" :showBtn="false" :showleft="false"></head-title> |
|||
<div class="ios"> |
|||
<i></i> |
|||
<div class="notsupport">{{ detail_error_one }}</div> |
|||
<div class="movetopc">{{ detail_error_two }}</div> |
|||
<div class="movetopc">{{ copy_url_host }}</div> |
|||
<div v-if="copy_url_host" class="operatebtn" v-clipboard:copy="copy_url_host" v-clipboard:success="onCopy" v-clipboard:error="onError"> |
|||
复制链接 |
|||
</div> |
|||
</div> |
|||
<div class="prompt" v-if="showprompt"> |
|||
<div class="promptbg"></div> |
|||
<div class="promptbox"> |
|||
<div class="promptcontent">{{ promptcontent }}</div> |
|||
<div class="promptbtn" @click="closeprompt">确定</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import headTitle from './common/headTitle.vue' |
|||
|
|||
export default { |
|||
name: 'h5openerror', |
|||
data() { |
|||
return { |
|||
msg: '错误页', |
|||
copy_url_host: this.$route.query.url, |
|||
title_error: '', |
|||
detail_error_one: '', |
|||
detail_error_two: '', |
|||
promptcontent: '', |
|||
showprompt: false, |
|||
device: '' |
|||
} |
|||
}, |
|||
components: { |
|||
headTitle |
|||
}, |
|||
methods: { |
|||
promptshow: function (content) { |
|||
this.showprompt = true; |
|||
this.promptcontent = content; |
|||
}, |
|||
closeprompt: function () { |
|||
this.showprompt = false; |
|||
this.promptcontent = ''; |
|||
}, |
|||
onCopy: function (e) { |
|||
this.promptshow("地址已复制,请发送到" + this.device + "去访问吧"); |
|||
}, |
|||
onError: function (e) { |
|||
this.promptshow('此浏览器不支持点击复制,请更换到手机微信浏览器中打开!'); |
|||
}, |
|||
}, |
|||
mounted: function () { |
|||
let error = JSON.parse(localStorage.getItem('H5OpenError')); |
|||
|
|||
this.title_error = error.title_error; |
|||
this.detail_error_one = error.detail_error_one; |
|||
this.detail_error_two = error.detail_error_two; |
|||
this.device = error.device; |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<!-- Add "scoped" attribute to limit CSS to this component only --> |
|||
<style scoped> |
|||
.xh5 { |
|||
background: #ffffff; |
|||
height: 100%; |
|||
} |
|||
|
|||
.ios { |
|||
width: 100%; |
|||
height: 100%; |
|||
background: #f7f7f7; |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
z-index: 10; |
|||
} |
|||
|
|||
.ios i { |
|||
display: block; |
|||
width: 3.24rem; |
|||
height: 1rem; |
|||
margin: 3rem auto 0; |
|||
background: url(../assets/pic_direction.svg) 0 0 no-repeat; |
|||
background-size: 3.24rem 1rem; |
|||
} |
|||
|
|||
.notsupport { |
|||
margin-top: 0.8rem; |
|||
opacity: 0.6; |
|||
font-size: 0.4rem; |
|||
color: #404B67; |
|||
line-height: 0.56rem; |
|||
text-align: center; |
|||
} |
|||
|
|||
.movetopc { |
|||
margin-top: 0.3rem; |
|||
opacity: 0.4; |
|||
font-size: 0.28rem; |
|||
line-height: 0.4rem; |
|||
color: #404B67; |
|||
text-align: center; |
|||
} |
|||
|
|||
.operatebtn { |
|||
width: 1.86rem; |
|||
height: 0.74rem; |
|||
border: 0.02rem solid rgba(38, 38, 38, 0.10); |
|||
border-radius: 1rem; |
|||
text-align: center; |
|||
line-height: 0.74rem; |
|||
margin-left: 2.8rem; |
|||
margin-top: 0.40rem; |
|||
font-size: 0.28rem; |
|||
} |
|||
</style> |
@ -0,0 +1,113 @@ |
|||
<template> |
|||
<div class="hello"> |
|||
<h1>{{ msg }}</h1> |
|||
<h2>Essential Links</h2> |
|||
<ul> |
|||
<li> |
|||
<a |
|||
href="https://vuejs.org" |
|||
target="_blank" |
|||
> |
|||
Core Docs |
|||
</a> |
|||
</li> |
|||
<li> |
|||
<a |
|||
href="https://forum.vuejs.org" |
|||
target="_blank" |
|||
> |
|||
Forum |
|||
</a> |
|||
</li> |
|||
<li> |
|||
<a |
|||
href="https://chat.vuejs.org" |
|||
target="_blank" |
|||
> |
|||
Community Chat |
|||
</a> |
|||
</li> |
|||
<li> |
|||
<a |
|||
href="https://twitter.com/vuejs" |
|||
target="_blank" |
|||
> |
|||
Twitter |
|||
</a> |
|||
</li> |
|||
<br> |
|||
<li> |
|||
<a |
|||
href="http://vuejs-templates.github.io/webpack/" |
|||
target="_blank" |
|||
> |
|||
Docs for This Template |
|||
</a> |
|||
</li> |
|||
</ul> |
|||
<h2>Ecosystem</h2> |
|||
<ul> |
|||
<li> |
|||
<a |
|||
href="http://router.vuejs.org/" |
|||
target="_blank" |
|||
> |
|||
vue-router |
|||
</a> |
|||
</li> |
|||
<li> |
|||
<a |
|||
href="http://vuex.vuejs.org/" |
|||
target="_blank" |
|||
> |
|||
vuex |
|||
</a> |
|||
</li> |
|||
<li> |
|||
<a |
|||
href="http://vue-loader.vuejs.org/" |
|||
target="_blank" |
|||
> |
|||
vue-loader |
|||
</a> |
|||
</li> |
|||
<li> |
|||
<a |
|||
href="https://github.com/vuejs/awesome-vue" |
|||
target="_blank" |
|||
> |
|||
awesome-vue |
|||
</a> |
|||
</li> |
|||
</ul> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'HelloWorld', |
|||
data () { |
|||
return { |
|||
msg: 'Welcome to Your Vue.js App' |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<!-- Add "scoped" attribute to limit CSS to this component only --> |
|||
<style scoped> |
|||
h1, h2 { |
|||
font-weight: normal; |
|||
} |
|||
ul { |
|||
list-style-type: none; |
|||
padding: 0; |
|||
} |
|||
li { |
|||
display: inline-block; |
|||
margin: 0 10px; |
|||
} |
|||
a { |
|||
color: #42b983; |
|||
} |
|||
</style> |
@ -0,0 +1,353 @@ |
|||
<template> |
|||
<div class="cardSecretBuy"> |
|||
<login :page="login_page" :mckey="mckey" @loaded="loginLoaded"></login> |
|||
|
|||
<div v-if="prompt" class="prompt-alert">{{ prompt }}</div> |
|||
|
|||
<div class="card-secret-buy"> |
|||
<div class="card-content"> |
|||
<div class="card-buy" v-if="tab==0"> |
|||
<div class="card-title"> |
|||
<div class="card-circle">卡密购买</div> |
|||
</div> |
|||
<div class="card-types"> |
|||
<div class="card-type" v-for="(item, key) in card_type_list" @click="buyCard(item)"> |
|||
<div class="type-name">{{ item.title }}</div> |
|||
<div class="type-price">{{ item.price }}元</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="card-search" v-if="tab==1"> |
|||
<div class="card-title"> |
|||
<div class="card-circle">卡密查询</div> |
|||
<div @click="toOrderSample()" class="card-order">订单编号指引</div> |
|||
</div> |
|||
<div class="search-input"> |
|||
<input type="text" placeholder="请输入订单编号" v-model="inputValue"> |
|||
<div @click="search()">搜索</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="footernav"> |
|||
<div class="itemList" @click="toTab(0)"> |
|||
<img v-if="tab==0" class="tabbar_item_img1" src="../assets/images/card_secret_buy/tabs_buy_on.png" alt=""> |
|||
<img v-else class="tabbar_item_img1" src="../assets/images/card_secret_buy/tabs_buy.png" alt=""> |
|||
<span v-bind:class="[{'selected':tab==0}]">卡密购买</span> |
|||
</div> |
|||
<div class="itemList" @click="toTab(1)"> |
|||
<img v-if="tab==1" class="tabbar_item_img1" src="../assets/images/card_secret_buy/tabs_search_on.png" alt=""> |
|||
<img v-else class="tabbar_item_img1" src="../assets/images/card_secret_buy/tabs_search.png" alt=""> |
|||
<span v-bind:class="[{'selected':tab==1}]">卡密搜索</span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import Login from './common/Login.vue' |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
prompt: '', |
|||
agent_url: "", |
|||
|
|||
islogin:false, |
|||
login_page: "cardSecretBuy", |
|||
mckey: this.$route.query.mckey, |
|||
|
|||
tab: 0, |
|||
card_type_list: [], |
|||
|
|||
inputValue: '', |
|||
orderid: "", |
|||
}; |
|||
}, |
|||
methods: { |
|||
loginLoaded(){ |
|||
this.islogin = true |
|||
}, |
|||
promptshow(content) { |
|||
this.prompt = content; |
|||
setTimeout(() => { |
|||
this.prompt = "" |
|||
}, 2000); |
|||
}, |
|||
getCardSecretTypes: function () { |
|||
this.$http.post(this.agent_url + "/h5_get_card_secret_types", {}).then(response => { |
|||
if (response.data.status) { |
|||
this.card_type_list = response.data.data; |
|||
} else { |
|||
this.promptshow(response.data.info); |
|||
} |
|||
}, |
|||
response => { |
|||
this.promptshow("网络错误,请重试"); |
|||
}); |
|||
}, |
|||
toTab: function (tab) { |
|||
this.tab = tab; |
|||
localStorage.setItem('cardSecretBuyTab', tab) |
|||
}, |
|||
search: function () { |
|||
this.tid = this.inputValue; |
|||
if (this.tid == '') { |
|||
this.promptshow('请输入订单编号'); |
|||
return; |
|||
} |
|||
this.$http.post(this.agent_url + "/h5_get_card_secret", { |
|||
orderid: this.tid, |
|||
}).then(response => { |
|||
if (response.data.status) { |
|||
this.is_buy = false; |
|||
this.inputValue = ""; |
|||
this.toCardSecretQuery(); |
|||
} else { |
|||
this.promptshow(response.data.info); |
|||
} |
|||
}, |
|||
response => { |
|||
this.promptshow("网络错误,请重试"); |
|||
}); |
|||
}, |
|||
toOrderSample: function () { |
|||
location.href = `#/orderSample/?url=${this.$route.query.url}`; |
|||
}, |
|||
buyCard: function (card) { |
|||
let openid = this.$cookies.get('openid_' + this.$cookies.get('site_uid')); |
|||
var total_fee = card.price < 0.01 ? 0.01 : card.price; |
|||
let param = { |
|||
identity: openid, |
|||
total_fee: total_fee, |
|||
unique_id: card.id, |
|||
page_id: 888, |
|||
buytype: 'cardsecret', |
|||
back_url: this.agent_url, |
|||
desc: card.desc, |
|||
}; |
|||
this.$http.post(this.agent_url + "/h5_service_awaken_pay", param).then(response => { |
|||
if (response.data.status) { |
|||
this.tid = response.data.data.tid; |
|||
this.callpay(response.data.data); |
|||
} else { |
|||
this.promptshow(response.data.info); |
|||
} |
|||
}, |
|||
response => { |
|||
this.promptshow("网络错误,请重试"); |
|||
}); |
|||
}, |
|||
callpay: function (data) { |
|||
if (typeof WeixinJSBridge == "undefined") { |
|||
if (document.addEventListener) { |
|||
document.addEventListener('WeixinJSBridgeReady', this.jsApiCall, false); |
|||
} else if (document.attachEvent) { |
|||
document.attachEvent('WeixinJSBridgeReady', this.jsApiCall); |
|||
document.attachEvent('onWeixinJSBridgeReady', this.jsApiCall); |
|||
} |
|||
} else { |
|||
this.jsApiCall(data); |
|||
} |
|||
}, |
|||
jsApiCall: function (data) { |
|||
WeixinJSBridge.invoke( |
|||
'getBrandWCPayRequest', { |
|||
"appId": data.appId, |
|||
"timeStamp": data.timeStamp + '', |
|||
"nonceStr": data.nonceStr, |
|||
"package": data.package, |
|||
"signType": data.signType, |
|||
"paySign": data.paySign |
|||
}, (res) => { |
|||
//此处需要转化为字符串 |
|||
if (res.errMsg.indexOf('ok') > -1) { |
|||
this.checkpayresult(); |
|||
} else if (res.errMsg.indexOf('cancel') > -1) { |
|||
|
|||
} else { |
|||
this.promptshow('支付失败'); |
|||
} |
|||
}); |
|||
}, |
|||
checkpayresult: function () { |
|||
var paytype = 2; |
|||
this.$http.post(this.agent_url + "/h5_pay_result", { |
|||
tid: this.tid, |
|||
pay_type: paytype |
|||
}).then(response => { |
|||
if (response.data.status) { |
|||
this.toCardSecretQuery(); |
|||
} else { |
|||
this.promptshow(response.data.info); |
|||
} |
|||
}, |
|||
response => { |
|||
this.promptshow("网络错误,请重试"); |
|||
}); |
|||
}, |
|||
toCardSecretQuery() { |
|||
location.href = "#/cardSecretQuery/?orderid=" + this.tid; |
|||
} |
|||
}, |
|||
components: { |
|||
Login |
|||
}, |
|||
mounted() { |
|||
if(this.islogin){ |
|||
this.agent_url = localStorage.getItem('agent_url'); |
|||
this.getCardSecretTypes(); |
|||
} |
|||
if(localStorage.getItem('cardSecretBuyTab') != null){ |
|||
this.tab = localStorage.getItem('cardSecretBuyTab') |
|||
} |
|||
} |
|||
}; |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.cardSecretBuy { |
|||
background: #F8F8F8; |
|||
font-size: 17px; |
|||
height: 100vh; |
|||
} |
|||
|
|||
.card-content { |
|||
padding: 20px 20px; |
|||
} |
|||
|
|||
.card-title { |
|||
line-height: 20px; |
|||
display: flex; |
|||
} |
|||
|
|||
.card-circle { |
|||
width: 50%; |
|||
padding-left: 30px; |
|||
background-image: url(../assets/images/title_pic.png); |
|||
background-repeat: no-repeat; |
|||
background-position: 0 70%; |
|||
} |
|||
|
|||
.card-types { |
|||
background: #fff; |
|||
padding: 0 20px; |
|||
margin-top: 30px; |
|||
border: 1px solid #F8F8F8; |
|||
border-radius: 10px; |
|||
box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.1); |
|||
} |
|||
|
|||
.card-type { |
|||
border-top: 1px solid #E8ECF0; |
|||
line-height: 84px; |
|||
display: flex; |
|||
} |
|||
|
|||
.card-type:first-child { |
|||
border: none; |
|||
} |
|||
|
|||
.type-name { |
|||
color: #071432; |
|||
width: 50%; |
|||
text-align: left; |
|||
} |
|||
|
|||
.type-price { |
|||
color: #0F83FF; |
|||
width: 50%; |
|||
text-align: right; |
|||
padding-right: 20px; |
|||
background-image: url(../assets/images/card_secret_buy/buy_pic.png); |
|||
background-repeat: no-repeat; |
|||
background-position: 100% 52%; |
|||
} |
|||
|
|||
.card-order { |
|||
width: 50%; |
|||
display: inline-block; |
|||
text-align: right; |
|||
font-size: 15px; |
|||
} |
|||
|
|||
.search-input { |
|||
background: #fff; |
|||
display: flex; |
|||
margin: 30px 0; |
|||
border: 1px solid #BED4F1; |
|||
border-radius: 6px; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.search-input input { |
|||
padding: 10px; |
|||
width: 100%; |
|||
border: none; |
|||
font-size: 16px; |
|||
} |
|||
|
|||
.search-input div { |
|||
width: 105px; |
|||
line-height: 44px; |
|||
background: #fff; |
|||
color: #0F83FF; |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
.search-input div:before { |
|||
content: ''; |
|||
height: 5px; |
|||
border-left: 2px solid #BED4F1; |
|||
padding-right: 20px; |
|||
} |
|||
|
|||
.footernav { |
|||
display: flex; |
|||
justify-content: center; |
|||
border-top: 1px solid #EEEEEE; |
|||
width: 100%; |
|||
height: 90px; |
|||
position: fixed; |
|||
z-index: 9; |
|||
box-sizing: border-box; |
|||
bottom: 0; |
|||
background: #FFFFFF; |
|||
} |
|||
|
|||
.itemList { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-content: center; |
|||
float: left; |
|||
width: 50%; |
|||
height: 100%; |
|||
box-sizing: border-box; |
|||
position: relative; |
|||
text-align: center; |
|||
} |
|||
|
|||
.selected { |
|||
color: #000 !important; |
|||
} |
|||
|
|||
.tabbar_item_img1 { |
|||
position: absolute; |
|||
width: 30px; |
|||
height: 30px; |
|||
bottom: 45px; |
|||
} |
|||
|
|||
.itemList span { |
|||
font-size: 12px; |
|||
line-height: 15px; |
|||
font-weight: 400; |
|||
color: #979797; |
|||
display: block; |
|||
position: absolute; |
|||
width: 100%; |
|||
bottom: 26px; |
|||
text-align: center; |
|||
} |
|||
</style> |
@ -0,0 +1,194 @@ |
|||
<template> |
|||
<div class="cardSecretBuy"> |
|||
<div v-if="prompt" class="prompt-alert">{{ prompt }}</div> |
|||
|
|||
<div class="card-secret-detail"> |
|||
<div class="detail-content"> |
|||
<div class="detail-title"> |
|||
<div class="msg1">卡密提取成功!</div> |
|||
<div class="msg2">你可以<span class="blue">复制</span>、<span class="blue">截屏</span>或者<span |
|||
class="blue">拍照</span>留存,以免遗忘 |
|||
</div> |
|||
</div> |
|||
<div class="detail-info"> |
|||
<div>订单编号:</div> |
|||
<div>{{ orderid }}</div> |
|||
</div> |
|||
<div class="detail-info"> |
|||
<div>卡号:</div> |
|||
<div>{{ cardid }}</div> |
|||
</div> |
|||
|
|||
<div class="detail-btn"> |
|||
<div @click="back()" class="back">返回</div> |
|||
<div ref="copyBtn" class="copy" v-model="copyText">复制卡密</div> |
|||
</div> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import Clipboard from 'clipboard'; |
|||
export default { |
|||
data() { |
|||
return { |
|||
prompt: '', |
|||
agent_url: localStorage.getItem('agent_url'), |
|||
|
|||
orderid: this.$route.query.orderid, |
|||
cardid: "", |
|||
|
|||
copyText: '', |
|||
clipboardInstance: null, |
|||
}; |
|||
}, |
|||
methods: { |
|||
promptshow(content) { |
|||
this.prompt = content; |
|||
setTimeout(() => { |
|||
this.prompt = "" |
|||
}, 2000); |
|||
}, |
|||
initClipboard() { |
|||
if (this.clipboardInstance) { |
|||
this.clipboardInstance.destroy(); |
|||
} |
|||
|
|||
// 创建新的 Clipboard 实例 |
|||
this.clipboardInstance = new Clipboard(this.$refs.copyBtn, { |
|||
text: () => this.copyText, // 每次复制时获取当前的 copyText |
|||
}); |
|||
|
|||
// 监听复制失败事件 |
|||
this.clipboardInstance.on("success", () => { |
|||
this.promptshow("复制成功"); |
|||
}); |
|||
|
|||
// 监听复制失败事件 |
|||
this.clipboardInstance.on("error", () => { |
|||
this.promptshow("复制失败,请手动复制。"); |
|||
}); |
|||
}, |
|||
getCardSecret() { |
|||
this.$http.post(this.agent_url + "/h5_get_card_secret", { |
|||
orderid: this.orderid, |
|||
}).then(response => { |
|||
if (response.data.status) { |
|||
this.cardid = response.data.data.cardid; |
|||
this.copyText = "订单编号:" + this.orderid + "\n" + "卡号:" + this.cardid; |
|||
} else { |
|||
this.promptshow(response.data.info); |
|||
} |
|||
}, |
|||
response => { |
|||
this.promptshow("网络错误,请重试"); |
|||
}); |
|||
}, |
|||
back: function () { |
|||
this.$router.go(-1); |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.getCardSecret() |
|||
// 确保 ref 元素已经存在 |
|||
if (this.$refs.copyBtn) { |
|||
this.initClipboard() |
|||
} else { |
|||
console.error('复制按钮未找到'); |
|||
} |
|||
}, |
|||
beforeDestroy() { |
|||
// 组件销毁时清理 Clipboard 实例,防止内存泄漏 |
|||
if (this.clipboardInstance) { |
|||
this.clipboardInstance.destroy(); |
|||
} |
|||
} |
|||
}; |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.cardSecretBuy { |
|||
background: #F8F8F8; |
|||
font-size: 17px; |
|||
height: 100vh; |
|||
} |
|||
|
|||
.card-secret-detail { |
|||
height: 100vh; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.detail-content { |
|||
height: calc(100% - 120px); |
|||
background: #fff; |
|||
margin: 40px 20px; |
|||
padding: 20px; |
|||
position: relative; |
|||
} |
|||
|
|||
.detail-title { |
|||
border-bottom: 1px solid #ccc; |
|||
line-height: 30px; |
|||
text-align: center; |
|||
padding: 20px 0 40px; |
|||
} |
|||
|
|||
.msg1 { |
|||
font-weight: bold; |
|||
} |
|||
|
|||
.msg2 { |
|||
color: #747B8B; |
|||
} |
|||
|
|||
.blue { |
|||
color: #0F83FF; |
|||
} |
|||
|
|||
.detail-info { |
|||
margin-top: 30px; |
|||
display: flex; |
|||
line-height: 20px; |
|||
} |
|||
|
|||
.detail-info div:first-child { |
|||
text-align: left; |
|||
width: 50%; |
|||
color: #828897; |
|||
} |
|||
|
|||
.detail-info div:last-child { |
|||
text-align: right; |
|||
width: 50%; |
|||
color: #071432; |
|||
} |
|||
|
|||
.detail-btn { |
|||
display: flex; |
|||
width: 100%; |
|||
position: absolute; |
|||
bottom: 20px; |
|||
left: 0; |
|||
} |
|||
|
|||
.back { |
|||
border: 1px solid #0F83FF; |
|||
color: #0F83FF; |
|||
} |
|||
|
|||
.copy { |
|||
border: 1px solid #0F83FF; |
|||
background: #0F83FF; |
|||
color: #fff; |
|||
} |
|||
|
|||
.back, .copy { |
|||
margin: 20px; |
|||
padding: 12px; |
|||
width: 50%; |
|||
text-align: center; |
|||
border-radius: 5px; |
|||
} |
|||
</style> |
@ -0,0 +1,100 @@ |
|||
<template> |
|||
<div class="login"></div> |
|||
</template> |
|||
|
|||
<script> |
|||
import _global from "../utils/Global.vue"; |
|||
|
|||
export default { |
|||
name: 'Login', |
|||
data() { |
|||
return { |
|||
query_url:"", |
|||
agent_url: localStorage.getItem('agent_url'), |
|||
} |
|||
}, |
|||
props: { |
|||
page: { |
|||
type: String, |
|||
default: "" |
|||
}, |
|||
mckey: { |
|||
type: String, |
|||
default: "" |
|||
}, |
|||
}, |
|||
methods: { |
|||
tologin: function () { |
|||
this.$http.post(this.agent_url + "/get_wxlogin_url", { |
|||
query_url: this.query_url, |
|||
page: this.page |
|||
}).then(res => { |
|||
if (!res.data.status) { |
|||
alert("登录失败," + res.data.info); |
|||
} else { |
|||
location.href = res.data.data.loginurl; |
|||
} |
|||
}, response => { |
|||
alert("网络错误,请重试"); |
|||
}); |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.query_url = this.$route.query.url |
|||
if(!this.query_url){ |
|||
let error = { |
|||
title_error:"商家尚未开通手机访问功能", |
|||
detail_error_one:"商家尚未开通手机访问功能", |
|||
} |
|||
localStorage.setItem('H5OpenError', JSON.stringify(error)); |
|||
location.href = _global.hostname + '/index.html#/h5OpenError'; |
|||
} |
|||
const parsedUrl = new URL(decodeURIComponent(this.query_url)); |
|||
|
|||
this.agent_url = parsedUrl.origin |
|||
localStorage.setItem('agent_url', this.agent_url); |
|||
|
|||
this.$emit('loaded'); |
|||
|
|||
let isweixin = navigator.userAgent.toLowerCase().indexOf('micromessenger') > -1; |
|||
isweixin = true |
|||
if (!isweixin) { |
|||
let error = { |
|||
title_error:"只支持在微信中访问", |
|||
detail_error_one:"移动端只能在微信浏览器中访问", |
|||
detail_error_two:"请复制链接发送到手机微信端或者电脑端访问", |
|||
device:"手机微信端或者电脑端", |
|||
} |
|||
localStorage.setItem('H5OpenError', JSON.stringify(error)); |
|||
location.href = _global.hostname + '/index.html#/h5OpenError?url=' + this.query_url; |
|||
} |
|||
|
|||
if (this.mckey) { |
|||
this.$http.post(this.agent_url + "/h5_get_wxlogin_info", {mckey: this.mckey}).then(response => { |
|||
if (!response.data.status) { |
|||
this.tologin(); |
|||
return false; |
|||
} |
|||
|
|||
let uid = response.data.data.site_uid |
|||
let openid = response.data.data.openid |
|||
if (!uid || !openid) { |
|||
this.tologin(); |
|||
return false; |
|||
} |
|||
|
|||
window.islogin = true; |
|||
this.$cookies.set("site_uid", uid); |
|||
this.$cookies.set("openid_" + uid, openid); |
|||
}, response => { |
|||
alert("网络错误,请重试"); |
|||
}); |
|||
return; |
|||
} |
|||
|
|||
if (!window.islogin) { |
|||
this.tologin(); |
|||
} |
|||
} |
|||
} |
|||
</script> |
@ -0,0 +1,141 @@ |
|||
<template> |
|||
<div class="headtitle" v-cloak v-bind:class="{headerbg:headerbg}"> |
|||
<div class="leftbtn" v-on:click="leftbtn" v-if="showleft"></div> |
|||
<div class="rightbtn" v-if="showBtn" v-on:click="rightbtn"></div> |
|||
<div class="rightconcern" v-if="showconcern" v-on:click="shareqrcode">+关注</div> |
|||
<div class="addbtn" v-if="showadd" v-on:click="addbtn"><i></i>添加</div> |
|||
<div class="titlecontent" v-if="!title.isredhead && title.title">{{title.title}}</div> |
|||
<div class="titlecontent" v-else-if="title.isredhead" v-bind:class="{ redstyle : title.isredhead }">正品保障 直通官网</div> |
|||
<div class="titlecontent" v-else>{{title}}</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: "headTitle", |
|||
data() { |
|||
return {}; |
|||
}, |
|||
props: { |
|||
title: { |
|||
type: String, |
|||
default: "" |
|||
}, |
|||
showBtn: { |
|||
type: Boolean, |
|||
default: true |
|||
}, |
|||
headerbg: { |
|||
type: Boolean, |
|||
default: false |
|||
}, |
|||
showadd: { |
|||
type: Boolean, |
|||
default: false |
|||
}, |
|||
showleft: { |
|||
type: Boolean, |
|||
default: true |
|||
}, |
|||
showconcern: { |
|||
type: Boolean, |
|||
default: false |
|||
} |
|||
}, |
|||
methods: { |
|||
leftbtn() { |
|||
window.history.back(); |
|||
}, |
|||
rightbtn() { |
|||
}, |
|||
addbtn() { |
|||
}, |
|||
shareqrcode: function() { |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.headtitle { |
|||
width: 100%; |
|||
height: 1rem; |
|||
background: #ffffff; |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
z-index: 100; |
|||
} |
|||
.leftbtn { |
|||
width: 0.16rem; |
|||
height: 0.28rem; |
|||
background: url(../../assets/btn_back.svg) 0.32rem 0.36rem no-repeat; |
|||
background-size: 0.16rem 0.28rem; |
|||
padding: 0.36rem 0.5rem 0.36rem 0.32rem; |
|||
position: absolute; |
|||
left: 0; |
|||
top: 0; |
|||
} |
|||
.rightbtn { |
|||
width: 0.4rem; |
|||
height: 0.42rem; |
|||
background: url(../../assets/btn_personal.svg) 0.29rem 0.32rem no-repeat; |
|||
background-size: 0.4rem 0.42rem; |
|||
padding: 0.29rem 0.32rem; |
|||
position: absolute; |
|||
bottom: 0; |
|||
right: 0; |
|||
} |
|||
.rightconcern { |
|||
width: 1.5rem; |
|||
height: 0.75rem; |
|||
padding:0; |
|||
box-sizing:border-box; |
|||
background: #FE6710/* red *//* #3471EF */; |
|||
line-height: 0.75rem; |
|||
text-align: center; |
|||
font-size: 0.32rem; |
|||
position: absolute; |
|||
border-radius: 0.1rem; |
|||
bottom: 0.125rem; |
|||
right: 0.35rem; |
|||
color:white; |
|||
} |
|||
.titlecontent { |
|||
text-align: center; |
|||
height: 100%; |
|||
line-height: 1rem; |
|||
font-size: 0.32rem; |
|||
color: #262626; |
|||
} |
|||
.addbtn { |
|||
height: 100%; |
|||
width: 2rem; |
|||
line-height: 1rem; |
|||
position: absolute; |
|||
bottom: 0; |
|||
right: 0.4rem; |
|||
font-size: 0.28rem; |
|||
color: #262626; |
|||
text-align: right; |
|||
} |
|||
.addbtn i { |
|||
position: absolute; |
|||
bottom: 0; |
|||
right: 0.66rem; |
|||
width: 0.42rem; |
|||
height: 0.42rem; |
|||
background: url(../../assets/btn_add.svg) 0.1rem 0.29rem no-repeat; |
|||
background-size: 0.42rem; |
|||
padding: 0.29rem 0.1rem; |
|||
} |
|||
.headerbg{ |
|||
background:#E8E8E8; |
|||
} |
|||
.redstyle { |
|||
color:red; |
|||
} |
|||
[v-cloak] { |
|||
display: none; |
|||
} |
|||
</style> |
@ -0,0 +1,74 @@ |
|||
<template> |
|||
<div class="orderSample"> |
|||
<div class="sample-title"> |
|||
<div class="sample-circle">微信支付</div> |
|||
</div> |
|||
<div class="sample-content"> |
|||
<div class="sample-step step1">微信列表找到微信支付</div> |
|||
<img class="step-icon" src="../assets/images/order_sample/order_sample_one.png" alt="" srcset=""> |
|||
<div class="sample-step step2">微信列表找到微信支付</div> |
|||
<img class="step-icon" src="../assets/images/order_sample/order_sample_two.png" alt="" srcset=""> |
|||
<div class="sample-step step3">微信列表找到微信支付</div> |
|||
<img class="step-icon" src="../assets/images/order_sample/order_sample_three.png" alt="" srcset=""> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
|
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.orderSample { |
|||
background: #F8F8F8; |
|||
font-size: 17px; |
|||
} |
|||
|
|||
.sample-title { |
|||
line-height: 20px; |
|||
display: flex; |
|||
padding: 20px; |
|||
} |
|||
|
|||
.sample-circle { |
|||
width: 50%; |
|||
padding-left: 30px; |
|||
background-image: url(../assets/images/title_pic.png); |
|||
background-repeat: no-repeat; |
|||
background-position: 0 70%; |
|||
} |
|||
|
|||
.sample-content { |
|||
background: #fff; |
|||
padding:0 20px 20px; |
|||
margin:0 20px 20px; |
|||
border: 1px solid #F8F8F8; |
|||
border-radius: 10px; |
|||
box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.1); |
|||
} |
|||
|
|||
.sample-step { |
|||
background-repeat: no-repeat; |
|||
background-position: 0 50%; |
|||
line-height: 60px; |
|||
padding-left: 30px; |
|||
} |
|||
|
|||
.step1 { |
|||
background-image: url("../assets/images/order_sample/order_sample_1.png"); |
|||
} |
|||
|
|||
.step2 { |
|||
background-image: url("../assets/images/order_sample/order_sample_2.png"); |
|||
} |
|||
|
|||
.step3 { |
|||
background-image: url("../assets/images/order_sample/order_sample_3.png"); |
|||
} |
|||
|
|||
.step-icon { |
|||
width: 100%; |
|||
} |
|||
</style> |
@ -0,0 +1,10 @@ |
|||
<script type="text/javascript"> |
|||
const hostname = "http://" + window.location.hostname; // 域名 |
|||
// const hostname = "http://localhost:8082"; // 域名 |
|||
const css_url = "//css.pengda.checkcopy.com"; |
|||
|
|||
export default { |
|||
hostname, |
|||
css_url |
|||
}; |
|||
</script> |
@ -0,0 +1,64 @@ |
|||
// 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 App from './App' |
|||
import router from './router' |
|||
import VueWechatTitle from 'vue-wechat-title' |
|||
import VueTouch from 'vue-touch' |
|||
import VueClipboard from 'vue-clipboard2' |
|||
// 导入全局变量模块
|
|||
import _global from './components/utils/Global' |
|||
Vue.prototype.GLOBAL = _global |
|||
//倒入全局weui
|
|||
import 'weui' |
|||
import weui from 'weui.js' |
|||
Vue.prototype.$weui = weui; |
|||
|
|||
require('es6-promise').polyfill(); |
|||
|
|||
Vue.config.productionTip = false |
|||
|
|||
Vue.use(VueWechatTitle) |
|||
Vue.use(VueTouch) |
|||
Vue.use(VueClipboard) |
|||
Vue.use(VueLazyload, { |
|||
error: '',//这个是请求失败后显示的图片
|
|||
loading: 'static/loading.gif',//这个是加载的loading过渡效果
|
|||
try: 4 // 这个是加载图片数量
|
|||
}) |
|||
Vue.http.interceptors.push(function (request, next) {//拦截器
|
|||
// 跨域携带cookie
|
|||
request.credentials = true; |
|||
request.crossDomain = true; |
|||
// request.Cookies = document.cookie;
|
|||
next() |
|||
}) |
|||
Vue.http.headers = {'Content-Type': 'application/x-www-form-urlencoded'} |
|||
Vue.http.options.xhr = {withCredentials: true} |
|||
Vue.http.options.emulateJSON = true |
|||
|
|||
//判断是否登录
|
|||
let cookieobj = document.cookie; |
|||
let Cookies = {}; |
|||
cookieobj.split(';').forEach(l => { |
|||
var parts = l.split('='); |
|||
Cookies[parts[0].trim()] = (parts[1] || '').trim(); |
|||
}); |
|||
|
|||
let islogin = false; |
|||
let site_uid = Cookies['site_uid']; |
|||
let openid = 'openid_' + site_uid; |
|||
if (Cookies[openid] && Cookies['site_uid']) { |
|||
islogin = true; |
|||
} |
|||
window.islogin = islogin; |
|||
|
|||
/* eslint-disable no-new */ |
|||
new Vue({ |
|||
el: '#app', |
|||
router, |
|||
components: {App}, |
|||
template: '<App/>', |
|||
mounted: function () { |
|||
} |
|||
}); |
@ -0,0 +1,79 @@ |
|||
import _global from "../components/utils/Global.vue"; |
|||
|
|||
var router = new VueRouter({ |
|||
routes: [ |
|||
{ |
|||
path: '/h5OpenError', |
|||
name: '/H5OpenError', |
|||
component: resolve => require(['@/components/H5OpenError'], resolve), //打开页面不正确
|
|||
meta: { title: '' }, |
|||
}, |
|||
{ |
|||
path: '/cardSecretBuy', |
|||
name: '/cardSecretBuy', |
|||
component: resolve => require(['@/components/cardSecretBuy'], resolve), |
|||
meta: { title: '购买卡密' }, |
|||
}, |
|||
{ |
|||
path: '/cardSecretQuery', |
|||
name: '/cardSecretQuery', |
|||
component: resolve => require(['@/components/cardSecretQuery'], resolve), |
|||
meta: { title: '卡密提取' }, |
|||
}, |
|||
{ |
|||
path: '/orderSample', |
|||
name: '/orderSample', |
|||
component: resolve => require(['@/components/orderSample'], resolve), |
|||
meta: { title: '订单指引' }, |
|||
} |
|||
] |
|||
}); |
|||
|
|||
router.afterEach((to, from) => { |
|||
(function(doc, win) { |
|||
var userAgentInfo = navigator.userAgent; |
|||
var Agents = ["Android", "iPhone", |
|||
"SymbianOS", "Windows Phone", |
|||
"iPad", "iPod"]; |
|||
var isphone = false; |
|||
for (var v = 0; v < Agents.length; v++) { |
|||
if (userAgentInfo.indexOf(Agents[v]) > 0) { |
|||
isphone = true; |
|||
break; |
|||
} |
|||
} |
|||
if(!isphone) { |
|||
var jump_true = decodeURIComponent(location.href.split('?url=')[1]); |
|||
if(jump_true) { |
|||
location.href=jump_true; |
|||
} |
|||
} |
|||
var docEl = doc.documentElement, |
|||
resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize'; |
|||
var recalc = function() { |
|||
var width = docEl.clientWidth; |
|||
if (width < 300) { |
|||
width = 300; |
|||
} |
|||
if(width>414){ |
|||
width=414; |
|||
} |
|||
docEl.dataset.width = width |
|||
docEl.dataset.percent = 100 * (width / 750); |
|||
docEl.style.fontSize = 100 * (width / 750) + 'px'; |
|||
}; |
|||
recalc(); |
|||
if (!doc.addEventListener) return; |
|||
win.addEventListener(resizeEvt, recalc, false); |
|||
})(document, window); |
|||
|
|||
if(typeof(islogin)!='undefined'){ |
|||
if(!islogin) { |
|||
return; |
|||
} |
|||
} |
|||
window.hashistory = from.path; |
|||
document.getElementById('app') && document.getElementById('app').scrollTo(0,0); |
|||
}); |
|||
|
|||
export default router; |
After Width: | Height: | Size: 6.1 KiB |
@ -0,0 +1,27 @@ |
|||
// A custom Nightwatch assertion.
|
|||
// The assertion name is the filename.
|
|||
// Example usage:
|
|||
//
|
|||
// browser.assert.elementCount(selector, count)
|
|||
//
|
|||
// For more information on custom assertions see:
|
|||
// http://nightwatchjs.org/guide#writing-custom-assertions
|
|||
|
|||
exports.assertion = function (selector, count) { |
|||
this.message = 'Testing if element <' + selector + '> has count: ' + count |
|||
this.expected = count |
|||
this.pass = function (val) { |
|||
return val === this.expected |
|||
} |
|||
this.value = function (res) { |
|||
return res.value |
|||
} |
|||
this.command = function (cb) { |
|||
var self = this |
|||
return this.api.execute(function (selector) { |
|||
return document.querySelectorAll(selector).length |
|||
}, [selector], function (res) { |
|||
cb.call(self, res) |
|||
}) |
|||
} |
|||
} |
@ -0,0 +1,46 @@ |
|||
require('babel-register') |
|||
var config = require('../../config') |
|||
|
|||
// http://nightwatchjs.org/gettingstarted#settings-file
|
|||
module.exports = { |
|||
src_folders: ['test/e2e/specs'], |
|||
output_folder: 'test/e2e/reports', |
|||
custom_assertions_path: ['test/e2e/custom-assertions'], |
|||
|
|||
selenium: { |
|||
start_process: true, |
|||
server_path: require('selenium-server').path, |
|||
host: '127.0.0.1', |
|||
port: 4444, |
|||
cli_args: { |
|||
'webdriver.chrome.driver': require('chromedriver').path |
|||
} |
|||
}, |
|||
|
|||
test_settings: { |
|||
default: { |
|||
selenium_port: 4444, |
|||
selenium_host: 'localhost', |
|||
silent: true, |
|||
globals: { |
|||
devServerURL: 'http://localhost:' + (process.env.PORT || config.dev.port) |
|||
} |
|||
}, |
|||
|
|||
chrome: { |
|||
desiredCapabilities: { |
|||
browserName: 'chrome', |
|||
javascriptEnabled: true, |
|||
acceptSslCerts: true |
|||
} |
|||
}, |
|||
|
|||
firefox: { |
|||
desiredCapabilities: { |
|||
browserName: 'firefox', |
|||
javascriptEnabled: true, |
|||
acceptSslCerts: true |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,48 @@ |
|||
// 1. start the dev server using production config
|
|||
process.env.NODE_ENV = 'testing' |
|||
|
|||
const webpack = require('webpack') |
|||
const DevServer = require('webpack-dev-server') |
|||
|
|||
const webpackConfig = require('../../build/webpack.prod.conf') |
|||
const devConfigPromise = require('../../build/webpack.dev.conf') |
|||
|
|||
let server |
|||
|
|||
devConfigPromise.then(devConfig => { |
|||
const devServerOptions = devConfig.devServer |
|||
const compiler = webpack(webpackConfig) |
|||
server = new DevServer(compiler, devServerOptions) |
|||
const port = devServerOptions.port |
|||
const host = devServerOptions.host |
|||
return server.listen(port, host) |
|||
}) |
|||
.then(() => { |
|||
// 2. run the nightwatch test suite against it
|
|||
// to run in additional browsers:
|
|||
// 1. add an entry in test/e2e/nightwatch.conf.js under "test_settings"
|
|||
// 2. add it to the --env flag below
|
|||
// or override the environment flag, for example: `npm run e2e -- --env chrome,firefox`
|
|||
// For more information on Nightwatch's config file, see
|
|||
// http://nightwatchjs.org/guide#settings-file
|
|||
let opts = process.argv.slice(2) |
|||
if (opts.indexOf('--config') === -1) { |
|||
opts = opts.concat(['--config', 'test/e2e/nightwatch.conf.js']) |
|||
} |
|||
if (opts.indexOf('--env') === -1) { |
|||
opts = opts.concat(['--env', 'chrome']) |
|||
} |
|||
|
|||
const spawn = require('cross-spawn') |
|||
const runner = spawn('./node_modules/.bin/nightwatch', opts, { stdio: 'inherit' }) |
|||
|
|||
runner.on('exit', function (code) { |
|||
server.close() |
|||
process.exit(code) |
|||
}) |
|||
|
|||
runner.on('error', function (err) { |
|||
server.close() |
|||
throw err |
|||
}) |
|||
}) |
@ -0,0 +1,19 @@ |
|||
// For authoring Nightwatch tests, see
|
|||
// http://nightwatchjs.org/guide#usage
|
|||
|
|||
module.exports = { |
|||
'default e2e tests': function (browser) { |
|||
// automatically uses dev Server port from /config.index.js
|
|||
// default: http://localhost:8080
|
|||
// see nightwatch.conf.js
|
|||
const devServer = browser.globals.devServerURL |
|||
|
|||
browser |
|||
.url(devServer) |
|||
.waitForElementVisible('#app', 5000) |
|||
.assert.elementPresent('.hello') |
|||
.assert.containsText('h1', 'Welcome to Your Vue.js App') |
|||
.assert.elementCount('img', 1) |
|||
.end() |
|||
} |
|||
} |
@ -0,0 +1,7 @@ |
|||
{ |
|||
"env": { |
|||
"jest": true |
|||
}, |
|||
"globals": { |
|||
} |
|||
} |
@ -0,0 +1,30 @@ |
|||
const path = require('path') |
|||
|
|||
module.exports = { |
|||
rootDir: path.resolve(__dirname, '../../'), |
|||
moduleFileExtensions: [ |
|||
'js', |
|||
'json', |
|||
'vue' |
|||
], |
|||
moduleNameMapper: { |
|||
'^@/(.*)$': '<rootDir>/src/$1' |
|||
}, |
|||
transform: { |
|||
'^.+\\.js$': '<rootDir>/node_modules/babel-jest', |
|||
'.*\\.(vue)$': '<rootDir>/node_modules/vue-jest' |
|||
}, |
|||
testPathIgnorePatterns: [ |
|||
'<rootDir>/test/e2e' |
|||
], |
|||
snapshotSerializers: ['<rootDir>/node_modules/jest-serializer-vue'], |
|||
setupFiles: ['<rootDir>/test/unit/setup'], |
|||
mapCoverage: true, |
|||
coverageDirectory: '<rootDir>/test/unit/coverage', |
|||
collectCoverageFrom: [ |
|||
'src/**/*.{js,vue}', |
|||
'!src/main.js', |
|||
'!src/router/index.js', |
|||
'!**/node_modules/**' |
|||
] |
|||
} |
@ -0,0 +1,3 @@ |
|||
import Vue from 'vue' |
|||
|
|||
Vue.config.productionTip = false |
@ -0,0 +1,11 @@ |
|||
import Vue from 'vue' |
|||
import HelloWorld from '@/components/HelloWorld' |
|||
|
|||
describe('HelloWorld.vue', () => { |
|||
it('should render correct contents', () => { |
|||
const Constructor = Vue.extend(HelloWorld) |
|||
const vm = new Constructor().$mount() |
|||
expect(vm.$el.querySelector('.hello h1').textContent) |
|||
.toEqual('Welcome to Your Vue.js App') |
|||
}) |
|||
}) |