Commit 713b54b0 authored by Gakki's avatar Gakki

主项目拆分

parent 26b10ad4
{
"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": "ant-design-vue",
"LibraryDirectory": "es",
"style": "css"
}]
]
}
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
module.exports = {
// 当前文件为eslint的根配置文件
root: true,
// 解析器
parserOptions: {
parser: 'babel-eslint',
},
// 运行环境
env: {
browser: true,
},
// 规则继承,vue主要的额外规则是v-if等指令的检测
extends: ['plugin:vue/essential'],
// 使用eslint-plugin-vue插件帮忙检测.vue文件的代码
plugins: [
'vue'
],
/**
* 自定义规则
* "off" 或 0 : 关闭规则
* "warn" 或 1 : 触犯规则为警告(不会中止程序)
* "error" 或 2 : 触犯规则为错误(触发时会中止程序)
* 额外选项可以通过数组字面量指定,例子如下:
* "quotes": ["error", "single"]
*/
rules: {
"no-debugger": process.env.NODE_ENV === 'production' ? 2 : 0, // 生产环境禁止debugger
"no-console": process.env.NODE_ENV === 'production' ? 2 : 0, // 生产环境禁止console
"no-alert": process.env.NODE_ENV === 'production' ? 2 : 0, // 生产环境禁止alert
"no-shadow-restricted-names": 2, // 禁用关键字及保留字等
"dot-notation": 1, // 尽可能使用 . 来访问对象属性
"no-multi-spaces": 1, // 禁止使用多个空格
"brace-style": 1, // 大括号风格 - one true brace style
"no-var": 1, // 禁用var声明
"no-new-object": 1, // 禁止new Object
"no-array-constructor": 1, // 禁止new Array
"prefer-const": 0, // 要求使用 const 声明那些声明后不再被修改的变量
"prefer-destructuring": 0, // 优先使用数组和对象解构
"no-param-reassign": 0, // 禁止在函数中对函数参数重新赋值
"no-extra-semi": 1, // 禁用不必要的分号
"no-unused-vars": 0, // 禁止已声明但未使用的变量
"indent": [1, 2], // 使用2个空格缩进
"no-multiple-empty-lines": [1, {max: 1}], // 禁止连续出现2个及以上空行
"default-case": 1, // 要求switch语句必须有default分支
"key-spacing": [1, {"beforeColon": false, "afterColon": true}], // 冒号前不要空格,后需要空格
"comma-spacing": [1, {"before": false, "after": true}], // 逗号前不要空格,后需要空格
"arrow-spacing": [1, {"before": true, "after": true}], // 箭头函数中的箭头前后需要留空格
"quotes": [1, "single"], // 字符串使用单引号
"semi": [1, "never"], // 禁止使用分号
"linebreak-style": 0, // 强制使用一样的换行符风格
}
}
.DS_Store
node_modules/
/node_modules/
/dist/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# Next.js build output
.next
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and *not* Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
node_modules
node_modules
node_modules
// 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": {}
}
}
FROM 10.0.6.228:5000/node-nginx:8.12.0-slim
WORKDIR /app
COPY . /app/
RUN npm config set proxy=http://10.0.6.228:3128 && npm set registry https://registry.npm.taobao.org && npm install && npm run build:devol && cp -r dist/* /var/www/html && cp nginx.conf /etc/nginx/conf.d && rm -rf /etc/nginx/sites-enabled && rm -rf /app
pipeline {
agent {
node {
label 'nodejs'
}
}
environment {
KUBECONFIG_CREDENTIAL_ID = 'devops-kubeconfig'
REGISTRY = '10.0.6.228:5000'
DOCKERHUB_NAMESPACE = 'housemanage-test'
APP_NAME = 'web-pudong'
NAMESPACE = 'housemanage-test'
}
stages {
stage ('checkout scm') {
steps {
checkout(scm)
}
}
stage ('build & push') {
steps {
container ('nodejs') {
sh 'docker build -f Dockerfile -t $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:$BUILD_NUMBER .'
sh 'docker push $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:$BUILD_NUMBER'
}
}
}
stage('deploy') {
steps {
kubernetesDeploy(configs: 'deploy/**', enableConfigSubstitution: true, kubeconfigId: "$KUBECONFIG_CREDENTIAL_ID")
}
}
}
}
MIT License
Copyright (c) 2020 Max Kwok
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# micfrontend-template
## 微前端项目用模板
> ## 子项目接入须知
### 1. 建立子项目唯一标识,下面都将以‘child’为例
### 2. 在/build/webpack.base.conf.js文件中的output对象添加如下配置:
```javascript
output: {
library: 'child',
libraryTarget: 'umd',
// 原来的配置项此处省略了,别删掉了
}
```
### 3. 在/router/index.js文件中的router实例添加如下配置:
```javascript
new Router({
mode: 'history',
base: window.__POWERED_BY_QIANKUN__ ? "/child/" : "/",
// 原来的配置项此处省略了,别删掉了
})
```
### 4. 修改项目入口文件/src/main.js文件代码,暴露出3个生命周期函数:
```javascript
// 原来的方法
/* eslint-disable no-new */
// new Vue({
// el: '#app',
// router,
// store,
// components: { App },
// template: '<App/>'
// })
// 替换为如下代码
/* eslint-disable no-new */
let instance = null
export async function bootstrap() {}
export async function mount() {
instance = new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
}
export async function unmount() {
instance.$destroy()
instance = null
}
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
} else {
mount()
}
```
---
## 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).
'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:'))
for (let i = 0; i < warnings.length; i++) {
const warning = warnings[i]
console.log(' ' + warning)
}
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,
fallback: 'vue-style-loader'
})
} else {
return ['vue-style-loader'].concat(loaders)
}
}
// https://vue-loader.vuejs.org/en/configurations/extract-css.html
return {
css: generateLoaders(),
postcss: generateLoaders(),
less: generateLoaders('less'),
sass: generateLoaders('sass', { indentedSyntax: true }),
scss: generateLoaders('sass'),
stylus: generateLoaders('stylus'),
styl: generateLoaders('stylus')
}
}
// Generate loaders for standalone style files (outside of .vue)
exports.styleLoaders = function (options) {
const output = []
const loaders = exports.cssLoaders(options)
for (const extension in loaders) {
const loader = loaders[extension]
output.push({
test: new RegExp('\\.' + extension + '$'),
use: loader
})
}
return output
}
exports.createNotifierCallback = () => {
const notifier = require('node-notifier')
return (severity, errors) => {
if (severity !== 'error') return
const error = errors[0]
const filename = error.file && error.file.split('!').pop()
notifier.notify({
title: packageConfig.name,
message: severity + ': ' + error.name,
subtitle: filename || '',
icon: path.join(__dirname, 'logo.png')
})
}
}
'use strict'
const utils = require('./utils')
const config = require('../config')
const isProduction = process.env.NODE_ENV === 'production'
const sourceMapEnabled = isProduction
? config.build.productionSourceMap
: config.dev.cssSourceMap
module.exports = {
loaders: utils.cssLoaders({
sourceMap: sourceMapEnabled,
extract: isProduction
}),
cssSourceMap: sourceMapEnabled,
cacheBusting: config.dev.cacheBusting,
transformToRequire: {
video: ['src', 'poster'],
source: 'src',
img: 'src',
image: 'xlink:href'
}
}
'use strict'
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')
function resolve (dir) {
return path.join(__dirname, '..', dir)
}
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'
}
}
'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')
let env = require('../config/prod.env')
console.log(process.env.NODE_ENV)
if (process.env.NODE_ENV === 'sit') {
env = require('../config/sit.env')
} else if (process.env.NODE_ENV === 'uat') {
env = require('../config/uat.env')
} else if (process.env.NODE_ENV === 'devol') {
env = require('../config/devOnline.env')
} else if (process.env.NODE_ENV === 'pudong-sit') {
env = require('../config/pudong/sit.env')
} else if (process.env.NODE_ENV === 'pudong-uat') {
env = require('../config/pudong/uat.env')
} else if (process.env.NODE_ENV === 'xuhui-sit') {
env = require('../config/xuhui/sit.env')
} else if (process.env.NODE_ENV === 'xuhui-uat') {
env = require('../config/xuhui/uat.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,
drop_debugger: true,
drop_console: true,
}
},
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'
module.exports = {
NODE_ENV: '"devol"'
}
'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: {
// '/api': {
// target: 'http://localhost:7771',
// changOrigin: true,
// pathRewrite: {
// '^/api': ''
// }
// }
},
// 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: false,
// 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: true,
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"'
}
'use strict'
module.exports = {
NODE_ENV: '"pudong-sit"'
}
'use strict'
module.exports = {
NODE_ENV: '"pudong-uat"'
}
'use strict'
module.exports = {
NODE_ENV: '"sit"'
}
'use strict'
module.exports = {
NODE_ENV: '"xuhui-sit"'
}
'use strict'
module.exports = {
NODE_ENV: '"xuhui-uat"'
}
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
labels:
app: $APP_NAME
name: $APP_NAME
namespace: $NAMESPACE
spec:
progressDeadlineSeconds: 600
replicas: 1
selector:
matchLabels:
app: $APP_NAME
template:
metadata:
labels:
app: $APP_NAME
spec:
containers:
- image: $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:$BUILD_NUMBER
imagePullPolicy: Always
name: $APP_NAME
readinessProbe:
httpGet:
path: /
port: 80
timeoutSeconds: 10
failureThreshold: 30
periodSeconds: 5
ports:
- containerPort: 80
protocol: TCP
resources:
limits:
cpu: 200m
memory: 500Mi
requests:
cpu: 100m
memory: 100Mi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Always
terminationGracePeriodSeconds: 30
---
apiVersion: v1
kind: Service
metadata:
labels:
app: $APP_NAME
name: $APP_NAME
namespace: $NAMESPACE
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: 80
selector:
app: $APP_NAME
sessionAffinity: None
type: ClusterIP
<!DOCTYPE html>
<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>demo</title>
</head>
<body>
<div id="portal"></div>
<div id="helperContainer"> </div>
<!-- built files will be auto injected -->
</body>
<!-- 参数:iconStyle可以为'' 默认箭头图标
或者bottom ?和 x 图标
className可以为'' 帮助中心高度100%
或者contTop 上面不到顶
-->
<script id="helperContainerScript" src="http://help.omniview.pro/script/do.js?v=2&iconStyle=bottom&className=contTop&key=26a2a7a3048b31292696a63e0ac3c3e5e0773c0ca9b97b2fbf65cbfde8c7fc426523c29dae10c697c62be63b88be7a69657927610b9dbdbd"></script>
</html>
server {
listen 80;
server_name localhost;
#vue项目的打包后的dist
root /var/www/html;
location / {
add_header Access-Control-Allow-Origin *;
add_header X-Frame-Options ALLOWALL;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
try_files $uri $uri/ @router;#需要指向下面的@router否则会出现vue的路由在nginx中刷新出现404
index index.html index.htm;
}
#对应上面的@router,主要原因是路由的路径资源并不是一个真实的路径,所以无法找到具体的文件
#因此需要rewrite到index.html中,然后交给路由在处理请求资源
location @router {
rewrite ^.*$ /index.html last;
}
}
This diff is collapsed.
{
"name": "micfrontend-template",
"version": "1.0.0",
"description": "微前端项目用模板",
"author": "yaominguo <missgmy@yahoo.com>",
"private": true,
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"start": "npm run dev",
"lint": "eslint --fix --ext .js,.vue src",
"build": "cross-env NODE_ENV='production' node build/build.js",
"build:devol": "cross-env NODE_ENV='devol' node build/build.js",
"build:sit": "cross-env NODE_ENV='sit' node build/build.js",
"build:uat": "cross-env NODE_ENV='uat' node build/build.js",
"build:pudong-sit": "cross-env NODE_ENV='pudong-sit' node build/build.js",
"build:pudong-uat": "cross-env NODE_ENV='pudong-uat' node build/build.js",
"build:xuhui-sit": "cross-env NODE_ENV='xuhui-sit' node build/build.js",
"build:xuhui-uat": "cross-env NODE_ENV='xuhui-uat' node build/build.js"
},
"dependencies": {
"ant-design-vue": "^1.4.3",
"axios": "^0.19.2",
"babel-polyfill": "^6.26.0",
"crypto-js": "^4.0.0",
"js-cookie": "^2.2.1",
"js-md5": "^0.7.3",
"qiankun": "^1.4.6",
"qs": "^6.9.3",
"vue": "^2.5.2",
"vue-router": "^3.0.1",
"vuex": "^3.4.0"
},
"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.13.0",
"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",
"compression-webpack-plugin": "^1.1.12",
"copy-webpack-plugin": "^4.0.1",
"cross-env": "^5.2.0",
"css-loader": "^0.28.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",
"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="portalApp">
<Loader />
<router-view/>
</div>
</template>
<script>
import Loader from '@/components/Layout/loader'
// import {routes} from '@/router/routes'
import {mapMutations} from 'vuex'
export default {
name: 'portalApp',
components: {
Loader,
},
props: {
content: String,
loading: Boolean,
},
methods: {
...mapMutations([
'setContent',
'setLoading',
])
},
mounted() {
// /** 持久化存储vuex 使其页面刷新后数据不丢失 */
// //在页面加载时读取sessionStorage里的状态信息
// if (sessionStorage.getItem('VuexStore')) {
// this.$store.replaceState(Object.assign({}, this.$store.state, JSON.parse(sessionStorage.getItem('VuexStore'))))
// }
// //在页面刷新时将vuex里的信息保存到sessionStorage里
// window.addEventListener('beforeunload', () => {
// sessionStorage.setItem('VuexStore', JSON.stringify(this.$store.state))
// })
const addRoutes = (data) => {
const {routes} = this.$router.options
const parent = routes.find(item => item.name === 'Layout')
parent.children.push(...data)
this.$router.addRoutes([parent])
}
if(this.$store.state.routes.length > 0) {
addRoutes(this.$store.state.routes)
return
}
},
beforeDestroy() {
window.removeEventListener('beforeunload', () => {
sessionStorage.setItem('VuexStore', JSON.stringify(this.$store.state))
})
},
watch: {
content(cur) {
this.setContent(cur)
},
loading(cur) {
this.setLoading(cur)
}
}
}
</script>
<style>
#portalApp {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
width: 100%;
height: 100%;
overflow: hidden;
}
</style>
.layoutMargin {
background-color: #fff;
margin: 16px 16px 0 16px;
}
.layoutPadding {
padding: 20px;
}
.routerWapper { height: 100%;}
.contentPadding { padding: 20px 10px }
/* 全局table设置 */
/* .routerWapper{ */
/* overflow: hidden; */
/* overflow-y:scroll; */
/* height: 100%; */
/* } */
a, a:focus, a:active, a:visited {
text-decoration: none;
}
.portalTableOperates {
margin-bottom: 10px;
}
.portalTable {
margin-bottom: 16px;
padding: 10px;
}
.portalTable .actionBtn {
color: #1890ff;
cursor: pointer;
}
/* 全局基础样式设置 */
.algin-right {
text-align: right;
}
.gayLine {
display: block;
clear: both;
width: 100%;
border-bottom: 1px dashed #e0e0e0;
margin: 20px 0
}
.gayLine.noline {
border-color: transparent
}
/* 全局表单样式 */
.protalForm .formItem {
width: 100%
}
.protalForm .formItemLine {
margin-bottom: 10px;
}
/* 详情页 */
.portalDetailWapper {
height: 100%;
}
.portalDetailTitle {
position: relative;
z-index: 2;
background-color: #fff;
text-align: left;
box-shadow: 0 2px 5px #e0e0e0
}
.portalDetailTitle .title {
font-size: 16px;
font-weight: bold;
color: #232323;
height: 60px;
line-height: 60px;
padding-left: 1rem
}
.portalDetailTitle .detailOperations {
float: right;
margin: 14px 1rem 0 0
}
.portalDetailContentWapper {
position: relative;
z-index: 1;
height: calc(100% - 60px)
}
.portalDetailContentBody {
position: relative;
z-index: 1;
overflow: hidden;
overflow-y: scroll;
padding-bottom: 20px;
height: 100%;
}
.portalDetailContentWapper .detailsPartSection {
margin-top: 20px;
padding-bottom: 20px;
}
.portalDetailContentWapper .detailsPartTitle {
text-align: left;
font-weight: bold;
color: #232323;
margin: 0 16px 16px 16px;
font-size: 16px;
text-indent: 0.5rem;
line-height: 60px;
border-bottom: 1px solid #e0e0e0;
}
.portalDetailContentWapper .detailsPartLine { margin-bottom: 16px }
/* 权限树详情页 */
.portalRoleTree { display: flex; flex-wrap: wrap; }
.portalRoleTree>li { flex: 0 0 25%; }
.portalRoleConfigTree .ant-tree-child-tree{ display: flex; flex-wrap: wrap; }
.portalRoleConfigTree .ant-tree-child-tree{ display: flex; flex-wrap: wrap; }
/* .portalRoleTree.ant-tree>li>.ant-tree-node-content-wrapper, */
.portalRoleConfigTree.ant-tree>li>.ant-tree-node-content-wrapper{ font-weight: bold }
.ant-input,
.ant-select,
.ant-select-selection,
.ant-input-number,
.ant-table {
border-radius: 2px;
}
.ant-btn {border-radius:2px; cursor: pointer;}
.ant-btn.ant-btn-default { border-color:#1890ff; color: #1890ff }
.has-error .ant-form-explain, .has-error .ant-form-split {font-size: 12px;}
.ant-form-item-control .ant-form-explain, .ant-form-item-control .ant-form-split { margin-top: 0px}
.ant-layout { height:100%}
/* 去除表单验证提示下方外边距 */
.protalForm .ant-form-item { margin-bottom: 0}
.protalForm.ant-form-inline .ant-form-item-with-help { margin-bottom: 0px}
/* 去掉进度条圆角 */
.ant-progress-inner,
.ant-progress-bg {
border-radius: 0 !important;
}
.ant-progress-inner {
background: #fff;
border: 1px solid #1890ff;
}
.ant-layout-sider-zero-width-trigger{
height: 0;
}
.portalDetailContentWapper .detailsPartLine{
margin-right: 1px;
margin-bottom: 1px;
}
/* 表格的操作那一列居中 */
.ant-table-tbody > tr > td:nth-last-child(1) {
text-align: center;
}
.ant-table-small > .ant-table-content > .ant-table-header > table > .ant-table-thead > tr > th, .ant-table-small > .ant-table-content > .ant-table-body > table > .ant-table-thead > tr > th, .ant-table-small > .ant-table-content > .ant-table-scroll > .ant-table-header > table > .ant-table-thead > tr > th, .ant-table-small > .ant-table-content > .ant-table-scroll > .ant-table-body > table > .ant-table-thead > tr > th, .ant-table-small > .ant-table-content > .ant-table-fixed-left > .ant-table-header > table > .ant-table-thead > tr > th, .ant-table-small > .ant-table-content > .ant-table-fixed-right > .ant-table-header > table > .ant-table-thead > tr > th, .ant-table-small > .ant-table-content > .ant-table-fixed-left > .ant-table-body-outer > .ant-table-body-inner > table > .ant-table-thead > tr > th, .ant-table-small > .ant-table-content > .ant-table-fixed-right > .ant-table-body-outer > .ant-table-body-inner > table > .ant-table-thead > tr > th{
text-align: center;
}
.ant-calendar-picker{
width: 100%;
}
/* 各个表单的搜索与重置. */
.algin-right {
margin-right: 10px;
margin-top: 14px;
}
This diff is collapsed.
<template>
<a-form :form="form">
<slot name="title"/>
<a-row v-for="(row, rowIndex) in layout" :key="rowIndex">
<a-col v-for="(item, key) in row" :key="key" :span="item.width" :offset="item.offset || 0" v-show="!item.hidden">
<!-- 不想包裹在a-form-item中可以设置custom为true, 否则render的组件在ActiveFormItem中定义 -->
<template v-if="item.custom && item.render">
<component :is="custom(key, item.render, item.props)"/>
</template>
<ActiveFormItem
v-else
:entry="key"
:model="model"
:item="item"
:labelWidth="labelWidth"
/>
</a-col>
</a-row>
<slot />
</a-form>
</template>
<script>
import Vue from 'vue'
import moment from 'moment'
import ActiveFormItem from './ActiveFormItem'
export default {
name: 'ActiveForm',
components: {
ActiveFormItem
},
props: {
layout: {
type: Array,
required: true
},
model: {
type: Object,
default () {
return {}
}
},
labelWidth: {
type: Number,
default () {
return 5
}
}
},
created () {
this.filterDateItem()
},
data () {
return {
form: this.$form.createForm(this, {
// 当表单值变化时同时赋给model
onValuesChange: (e, val) => {
this.model = Object.assign(this.model, this.operateDateItem(val, true))
}
}),
dateItems: {}
}
},
mounted () {
const model = this.filterDataModel(this.model)
// 根据model初始化表单值
this.form.setFieldsValue(this.operateDateItem(model, false))
},
methods: {
custom(entry, render, props) {
return Vue.component(entry, {
render: render,
props: props,
})
},
// 表单验证,上级组件可以通过this.$refs来调用此函数
validate (callback) {
this.form.validateFields((err, values) => {
if (err) {
this.$com.getFormValidErrTips(this, err) // 这边是后来加的需求,说要全局弹窗
}
callback(err, values)
})
},
// 筛选layout中的日期组件
filterDateItem () {
const result = {}
this.layout.forEach(item => {
for (const key in item) {
if (item[key].type && (item[key].type == 'date' || item[key].type == 'daterange')) {
result[key] = item[key]
}
}
})
this.dateItems = result
},
// 由于antd的日期组件都是moment格式,这里进行了转化成字符串
operateDateItem (obj, isMomentToString) {
const model = { ...obj }
for (const key in model) {
const dateItem = this.dateItems[key]
if (dateItem) {
if (dateItem.type == 'date') {
if (isMomentToString) {
if (!moment.isMoment(model[key])) return model
model[key] = moment(model[key]).format(dateItem.format || 'YYYY-MM-DD')
} else {
model[key] = moment(model[key], dateItem.format || 'YYYY-MM-DD')
}
} else if (dateItem.type == 'daterange') {
if (isMomentToString) {
if (!moment.isMoment(model[key][0]) || !moment.isMoment(model[key][1])) return model
model[key] = [moment(model[key][0]).format(dateItem.format || 'YYYY-MM-DD'), moment(model[key][1]).format(dateItem.format || 'YYYY-MM-DD')]
} else {
model[key] = [moment(model[key][0], dateItem.format || 'YYYY-MM-DD'), moment(model[key][1], dateItem.format || 'YYYY-MM-DD')]
}
}
}
}
return model
},
// 过滤掉layout中不存在的字段,防止You cannot set a form field before rendering a field associated with the value.的错误
filterDataModel (model) {
const keys = Object.keys(model)
if (keys.length <= 0) return {}
const list = []
if (this.layout.length > 0) {
this.layout.forEach(item => {
list.push(...Object.keys(item))
})
}
const result = {}
keys.forEach(key => {
if (list.indexOf(key) >= 0) {
result[key] = model[key]
}
})
return result
}
},
watch: {
model (cur) {
// 通过监听model来判断reset表单或给表单重新设置值
const keys = Object.keys(cur)
const result = this.filterDataModel(cur)
if (keys.length <= 0) {
this.form.resetFields()
} else {
this.form.resetFields()
this.form.setFieldsValue(this.operateDateItem(result, false))
}
}
}
}
</script>
<template>
<a-form-item class="activeform-item" :label-col="labelCol" :wrapper-col="wrapperCol" :label="item.label">
<a-input
v-if="item.type == 'input'"
v-decorator="validate"
:placeholder="placeholder"
:disabled="item.disabled" />
<a-textarea
v-if="item.type == 'textarea'"
v-decorator="validate"
:placeholder="placeholder"
:disabled="item.disabled" />
<a-checkbox-group
v-if="item.type == 'checkbox'"
v-decorator="validate"
:options="item.options"
:disabled="item.disabled" />
<a-radio-group
v-if="item.type == 'radio'"
v-decorator="validate"
:options="item.options"
:disabled="item.disabled" />
<a-select
v-if="item.type == 'select'"
v-decorator="validate"
allowClear
:placeholder="placeholder"
:disabled="item.disabled">
<a-select-option
v-for="option in item.options"
:key="option.value"
:value="option.value">
{{option.label}}
</a-select-option>
</a-select>
<a-cascader
v-if="item.type == 'cascader'"
v-decorator="validate"
allowClear
:options="item.options"
:placeholder="placeholder"
:disabled="item.disabled" />
<a-date-picker
v-if="item.type == 'date'"
style="width: 100%"
v-decorator="validate"
:format="item.format"
allowClear
:disabledDate="item.disabledDate || null"
:placeholder="placeholder"
:disabled="item.disabled" />
<a-range-picker
v-if="item.type == 'daterange'"
style="width: 100%"
v-decorator="validate"
:format="item.format"
allowClear
:disabledDate="item.disabledDate || null"
:placeholder="placeholder"
:disabled="item.disabled" />
<a-upload
v-if="item.type == 'upload'"
multiple
v-decorator="validate"
:customRequest="handleRequest"
@change="handleChange"
:remove="item.remove"
accept='.jpg,.jpeg,.png,.gif,.doc,.docx,.xlsx,.xls,.xlsm,.txt,.pdf'
:beforeUpload='item.beforeUpload'>
<a-button>
<a-icon type="upload" /> {{item.txt || '上传'}}
</a-button>
</a-upload>
<a-button class="ActiveForm-view-btn" v-if="item.type == 'view'" v-decorator="validate" @click="handleClick">
<a v-if="model[entry] && model[entry].fileType == 'file'" :href='model[entry].url' target="_blank">{{model[entry] && model[entry].name}}</a>
<span v-else-if="model[entry] && model[entry].fileType == 'pic'">{{model[entry] && model[entry].name}}</span>
<span v-else>{{model[entry] && model[entry].name}}</span>
</a-button>
<span v-if="item.type == 'text'" v-decorator="validate">
{{item.formatter ? item.formatter(model[entry]) : model[entry]}}
</span>
<template v-if="item.render">
<component :is="component" v-decorator="validate"/>
</template>
</a-form-item>
</template>
<script>
import Vue from 'vue'
export default {
name: 'ActiveFormItem',
props: {
entry: {
type: String,
required: true,
},
item: {
type: Object,
required: true,
},
model: {
type: Object,
default() {
return {}
}
},
labelWidth: {
type: Number,
default() {
return 5
}
},
},
data() {
return {
curData: null,
component: null,
}
},
created() {
if (this.item.render) {
this.component = Vue.component(this.entry, {
render: this.item.render,
props: this.item.props,
})
}
},
methods: {
handleRequest(obj) {
// 这里的obj是用来onProgress、onSuccess、onError的
this.$nextTick(() => {
this.item.customRequest(this.curData.file, obj)
})
},
handleChange(data) {
// 这里的data是用来响应改变model数据的
this.curData = data
},
// 点击查看文件按钮的回调
handleClick() {
this.item.onClick(this.model[this.entry].url)
},
// 上传文件的过滤,防止类型错误的报错
normFile(e) {
if (Array.isArray(e)) return e
return e && e.fileList
},
},
computed: {
// 默认表单验证
validate() {
if (this.item.type == 'checkbox') {
// 如果是CheckBox的话初始化要是个数组
return [this.entry, Object.assign(this.item.validate || {}, {initialValue: []})]
}
if (this.item.type == 'upload') {
return [this.entry, Object.assign(this.item.validate || {}, {valuePropName: 'fileList', getValueFromEvent: this.normFile})]
}
return [this.entry, this.item.validate || {}]
},
// 默认placeholder
placeholder() {
if (this.item.placeholder) {
return this.item.placeholder
}
if (this.item.type == 'input' || this.item.type == 'textarea') {
return '请输入'
}
if (this.item.type == 'daterange') {
return ['开始日期', '结束日期']
}
return '请选择'
},
labelCol() {
return {
style: {
width: `${this.labelWidth}px`
},
}
},
wrapperCol() {
return {
style: {
display: 'inline-block',
width: `calc(90% - ${this.labelWidth}px)`
}
}
}
}
}
</script>
<style scoped>
.ActiveForm-view-btn {
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.activeform-item.ant-row.ant-form-item {
display: flex;
}
</style>
/** ActiveForm 使用示例 */
// 首先在入口文件引入并use组件
// import ActiveForm from '@/components/ActiveForm'
// Vue.use(ActiveForm)
<template>
<a-card>
<ActiveForm :layout="layout" :label-width="7" ref="exampleForm" :model="model">
<div slot="title">
<h2>ActiveForm Title(可选, 样式自己定)</h2>
</div>
<div style="text-align:right">
<a-button @click="handleSearch" type="primary">查询</a-button>
<a-button @click="handleReset">重置</a-button>
</div>
</ActiveForm>
</a-card>
</template>
<script>
import ActiveForm from '@/components/ActiveForm'
export default {
name: 'ExampleComponent',
components: {
ActiveForm,
},
data() {
return {
layout: [
{
example1: {
label: '输入',
type: 'input',
width: 8,
validate: {
rules: [{required: true, message: '请输入'}]
}
},
example2: {
label: '单选',
type: 'radio',
width: 8,
options: [
{label: '男', value: '1'},
{label: '女', value: '0'},
]
},
example3: {
label: '选择',
type: 'select',
width: 8,
options: [
{label: '苹果', value: '苹果'},
{label: '香蕉', value: '香蕉'},
],
disabled: true
},
example4: {
label: '日期',
type: 'date',
width: 8,
validate: {
rules: [{required: true, message: '请选择日期'}]
}
},
example5: {
label: '日期区间',
type: 'daterange',
width: 8,
validate: {
rules: [{required: true, message: '请选择'}]
}
},
example6: {
label: '级联',
type: 'cascader',
width: 8,
options: [{
value: 'zhejiang',
label: 'Zhejiang',
children: [{
value: 'hangzhou',
label: 'Hangzhou',
children: [{
value: 'xihu',
label: 'West Lake',
}],
}],
}, {
value: 'jiangsu',
label: 'Jiangsu',
children: [{
value: 'nanjing',
label: 'Nanjing',
children: [{
value: 'zhonghuamen',
label: 'Zhong Hua Men',
}],
}],
}]
},
example7: {
label: '多选框',
type: 'checkbox',
width: 8,
options: [
{label: '龙', value: '龙'},
{label: '蛇', value: '蛇'},
],
validate: {
rules: [{required: true, message: '请选择'}]
}
},
example8: {
label: '查看文件',
type: 'view',
width: 8,
onClick: this.handleClick, // 点击后触发的回调,返回对应的url
},
},
{
example9: {
label: '上传',
type: 'upload',
txt: '上传文件', // 上传按钮的名字,不传的话默认是‘上传’
width: 8,
remove: this.remove, // remove动作会自动完成,没有其他特殊要求的操作可以不用调用了
customRequest: this.customRequest, // 上传请求
beforeUpload: this.beforeUpload, // 上传前的校验,没有其他特殊要求的操作可以不用调用了
validate: {
rules: [{required: true, message: '请上传'}]
}
},
example10: {
label: '文字',
type: 'text',
width: 8,
formatter: (val) => val += '(进行格式化处理)'
},
example11: {
label: 'test',
width: 8,
render: (h) => {
// render自定义组件,会比较麻烦
return h('div', [
h('p', '测试render2个'),
h('a-select', {
props: {
placeholder: 'placeholder',
allowClear: true,
options: [{value: 'test', label: '测试render select'}],
},
on: {
select(val) {}
},
style: 'color: red',
})
])
},
}
}
],
model: {
example4: '2019/08/23',
example5: ['2019/08/23', '2019/08/24'],
example7: ['龙'],
example8: {
name: 'accounts.xlsx',
fileType: 'file', // file为新开页下载,pic根据你的event回调来定
url: 'http://iftp.omniview.pro/temp/1567069629359-634052a98b43d554976a440bf07a35af.xlsx',
},
example9: [
{
name: 'accounts.xlsx',
objId: null,
response: null,
status: null,
type: null,
uid: 'f58ba55c2ce847a0bc7ea0ca74fadcb9',
url: 'http://iftp.omniview.pro/temp/1567069629359-634052a98b43d554976a440bf07a35af.xlsx',
}
],
example10: '纯展示数据用',
},
}
},
methods: {
handleSearch() {
this.$refs.exampleForm.validate(err => {
if (err) return
// TODO 这里做接下来的其他操作
this.model.example10 = JSON.stringify(this.model)
})
},
handleReset() {
this.model = {
example8: {
name: 'accounts.xlsx',
fileType: 'file',
url: 'http://iftp.omniview.pro/temp/1567069629359-634052a98b43d554976a440bf07a35af.xlsx',
},
}
},
// 上传的请求
customRequest(data, fn) { // data是数据,可修改data来同步更新model;fn用来调用onProgress、onSuccess、onError这些函数
setTimeout(() => { // 模拟请求完成后的操作
// 这里可以修改data的一些所需的字段值,比如插入url什么的
data.url = 'http://www.baidu.com'
// !!有一点不同的是没必要再手动插入model中了,model会自动更新
fn.onSuccess()
}, 500)
},
// remove动作会自动完成,如果没有其他特殊要求的操作可以去掉了
remove(data) {
},
// 上传前的校验,没有其他特殊要求的操作可以去掉了
beforeUpload(data) {
},
handleClick(data) {
},
}
}
</script>
import ActiveFormComponent from './ActiveForm'
export default (Vue) => {
Vue.component(ActiveFormComponent.name, ActiveFormComponent)
}
<template>
<a-table
:size="size"
:rowKey="rowKey"
:columns="layout"
:dataSource="data"
:bordered="bordered"
:rowClassName="setClassName"
:rowSelection="rowSelections"
:customRow="customRow"
:pagination="pagination"
@change="handleTableChange"
>
<template v-for="item in renderItems" :slot="item.dataIndex" slot-scope="text, record">
<a v-if="item.type === 'link'" :key="item.dataIndex" @click="item.onClick(record)">{{ text || item.linkText }}</a>
<span v-else-if="item.type === 'date'" :key="item.dataIndex">{{ $com.formatDate(text) }}</span>
<span v-else-if="item.type === 'money'" :key="item.dataIndex">{{ $com.toMoney(text) }}</span>
<a-input
v-else-if="item.type === 'input'"
v-model="record[item.dataIndex]"
:disabled="item.disabled"
:placeholder="item.placeholder"
style="width: 100%;"
:key="item.dataIndex"
/>
<a-select
v-else-if="item.type === 'select'"
v-model="record[item.dataIndex]"
:disabled="item.disabled"
:placeholder="item.placeholder"
allowClear
style="width: 100%;"
:key="item.dataIndex"
>
<a-select-option
v-for="option in item.options"
:key="option.value"
:value="option.value"
>{{ option.label }}</a-select-option>
</a-select>
<a-radio-group
v-if="item.type === 'radio'"
v-model="record[item.dataIndex]"
:options="item.options"
:disabled="item.disabled"
:key="item.dataIndex"
/>
</template>
<template slot="footer">
<slot name="footer" />
</template>
<template slot="title">
<slot name="title" />
</template>
<template v-for="item in slotItems" :slot="item.scopedSlots.customRender" slot-scope="text, record, index">
<slot :name="item.scopedSlots.customRender" :text="text" :record="record" :index="index" />
</template>
</a-table>
</template>
<script>
export default {
name: 'ActiveTable',
props: {
columns: {
type: Array,
default() {
return []
}
},
rowKey: {
type: String,
default: ''
},
data: {
type: Array,
default() {
return []
}
},
size: {
type: String,
default: 'small'
},
bordered: {
type: Boolean,
default: false,
},
stripe: {
// 是否显示斑马纹
type: Boolean,
default: false,
},
rowSelect: {
// 开启单行选择
type: Boolean,
default: false,
},
multiSelect: {
// 开启多选
type: Boolean,
default: false
},
multiSelectDisabled: {
// 开启多选后, 是否disable多选的checkbox
type: Boolean,
default: false
},
multiSelectDefaultChecked: {
// 开启多选后,根据此key来判断每行默认选中状态
type: [Boolean, String, Function],
default: ''
},
rowSelection: {
type: Object,
default: () => {
return {}
}
},
showPager: {
type: Boolean,
default: false,
},
total: {
type: Number,
},
currentPage: {
type: Number,
default: 1,
},
pageSize: {
type: Number,
default: 10,
}
},
data() {
return {
selectedRowKeys: [],
selectedRows: {},
renderItems: [],
slotItems: [],
}
},
methods: {
setClassName(record, index) {
if (this.selectedRowKeys.indexOf(record[this.rowKey]) >= 0 && this.rowSelect) {
return 'selected-row'
} else {
if (!this.stripe) {
return ''
}
return index % 2 === 1 ? 'odd' : 'even'
}
},
handleTableChange(pagination, filters) {
this.$emit('on-filter-change', filters)
this.$emit('on-page-change', pagination)
},
customRow(record) {
if (!this.rowSelect) return {}
return {
props: {},
on: {
click: () => {
// 选中项
this.selectedRows = record
// 选中项主键
this.selectedRowKeys = [record[this.rowKey]]
this.$emit('on-select-change', [record[this.rowKey]], record)
}
}
}
},
onSelectChange(selectedRowKeys, selectedRows) {
this.$emit('on-select-change', selectedRowKeys, selectedRows)
},
// 开启多选后 - 选择框的默认属性配置
getCheckboxProps(record) {
return {
props: {
defaultChecked: record[this.multiSelectDefaultChecked],
disabled: this.multiSelectDisabled
}
}
}
},
computed: {
rowSelections() {
if (!this.multiSelect) {
if (this.rowSelection.hasOwnProperty('type')) {
return { getCheckboxProps: this.getCheckboxProps, type: this.rowSelection.type }
} else {
return
}
} else {
return { onChange: this.onSelectChange, getCheckboxProps: this.getCheckboxProps }
}
},
pagination () {
if (!this.showPager) return false
return { showQuickJumper: true, total: this.total, current: this.currentPage, pageSize: this.pageSize }
},
layout() {
/* eslint-disable */
this.selectedRowKeys = this.data.length > 0 ? [this.data[0][this.rowKey]] : []
this.selectedRows = this.data.length > 0 ? this.data[0] : {}
const columns = [...this.columns]
columns.forEach(item => {
if (item.type) {
item.scopedSlots = { customRender: item.dataIndex }
this.renderItems.push(item)
} else {
if (item.scopedSlots) {
this.slotItems.push(item)
}
}
})
return columns
}
}
}
</script>
<template>
<ActiveTable
rowKey="id"
:columns="columns"
:data="list"
@on-page-change="test"
@on-select-change="select"
:currentPage="currentPage"
:total="total"
showPager
>
<div slot="test" slot-scope="{ text, record }">
<span>{{ text }}</span>
<a-input :value="record.gender"></a-input>
</div>
</ActiveTable>
</template>
<script>
import ActiveTable from '@/components/ActiveTable'
export default {
name: 'TableExample',
components: {
ActiveTable,
},
data () {
return {
total: 30,
currentPage: 1,
columns: [{
title: 'Test',
dataIndex: 'test',
scopedSlots: { customRender: 'test' }
}, {
title: 'Name',
dataIndex: 'name',
type: 'link',
align: 'center',
onClick: this.testClick
}, {
title: 'Gender',
dataIndex: 'gender',
align: 'center',
type: 'input',
placeholder: '请输入',
filterMultiple: false,
filters: [
{ text: 'Male', value: 'male' },
{ text: 'Female', value: 'female' }
]
}, {
title: 'Email',
dataIndex: 'email',
align: 'center',
type: 'select',
placeholder: '请选择',
options: [
{ label: 'qq', value: '@qq.com' },
{ label: 'gmail', value: '@gmail.com' }
]
}],
list: [
{ test: 'aa', id: '1', name: 'test', gender: 'male', email: '@qq.com' },
{ id: '2', name: 'test', gender: 'male', email: '@qq.com' },
{ id: '3', name: 'test', gender: 'female', email: '@qq.com' },
{ id: '4', name: 'test', gender: 'male', email: '@qq.com' }
]
}
},
methods: {
log (a, b) {
},
test ({ current }) {
this.currentPage = current
},
select (a, b) {
},
testClick (data) {
}
}
}
</script>
import ActiveTableComponent from './ActiveTable'
export default (Vue) => {
Vue.component(ActiveTableComponent.name, ActiveTableComponent)
}
<template>
<router-view></router-view>
</template>
<script>
export default {
name: 'Wrapper',
}
</script>
<style>
</style>
This diff is collapsed.
<template>
<div class="loader" v-show="loading">
<a-spin :tip="msg" :spinning="loading" size="large"/>
</div>
</template>
<script>
export default {
name: 'Loader',
props: {
msg: {
type: String,
default: '加载中...',
}
},
computed: {
loading() {
return this.$store.state.showLoading
}
},
}
</script>
<style scoped>
.loader {
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-color: rgba(255,255,255,0.4);
display: flex;
align-items: center;
justify-content: center;
z-index: 999;
}
</style>
This diff is collapsed.
<template>
<a-breadcrumb :routes="routes">
<template slot="itemRender" slot-scope="{route}">
<template v-if="$route.path.startsWith(route.path) || route.path == '/portal-home'">
<!-- <span v-if="routes.indexOf(route) === routes.length - 1">
{{route.meta.title}}
</span> -->
<span v-if="route.path != '/portal-home'">
{{route.meta.title}}
</span>
<router-link v-else :to="route.path">
{{route.meta.title}}
</router-link>
</template>
</template>
</a-breadcrumb>
</template>
<script>
import {routes} from '@/router/routes.js'
export default {
name: 'NavBar',
computed: {
routes() {
const result = []
const routeList = routes[0].children.slice(1)
if (routeList && routeList.length > 0) {
routeList.forEach(route => {
result.push(route)
if (route.children && route.children.length > 0) {
result.push(...route.children)
}
})
}
return [{path: '/portal-home', name: 'Home', meta: {title: '首页'}}, ...result]
}
},
}
</script>
<template>
<a-menu
class="layout-side-menu"
mode="inline"
theme="dark"
:openKeys="openKeys"
v-model="selectedKeys"
@openChange="onOpenChange"
>
<template v-if="menus && menus.length > 0">
<template v-for="menu in menus">
<template v-if="!!menu.children">
<a-sub-menu :key="menu.name">
<span slot="title">
<a-icon :type="menu.meta.menuIcon?menu.meta.menuIcon:'bars'" />
<span>{{menu.meta.title}}</span>
</span>
<template v-for="child in menu.children">
<a-menu-item :key="child.key" @click="onclick(child.path)">
<a-icon :type="child.meta.menuIcon?child.meta.menuIcon:'bars'" />
{{child.meta.title}}
</a-menu-item>
</template>
</a-sub-menu>
</template>
<template v-else>
<a-menu-item :key="menu.name" @click="onclick(menu.path)">
<a-icon :type="menu.meta.menuIcon?menu.meta.menuIcon:'bars'" />
{{menu.meta.title}}
</a-menu-item>
</template>
</template>
</template>
</a-menu>
</template>
<script>
import {routes} from '@/router/routes'
export default {
name: 'SideMenu',
data() {
return {
openKeys: [],
selectedKeys: [],
menus: [],
}
},
watch: {
$route(cur) {
const notInSideMenus = ['home', 'info', 'person', 'noauth', 'login', 'networkErr', 'demo']
if (notInSideMenus.indexOf(cur.name) >= 0) {
this.openKeys = []
this.selectedKeys = []
}
},
},
mounted(){
let menus=[]
for(let i=0;i<routes.length;i++){
if(!!routes[i].children){
for(let j=0;j<routes[i].children.length;j++){
if(!!routes[i].children[j].meta.menuIcon){
menus.push(routes[i].children[j])
this.menus=menus
}
}
}
}
},
methods: {
// 点击菜单,收起其他展开的菜单
onOpenChange(keys) {
if (keys.length >= 2) {
this.openKeys = keys.slice(1)
} else {
this.openKeys = keys
}
},
onclick(key) {
this.$router.push({
path: key,
})
}
},
}
</script>
<style>
.layout-side-menu {
height: 90%;
overflow-y: auto;
scrollbar-arrow-color: #00284e; /*三角箭头的颜色*/
scrollbar-face-color: #00284e; /*立体滚动条的颜色(包括箭头部分的背景色)*/
scrollbar-3dlight-color: #00284e; /*立体滚动条亮边的颜色*/
scrollbar-highlight-color: #00284e; /*滚动条的高亮颜色(左阴影?)*/
scrollbar-shadow-color: #00284e; /*立体滚动条阴影的颜色*/
scrollbar-darkshadow-color: #00284e; /*立体滚动条外阴影的颜色*/
scrollbar-track-color: #000c17; /*立体滚动条背景颜色*/
scrollbar-base-color:#00284e; /*滚动条的基色*/
}
/* 设置滚动条的样式 */
.layout-side-menu::-webkit-scrollbar {
width: 10px;
}
/* 滚动条滑块 */
.layout-side-menu::-webkit-scrollbar-thumb {
background:#00284e;
}
</style>
<template>
<div class="loader" v-show="$store.state.showLoading">
<a-spin :tip="msg" :spinning="$store.state.showLoading" size="large"/>
</div>
</template>
<script>
export default {
name: 'Loader',
props: {
msg: {
type: String,
default: '加载中...',
}
}
}
</script>
<style scoped>
.loader {
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-color: rgba(0,0,0,0.1);
display: flex;
align-items: center;
justify-content: center;
z-index: 999;
}
</style>
<template>
<div>
<a-row type="flex" justify="center" align="top" class="detailContent">
<a-col v-if="label" :span="labelSpan" class="label">{{label}}</a-col>
<a-col :span="textSpan" class="text">
<template v-for="(item,index) in fileList">
<template v-if="'pic'==item.fileType">
<p :key='index' @click="showOrgPic(item.url)" class="canload fileItem">{{item.name}}</p>
</template>
<template v-else-if="'file'==item.fileType">
<p :key='index' class="canload fileItem"><a :href='item.url' target="_blank">{{item.name}}</a></p>
</template>
<template v-else="">
<p :key='index' class="fileItem"><a :href='item.url' target="_blank">{{item.name}}</a></p>
</template>
</template>
</a-col>
</a-row>
<a-modal
:title='orgPic.name'
v-model="visibleOrgPic"
@ok="handleOk"
:footer="null"
>
<p class="orgPicContent"><img :src='orgPic.url' /></p>
</a-modal>
</div>
</template>
<script>
export default {
name: 'DetailFiles',
props: {
labelSpan: {
type: Number,
default: 10
},
textSpan: {
type: Number,
default: 14
},
label: {
type: String,
default: null,
},
/**
* 需要展示的文件列表
* [{name:文件名, url:文件链接}]
*/
files: {
type: Array,
default() {
return []
}
},
/**
* 需要展示的网络视频列表
*/
file: {
type: Array,
default() {
return []
}
}
},
data() {
return {
fileList: [],
netList: [],
visibleOrgPic: false,
orgPic: {
'url': '',
'name': ''
},
orgPicUrl: ''
}
},
computed: {
},
created(){
if(Array.isArray(this.files)){
for(let i=0;i<this.files.length;i++){
this.fileList.push({
'name': this.files[i].name,
'fileType': this.getFileType(this.files[i].name),
// 'uid':this.files[i].uid,
'url': this.files[i].url,
})
}
}
if(Array.isArray(this.file)){
for(let i=0;i<this.file.length;i++){
this.netList.push({
'name': this.file[i],
'fileType': '',
'url': this.file[i],
})
}
}
this.fileList = this.netList.concat(this.fileList)
},
methods: {
showOrgPic(url, name){
if(!!url){
this.orgPic.url = url
this.orgPic.name = !name?'查看图片':name
this.visibleOrgPic = true
}
},
handleOk(){
this.visibleOrgPic = false
this.orgPic = {
'url': '',
'name': ''
}
},
/**
* 获取文件后缀名,判别文件为图片(pic)或文件(file)
* @param {String} name
* @returns 图片(pic)或文件(file);否则为空
*/
getFileType(name){
name2 = !name?'':name
const arr = name2.split('.')
if(arr.length>0){
const len = arr.length
const suffix = arr[len-1].toLowerCase()
if(this.$com.oneOf(suffix, ['jpeg', 'jpg', 'gif', 'png'])){
return 'pic'
}else if(this.$com.oneOf(suffix, ['pdf', 'txt', 'doc', 'docx', 'xlsx', 'xls', 'xlsm', 'ppt', 'pptx'])){
return 'file'
}else{
return ''
}
}else{
return ''
}
}
}
}
</script>
<style>
.detailContent { font-size: 14px; }
.detailContent .label { text-align: right; color:rgba(0, 0, 0, 0.45)}
.detailContent .text { text-align: left; word-break:break-all;}
.detailContent .fileItem { border-radius: 2px; margin-left: 5px; border: 1px solid #ccc; display:inline-block; padding:2px 5px; font-size: 12px; line-height: 20px}
.detailContent .fileItem.canload { border-color: #1890ff; color: #1890ff; cursor: pointer;}
.orgPicContent { text-align: center}
.orgPicContent img{ width: 100%}
</style>
<template>
<a-row type="flex" justify="center" align="top" class="detailContent">
<a-col v-if="label !== ''" :title="label" :span="labelSpan" class="label">{{label}}</a-col>
<a-col v-else :title="label" :span="labelSpan" class="label" style="color:#fafafa">.</a-col>
<a-col :span="textSpan" class="text">
<a-tooltip>
<template slot="title">
{{text}}
</template>
<template v-if="text && text.length>0">{{text}}</template>
</a-tooltip>
<slot name='detailContent'></slot>
</a-col>
</a-row>
</template>
<script>
export default {
name: 'DetailItem',
props: {
labelSpan: {
type: Number,
default: 10
},
textSpan: {
type: Number,
default: 14
},
label: {
type: String,
required: true
},
text: {
// type: String,
default() {
return ''
}
}
},
data() {
return {
pointColor: ''
}
},
computed: {
},
created(){
},
methods: {
}
}
</script>
<style>
.detailContent { margin: -1px; font-size: 14px; line-height: 40px;border: 1px solid #ccc}
.detailContent .label { white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;border-right:1px solid #ccc; background-color: #fafafa; text-align: right; color:rgba(0, 0, 0, 0.65)}
.detailContent .text {white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;padding-left: 8px; text-align: left; word-break:break-all;}
</style>
<template>
<div style="margin-top:-24px">
<div class='input_span' >
<span id="one" :style="returnStyle"></span>
<span id="two" :style="returnStyle"></span>
<span id="three" :style="returnStyle"></span>
</div>
</div>
</template>
<script>
export function checkStrong(sValue) {
let modes = 0
//正则表达式验证符合要求的
if (sValue.length < 1) return modes
if (/\d/.test(sValue)) modes++ //数字
if (/[a-z]/.test(sValue)) modes++ //小写
if (/[A-Z]/.test(sValue)) modes++ //大写
if (/\W/.test(sValue)) modes++ //特殊字符
//逻辑处理
switch (modes) {
case 1:
return 1
break
case 2:
return 2
break
case 3:
case 4:
return sValue.length < 10 ? 3 : 4
break
default:
break
}
return modes
}
export default {
props: {
pwd: {
type: String,
default(){
return ''
}
},
width: {
type: [String, Number]
}
},
data() {
return {
msgText: '',
}
},
computed: {
returnStyle(){
if(this.width){
return{
width: this.width+'px'
}
}
}
},
watch: {
pwd(newValue) {
this.msgText = checkStrong(newValue)
if (this.msgText > 1 || this.msgText == 1) {
document.getElementById('one').style.backgroundColor = 'red'
} else {
document.getElementById('one').style.backgroundColor = '#eee'
}
if (this.msgText > 2 || this.msgText == 2) {
document.getElementById('two').style.backgroundColor = 'orange'
} else {
document.getElementById('two').style.backgroundColor = '#eee'
}
if (this.msgText == 4) {
document.getElementById('three').style.backgroundColor = '#00D1B2'
} else {
document.getElementById('three').style.backgroundColor = '#eee'
}
}
},
}
</script>
<style scoped>
#inputValue {
width: 240px;
margin-left: 20px;
padding-left: 10px;
border-radius: 3px;
}
.input_span {
height: 24px;
}
.input_span span {
display: inline-block;
width: 84px;
height: 6px;
background: #eee;
line-height: 20px;
}
#one {
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
border-right: 0px solid;
margin-right: 5px;
}
#two {
border-left: 0px solid;
border-right: 0px solid;
margin-left: -5px;
margin-right: 5px;
}
#three {
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
border-left: 0px solid;
margin-left: -5px;
}
#font {
font-size: 12px;
}
#font span:nth-child(1) {
color: red;
margin-left: 35px;
}
#font span:nth-child(2) {
color: orange;
margin: 0 60px;
}
#font span:nth-child(3) {
color: #00D1B2;
}
</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 store from './store'
import router from './router'
import jscookie from 'js-cookie'
import ajax from '@/server/ajax'
import api from '@/server/api'
import Axios from 'axios'
import common from './util/common'
import {registerMicroApps, start} from 'qiankun'
import {PermissionFilter} from './util/permission-filter.js' // 权限全局方法 v-if="$permission('code')"
import {
Button,
message,
Spin,
Layout,
Menu,
Icon,
Breadcrumb,
Form,
Input,
InputNumber,
Card,
Dropdown,
Row,
Col,
Checkbox,
Select,
Alert,
Table,
Divider,
Upload,
Modal,
// Tree,
Tabs,
DatePicker,
// skeleton,
Pagination,
Tag,
Badge,
// TreeSelect,
Radio,
Cascader,
LocaleProvider,
// Steps,
Anchor,
// Collapse,
Popconfirm,
// Progress,
// Switch,
Calendar,
// BackTop,
// Carousel,
Tooltip,
// CollapsePanel
} from 'ant-design-vue'
import DetailsItem from '@/components/detail/detailItem'
// import DetailsFile from '@/components/detail/detailFile'
import './assets/base.css' // 引入全局样式
import './assets/reset-ant.css' // 重置ant-design样式
import RouterWapper from '@/components/Layout/content-wrapper'
import GetRoutes from '@/router/getMicRouters'
import ZdyModal from '@/views/components/zdyModal' // 自定义字段修改弹框
import MutSelect from '@/views/components/mutSelect' // 多选框(控制表格展示列)
// import Demo from '@/views/components/demo' // 多选框(控制表格展示列)
import tableAndMut from '@/views/components/tableAndMut' // 多选框(控制表格展示列)
import BatchOperation from '@/views/components/BatchOperation' // 多选框(控制表格展示列)
import micSystemsList from '@/router/micSystemsList.json'
// 由于日期组件默认是英文的,需要本地化
import moment from 'moment'
import 'moment/locale/zh-cn'
moment.locale('zh-cn')
Vue.component('tableAndMut', tableAndMut)
Vue.component('ZdyModal', ZdyModal)
Vue.component('MutSelect', MutSelect)
Vue.component('BatchOperation', BatchOperation)
Vue.component('DetailsItem', DetailsItem)
// Vue.component('DetailsFile', DetailsFile)
Vue.component('RouterWapper', RouterWapper)
Vue.use(router)
Vue.use(Button)
Vue.use(Spin)
Vue.use(Layout)
Vue.use(Menu)
Vue.use(Icon)
Vue.use(Breadcrumb)
Vue.use(Form)
Vue.use(Input)
Vue.use(InputNumber)
Vue.use(Card)
Vue.use(Dropdown)
Vue.use(Row)
Vue.use(Col)
Vue.use(Checkbox)
Vue.use(Select)
Vue.use(Alert)
Vue.use(Table)
Vue.use(Divider)
Vue.use(Upload)
Vue.use(Modal)
// Vue.use(badge)
// Vue.use(skeleton)
// Vue.use(Tree)
Vue.use(Tabs)
Vue.use(DatePicker)
Vue.use(Pagination)
Vue.use(Tag)
Vue.use(Badge)
// Vue.use(TreeSelect)
Vue.use(Radio)
Vue.use(Cascader)
Vue.use(LocaleProvider)
// Vue.use(Steps)
Vue.use(Anchor)
// Vue.use(Collapse)
Vue.use(Popconfirm)
// Vue.use(Progress)
// Vue.use(Switch)
Vue.use(Calendar)
// Vue.use(BackTop)
// Vue.use(Carousel)
Vue.use(Tooltip)
Vue.config.productionTip = false
Vue.prototype.$ajax = ajax
Vue.prototype.$api = api
Vue.prototype.$cookie = jscookie
Vue.prototype.$com = common
Vue.prototype.$permission = PermissionFilter
Vue.prototype.$message = message
Vue.prototype.$modal = Modal
Vue.prototype.$store = store
Vue.prototype.$moment = moment
Vue.directive('title', {
inserted: function (el) {
document.title = el.dataset.title
}
})
/* eslint-disable no-new */
let app = null
const checkPrefix = (prefix) => { // 检查路径前缀
return location => location.pathname.startsWith(prefix)
}
const render = ({appContent, loading} = {}) => { // 渲染方法
if (!app) {
GetRoutes(router)
app = new Vue({
el: '#portal',
store,
router,
data() {
return {
content: appContent,
loading,
}
},
render(h) {
return h(App, {
props: {
content: this.content,
loading: this.loading,
}
})
}
})
} else {
app.content = appContent
app.loading = loading
}
}
// 动态加载子项目的url
let system = micSystemsList
let projects = []
for (let i = 0; i < system.length; i++) {
projects.push({
name: system[i].name,
entry: system[i].entry,
render,
activeRule: checkPrefix(system[i].activeRule)
})
}
registerMicroApps(projects) // 注册子项目
render()
start()
import TipsOutsite from '@/views/tips/outside'
import pudong from '@/router/pudongRoutes.json'
import xuhui from '@/router/xuhuiRoutes.json'
async function GetRoutes(router) {
let env = process.env.NODE_ENV
let MicRouters
switch (env) {
case env.indexOf('pudong') > -1:
MicRouters = pudong
break
case env.indexOf('xuhui') > -1:
MicRouters = xuhui
break
default:
MicRouters = pudong
break
}
// const MicRouters = require('@/router/micRouter.json')
// const rv = Math.floor(Math.random() * Math.random() * 10000)
// const MicRouters = (
// await Axios.get(api.CONFIGS_MICSYSTEMS_ROUTERS + '?v=' + rv)
// ).data
const micSystemRoutersConfigs = Object.assign({}, MicRouters)
const { routes } = router.options
const parent = routes.find(item => item.name === 'Layout')
for (let key in micSystemRoutersConfigs) {
for (let i = 0; i < micSystemRoutersConfigs[key].length; i++) {
let firstRouter = Object.assign({}, micSystemRoutersConfigs[key][i])
if (
!!firstRouter.meta.openMode &&
firstRouter.meta.openMode == 'outsite'
) {
firstRouter.component = TipsOutsite
}
parent.children.push(Object.assign({}, firstRouter))
router.addRoutes([ parent ])
}
}
}
export default GetRoutes
import Vue from 'vue'
import Router from 'vue-router'
import {routes} from './routes'
import store from '@/store'
import Cookie from '@/util/local-cookie'
Vue.use(Router)
const router = new Router({
mode: 'history',
// base: process.env.NODE_ENV === 'development' ? '/' : '/portal/',
routes,
})
router.beforeEach((to, from, next) => {
// TODO
// console.log(to.path)
store.commit('setWebviewSrc', to.meta && to.meta.src) // 判断有src的话为需要嵌入iframe的子项目
const token = Cookie.get('token')
// 当前无token且不在login页面则推到登录页面
if (to.path != '/login' && !token) {
next('/login')
} else {
next()
}
})
export default router
[
{
"name": "pudong",
"entry": "http://211.136.105.193/elvweb",
"activeRule": "/pudong"
},
{
"name": "danger",
"entry": "http://211.136.105.193/dangerweb",
"activeRule": "/danger"
}
]
{
"Layout": [
{
"path": "/pudong", "name": "pudong",
"meta": { "title": "小区电梯加装", "menuPath": true, "menuIcon": "profile", "hideInBread": true },
"children": [
{
"path": "/pudong/elevator/elevatorData", "name": "elevatorData",
"meta": { "title": "小区电梯加装信息", "menuPath": true, "menuIcon": "profile", "hideInBread": false},
"children": [
{
"path": "/pudong/elevator/elevatorData/streetList", "name": "streetList",
"meta": { "title": "街道列表", "menuPath": true, "menuIcon": "profile", "hideInBread": false },
"children": [
{
"path": "/pudong/elevator/elevatorData/streetList/targetList", "name": "targetList",
"meta": { "title": "小区列表", "menuPath": true, "menuIcon": "profile", "hideInBread": false },
"children": [
{
"path": "/pudong/elevator/elevatorData/streetList/targetList/targetReportInfo", "name": "targetReportInfo",
"meta": { "title": "小区上报详情", "menuPath": true, "menuIcon": "profile", "hideInBread": false}
}
]
}
]
}
]
},
{
"path": "/pudong/policy", "name": "policy",
"meta": { "title": "加装政策", "menuPath": true, "menuIcon": "profile", "hideInBread": false }
},
{
"path": "/pudong/successCase", "name": "successCase",
"meta": { "title": "成功案例", "menuPath": true, "menuIcon": "profile", "hideInBread": false }
}
]
},
{
"path": "/pudong/complaintPath", "name": "complaintPath",
"meta": { "title": "投诉直通车", "menuPath": true, "menuIcon": "profile", "hideInBread": true },
"children": [
{
"path": "/pudong/complaintPath/complaintList", "name": "complaintList",
"meta": { "title": "投诉列表", "menuPath": true, "menuIcon": "profile", "hideInBread": false }
}
]
},
{
"path": "/danger/creditTitle", "name": "creditTitle",
"meta": { "title": "信用主体评分", "menuPath": true, "menuIcon": "profile", "hideInBread": false }
},
{
"path": "/danger/creditManage", "name": "creditManage",
"meta": { "title": "隐患管理", "menuPath": true, "menuIcon": "profile", "hideInBread": true },
"children": [
{
"path": "/danger/creditManage/riskImportExport", "name": "riskImportExport",
"meta": { "title": "小区隐患列表", "menuPath": true, "menuIcon": "profile", "hideInBread": false }
},
{
"path": "/danger/creditManage/potRiskPoiManage", "name": "potRiskPoiManage",
"meta": { "title": "隐患点管理", "menuPath": true, "menuIcon": "profile", "hideInBread": false }
}
]
}
]
}
\ No newline at end of file
// import Layout from '@/components/Layout'
// import Home from '@/views/home'
// import LoginPage from '@/views/login'
// import PersonCenter from '@/views/person-center'
// import TipsNoAuth from '@/views/errorTips/auth'
// import TipsNetworkErr from '@/views/errorTips/network'
// import ContentWrapper from '@/components/Layout/content-wrapper'
// import basicInfo from '@/views/houseData/basicInfo'
// import PropertyInfo from '@/views/houseData/propertyInfo'
// import CmDivision from '@/views/houseData/cmDivision'
// import Managers from '@/views/houseData/managers'
// import IndCous from '@/views/houseData/indCous'
// import NonResidents from '@/views/houseData/nonResidents'
// import Buildings from '@/views/houseData/buildings'
// import Members from '@/views/houseData/members'
// import BasicView from '@/views/houseData/basicView'
// import Shebei from '@/views/houseData/shebei'
// import PropertyInfoView from '@/views/houseData/propertyInfoView'
// import Tbls from '@/views/houseData/tbls'
// import Demo from '@/views/components/demo'
const appRoutes = [
{
path: '/', name: 'Layout', redirect: '/portal-home',
component: resolve => require(['@/components/Layout'], resolve), //Layout,
children: [
{
path: '/portal-home', name: 'home', component: resolve => require(['@/views/home'], resolve), //Home,
meta: { title: '首页' },
},
{ path: '/person', name: 'person', component: resolve => require(['@/views/person-center'], resolve), //PersonCenter,
meta: { title: '个人中心' },
},
{ path: '/noauth', name: 'noauth', component: resolve => require(['@/views/errorTips/auth'], resolve), //TipsNoAuth,
meta: { title: '无权访问', },
},
{
path: '/house', name: 'house', component: resolve => require(['@/components/Layout/content-wrapper'], resolve), // ContentWrapper,
meta: { title: '住宅信息', menuPath: true, menuIcon: 'profile', hideInBread: true },
children: [
{ // 小区列表
path: '/houseData/basicInfo', name: 'basicInfo', component: resolve => require(['@/views/houseData/basicInfo'], resolve), //basicInfo,
meta: { title: '小区列表', menuPath: true, hideInBread: false, },
children: [
{
path: '/houseData/basicInfo/:id', name: 'basicView', component: resolve => require(['@/views/houseData/basicView'], resolve), //BasicView,
meta: { title: '小区详细情况', hideInBread: false, },
},
{
path: '/houseData/buildings', name: 'buildings', component: resolve => require(['@/views/houseData/buildings'], resolve), //Buildings,
meta: { title: '门牌栋', hideInBread: false, },
children: [
{
path: '/houseData/buildings/:id', name: 'buildingView', component: resolve => require(['@/views/houseData/propertyInfoView'], resolve), //PropertyInfoView,
meta: { title: '门牌栋详情', hideInBread: false, }
}
]
},
{
path: '/houseData/shebei/:id', name: 'shebei', component: resolve => require(['@/views/houseData/shebei'], resolve), //Shebei,
meta: { title: '设施设备', menuPath: true, hideInBread: false, },
children: [
]
},
]
},
{//业委会列表
path: '/houseData/indCous', name: 'indCous', component: resolve => require(['@/views/houseData/indCous'], resolve), //IndCous,
meta: { title: '业委会信息列表', menuPath: true, hideInBread: false, },
children: [
{
path: '/houseData/indCou/:id', name: 'indCouView', component: resolve => require(['@/views/houseData/propertyInfoView'], resolve), //PropertyInfoView,
meta: { title: '业委会详细情况', menuPath: false, hideInBread: false, },
},
{
path: '/houseData/members', name: 'members', component: resolve => require(['@/views/houseData/members'], resolve), //Members,
meta: { title: '业委会成员列表', hideInBread: false, },
children: [
{
path: '/houseData/member/:id', name: 'memberView', component: resolve => require(['@/views/houseData/propertyInfoView'], resolve), //PropertyInfoView,
meta: { title: '业委会成员详情', hideInBread: false, }
}
]
},
]
},
{//物业列表
path: '/houseData/propertyInfo', name: 'propertyInfo', component: resolve => require(['@/views/houseData/propertyInfo'], resolve), //PropertyInfo,
meta: { title: '物业企业列表', menuPath: true, hideInBread: false, },
children: [
{
path: '/houseData/propertyInfo/:id', name: 'propertyInfoView', component: resolve => require(['@/views/houseData/propertyInfoView'], resolve), //PropertyInfoView,
meta: { title: '物业服务企业详细情况', hideInBread: false, }
}
]
},
{ // 小区管理处
path: '/houseData/cmDivision', name: 'cmDivision', component: resolve => require(['@/views/houseData/cmDivision'], resolve), //CmDivision,
meta: { title: '小区管理处列表', menuPath: true, hideInBread: false, },
children: [
{
path: '/houseData/cmDivision/:id', name: 'cmDivisionView', component: resolve => require(['@/views/houseData/propertyInfoView'], resolve), //PropertyInfoView,
meta: { title: '小区管理处详细情况', menuPath: true, hideInBread: false, }
}
]
},
{ // 小区经理
path: '/houseData/managers', name: 'managers', component: resolve => require(['@/views/houseData/managers'], resolve), //Managers,
meta: { title: '小区经理列表', menuPath: true, hideInBread: false, },
children: [
{
path: '/houseData/managers/:id', name: 'managerView', component: resolve => require(['@/views/houseData/propertyInfoView'], resolve), //PropertyInfoView,
meta: { title: '小区经理详细情况', menuPath: false, hideInBread: false, }
},
]
},
]
},
{
path: '/noN', name: 'feiju', redirect: { name: 'home' }, component: resolve => require(['@/components/Layout/content-wrapper'], resolve), //ContentWrapper,
meta: { title: '非居信息', menuPath: true, menuIcon: 'profile', hideInBread: true },
children: [
{ // 非居列表
path: '/houseData/nonResidents', name: 'nonResidents', component: resolve => require(['@/views/houseData/nonResidents'], resolve), //NonResidents,
meta: { title: '非居项目信息列表', menuPath: true, hideInBread: false, },
children: [
{
path: '/houseData/nonResident/:id', name: 'nonResidentsView', component: resolve => require(['@/views/houseData/propertyInfoView'], resolve), //PropertyInfoView,
meta: { title: '非居详细情况', menuPath: false, hideInBread: false, }
},
]
},
]
},
{ // 拓展信息管理
path: '/tbls', name: 'tbls', component: resolve => require(['@/views/houseData/tbls'], resolve), //Tbls,
meta: { title: '拓展信息管理', menuPath: true, menuIcon: 'setting', hideInBread: false, },
},
],
},
{
path: '/login',
name: 'login',
meta: { title: '登录' },
component: resolve => require(['@/views/login'], resolve), //LoginPage,
},
{ path: '/networkerr', name: 'networkErr', component: resolve => require(['@/views/errorTips/network'], resolve), //TipsNetworkErr,
meta: { title: '网络异常', },
},
{ path: '/demo', name: 'demo', component: resolve => require(['@/views/components/demo'], resolve), //Demo,
meta: { title: 'demo', },
},
]
export const routes = [
...appRoutes,
]
\ No newline at end of file
[]
\ No newline at end of file
import axios from 'axios'
import qs from 'qs'
import api from './api'
import Store from '@/store'
import Cookie from '@/util/local-cookie'
import router from '@/router'
import Common from '@/util/common'
import { Modal } from 'ant-design-vue'
// 配置请求的根域名和超时时间
const Axios = axios.create({
baseURL: api.BASE_URL,
timeout: 150000,
})
const {CancelToken} = axios
let cancelRequest = null
let currentRouterName ='', currentApi='', currentMethod=''
// 处理请求状态码
const reponseCodeHandler = (res) => {
const code = res.data && res.data.code
if ('string' == typeof code) {
if (code == '200') {
} else if (code == '911') {
Cookie.remove('token')
Cookie.remove('refresh_token')
router.push({name: 'login'})
} else if (code == '900') {
router.push({ name: 'noauth' })
} else if (code == '429') {//同一对外IP,2s内请求超过100次
router.push({ name: 'upperLimitErr' })
}else if (code == '710' || code == '720') {
if(Common.oneOf(res.config.method.toLocaleLowerCase(), ['post', 'put', 'delete'])){
Modal.error({
title: '提交错误',
content: !res.data.msg?'':res.data.msg,
okText: '确认',
cancelText: '取消',
})
}
}else if (code == '912') {
//在refresh token 里的返回里已做处理,这里不做额外提示
}else if (code == '500') {
router.push({ name: 'networkErr' })
} else{
if(Common.oneOf(currentMethod.toLocaleLowerCase(), ['post', 'put', 'delete'])){
Modal.error({
title: '提交错误',
content: '系统异常',
okText: '确认',
cancelText: '取消',
})
}
}
}
}
const showErrPage= (api, routername) => {
if(Common.oneOf(routername, ['login', 'register', 'bindPhone'])){
if(!Common.oneOf(api, ['/service-release/release/public/news'])){
router.push({
name: 'outerNetworkerr'
})
}
}else if(!!routername && routername.length>0){
router.push({
name: 'innerNetworkerr'
})
}else{
router.push({
name: 'outerNetworkerr'
})
}
}
// 根据报错的状态码进行错误处理
const errorHandler = (err) => {
const errStatus = (err.response && err.response.status) || (err.data && err.data.errcode)
if (errStatus) {
switch (errStatus) {
case 404: // 网络请求不存在,跳转统一报错页面
showErrPage(currentApi, currentRouterName)
break
/** 强说home页的请求报500就跳过去了,无法进行下一步操作,故此先注释掉 */
// case 500:
// const code = err.response.data && err.response.data.code
// showErrPage(currentApi,currentRouterName)
// break
default: // 其他错误,统一到网络异常页面
showErrPage(currentApi, currentRouterName)
break
}
/**超时了就跳转了且无法进行下一步操作,故此先注释掉 */
// } else if (err.toString().indexOf('timeout') != -1) { // 统一到网络异常页面
// showErrPage(currentApi,currentRouterName)
} else if (err.toString().indexOf('Network Error') != -1) { // 统一到网络异常页面
showErrPage(currentApi, currentRouterName)
}
}
Axios.interceptors.request.use(config => {
const token = Cookie.get('token') || Store.state.token
if (token) {
config.headers.Authorization = token
}
return config
}, error => {
return Promise.reject(error)
})
Axios.interceptors.response.use(
response => {
if(response.status === 200){
reponseCodeHandler(response)
return Promise.resolve(response.data)
}else{
return Promise.resolve(response.data)
}
}, error => {
if(currentMethod.toLowerCase() != 'get'){
errorHandler(error)
}
return Promise.reject(error)
}
)
/**
* 请求
* @param {String} method [请求方法]
* @param {String} url [请求地址]
* @param {Object} params [请求参数]
* @param {String} contentType [请求头,默认为'application/json;charset=UTF-8']
* @param {Boolean} hideLoading [隐藏请求时的loading图,默认为false]
*/
const request = ({ method, url, params, contentType = 'application/json;charset=UTF-8', hideLoading = false, routername }) => {
if (!url || typeof(url) != 'string') {
throw new Error('接口URL不正确')
}
// 存储当前调用接口所在的路由和API地址
currentApi = url
currentRouterName = !routername?'':routername
currentMethod = method
// transformResponse()执行完再执行then()。transformResponse函数用于提前处理返回的数据。返回的result对象比transformResponse函数的data对象包含的数据多。
// if (method == 'get') {
// let timestamp = Date.now()
// url = (url.indexOf('?') != -1) ? (url + '&timestamp=' + timestamp) : (url + '?timestamp=' + timestamp)
// url = encodeURI(url) //针对IE下地址传值带中文,对其转义
// }
if (!params || typeof(params) == 'string' || typeof(params) == 'number') {
params = {}
}
let config = {
method,
url,
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': contentType,
},
cancelToken: new CancelToken((c) => {
cancelRequest = c
}),
}
if (method === 'GET') {
config = Object.assign(config, { params })
} else {
if (contentType.toLowerCase().indexOf('x-www-form-urlencoded') >= 0) {
config = Object.assign(config, { data: qs.stringify(params) })
} else {
config = Object.assign(config, { data: params })
}
}
if (!hideLoading) {
Store.commit('SET_LOADING', true)
}
return new Promise((resolve, reject) => {
Axios(config)
.then(res => {
resolve(res)
Store.commit('SET_LOADING', false)
}).catch(err => {
reject(err)
Store.commit('SET_LOADING', false)
})
})
}
export default {
/**
* 取消请求
* @param {String} txt [取消请求时需要显示在控制台的提示信息]
*/
cancel(txt = '取消请求') {
Store.commit('SET_LOADING', false)
if (typeof(cancelRequest) === 'function') {
return cancelRequest(txt)
}
},
get(args) {
return request({ method: 'GET', ...args })
},
post(args) {
return request({ method: 'POST', ...args })
},
put(args) {
return request({ method: 'PUT', ...args })
},
delete(args) {
return request({ method: 'DELETE', ...args })
},
all(...ajaxs) {
return Promise.all(ajaxs)
},
}
let BASE_URL = '', MOCK_URL=''
/**
* todo
* 1、此处配置当前项目在不同环境下的API请求前缀
* 2、前端服务间、后端服务间需做跨域处理
*/
switch (process.env.NODE_ENV) {
case 'devol': // 本地线上部署环境下
// BASE_URL = 'http://search.omniview.pro/api'
// BASE_URL = 'http://211.136.105.193/apiv2'
BASE_URL = 'http://hm.omniview.pro/api'
break
case 'sit': // sit环境下
// BASE_URL = 'http://search.omniview.pro/api'
// BASE_URL = 'http://211.136.105.193/apiv2'
BASE_URL = 'http://hm.omniview.pro/api'
break
case 'uat': // uat环境下
// BASE_URL = 'http://search.omniview.pro/api'
// BASE_URL = 'http://211.136.105.193/apiv2'
BASE_URL = 'http://hm.omniview.pro/api'
break
case 'production': // 生产环境下
// BASE_URL = 'http://search.omniview.pro/api'
// BASE_URL = 'http://211.136.105.193/apiv2' //浦东
BASE_URL = 'http://hm.omniview.pro/api'
break
case 'pudong-sit':
BASE_URL = 'http://211.136.105.193/apiv2' //浦东
break
case 'pudong-uat':
BASE_URL = 'http://211.136.105.193/apiv2' //浦东
break
case 'pudong-prod':
BASE_URL = 'http://211.136.105.193/apiv2' //浦东
break
case 'xuhui-sit':
BASE_URL = 'http://31.0.161.39/apiv2' // 徐汇
break
case 'xuhui-uat':
BASE_URL = 'http://31.0.161.39/apiv2' // 徐汇
break
case 'xuhui-prod':
BASE_URL = 'http://31.0.161.39/apiv2' // 徐汇
break
default: // 默认环境下(开发环境)
BASE_URL = 'http://211.136.105.193/apiv2'
// BASE_URL = 'http://hm.omniview.pro/api'
// MOCK_URL = 'https://yapi.omniview.pro/mock/278'
break
}
/**
* 此处配置本项目涉及到的所有
* 要求
* 1、前端服务间、后端服务间需做跨域处理
* 2、所有的API都需要注释说明,标记业务动作是什么
* 3、在API的名称定义上,需体现本接口的请求方式。如USERINFO_POST、USERINFO_GET
* 4、所有的API按功能模块要求,分段并注释说明
*/
export default {
/**
* 各类请求的BASE_URL
*/
BASE_URL,
GET_USER_INFO: '/service-user/login/user/info', // 获取用户信息
PUT_PERSONAL_RESET_PWD: 'service-user/pwd', // 修改密码
GET_HOME_DISPOSAL: '/service-special-xh/dashboard/disposal', //处置单统计
GET_HOUSE_MONTH: '/service-customkey/dashboard/house/month', //房办月查统计
GET_KEYS: 'service-customkey/show/{table}/keys', // 某表下所有可显示的字段
POST_KEYS: 'service-customkey/show/keys', // 保存已选字段
GET_CAN_TBLS: 'service-customkey/tbls', // 可进行数据拓展的表
GET_CONFIG: 'config', //判断自定义字段功能是否开启
GET_PROJECT: '/service-basicdatasync-ddd/public/projectConfig', //查看项目信息
POST_PROJECT: '/service-basicdatasync-ddd/projectConfig', //配置项目信息
UPLOAD_TEMP: '/service-basicdatasync-ddd/img/temp', //项目图片上传
GET_TBLS_LIST: 'service-customkey/tbls', // 可进行数据拓展的表
POST_TBLS_KEYS: 'service-customkey/key', // 新增自定义字段
PUT_TBLS_KEYS: 'service-customkey/key/{id}', // 修改自定义字段
DELETE_TBLS_KEYS: 'service-customkey/key/{id}', // 删除自定义字段
GET_TBLS_KEYS: 'service-customkey/keys', // 某表下有哪些自定义字段
GET_EXT: '/service-basicdatasync-ddd/entity/{id}/ext', // 查看某数据的自定义信息
POST_EXT: '/service-basicdatasync-ddd/entity/ext', // 保存某数据的自定义信息
GET_SAFE_EXT: '/service-basicdatasync-ddd/{table}/entity/{id}/ext', // 维护自定义信息的借口
POST_EXT_BATCH: '/service-basicdatasync-ddd/entity/ext/batch', // 批量操作
GET_EXPORT: '/service-basicdatasync-ddd/export/{table}', //数据导出
GET_EXPORT_EWM: BASE_URL+'/service-basicdatasync-ddd/public/qrCodeGenerate', //导出二维码
GET_STREET_LIST: '/service-basicdatasync-ddd/streets', //街道下拉列表
// 小区列表
GET_BASIC_LIST: '/service-basicdatasync-ddd/communities',
// 小区详情
GET_BASIC_ID: '/service-basicdatasync-ddd/community/{id}',
// 物业服务企业列表
GET_PROPCOMPANIES_LIST: '/service-basicdatasync-ddd/propCompanies',
// 物业服务企业详情
GET_PROPCOMPANY_ID: '/service-basicdatasync-ddd/propCompany/{id}',
// 小区管理处列表
GET_CSS_LIST: '/service-basicdatasync-ddd/css',
// 小区管理处详情
GET_CS_ID: '/service-basicdatasync-ddd/css/{id}',
// 小区经理列表
GET_MANAGERS_LIST: '/service-basicdatasync-ddd/managers',
// 小区经理详情
GET_MANAGER_ID: '/service-basicdatasync-ddd/manager/{id}',
// 业委会列表
GET_INDCOUS_LIST: '/service-basicdatasync-ddd/indCous',
// 业委会详情
GET_INDCOU_ID: '/service-basicdatasync-ddd/indCou/{id}',
// 非居列表
GET_NONRESIDENTS_LIST: '/service-basicdatasync-ddd/nonResidents',
// 非居详情
GET_NONRESIDENT_ID: '/service-basicdatasync-ddd/nonResident/{id}',
// 小区楼栋列表
GET_BUILDINGS_LIST: '/service-basicdatasync-ddd/community/buildings',
// 小去楼栋详情
GET_BUILDING_ID: '/service-basicdatasync-ddd/community/building/{id}',
// 业委会成员列表
GET_MEMBERS_LIST: '/service-basicdatasync-ddd/indcou/members',
// 业委会成员详情
GET_MEMBER_ID: '/service-basicdatasync-ddd/indcou/member/{id}',
// 设施设备列表
GET_FACEQUS_LIST: '/service-basicdatasync-ddd/community/facEqus',
// 房办列表
GET_HOS_LIST: '/service-basicdatasync-ddd/hos',
// 首页统计列表
GET_RESOURE_LIST: '/service-basicdatasync-ddd/resource/count',
// 首页统计列表
POST_LOGIN: '/service-user/public/login',
/**
* SSO
*/
GET_TOKEN: BASE_URL+'/uaa/oauth/token', // 获取token
/**
* XXX审查
*/
SHENGCHA_POST: '', // 提交需要XX审查的数据信息
}
import Vue from 'vue'
import Vuex from 'vuex'
import state from './state'
import actions from './actions'
import mutations from './mutations'
Vue.use(Vuex)
const isDev = process.env.NODE_ENV === 'development'
export default new Vuex.Store({
strict: isDev,
state,
actions,
mutations,
})
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/* 用于判断electron状态下使用localstorage替换js-cookie */
import jscookie from 'js-cookie'
import localcookie from './local-cookie'
const isElectronApp = window.navigator.userAgent.indexOf('Electron') !== -1
export default isElectronApp ? localcookie : jscookie
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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