Browse Source

webpack5

master
陈裕财 4 years ago
parent
commit
3523138a8d
  1. 9
      .postcssrc.js
  2. 43
      build/utils.js
  3. 3
      build/vue-loader.conf.js
  4. 298
      build/webpack.base.conf.js
  5. 41
      build/webpack.dev.conf.js
  6. 172
      build/webpack.prod.conf.js
  7. 106
      package.json
  8. 518
      src/components/Image/ImageCategoryTree.vue
  9. 4
      src/components/Image/More/Index.vue
  10. 79
      src/components/Image/More/IndexOneUpdate.vue
  11. 2
      src/components/Image/More/sizeimg.vue
  12. 38
      src/components/Image/ShearSelectUpload.vue
  13. 22
      src/components/Image/Single/Index.vue
  14. 197
      src/components/Image/UploadImage.vue

9
.postcssrc.js

@ -1,10 +1,17 @@
// https://github.com/michael-ciniawsky/postcss-load-config
module.exports = {
"autoprefixer": {
"grid": true
},
"plugins": {
"postcss-import": {},
"postcss-url": {},
// to edit target browsers: use "browserslist" field in package.json
"autoprefixer": {}
"autoprefixer": {},
"cssnano":{
autoprefixer:false,
"postcss-zindex":false,
}
}
}

43
build/utils.js

@ -1,7 +1,7 @@
'use strict'
const path = require('path')
const config = require('../config')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const packageConfig = require('../package.json')
exports.assetsPath = function (_path) {
@ -15,6 +15,13 @@ exports.assetsPath = function (_path) {
exports.cssLoaders = function (options) {
options = options || {}
const threadLoader = {
loader: 'thread-loader',
options: {
sourceMap: options.sourceMap
}
}
const cssLoader = {
loader: 'css-loader',
options: {
@ -31,7 +38,7 @@ exports.cssLoaders = function (options) {
// generate loader string to be used with extract text plugin
function generateLoaders (loader, loaderOptions) {
const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]
let loaders = options.usePostCSS ? [ cssLoader, postcssLoader] : [ cssLoader]
if (loader) {
loaders.push({
@ -44,14 +51,26 @@ exports.cssLoaders = function (options) {
// 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',
publicPath:'../'
})
let loaderss=[];
if (options.extract) {
loaderss=[
threadLoader,
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath:'../'
},
},
]
loaderss=loaderss.concat(loaders)
return loaderss
} else {
return ['vue-style-loader'].concat(loaders)
loaderss=[
threadLoader,
'vue-style-loader'
]
loaderss=loaderss.concat(loaders)
return loaderss
}
}
@ -76,7 +95,8 @@ exports.styleLoaders = function (options) {
const loader = loaders[extension]
output.push({
test: new RegExp('\\.' + extension + '$'),
use: loader
use: loader,
exclude:/node_modules/
})
}
@ -90,8 +110,7 @@ exports.createNotifierCallback = () => {
if (severity !== 'error') return
const error = errors[0]
const filename = error.file && error.file.split('!').pop()
const filename = error.file && error.file.split('!').pop()
notifier.notify({
title: packageConfig.name,
message: severity + ': ' + error.name,

3
build/vue-loader.conf.js

@ -18,6 +18,5 @@ module.exports = {
source: 'src',
img: 'src',
image: 'xlink:href'
},
hotReload: false
}
}

298
build/webpack.base.conf.js

@ -2,101 +2,223 @@
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const webpack = require('webpack')
const pkg = require('../package.json');
const vueLoaderConfig = require('./vue-loader.conf')
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const threadLoader = require('thread-loader');
threadLoader.warmup({
// pool options, like passed to loader options
// must match loader options to boot the correct pool
}, [
// modules to load
// can be any module, i. e.
'vue-loader',
'css-loader',
'babel-loader',
'babel-preset-es2015',
'sass-loader',
]);
var threadLoaderConfig={
loader: "thread-loader",
// 有同样配置的 loader 会共享一个 worker 池(worker pool)
options: {
// 产生的 worker 的数量,默认是 cpu 的核心数
//workers: 8,
// 一个 worker 进程中并行执行工作的数量
// 默认为 20
//workerParallelJobs: 20,
// 额外的 node.js 参数
//workerNodeArgs: ['--max-old-space-size', '1024'],
// 闲置时定时删除 worker 进程
// 默认为 500ms
// 可以设置为无穷大, 这样在监视模式(--watch)下可以保持 worker 持续存在
//poolTimeout: 2000,
function resolve (dir) {
return path.join(__dirname, '..', dir)
// 池(pool)分配给 worker 的工作数量
// 默认为 200
// 降低这个数值会降低总体的效率,但是会提升工作分布更均一
//poolParallelJobs: 200,
// 池(pool)的名称
// 可以修改名称来创建其余选项都一样的池(pool)
name: "my-pool"
}
}
const publicCssLoaders=process.env.NODE_ENV === 'production'?[{loader:MiniCssExtractPlugin.loader,options:{publicPath:'../'}},'css-loader']:[ 'style-loader','css-loader']
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
}
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?cacheDirectory',
exclude: /node_modules(?!\/quill-image-drop-module|quill-image-resize-module)/,
//include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
},
{
test: /\.svg$/,
loader: 'svg-sprite-loader',
include: [resolve('src/icons')],
options: {
symbolId: 'icon-[name]'
context: path.resolve(__dirname, '../'),
entry: {
app: './src/main.js'
},
output: {
clean:true,
path: config.build.assetsRoot,
filename: 'js/[name].[contenthash].js',
pathinfo: false,
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'),
}
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
exclude: [resolve('src/icons')],
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'
}
},
// 加载器
module: {
// https://doc.webpack-china.org/guides/migrating/#module-loaders-module-rules
rules: [
//...(config.dev.useEslint ? [createLintingRule()] : []),
{
test: /\.vue$/,
include: resolve('src'),
use:[
threadLoaderConfig,
{
loader: 'vue-loader',
/**
options:vueLoaderConfig,
*/
options: {
postcss: [require('postcss-cssnext')()],
loaders: {
js: [
{ loader: 'cache-loader' },
{ loader: 'babel-loader', options: { presets: ['env'] } }
]
},
extractCSS: true,
hotReload:true,
},
}
]
},
{
test: /\.css$/,
use: publicCssLoaders,
},
{
test: /\.(sa|sc)ss$/,
use: publicCssLoaders.concat([
// 将 Sass 编译成 CSS
'sass-loader',
]),
},
{
test: /\.less$/,
use: publicCssLoaders.concat([
// 将 Sass 编译成 CSS
'less-loader',
]),
},
{
test: /\.(stylus|styl)$/,
use: publicCssLoaders.concat([
// 将 Sass 编译成 CSS
'stylus-loader',
]),
},
{ // 配置Babel将ES6+ 转换为ES5
test: /\.js$/,
use:[
threadLoaderConfig,
{
loader: 'babel-loader',
options: {
presets: ['env'],
plugins: ['transform-runtime']
},
},
],
include: resolve('src'),
},
{
test: /\.svg$/,
loader: 'svg-sprite-loader',
include: [resolve('src/icons')],
options: {
symbolId: 'icon-[name]'
}
},
{
test: /\.(png|jpe?g|gif|tif?f|bmp|webp|svg)(\?.*)?$/,
exclude: [resolve('src/icons')],
type: 'asset',
generator: {
filename: 'img/[hash][ext][query]'
}
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
type: 'asset/resource',
generator: {
filename: 'media/[hash][ext][query]'
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
type: 'asset/resource',
generator: {
filename: 'fonts/[hash][ext][query]'
}
}
]
},
plugins: [
new VueLoaderPlugin(),
],
optimization: {
splitChunks: {
chunks: 'all',
minSize: 200000,
enforceSizeThreshold: 400000,
cacheGroups: {
defaultVendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
reuseExistingChunk: true,
enforceSizeThreshold: 400000,
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
enforceSizeThreshold: 400000,
},
},
},
},
}

41
build/webpack.dev.conf.js

@ -5,7 +5,8 @@ const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
const portfinder = require('portfinder')
@ -17,49 +18,49 @@ const HOST = process.env.HOST
const PORT = process.env.PORT && Number(process.env.PORT)
const devWebpackConfig = merge(baseWebpackConfig, {
mode:'development',
module: {
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
//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: true,
hot: true,
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,
}
proxy: config.dev.proxyTable,
client: {
overlay: {
errors: config.dev.errorOverlay,
warnings: false,
},
},
},
plugins: [
new webpack.DefinePlugin({
'process.env.ASSET_PATH': resolve ("/assets/"),
'process.env': require('../config/dev.env')
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
// https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: 'index.html',
new HtmlWebpackPlugin({
template: 'index.html',
inject: true,
favicon: resolve('favicon.ico'),
title: 'vue-element-admin',
path: config.dev.assetsPublicPath + config.dev.assetsSubDirectory
title: 'mdp-arc',
}),
new webpack.ProvidePlugin({
'window.Quill': 'quill'
// copy custom static assets
new CopyWebpackPlugin( {
patterns: [
{ from: path.resolve(__dirname, '../static'), to: config.build.assetsSubDirectory },
]
})
]
})

172
build/webpack.prod.conf.js

@ -4,63 +4,30 @@ const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
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 HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const TerserPlugin = require("terser-webpack-plugin");
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
function resolve (dir) {
return path.join(__dirname, '..', dir)
}
const env = require('../config/'+process.env.env_config+'.env')
const env = require('../config/'+process.env.ENV_CONFIG+'.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')
},
const webpackConfig = merge(baseWebpackConfig, {
mode:'production',
devtool: config.build.productionSourceMap ? config.build.devtool : false,
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,
cache: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.
// increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
allChunks: false,
}),
// 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
@ -78,89 +45,58 @@ const webpackConfig = merge(baseWebpackConfig, {
// 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 vender modules does not change
new webpack.HashedModuleIdsPlugin(),
new webpack.ProvidePlugin({
'window.Quill': 'quill'
}),
chunksSortMode: 'auto'
}),
// 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
}),
// split echarts into its own file
new webpack.optimize.CommonsChunkPlugin({
async: 'echarts',
minChunks(module) {
var context = module.context;
return context && (context.indexOf('echarts') >= 0 || context.indexOf('zrender') >= 0);
}
new MiniCssExtractPlugin({
filename: "css/[name].[contenthash].css",
chunkFilename: "css/[id].[contenthash].css",
}),
// split xlsx into its own file
new webpack.optimize.CommonsChunkPlugin({
async: 'xlsx',
minChunks(module) {
var context = module.context;
return context && (context.indexOf('xlsx') >= 0);
}
// copy custom static assets
new CopyWebpackPlugin({
patterns: [
{
from: path.resolve(__dirname, '../static'), to: config.build.assetsSubDirectory
}
],
}),
// split codemirror into its own file
new webpack.optimize.CommonsChunkPlugin({
async: 'codemirror',
minChunks(module) {
var context = module.context;
return context && (context.indexOf('codemirror') >= 0);
}
new FriendlyErrorsPlugin({
onErrors: utils.createNotifierCallback()
}),
// copy custom static assets
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: config.build.assetsSubDirectory,
ignore: ['.*']
}
])
]
],
optimization: {
moduleIds:'hashed',
minimize: true,
minimizer:[
new CssMinimizerPlugin({
parallel:true
}),
new TerserPlugin({
extractComments: false,
minify: TerserPlugin.uglifyJsMinify,
// `terserOptions` options will be passed to `uglify-js`
// Link to options - https://github.com/mishoo/UglifyJS#minify-options
terserOptions: {},
})
],
splitChunks: {
chunks: 'all',
minSize: {
javascript: 80000,
webassembly: 80000,
},
},
},
})
if (config.build.productionGzip) {
const CompressionWebpackPlugin = require('compression-webpack-plugin')
webpackConfig.plugins.push(
new CompressionWebpackPlugin({
asset: '[path].gz[query]',
new CompressionWebpackPlugin({
algorithm: 'gzip',
test: new RegExp(
'\\.(' +

106
package.json

@ -6,7 +6,7 @@
"license": "MIT",
"private": true,
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"dev": "webpack-dev-server --progress --config build/webpack.dev.conf.js",
"build:prod": "cross-env NODE_ENV=production env_config=prod node build/build.js",
"build:sit": "cross-env NODE_ENV=production env_config=sit node build/build.js",
"build:m1prod": "cross-env NODE_ENV=production env_config=m1prod node build/build.js",
@ -17,33 +17,27 @@
"@jiaminghi/data-view": "^2.10.0",
"axios": "0.17.1",
"clipboard": "1.7.1",
"vue-clipboard2": "^0.3.3",
"codemirror": "5.32.0",
"dayjs": "^1.8.29",
"decimal.js": "^10.2.0",
"dropzone": "5.2.0",
"echarts": "^3.8.5",
"echarts": "3.8.5",
"element-ui": "^2.13.0",
"file-saver": "^2.0.1",
"font-awesome": "4.7.0",
"file-saver": "2.0.1",
"gantt-elastic": "^1.0.11",
"gantt-elastic-header": "^0.1.11",
"highlight.js": "^9.12.0",
"font-awesome": "4.7.0",
"html2canvas": "^1.0.0-alpha.9",
"i": "^0.3.6",
"js-cookie": "2.2.0",
"js-md5": "^0.7.3",
"jsonlint": "1.6.2",
"jszip": "3.2.1",
"less": "^3.12.2",
"less-loader": "^4.1.0",
"mockjs": "1.0.1-beta3",
"moment": "^2.24.0",
"normalize.css": "7.0.0",
"nprogress": "0.2.0",
"object-assign": "^4.1.1",
"qrcodejs2": "0.0.2",
"quill-image-drop-module": "^1.0.3",
"quill-image-resize-module": "^3.0.0",
"screenfull": "3.3.2",
"showdown": "1.8.5",
"simplemde": "1.11.2",
@ -55,67 +49,85 @@
"vue-cropper": "^0.2.9",
"vue-gantt-schedule-timeline-calendar": "^1.0.33",
"vue-i18n": "7.3.2",
"vue-image-crop-upload": "^1.3.14",
"vue-multiselect": "2.0.8",
"vue-quill-editor": "^3.0.6",
"vue-router": "3.0.1",
"vue-splitpane": "1.0.2",
"vuedraggable": "^2.24.3",
"vuedraggable": "2.15.0",
"vuex": "3.0.1",
"wl-gantt": "^1.0.4",
"xlsx": "^0.14.5"
},
"devDependencies": {
"autoprefixer": "7.2.3",
"babel-core": "6.26.0",
"babel-eslint": "8.0.3",
"babel-helper-vue-jsx-merge-props": "2.0.3",
"babel-loader": "7.1.2",
"babel-plugin-syntax-jsx": "6.18.0",
"babel-plugin-transform-runtime": "6.23.0",
"babel-plugin-transform-vue-jsx": "3.5.0",
"babel-preset-env": "1.6.1",
"babel-preset-stage-2": "6.24.1",
"@babel/core": "^7.15.8",
"@babel/preset-env": "^7.15.8",
"@babel/preset-react": "^7.14.5",
"acorn": "^8.5.0",
"acorn-import-assertions": "^1.8.0",
"autoprefixer": "^10.3.7",
"babel-core": "^6.26.3",
"babel-loader": "^7.1.5",
"babel-plugin-syntax-jsx": "^6.18.0",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-plugin-transform-vue-jsx": "^3.7.0",
"babel-polyfill": "^6.26.0",
"babel-preset-env": "^1.7.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-stage-2": "^6.24.1",
"babel-runtime": "^6.26.0",
"chalk": "2.3.0",
"copy-webpack-plugin": "4.3.0",
"compression-webpack-plugin": "^9.0.0",
"copy-webpack-plugin": "^9.0.1",
"cross-env": "5.1.1",
"css-loader": "0.28.7",
"css-loader": "^6.4.0",
"css-minimizer-webpack-plugin": "^3.1.1",
"cssnano": "^5.0.8",
"eslint": "4.13.1",
"eslint-friendly-formatter": "3.0.0",
"eslint-loader": "1.9.0",
"eslint-plugin-html": "4.0.1",
"extract-text-webpack-plugin": "3.0.2",
"file-loader": "1.1.5",
"friendly-errors-webpack-plugin": "1.6.1",
"html-webpack-plugin": "2.30.1",
"extract-text-webpack-plugin": "^3.0.2",
"file-loader": "^6.2.0",
"friendly-errors-plugin": "^1.1.2",
"friendly-errors-webpack-plugin": "^1.7.0",
"happypack": "^4.0.0",
"html-webpack-plugin": "^5.4.0",
"less": "^4.1.2",
"less-loader": "^10.2.0",
"mini-css-extract-plugin": "^2.4.3",
"node-loader": "^2.0.0",
"node-notifier": "5.1.2",
"node-sass": "^4.5.0",
"optimize-css-assets-webpack-plugin": "3.2.0",
"node-sass": "^4.14.1",
"ora": "1.3.0",
"portfinder": "1.0.13",
"postcss": "^8.3.11",
"postcss-cssnext": "^3.1.1",
"postcss-import": "11.0.0",
"postcss-loader": "2.0.9",
"postcss-loader": "^6.2.0",
"postcss-merge-rules": "^5.0.2",
"postcss-url": "7.3.0",
"pushstate-server": "3.0.1",
"quill-image-extend-module": "^1.1.2",
"rimraf": "2.6.2",
"sass-loader": "6.0.6",
"script-loader": "^0.7.2",
"sass-loader": "^12.2.0",
"script-loader": "0.7.2",
"semver": "5.4.1",
"shelljs": "0.7.8",
"svg-sprite-loader": "3.5.2",
"uglifyjs-webpack-plugin": "1.1.3",
"url-loader": "0.6.2",
"vue-loader": "13.5.0",
"vue-style-loader": "3.0.3",
"vue-template-compiler": "2.6.10",
"webpack": "3.10.0",
"stream": "0.0.2",
"style-loader": "^3.3.1",
"svg-sprite-loader": "^6.0.10",
"terser-webpack-plugin": "^5.2.4",
"thread-loader": "^3.0.4",
"uglifyjs-webpack-plugin": "^2.2.0",
"url-loader": "^4.1.1",
"vue-loader": "^15.9.8",
"vue-style-loader": "^4.1.3",
"vue-template-compiler": "^2.6.14",
"webpack": "^5.59.1",
"webpack-bundle-analyzer": "2.9.1",
"webpack-dev-server": "2.9.7",
"webpack-cli": "^4.9.1",
"webpack-dev-middleware": "^5.2.1",
"webpack-dev-server": "^4.3.1",
"webpack-merge": "4.1.1"
},
"engines": {
"node": ">= 4.0.0",
"node": ">= 10.13.0",
"npm": ">= 3.0.0"
},
"browserslist": [

518
src/components/Image/ImageCategoryTree.vue

@ -1,87 +1,125 @@
<template>
<section style="margin-top: 10px;margin-right: 10px;">
<el-input v-model="categoryFilterText" v-if="showFilter=='true'" placeholder="分类名称、编号过滤" auto-complete="off"></el-input>
<el-tree
class="filter-tree"
:data="categoryTreeData"
:props="defaultCategoryTreeProps"
:filter-node-method="filterCategoryNode"
:show-checkbox="showCheckbox"
:default-expand-all="defaultExpandAll"
:expand-on-click-node="expandOnClickNode"
:indent="indent"
:node-key="nodeKey_"
:default-expanded-keys="defaultExpandedKeys"
:default-checked-keys="defaultCheckedKeys"
auto-expand-parent
@check-change="handleCheckChange"
@current-change="handleCurrentChange"
@node-click="handleNodeClick"
check-strictly
:accordion="true"
highlight-current
:render-content="renderContent"
ref="categoryTree"
:style="treeStyle">
</el-tree>
<section>
<el-row>
<el-tree
:data="categoryTreeData"
:props="defaultTreeProps"
:filter-node-method="filterNode"
:show-checkbox="showCheckbox"
:default-expand-all="defaultExpandAll"
:expand-on-click-node="expandOnClickNode"
:node-key="nodeKey_"
:default-expanded-keys="defaultExpandedKeys"
:default-checked-keys="defaultCheckedKeys"
auto-expand-parent
@check-change="handleCheckChange"
@current-change="handleCurrentChange"
@node-click="handleNodeClick"
:check-strictly="true"
:check-on-click-node="true"
ref="nodeTree">
<div class="custom-tree-node" slot-scope="{ node, data}">
<span>{{data.categoryName=='根'?'移动鼠标到此添加分类':data.categoryName}}</span>
<span class="el-ic">
<i class="el-icon-circle-plus" @click.prevent.stop="addTopNode()" title="添加顶级分类"></i>
<i class="el-icon-plus" v-if=" !(!data.id || data.id=='C0'||data.id=='0')" @click.prevent.stop="addNode(data,node)" title="添加子分类"></i>
<i class="el-icon-edit" v-if=" !(!data.id || data.id=='C0'||data.id=='0')" @click.prevent.stop="editNode(data,node)" title="修改名字"></i>
<i class="el-icon-delete" v-if=" !(!data.id || data.id=='C0'||data.id=='0')" @click.prevent.stop="deleteNode(data,node)" title="删除该分类"> </i>
</span>
</div>
</el-tree>
<el-dialog
title="提示"
:visible.sync="addVisible"
width="60%" append-to-body>
<el-form ref="addImageCategory" :model="addImageCategory" label-width="200" >
<el-form-item label="分类编号">
<el-input v-model="addImageCategory.id" placeholder="如果为空,则系统自动生成"></el-input>
</el-form-item>
<el-form-item label="分类名称" prop="categoryName"
:rules="[
{ required: true, message: '名称不能为空'}
]">
<el-input v-model="addImageCategory.categoryName" ></el-input>
</el-form-item>
<el-form-item label="">
<el-button @click="addVisible = false"> </el-button>
<el-button type="primary" v-loading="addLoading" @click="addImageCategorySubmit"> </el-button>
</el-form-item>
</el-form>
</el-dialog>
<el-dialog
title="提示"
:visible.sync="editVisible"
width="60%" append-to-body>
<el-form ref="editImageCategory" :model="editImageCategory" label-width="200" >
<el-form-item label="分类编号" prop="id">
{{editImageCategory.id}}
</el-form-item>
<el-form-item label="分类名称" prop="categoryName"
:rules="[
{ required: true, message: '名称不能为空'}
]">
<el-input v-model="editImageCategory.categoryName" ></el-input>
</el-form-item>
<el-form-item label="">
<el-button @click="editVisible = false"> </el-button>
<el-button type="primary" v-loading="editLoading" @click="editImageCategorySubmit"> </el-button>
</el-form-item>
</el-form>
</el-dialog>
</el-row>
</section>
</template>
<script>
import util from '../../common/js/util'
import { getImageCategoryTrees } from '@/api/mdp/arc/imageCategory';
import { mapGetters } from 'vuex';
export default {
import { listImageCategory,addImageCategory, editImageCategory,delImageCategory } from '@/api/mdp/arc/imageCategory';
import { listOption } from '@/api/mdp/meta/itemOption';//
import { mapGetters } from 'vuex'
export default {
watch: {
categoryFilterText(val) {
this.$refs.categoryTree.filter(val);
nodeFilterText(val) {
this.$refs.nodeTree.filter(val);
},
// locationId(locationId) {
// this.getCategoryTreeData(false);
// },branchId
branchId(branchId) {
this.getCategoryTreeData(false);
},
checkedKeys(val){
this.$refs.categoryTree.setCheckedKeys(val);
this.$refs.nodeTree.setCheckedKeys(val);
},
refresh(val){
this.getCategoryTreeData(refresh);
refresh(val){
this.getTreeData(val);
},
/* currentKey(val){
//console.log("111111111111111111111111111");
//console.log(val);
this.categoryTreeData=[];
// this.$refs.categoryTreeTag.getCategoryTreeData();
this.getCategoryTreeData();
//this.$refs.categoryTree.setCheckedKeys([val]);
this.$refs.categoryTree.setCurrentKey(val);
}, */
currentKey(val){
this.$refs.nodeTree.setCheckedKeys([val]);
},
value(val){
this.nodeid=val;
},
nodeid(val){
this.$emit('input',val);
},
categoryType(val){
this.getTreeData()
}
},
computed:{
categoryTreeData() {
var datas= this.translateDataToTree(this.treeData);
if(datas==null || datas.length==0){
return [{pid:'',id:'C0',categoryType:'',categoryName:'根'}]
}else{
return datas;
}
},
defaultExpandedKeys(){
return this.defaultCheckedKeys;
},
defaultCheckedKeys(){
if(!!this.currentKey){
return [this.currentKey];
}
/* if(!!this.checkedKeys&&this.checkedKeys.length>0){
return this.checkedKeys
}; */
if(!!this.checkedKeys&&this.checkedKeys.length>0){
var flag=this.checkedKeys.some(y=>{
if(!y){
return true;
}
});
if(!flag){
return this.checkedKeys
}
if(this.value){
return [this.value];
}
return ["0"];
return this.checkedKeys;
},
nodeKey_(){
return this.nodeKey?this.nodeKey:'id'
@ -90,117 +128,327 @@
'userInfo'
])
},
props: ['visible','currentKey','nodeKey','showCount','countTips','showFilter','rootKey','multiple','checkedKeys','refresh','defaultExpandAll','expandOnClickNode','showCheckbox','indent','treeStyle','locationId'],
props: ['categoryType','value','isLeaf','visible','nodeKey','showCount','countTips','showFilter','rootKey','multiple','checkedKeys','refresh','defaultExpandAll','expandOnClickNode','showCheckbox','indent'],
data() {
return {
categoryFilterText: '',
categoryTreeData:[],
defaultCategoryTreeProps:{
return {
nodeFilterText: '',
treeData:[],
defaultTreeProps:{
id:this.nodeKey_,
label:'categoryName',
children: 'children'
},
listLoading: false
label:'name',
children: 'children',
disabled:function(data,node){
return !node.isLeaf;
}
},
listLoading: false,
addLoading:false,
editLoading:false,
nodeid:'',
currentImageCategory:{id:'',pid:'',categoryName:'',categoryType:''},
addImageCategory:{id:'',pid:'',categoryName:'',categoryType:''},
editImageCategory:{id:'',pid:'',categoryName:'',categoryType:''},
addVisible:false,
editVisible:false,
options:{categoryType:[]},
}
},
methods: {
methods: {
handleCheckChange(data, checked, indeterminate) {
let checkedKeys=this.$refs.categoryTree.getCheckedKeys();
if( !this.multiple || this.multiple==false||this.multiple=='false'){
let checkedKeys=this.$refs.nodeTree.getCheckedKeys();
console.log(this.multiple);
if( this.multiple===undefined || this.multiple===false||this.multiple==='false'){
if(checked==true){
if(checkedKeys.length>1){
this.$refs.categoryTree.setCheckedKeys([data[this.nodeKey_]]);
if(checkedKeys.length>1){
this.$refs.nodeTree.setCheckedKeys([data[this.nodeKey_]]);
this.$emit('check-change',data,checked,indeterminate);
this.nodeid=data[this.nodeKey_];
}else{
this.$emit('check-change',data,checked,indeterminate);
this.nodeid=data[this.nodeKey_];
}
}else{
if(checkedKeys.length==0){
this.nodeid='';
this.$emit('check-change',data,checked,indeterminate);
}
}
}
}else{
this.$emit('check-change',data,checked,indeterminate);
}
}
},
handleCurrentChange(data, node) {
this.$emit('current-change',data, node);
this.$emit('current-change',data, node);
},
handleNodeClick(data, node, comp) {
this.$emit('node-click',data, node, comp);
handleNodeClick(data, node, comp) {
this.currentImageCategory=Object.assign({},data)
this.$emit('node-click',data, node, comp);
},
handleAddImageCategoryClose(){
this.addVisible=false;
},
addImageCategorySubmit(){
this.addImageCategory.pid=this.currentImageCategory.id
this.addImageCategory.isShow='1'
this.addImageCategory.branchId=this.currentImageCategory.branchId
if(!this.addImageCategory.branchId){
this.addImageCategory.branchId=this.userInfo.branchId
}
this.$refs.addImageCategory.validate((valid) => {
if (valid) {
this.$confirm('确认提交吗?', '提示', {}).then(() => {
this.addLoading = true;
addImageCategory(this.addImageCategory).then(res=>{
//console.log("res--"+JSON.stringify(res));
this.addLoading=false;
if(res.data.tips.isOk){
this.$message.success(res.data.tips.msg);
this.getTreeData(true);
}else{
this.$message.error(res.data.tips.msg);
}
}).catch(e=>this.addLoading = false );
});
}
});
},
editImageCategorySubmit(){
this.$refs.editImageCategory.validate((valid) => {
if (valid) {
this.$confirm('确认提交吗?', '提示', {}).then(() => {
this.editLoading = true;
editImageCategory({id:this.editImageCategory.id,categoryName:this.editImageCategory.categoryName,branchId:this.editImageCategory.branchId}).then(res=>{
//console.log("res--"+JSON.stringify(res));
this.editLoading = false;
if(res.data.tips.isOk){
this.editVisible=false;
this.$message.success(res.data.tips.msg);
this.getTreeData(true);
}else{
this.$message.error(res.data.tips.msg);
}
}).catch(e=>this.editLoading = false );
});
}
});
},
addTopNode(){
this.currentImageCategory={};
this.addVisible=true;
this.addImageCategory.categoryType=this.categoryType
return false;
},
addNode(data, node, comp) {
this.currentImageCategory=Object.assign({},data)
this.addVisible=true;
this.addImageCategory.categoryType=this.currentImageCategory.categoryType
return false;
},
editNode(data, node, comp) {
this.editImageCategory=Object.assign({},data)
this.editVisible=true;
console.log("editNode__"+JSON.stringify(data));
return false;
},
deleteNode(data, node, comp) {
console.log("deleteNode__"+JSON.stringify(data));
if(data.children){
this.$message.error("请先删除子元素");
return;
}
let params={
id:data.id,
branchId:data.branchId
}
if(!params.branchId){
params.branchId=this.userInfo.branchId
}
this.$confirm('确认删除吗?', '提示', {}).then(() => {
delImageCategory(params).then(res=>{
//console.log("res--"+JSON.stringify(res));
if(res.data.tips.isOk){
this.editVisible=false;
this.$message.success(res.data.tips.msg);
this.getTreeData(true);
}else{
this.$message.error(res.data.tips.msg);
}
});
})
return false;
},
//
getCategoryTreeData(refresh) {
console.log("进来这里");
getTreeData(refresh) {
let id='';
if(this.rootKey!='' && this.rootKey!=null){
id=this.rootKey;
}
let params = {
let params = {
id: id,
branchId:this.userInfo.branchId
branchId:this.userInfo.branchId,
};
console.log("进来这里第二部");
// if(this.branchId!=''&&this.branchId!=undefined){
// params.branchId=this.branchId
// }else{
// this.categoryTreeData=[];
// return ;
// }
if(refresh==true){
params.refresh=1;
if(refresh){
params.refresh=true;
}
if(this.categoryType!='' && this.categoryType!=null && this.categoryType!=undefined){
params.categoryType=this.categoryType
}
this.listLoading = true;
this.categoryTreeData=[];
getImageCategoryTrees(params).then((res) => {
listImageCategory(params).then((res) => {
var tips=res.data.tips;
console.log("进来这里第三部");
if(tips.isOk==true){
console.log("进来这里第四部");
var data = res.data.data;
data.disabled=true;
console.log("数据");
console.log(data);
this.categoryTreeData=[res.data.data];
this.$refs.categoryTree.setCurrentKey(this.currentKey);
if(tips.isOk==true){
this.treeData=res.data.data;
console.log("this.treeData----"+JSON.stringify(this.treeData));
}else{
this.$message({showClose: true, message: tips.msg, type: 'error'});
}
this.$message({ message: tips.msg, type: 'error'});
}
this.listLoading = false;
}).catch(() => {
this.listLoading = false;
});
},
filterCategoryNode(value, data) {
},
filterNode(value, data) {
if (!value) return true;
return data.categoryName.indexOf(value) !== -1;
},
renderContent(h, { node, data, store }) {
var countMsg='';
if(this.countTips){
countMsg=this.countTips;
}
if(this.showCount==true || this.showCount=='true'){
return h('span',node.label) ;
}else{
return h('span',node.label+"("+(data.isPub=='1'?'公共分类':'')+countMsg+")") ;
}
}
var countMsg='';
var that=this;
if(this.countTips){
countMsg=this.countTips;
}
if(this.showCount==true || this.showCount=='true'){
return h('div'[h('span',node.label+"("+data.count+countMsg+")")]) ;
}else{
return h('div',[h('span',node.label+"("+data.count+countMsg+")")]) ;
//return h('span',"@contextmenu.prevent='contextmenu('"+node.id+"')',"+node.label+"("+(data.children==null?0:data.children.length)+countMsg+")") ;
}
},
translateDataToTree(data2) {
var data=JSON.parse(JSON.stringify(data2));
let parents = data.filter(value =>{
//
if(value.pid == 'undefined' || value.pid == null || value.pid == ''||value.pid=='0'||value.pid=='C0'){
return true;
//
}else if(data.some(i=>value.pid==i.id)){
return false;
}else {
return true
}
})
let children = data.filter(value =>{
if(data.some(i=>value.pid==i.id)){
return true;
}else{
return false;
}
})
let translator = (parents, children) => {
parents.forEach((parent) => {
children.forEach((current, index) => {
if (current.pid === parent.id) {
let temp = JSON.parse(JSON.stringify(children))
temp.splice(index, 1)
translator([current], temp)
typeof parent.children !== 'undefined' ? parent.children.push(current) : parent.children = [current]
}
}
)
}
)
}
translator(parents, children)
return parents
},
},
mounted() {
this.getCategoryTreeData();
mounted() {
this.nodeid=this.value;
this.getTreeData();
let that=this;
this.defaultTreeProps.disabled=function(data,node){
if(that.isLeaf && that.isLeaf==true){
return !node.isLeaf;
}else{
return false;
}
}
if(this.categoryType){
this.addImageCategory.categoryType=this.categoryType
}
listOption([{categoryId:'all',itemCode:'categoryType'}]).then(res=>{
this.options=res.data.data;
})
}
}
</script>
<style scoped>
<style rel="stylesheet/scss" lang="scss" scoped>
.custom-tree-node {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
color: #4386c6;
}
.el-ic {
display: none;
i, span {
padding: 0 1px;
font-size: 18px;
font-weight: 600;
}
}
.el-tree-node__content:hover .el-ic {
color: #428bca !important;
display: inline-block;
margin-left: 2px;
}
.el-tree-node__content:hover {
font-weight: bold;
}
.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content :hover {
.el-tree-node__expand-icon.is-leaf {
color: transparent;
cursor: default;
}
/*background-color: #3998d9;*/
.custom-tree-node {
font-weight: bold;
}
.el-tree-node__expand-icon {
font-weight: bold;
}
}
</style>
</style>

4
src/components/Image/More/Index.vue

@ -2,7 +2,7 @@
<section>
<div class="SpeListOverFlow">
<draggable v-model="imageLists" :options="{group:'img'}" @start="drag=true" @end="drag=false">
<el-col :span="8" v-for="(o, index) in imageLists" >
<el-col :span="8" v-for="(o, index) in imageLists" :key="index">
<el-card :body-style="{ padding: '0px' }">
<div class="avatar-uploader" @click="selectedImage(index)">
<div style="height: 178px;width: 186px;display: flex;">
@ -126,7 +126,7 @@
},
addImg(){
if(parseInt(this.limit)<=this.imageLists.length){
this.$message({showClose: true, message: "图片数量已经超过", type: 'error' });
this.$message({ message: "图片数量已经超过", type: 'error' });
return;
}
this.addFormVisible = true;

79
src/components/Image/More/IndexOneUpdate.vue

@ -2,7 +2,7 @@
<section>
<div class="SpeListOverFlow">
<draggable v-model="imageLists" :options="{group:'img'}" @start="drag=true" @end="drag=false">
<el-col :span="8" v-for="(o, index) in imageLists" >
<el-col :span="8" v-for="(o, index) in imageLists" :key="index">
<el-card :body-style="{ padding: '0px' }">
<div class="avatar-uploader" @click="selectedImage(index)">
<div style="height: 178px;width: 186px;display: flex;">
@ -12,7 +12,23 @@
</div>
<span class="row-span" style="justify-content:center;align-items:center;display:flex;">
<span>{{index+1}},&nbsp;</span>
<span v-show="!!valueName" style="height: 35px;">{{o[valueName]}}</span>
<span v-show="!!desName" style="height: 35px;">{{o[desName]}}</span>
<el-popover
placement="top"
width="800"
trigger="click">
<el-row class="padding-top">
图片标题<el-input style="width:90%;" v-model="o[desName]" clearable></el-input>
</el-row>
<el-row class="padding-top">
跳转链接<el-input style="width:90%;" v-model="o[valueName]" clearable></el-input>
</el-row>
<el-row class="padding-top">
扩展信息<el-input style="width:90%;" v-model="o['ext']" clearable></el-input>
</el-row>
<el-button type="text" slot="reference">编辑</el-button>
</el-popover>
<i class="el-icon-zoom-in" @click="previewImg(index)"></i>
<el-button type="text" class="button" @click="delImg(index)">删除</el-button>
</span>
@ -30,7 +46,7 @@
<shear-mng :visible="shearMngVisible" :imgWidth="imgWidth" :imgHeight="imgHeight" :image="image" :branch-id="branchId" :deptid="deptid" :category-id="image.categoryId" :remark="remark" @cancel="shearMngVisible=false" @upload-success="uploadSuccess"></shear-mng>
</el-dialog>
<el-dialog title="选择图片" :visible.sync="addFormVisible" width="70%" :close-on-click-modal="false" append-to-body>
<upload-image :branch-id="branchId" :dept-id="deptid" :visible="addFormVisible" @cancel="addFormVisible=false" @confirm="handleConfirm"></upload-image>
<upload-image :multiple="true" :branch-id="branchId" :dept-id="deptid" :visible="addFormVisible" @cancel="addFormVisible=false" @confirm="handleConfirm"></upload-image>
</el-dialog>
<el-dialog :visible.sync="previewVisible" append-to-body>
<img width="100%" :src="imageUrl" alt>
@ -49,11 +65,11 @@
export default {
props:['branchId','categoryId','remark','showAdd','limit','urlName','desName','value','valueName','deptid','imgWidth','imgHeight'],
watch: {
'value':function(val){
this.imageLists = val;
value(val){
this.imageLists=val
},
'imageLists':function(val){
this.$emit('input',val);
imageLists(val){
this.$emit("input",val)
}
},
data() {
@ -67,48 +83,35 @@
imageLists:[],// {urlName:,desName:,opflag:add/del/edit,order:}
selectedImgIndex:this.value.length,
opflag:'',//add/del/edit
imageEditVisible:false,
/**end 在上面加自定义属性**/
}//end return
},//end data
methods: {
selectedImage(index){
this.selectedImgIndex = index;//url
this.image=this.imageLists[index]
this.opflag='edit';
this.addFormVisible = true;
},
handleConfirm(img){
this.image=img;
this.uploadSuccess(this.image)
console.log(this.image);
handleConfirm(imgs){
this.selectedImgIndex=0
this.image=imgs[0]
this.imageLists=imgs.map(i=>{
var img= { ...i }
img[this.urlName]=i.url
img[this.desName]=i.remark
img[this.valueName]=i.url
return img;
})
//this.shearMngVisible=true;
},
//64,
uploadSuccess(parm){
//,urlurl
if(this.opflag=='edit'){
this.imageLists[this.selectedImgIndex][this.urlName] = parm.url; //url
//this.$emit('input',this.imageLists);
this.$emit('editImg',this.imageLists[this.selectedImgIndex]);
this.shearMngVisible=false;
}else if(this.opflag=='add'){
//
//,
var g={};
g[this.urlName]=parm.url;
if(this.desName!=null&&this.desName!=''&&this.desName!='undefined'){
g[this.desName]=parm.remark;
}
this.imageLists.push(g);
this.shearMngVisible=false;
this.$emit('addImg',g);
//this.$emit('input',this.imageLists);
}
//
/*this.imageUrl = this.converUrl(parm.url);
this.shearMngVisible=false; */
uploadSuccess(parms){
},
/**begin 在下面加自定义方法,记得补上面的一个逗号**/
converUrl(o){
converUrl(o){
if(!o[this.urlName].indexOf('http')==0 && !o[this.urlName].indexOf('www')==0){
return config.getArcImagePath()+"/"+o[this.urlName];
}
@ -127,7 +130,7 @@
},
addImg(){
if(parseInt(this.limit)<=this.imageLists.length){
this.$message({showClose: true, message: "图片数量已经超过", type: 'error' });
this.$message({ message: "图片数量已经超过", type: 'error' });
return;
}
this.addFormVisible = true;
@ -142,6 +145,10 @@
this.$emit('delImg',returnDate);
});
},
showEditImage(img,index){
this.image=img;
this.imageEditVisible=true;
}
/**end 在上面加自定义方法**/
},//end method

2
src/components/Image/More/sizeimg.vue

@ -124,7 +124,7 @@
},
addImg(){
if(parseInt(this.limit)<=this.imageLists.length){
this.$message({showClose: true, message: "图片数量已经超过", type: 'error' });
this.$message({ message: "图片数量已经超过", type: 'error' });
return;
}
this.addFormVisible = true;

38
src/components/Image/ShearSelectUpload.vue

@ -63,7 +63,7 @@
</template>
<script>
import vueCropper from 'vue-cropper'
//import vueCropper from 'vue-cropper'
import config from '@/common/config';//import
import { uploadBase64 } from '@/api/mdp/arc/image';
import screenfull from 'screenfull'
@ -205,15 +205,15 @@ export default {
},
plusCjbk(){
if(this.crap==false){
this.$message({showClose: true, message: "请先开始裁剪", type: "warning" });
this.$message({ message: "请先开始裁剪", type: "warning" });
return;
}
if(this.option.autoCropWidth+this.defaultImgHeight*0.1>800){
this.$message({showClose: true, message: "不能再放大", type: "warning" });
this.$message({ message: "不能再放大", type: "warning" });
return;
}
if(this.option.autoCropHeight+this.defaultImgHeight*0.1>800){
this.$message({showClose: true, message: "不能再放大", type: "warning" });
this.$message({ message: "不能再放大", type: "warning" });
return;
}
@ -223,16 +223,16 @@ export default {
},
reduceCjbk(){
if(this.crap==false){
this.$message({showClose: true, message: "请先开始裁剪", type: "warning" });
this.$message({ message: "请先开始裁剪", type: "warning" });
return;
}
if(this.option.autoCropWidth-this.defaultImgWidth*0.1<=0){
this.$message({showClose: true, message: "不能再缩小", type: "warning" });
this.$message({ message: "不能再缩小", type: "warning" });
return;
}
if(this.option.autoCropHeight-this.defaultImgHeight*0.1<=0){
this.$message({showClose: true, message: "不能再缩小", type: "warning" });
this.$message({ message: "不能再缩小", type: "warning" });
return;
}
this.option.autoCropWidth=this.option.autoCropWidth-this.defaultImgWidth*0.1
@ -241,7 +241,7 @@ export default {
},
recoveryCjbk(){
if(this.crap==false){
this.$message({showClose: true, message: "请先开始裁剪", type: "warning" });
this.$message({ message: "请先开始裁剪", type: "warning" });
return;
}
@ -277,7 +277,7 @@ export default {
}
//var parm= this.$options.computed.uploadParams();
if(params.categoryId==''||params.categoryId==undefined){
this.$message({showClose: true, message: "分类不能为空", type: "warning" });
this.$message({ message: "分类不能为空", type: "warning" });
return;
}
if (type === 'blob') {
@ -310,13 +310,13 @@ export default {
//this.refreshCrop ();
this.$emit('upload-success',image);
}else{
this.$message({showClose: true, message: "上传错误", type: "warning" });
this.$message({ message: "上传错误", type: "warning" });
}
}).catch(()=>{
this.$message.warning("上传失败");
});
}).catch(() => {
this.$message({showClose: true,
this.$message({
type: 'info',
message: '已取消'
});
@ -332,13 +332,13 @@ export default {
//this.refreshCrop ();
this.$emit('upload-success',image);
}else{
this.$message({showClose: true, message: "上传错误", type: "warning" });
this.$message({ message: "上传错误", type: "warning" });
}
}).catch(()=>{
this.$message.warning("上传失败");
});
}else{
this.$message({showClose: true, message: "图片太大,不允许上传,请重新裁剪后上传", type: "warning" });
this.$message({ message: "图片太大,不允许上传,请重新裁剪后上传", type: "warning" });
}
}
@ -353,9 +353,9 @@ export default {
imgLoad(info){
this.imgLoading=false
if(info=='success'){
this.$message({showClose: true, message: "加载图片成功", type: "success" });
this.$message({ message: "加载图片成功", type: "success" });
}else{
this.$message({showClose: true, message: "加载图片失败", type: "error" });
this.$message({ message: "加载图片失败", type: "error" });
}
},
@ -398,20 +398,20 @@ export default {
//alert(jsonData);
/* var tips= res.tips;
if(tips.isOk){
this.$message({showClose: true, message: '上传成功', type: 'info' });
this.$message({ message: '上传成功', type: 'info' });
}else{
if(tips.msg=='该图片不支持'){
this.$message({showClose: true, message: '该图片不支持', type: 'info' });
this.$message({ message: '该图片不支持', type: 'info' });
}else{
this.$message({showClose: true, message: '未知异常', type: 'info' });
this.$message({ message: '未知异常', type: 'info' });
}
} */
}
},
components: {
'vue-cropper':vueCropper,
//'vue-cropper':vueCropper,
},
mounted () {
//this.changeImg()

22
src/components/Image/Single/Index.vue

@ -1,7 +1,7 @@
<template>
<section>
<el-col :span="8" >
<el-col :span="8" v-if="!unShowPreview">
<el-card :body-style="{ padding: '0px' }">
<div class="avatar-uploader" @click="showAdd">
<div style="height: 178px;width: 186px;display: flex;">
@ -9,14 +9,16 @@
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</div>
</div>
<span class="row-span" v-if="showTitle"><slot name="title" ></slot><i class="el-icon-zoom-in" @click="previewImg"></i></span>
</el-card>
<span class="row-span" v-if="showTitle"><slot name="title" ></slot><el-button><i class="el-icon-zoom-in" @click="previewImg">预览</i></el-button>&nbsp;&nbsp;<el-button type="text" class="el-icon-delete" @click="delImg"> 删除 </el-button>
</span>
</el-card>
</el-col>
<el-dialog title="裁剪图片" :visible.sync="shearMngVisible" top="0px" width="1100px" :lock-scroll="false" :close-on-click-modal="false" append-to-body>
<shear-mng :visible="shearMngVisible" :imgWidth="myWidth" :imgHeight="myHeight" :image="image" :branch-id="branchId" :deptid="deptid" :category-id="image.categoryId" :remark="remark" @cancel="shearMngVisible=false" @upload-success="uploadSuccess"></shear-mng>
</el-dialog>
<el-dialog title="选择图片" :visible.sync="addFormVisible" width="70%" :close-on-click-modal="false" append-to-body>
<upload-image :branch-id="branchId" :deptid="deptid" :visible="addFormVisible" @cancel="addFormVisible=false" @confirm="handleConfirm"></upload-image>
<upload-image :branch-id="branchId" :deptid="deptid" :visible="addFormVisible" @cancel="handleCancel" @confirm="handleConfirm"></upload-image>
</el-dialog>
<el-dialog :visible.sync="previewVisible" append-to-body>
<img width="100%" :src="imageUrl" alt>
@ -32,7 +34,7 @@
import config from '@/common/config';//config
export default {
props:['branchId','categoryId','remark','value','imgWidth','imgHeight','deptid','showTitle'],
props:['branchId','categoryId','remark','value','imgWidth','imgHeight','deptid','showTitle','unShowPreview'],
watch: {
'value':function(val){
this.imageUrl = this.converUrl(val);
@ -59,6 +61,10 @@
}//end return
},//end data
methods: {
handleCancel(){
this.addFormVisible=false;
this.$emit("cancel")
},
showAdd: function () {
this.addFormVisible = true;
},
@ -66,12 +72,14 @@
this.image=Object.assign(img);
//this.shearMngVisible=true;
this.uploadSuccess(this.image);
this.$emit("confirm",this.image)
},
//64,
uploadSuccess(parm){
this.$emit('input',parm.url);
this.imageUrl = this.converUrl(parm.url);
this.shearMngVisible=false;
},
/**begin 在下面加自定义方法,记得补上面的一个逗号**/
converUrl(url){
@ -85,6 +93,10 @@
},
previewImg(){
this.previewVisible=true;
},
delImg(){
this.$emit('input','');
this.imageUrl = '';
}
/**end 在上面加自定义方法**/
},//end method

197
src/components/Image/UploadImage.vue

@ -1,64 +1,18 @@
<template>
<section>
<el-row class="uploadImgWindow">
<el-col :span=6 class="leftBox">
<el-col :span=16>
<el-input v-model="filters.key" placeholder="请输入内容" clearable />
</el-col>
<el-col :span=6>
<el-button type="primary" v-loading="listLoading" v-on:click="searchImages">查询</el-button>
</el-col>
<el-col :span=24 class="allImg">
<el-menu @select="categoryChange" >
<el-menu-item-group>
<template slot="title">
<div>
<el-popover
placement="top"
width="160"
v-model="showAddCategoryForm">
<p>请输入图片分类名称</p>
<div style="text-align: right; margin: 0">
<el-input v-model="categoryName"></el-input>
<br>
<!-- <el-form-item label="公共分类" prop="isPub">
<el-checkbox :disabled="!!pisPub" v-model="isPub" true-label='1' false-label='0'>开启</el-checkbox>
</el-form-item> -->
<el-form-item label="公共分类" prop="isPub" class="md">
<el-switch :disabled="!!isPubs"
v-model="isPubs"
active-value="1"
inactive-value="0"
>
</el-switch>
</el-form-item>
<el-button size="mini" type="text" @click="showAddCategoryForm = false">取消</el-button>
<el-button type="text" size="mini" @click="handleAddCategoryForm">确定</el-button>
</div>
<el-button slot="reference" icon="el-icon-plus" round size="mini" :pcategory-id="categoryTree.refreshTree.id" @click="showAddCategory">分类</el-button>
</el-popover>
<el-button round size="mini" @click="getImageCategorys">刷新分类</el-button>
</div>
</template>
<!-- <el-menu-item index="全部" ><i class="el-icon-tickets"></i>全部</el-menu-item> -->
<!-- <el-menu-item :index="o.id" v-for="o in categorys" :key="o.id"><i class="el-icon-tickets"></i>{{o.categoryName}}</el-menu-item> -->
<!-- <category-tree
:expand-on-click-node="false"
@node-click="handleLeftCategoryTreeNodeClick"
:branch-id="filters.branchId"
ref="imageCategoryTreeTag"
></category-tree> -->
<category-tree :show-count="false" :refresh="categoryTree.refreshTree" :default-expand-all="true" :expand-on-click-node="false" v-on:node-click="handleLeftCategoryNodeClick"></category-tree>
</el-menu-item-group>
</el-menu>
</el-col>
<el-row class="uploadImgWindow" v-loading="listLoading">
<el-col :span=6 class="leftBox">
<category-tree ref="categoryTree" :show-count="false" show-checkbox :default-expand-all="true" :expand-on-click-node="false" v-on:check-change="handleLeftCategoryNodeClick"></category-tree>
</el-col>
<el-col :span=18 class="rightBox">
<el-col :span=24 class="windowTitle">
<el-col :span=16 class="windowTitlefistchild">支持jpg和png,建议大小不超过200KB超过2M将建议裁剪压缩</el-col>
<el-col :span=12 class="windowTitlefistchild">
<el-input v-model="filters.key" style="width:60%;" placeholder="按文件名模糊查询"></el-input>
<el-button type="primary" @click="searchImages" icon="el-icon-search"></el-button>
</el-col>
<el-col :span=4>
<el-upload :disabled="uploadOptions.categoryId==''||uploadOptions.categoryId==null" class="upload-demo" :show-file-list="false" :action="uploadAction" :on-change="fileChange" :on-success="handleSuccess" :before-upload="beforeupload" :data="uploadOptions" multiple>
<el-tooltip class="item" effect="dark" :content="uploadOptions.categoryId==''?'请先选择分类':'支持jpg和png,建议大小不超过200KB,超过1M将自动裁剪压缩'" placement="top-start">
<el-tooltip class="item" effect="dark" :content="uploadOptions.categoryId==''?'请先选择左边分类':'支持jpg和png,建议大小不超过200KB,超过1M将自动裁剪压缩'" placement="top-start">
<el-button type="primary">点击上传</el-button>
</el-tooltip>
@ -72,6 +26,10 @@
</el-upload>
</el-col>
<el-col :span=4>
<el-button type="danger" @click="handelDel" >删除</el-button>
</el-col>
</el-col>
<el-col :span=24>
@ -110,18 +68,13 @@
</template>
<script>
import { listImage } from '@/api/mdp/arc/image';
import { listImage,batchDelImage } from '@/api/mdp/arc/image';
import config from '@/common/config';//import
import { listImageCategory,addImageCategory } from '@/api/mdp/arc/imageCategory';
import ImageCategoryTree from './ImageCategoryTree'; //
import ShearMng from './ShearSelectUpload';
import { mapGetters } from 'vuex'
var gimages=[]
var gcategorys=[]
var gcategoryId=''
var gselectImages=[]
var isInit=true;
export default {
computed: {
@ -131,7 +84,7 @@
},
props:['branchId','remark','value','deptid','visible','imgWidth','imgHeight','storedb','multiple'],
watch:{
'visible':function(visible) {
'visible':function(visible) {
}
},
data() {
@ -158,11 +111,7 @@
categoryName: '',//
isPub:'',
treeId:'',
isPubs:'',
categoryTree:{//
selected:{},//
refreshTree:false,
},
isPubs:'',
}
},
methods:{
@ -170,25 +119,24 @@
let params = {
//jsessionid: this.jsessionid
};
if(this.branchId != undefined && this.branchId!= ''){
if(this.branchId){
params.branchId = this.branchId;
}else{
this.$message({showClose: true, message: '请先选择分类,如果分类为空,请联系管理员添加分类', type: 'error' });
this.$message({ message: '请先选择分类,如果分类为空,请联系管理员添加分类', type: 'error' });
return;
}
this.listLoading = true;
listImageCategory(params).then((res) => {
var ttips=res.data.tips;
if(ttips.isOk){
this.categorys = [res.data.data];
gcategorys=Object.assign(this.categorys)
this.categorys = res.data.data;
}else{
this.$message({showClose: true, message: tips.msg, type: 'error' });
this.$message({ message: tips.msg, type: 'error' });
}
this.listLoading = false;
}).catch(() => {
this.listLoading = false;
this.$message({showClose: true, message: '通讯异常', type: 'error' });
this.$message({ message: '通讯异常', type: 'error' });
});
},
// obj.order=ascending/descending, asc/desc ; obj.prop=,
@ -209,8 +157,7 @@
if(image.show==true){
image.show=false;
this.selectImages=this.selectImages.filter(i=>i.id!=image.id)
gselectImages=Object.assign(this.selectImages)
}else{
}else{
if(!this.multiple){
this.images.forEach(i=>{
if(i.id!=image.id){
@ -220,14 +167,12 @@
image.show=true
this.selectImages=[];
this.selectImages.push(Object.assign(image))
gselectImages=Object.assign(this.selectImages)
}
}
});
}else{
image.show=true
this.selectImages.push(Object.assign(image))
gselectImages=Object.assign(this.selectImages)
}
}
}
@ -239,13 +184,13 @@
//var jsonData = JSON.stringify(res, null, 4);
var tips= res.tips;
if(tips.isOk){
this.$message({showClose: true, message: '上传成功', type: 'success' });
this.$message({ message: '上传成功', type: 'success' });
this.getImages();
}else{
if(tips.msg=='该图片不支持'){
this.$message({showClose: true, message: '该图片不支持', type: 'info' });
this.$message({ message: '该图片不支持', type: 'info' });
}else{
this.$message({showClose: true, message: '未知异常', type: 'error' });
this.$message({ message: '未知异常', type: 'error' });
}
}
@ -253,23 +198,20 @@
categoryChange(index,indexPath){
console.log(index);
this.uploadOptions.categoryId = index;
gcategoryId=index
this.pageInfo.pageNum=1;
this.pageInfo.pageNum=1;
this.pageInfo.total=0;
this.getImages();
},
beforeupload(file){
console.log("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
console.log(file)
beforeupload(file){
if(this.uploadOptions.categoryId=='' || this.uploadOptions.categoryId==null){
this.$message({showClose: true, message: "请选择分类", type: "warning" });
this.$message({ message: "请选择分类", type: "warning" });
return false;
}
if(file.size<=1024*2024){//1M
this.$message({showClose: true, message: '小于2M的文件可直接上传图片库', type: 'success' });
this.$message({ message: '小于2M的文件可直接上传图片库', type: 'success' });
return true;
}else{
this.$message({showClose: true, message: '为了良好的客户体验,大于2M的文件需经过裁剪压缩处理', type: 'warning' });
this.$message({ message: '为了良好的客户体验,大于2M的文件需经过裁剪压缩处理', type: 'warning' });
return false;
}
@ -279,7 +221,7 @@
var that = this;
//this.imageUrl = URL.createObjectURL(file.raw);
if(file.raw.size<=1024*1024){//1M
//this.$message({showClose: true, message: '1M', type: 'success' });
//this.$message({ message: '1M', type: 'success' });
return true;
}
return true;
@ -288,12 +230,10 @@
fileChangeForShear(file, fileList) {
var that = this;
var reader = new FileReader();
console.log(file)
reader.readAsDataURL(file.raw);
reader.readAsDataURL(file.raw);
reader.onload = function(e){
// this.result // base64
console.log(this.result);
let image={
let image={
url:this.result,
branchId:that.branchId,
categoryId:that.uploadOptions.categoryId,
@ -329,7 +269,7 @@
//params.jsessionid=this.jsessionid;
this.listLoading = true;
if(this.branchId == undefined || this.branchId== ''){
this.$message({showClose: true, message: '机构不能为空', type: 'warning' });
this.$message({ message: '机构不能为空', type: 'warning' });
return;
}
params.branchId = this.branchId;
@ -342,16 +282,15 @@
this.pageInfo.count=false;
imagesList.forEach(i=>i.show=false);
this.images = imagesList;
gimages=Object.assign(this.images);
//url
//url
/* this.converUrl(this.images); */
}else{
this.$message({showClose: true, message: tips.msg, type: 'error' });
this.$message({ message: tips.msg, type: 'error' });
}
this.listLoading = false;
}).catch(() => {
this.listLoading = false;
this.$message({showClose: true, message: '通讯异常', type: 'error' });
this.$message({ message: '通讯异常', type: 'error' });
});
},
converUrl(url){
@ -381,11 +320,11 @@
},
handleConfirm(){
if(this.images==null || this.images.length==0){
this.$message({showClose: true, message: '请选择图片', type: 'error' });
this.$message({ message: '请选择图片', type: 'error' });
return
}
if(this.selectImages==null || this.selectImages.length==0){
this.$message({showClose: true, message: '请选择图片', type: 'error' });
this.$message({ message: '请选择图片', type: 'error' });
return
}
if(this.multiple){
@ -418,7 +357,7 @@
};
if(this.categoryName==''){
this.$message({showClose: true, message: '请输入分类名字', type: 'error' });
this.$message({ message: '请输入分类名字', type: 'error' });
return
}
addImageCategory(params).then(res=>{
@ -426,41 +365,49 @@
this.showAddCategoryForm=false
this.getImageCategorys()
}else{
this.$message({showClose: true, message: res.data.tips.msg, type: 'error' });
this.$message({ message: res.data.tips.msg, type: 'error' });
}
})
},
rowClick: function(row, event, column){
debugger
this.$emit('row-click',row, event, column);// @row-click="rowClick"
this.$emit('row-click',row, event, column);// @row-click="rowClick"
},
handleLeftCategoryNodeClick(row, node,comp) {
// debugger
this.filters.queryByCategory=true;
// this.categoryTree.selected=data;
this.uploadOptions.categoryId=row.id;
this.category=row;
this.pageInfo.count=true;
this.treeId=row.id;
this.isPubs=row.isPub;
handleLeftCategoryNodeClick( ) {
var nodes=this.$refs.categoryTree.$refs.nodeTree.getCheckedNodes();
var node=null;
if(nodes.length>0){
node=nodes[0]
this.category=node;
this.uploadOptions.categoryId=node.id;
} else{
this.uploadOptions.categoryId="";
this.category=null;
}
this.searchImages();
},
handelDel(){
if(this.selectImages.length==0){
this.$message({ message:"请选择要删除的图片", type: 'error' });
return;
}else{
batchDelImage(this.selectImages).then(res=>{
var tips = res.data.tips;
if(tips.isOk){
this.getImages();
}
this.$message({ message: res.data.tips.msg, type: tips.isOk==true?'success':'error' });
})
}
}
},
components: {
"category-tree": ImageCategoryTree,
'shear-mng':ShearMng
//
},
mounted() {
if(isInit==true){
this.getImageCategorys();
isInit=false
}else{
this.categorys=Object.assign(gcategorys)
this.images=Object.assign(gimages)
this.selectImages=Object.assign(gselectImages)
}
this.uploadOptions.categoryId=gcategoryId
mounted() {
//this.getImageCategorys();
this.getImages();
}
}

Loading…
Cancel
Save