first commit

main
zhangyanli 2026-04-17 16:30:01 +08:00
commit 45d23c4eee
379 changed files with 137075 additions and 0 deletions

41
build/build.js Normal file
View File

@ -0,0 +1,41 @@
'use strict'
require('./check-versions')()
process.env.NODE_ENV = 'production'
const ora = require('ora')
const rm = require('rimraf')
const path = require('path')
const chalk = require('chalk')
const webpack = require('webpack')
const config = require('../config')
const webpackConfig = require('./webpack.prod.conf')
const spinner = ora('building for production...')
spinner.start()
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
if (err) throw err
webpack(webpackConfig, (err, stats) => {
spinner.stop()
if (err) throw err
process.stdout.write(stats.toString({
colors: true,
modules: false,
children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
chunks: false,
chunkModules: false
}) + '\n\n')
if (stats.hasErrors()) {
console.log(chalk.red(' Build failed with errors.\n'))
process.exit(1)
}
console.log(chalk.cyan(' Build complete.\n'))
console.log(chalk.yellow(
' Tip: built files are meant to be served over an HTTP server.\n' +
' Opening index.html over file:// won\'t work.\n'
))
})
})

54
build/check-versions.js Normal file
View File

@ -0,0 +1,54 @@
'use strict'
const chalk = require('chalk')
const semver = require('semver')
const packageConfig = require('../package.json')
const shell = require('shelljs')
function exec (cmd) {
return require('child_process').execSync(cmd).toString().trim()
}
const versionRequirements = [
{
name: 'node',
currentVersion: semver.clean(process.version),
versionRequirement: packageConfig.engines.node
}
]
if (shell.which('npm')) {
versionRequirements.push({
name: 'npm',
currentVersion: exec('npm --version'),
versionRequirement: packageConfig.engines.npm
})
}
module.exports = function () {
const warnings = []
for (let i = 0; i < versionRequirements.length; i++) {
const mod = versionRequirements[i]
if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
warnings.push(mod.name + ': ' +
chalk.red(mod.currentVersion) + ' should be ' +
chalk.green(mod.versionRequirement)
)
}
}
if (warnings.length) {
console.log('')
console.log(chalk.yellow('To use this template, you must update following to modules:'))
console.log()
for (let i = 0; i < warnings.length; i++) {
const warning = warnings[i]
console.log(' ' + warning)
}
console.log()
process.exit(1)
}
}

BIN
build/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

102
build/utils.js Normal file
View File

@ -0,0 +1,102 @@
'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',
publicPath: '../../'
})
} 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')
})
}
}

22
build/vue-loader.conf.js Normal file
View File

@ -0,0 +1,22 @@
'use strict'
const utils = require('./utils')
const config = require('../config')
const isProduction = process.env.NODE_ENV === 'production'
const sourceMapEnabled = isProduction
? config.build.productionSourceMap
: config.dev.cssSourceMap
module.exports = {
loaders: utils.cssLoaders({
sourceMap: sourceMapEnabled,
extract: isProduction
}),
cssSourceMap: sourceMapEnabled,
cacheBusting: config.dev.cacheBusting,
transformToRequire: {
video: ['src', 'poster'],
source: 'src',
img: 'src',
image: 'xlink:href'
}
}

101
build/webpack.base.conf.js Normal file
View File

@ -0,0 +1,101 @@
'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',
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]')
}
},
{
test: /\.svg$/,
loader: 'svg-sprite-loader',
include: [resolve('src/icons')],
options: {
symbolId: 'icon-[name]'
}
}
]
},
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'
}
}

95
build/webpack.dev.conf.js Normal file
View File

@ -0,0 +1,95 @@
'use strict'
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const path = require('path')
const baseWebpackConfig = require('./webpack.base.conf')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
const portfinder = require('portfinder')
const HOST = process.env.HOST
const PORT = process.env.PORT && Number(process.env.PORT)
const devWebpackConfig = merge(baseWebpackConfig, {
module: {
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
},
// cheap-module-eval-source-map is faster for development
devtool: config.dev.devtool,
// these devServer options should be customized in /config/index.js
devServer: {
clientLogLevel: 'warning',
historyApiFallback: {
rewrites: [
{ from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
],
},
hot: true,
contentBase: false, // since we use CopyWebpackPlugin.
compress: true,
host: HOST || config.dev.host,
port: PORT || config.dev.port,
open: config.dev.autoOpenBrowser,
overlay: config.dev.errorOverlay
? { warnings: false, errors: true }
: false,
publicPath: config.dev.assetsPublicPath,
proxy: config.dev.proxyTable,
quiet: true, // necessary for FriendlyErrorsPlugin
watchOptions: {
poll: config.dev.poll,
}
},
plugins: [
new webpack.DefinePlugin({
'process.env': require('../config/dev.env')
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
new webpack.NoEmitOnErrorsPlugin(),
// https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: true
}),
// copy custom static assets
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: config.dev.assetsSubDirectory,
ignore: ['.*']
}
])
]
})
module.exports = new Promise((resolve, reject) => {
portfinder.basePort = process.env.PORT || config.dev.port
portfinder.getPort((err, port) => {
if (err) {
reject(err)
} else {
// publish the new Port, necessary for e2e tests
process.env.PORT = port
// add port to devServer config
devWebpackConfig.devServer.port = port
// Add FriendlyErrorsPlugin
devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
compilationSuccessInfo: {
messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
},
onErrors: config.dev.notifyOnErrors
? utils.createNotifierCallback()
: undefined
}))
resolve(devWebpackConfig)
}
})
})

149
build/webpack.prod.conf.js Normal file
View File

@ -0,0 +1,149 @@
'use strict'
const path = require('path')
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const env = process.env.NODE_ENV === 'testing'
? require('../config/test.env')
: require('../config/prod.env')
const webpackConfig = merge(baseWebpackConfig, {
module: {
rules: utils.styleLoaders({
sourceMap: config.build.productionSourceMap,
extract: true,
usePostCSS: true
})
},
devtool: config.build.productionSourceMap ? config.build.devtool : false,
output: {
path: config.build.assetsRoot,
filename: utils.assetsPath('js/[name].[chunkhash].js'),
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
},
plugins: [
// http://vuejs.github.io/vue-loader/en/workflow/production.html
new webpack.DefinePlugin({
'process.env': env
}),
new UglifyJsPlugin({
uglifyOptions: {
compress: {
warnings: false
}
},
sourceMap: config.build.productionSourceMap,
parallel: true
}),
// extract css into its own file
new ExtractTextPlugin({
filename: utils.assetsPath('css/[name].[contenthash].css'),
// Setting the following option to `false` will not extract CSS from codesplit chunks.
// Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
// It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`,
// increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
allChunks: true,
}),
// Compress extracted CSS. We are using this plugin so that possible
// duplicated CSS from different components can be deduped.
new OptimizeCSSPlugin({
cssProcessorOptions: config.build.productionSourceMap
? { safe: true, map: { inline: false } }
: { safe: true }
}),
// generate dist index.html with correct asset hash for caching.
// you can customize output by editing /index.html
// see https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: process.env.NODE_ENV === 'testing'
? 'index.html'
: config.build.index,
template: 'index.html',
inject: true,
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
// more options:
// https://github.com/kangax/html-minifier#options-quick-reference
},
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
chunksSortMode: 'dependency'
}),
// keep module.id stable when vendor modules does not change
new webpack.HashedModuleIdsPlugin(),
// enable scope hoisting
new webpack.optimize.ModuleConcatenationPlugin(),
// split vendor js into its own file
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks (module) {
// any required modules inside node_modules are extracted to vendor
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(
path.join(__dirname, '../node_modules')
) === 0
)
}
}),
// extract webpack runtime and module manifest to its own file in order to
// prevent vendor hash from being updated whenever app bundle is updated
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
minChunks: Infinity
}),
// This instance extracts shared chunks from code splitted chunks and bundles them
// in a separate chunk, similar to the vendor chunk
// see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
new webpack.optimize.CommonsChunkPlugin({
name: 'app',
async: 'vendor-async',
children: true,
minChunks: 3
}),
// copy custom static assets
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: config.build.assetsSubDirectory,
ignore: ['.*']
}
])
]
})
if (config.build.productionGzip) {
const CompressionWebpackPlugin = require('compression-webpack-plugin')
webpackConfig.plugins.push(
new CompressionWebpackPlugin({
asset: '[path].gz[query]',
algorithm: 'gzip',
test: new RegExp(
'\\.(' +
config.build.productionGzipExtensions.join('|') +
')$'
),
threshold: 10240,
minRatio: 0.8
})
)
}
if (config.build.bundleAnalyzerReport) {
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}
module.exports = webpackConfig

7
config/dev.env.js Normal file
View File

@ -0,0 +1,7 @@
'use strict'
const merge = require('webpack-merge')
const prodEnv = require('./prod.env')
module.exports = merge(prodEnv, {
NODE_ENV: '"development"'
})

75
config/index.js Normal file
View File

@ -0,0 +1,75 @@
'use strict'
// Template version: 1.3.1
// see http://vuejs-templates.github.io/webpack for documentation.
const path = require('path')
module.exports = {
dev: {
// Paths
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {},
// Various Dev Server settings
host: '192.168.0.79', // can be overwritten by process.env.HOST
port: 8082, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
autoOpenBrowser: false,
errorOverlay: true,
notifyOnErrors: true,
poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
// Use Eslint Loader?
// If true, your code will be linted during bundling and
// linting errors and warnings will be shown in the console.
useEslint: true,
// If true, eslint errors and warnings will also be shown in the error overlay
// in the browser.
showEslintErrorsInOverlay: false,
/**
* Source Maps
*/
// https://webpack.js.org/configuration/devtool/#development
devtool: 'cheap-module-eval-source-map',
// If you have problems debugging vue-files in devtools,
// set this to false - it *may* help
// https://vue-loader.vuejs.org/en/options.html#cachebusting
cacheBusting: true,
cssSourceMap: true
},
build: {
// Template for index.html
index: path.resolve(__dirname, '../dist/index.html'),
// Paths
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'static',
assetsPublicPath: './',
/**
* Source Maps
*/
productionSourceMap: true,
// https://webpack.js.org/configuration/devtool/#production
devtool: '#source-map',
// Gzip off by default as many popular static hosts such as
// Surge or Netlify already gzip all static assets for you.
// Before setting to `true`, make sure to:
// npm install --save-dev compression-webpack-plugin
productionGzip: false,
productionGzipExtensions: ['js', 'css'],
// Run the build command with an extra argument to
// View the bundle analyzer report after build finishes:
// `npm run build --report`
// Set to `true` or `false` to always turn it on or off
bundleAnalyzerReport: process.env.npm_config_report
}
}

4
config/prod.env.js Normal file
View File

@ -0,0 +1,4 @@
'use strict'
module.exports = {
NODE_ENV: '"production"'
}

7
config/test.env.js Normal file
View File

@ -0,0 +1,7 @@
'use strict'
const merge = require('webpack-merge')
const devEnv = require('./dev.env')
module.exports = merge(devEnv, {
NODE_ENV: '"testing"'
})

22
index.html Normal file
View File

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<!-- <title>教育培训平台-运营端</title>-->
<title>金安铸云全员培训平台</title>
<script src="./static/config.js"></script>
<script src="./static/aliyun-upload-sdk/lib/es6-promise.min.js"></script>
<script src="./static/aliyun-upload-sdk/lib/aliyun-oss-sdk-6.17.1.min.js"></script>
<script src="./static/aliyun-upload-sdk/aliyun-upload-sdk-1.5.3.min.js"></script>
<script src="./static/aliplayer/aliplayercomponents-1.0.9.min.js"></script>
<link rel="stylesheet" href="https://g.alicdn.com/de/prismplayer/2.9.19/skins/default/aliplayer-min.css" />
<link rel="icon" type="image/x-icon" href="./static/icons/logo.jpg">
<script type="text/javascript" charset="utf-8"
src="https://g.alicdn.com/de/prismplayer/2.9.19/aliplayer-min.js"></script>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

39515
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

110
package.json Normal file
View File

@ -0,0 +1,110 @@
{
"name": "qa-education-admin-vue",
"version": "1.0.0",
"description": "A Vue.js project",
"author": "",
"private": true,
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js --open",
"start": "npm run dev",
"unit": "jest --config test/unit/jest.conf.js --coverage",
"e2e": "node test/e2e/runner.js",
"test": "npm run unit && npm run e2e",
"lint": "eslint --ext .js,.vue src test/unit test/e2e/specs",
"build": "node build/build.js",
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml"
},
"dependencies": {
"axios": "^0.21.1",
"default-passive-events": "^2.0.0",
"element-ui": "^2.15.8",
"js-cookie": "^2.2.1",
"moment": "^2.29.1",
"nprogress": "^0.2.0",
"throttle-debounce": "^5.0.0",
"vue": "^2.5.2",
"vue-baidu-map": "^0.21.22",
"vue-count-to": "^1.0.13",
"vue-particles": "^1.0.9",
"vue-pdf": "^4.3.0",
"vue-print-nb": "^1.7.4",
"vue-qr": "^2.3.0",
"vue-router": "^3.0.1",
"vue-video-player": "^5.0.2"
},
"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-jest": "^21.0.2",
"babel-loader": "^7.1.1",
"babel-plugin-dynamic-import-node": "^1.2.0",
"babel-plugin-syntax-jsx": "^6.18.0",
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.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",
"babel-register": "^6.22.0",
"chalk": "^2.0.1",
"chromedriver": "^2.27.2",
"copy-webpack-plugin": "^4.0.1",
"cross-spawn": "^5.0.1",
"css-loader": "^0.28.0",
"echarts": "^4.9.0",
"eslint": "^4.15.0",
"eslint-config-standard": "^10.2.1",
"eslint-friendly-formatter": "^3.0.0",
"eslint-loader": "^1.7.1",
"eslint-plugin-import": "^2.7.0",
"eslint-plugin-node": "^5.2.0",
"eslint-plugin-promise": "^3.4.0",
"eslint-plugin-standard": "^3.0.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",
"jest": "^22.0.4",
"jest-serializer-vue": "^0.3.0",
"nightwatch": "^0.9.12",
"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",
"sass": "1.26.2",
"sass-loader": "^7.3.1",
"screenfull": "^5.1.0",
"selenium-server": "^3.0.1",
"semver": "^5.3.0",
"shelljs": "^0.7.6",
"svg-sprite-loader": "^4.1.3",
"svgo": "^1.2.0",
"uglifyjs-webpack-plugin": "^1.1.1",
"url-loader": "^0.5.8",
"v-viewer": "^1.6.3",
"vue-jest": "^1.0.2",
"vue-loader": "^13.3.0",
"vue-style-loader": "^3.0.1",
"vue-template-compiler": "^2.5.2",
"vuex": "^3.6.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"
]
}

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

11
src/App.vue Normal file
View File

@ -0,0 +1,11 @@
<template>
<div id="app">
<router-view/>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

BIN
src/assets/images/map.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
src/assets/images/map/c.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
src/assets/images/map/h.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
src/assets/images/map/l.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

BIN
src/assets/images/smwz.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

BIN
src/assets/images/sure.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
src/assets/images/yy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
src/assets/images/zgzs.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

BIN
src/assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

87
src/asyncRouter.js Normal file
View File

@ -0,0 +1,87 @@
// 进度条引入设置如上面第一种描述一样
import router from './router'
import request from '@/utils/request'
import store from './store'
import 'nprogress/nprogress.css' // progress bar style
import Layout from '@/layout'
var routers
router.beforeEach((to, from, next) => {
if (to.path == `/login`) {
sessionStorage.clear()
}
if (sessionStorage.getItem('user')) {
if (!routers) {
if (!sessionStorage.getItem('router')) {
// 异步获取store中的路由
request.post('main/index')
.then((res) => {
sessionStorage.setItem('router', JSON.stringify(res.menuList))
routers = res.menuList
try {
const accessRoutes = formatRoutes(routers, '')
// 动态添加格式化过的路由
store.dispatch('permission/generateRoutes', accessRoutes)
router.addRoutes(accessRoutes)
next({ ...to, replace: true })
} catch (error) {
console.info(error)
next(`/login`)
}
})
} else {
routers = JSON.parse(sessionStorage.getItem('router'))
try {
const accessRoutes = formatRoutes(routers, '')
// 动态添加格式化过的路由
store.dispatch('permission/generateRoutes', accessRoutes)
router.addRoutes(accessRoutes)
next({ ...to, replace: true })
} catch (error) {
console.info(error)
next(`/login`)
}
}
} else {
next()
}
} else {
if (to.path == `/login`) {
next()
} else {
next(`/login`)
}
}
})
function formatRoutes(routes, baseUrl) {
const res = []
routes.forEach(item => {
if (!item.hasMenu) {
return res
}
const newItem = {}
const meta = {}
if (item.parent_ID == '0') {
newItem.component = Layout
newItem.path = '/' + item.menu_URL
} else {
newItem.component = resolve => require([`@/views/${item.component}`], resolve)
newItem.path = item.menu_URL
}
newItem.hidden = item.menu_STATE == '0'
const _baseUrl = baseUrl + '/' + item.menu_URL
newItem.name = item.menu_NAME
newItem.children = item.subMenu
meta.title = item.menu_NAME
meta.icon = item.menu_ICON
meta.showModel = item.show_MODEL
newItem.meta = meta
// 若遍历的当前路由存在子路由,需要对子路由进行递归遍历
if (newItem.children && newItem.children.length) {
newItem.children = formatRoutes(item.subMenu, _baseUrl)
}
res.push(newItem)
})
// 返回处理好且可用的路由数组
return res
}

View File

@ -0,0 +1,82 @@
<template>
<el-breadcrumb class="app-breadcrumb" separator="/">
<transition-group name="breadcrumb">
<el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
<span v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect">{{ item.meta.title }}</span>
<a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
</el-breadcrumb-item>
</transition-group>
</el-breadcrumb>
</template>
<script>
import pathToRegexp from 'path-to-regexp'
export default {
data() {
return {
levelList: null
}
},
watch: {
$route(route) {
// if you go to the redirect page, do not update the breadcrumbs
if (route.path.startsWith('/redirect/')) {
return
}
this.getBreadcrumb()
}
},
created() {
this.getBreadcrumb()
},
methods: {
getBreadcrumb() {
// only show routes with meta.title
let matched = this.$route.matched.filter(item => item.meta && item.meta.title)
const first = matched[0]
if (!this.isDashboard(first)) {
matched = [{ path: '/index', meta: { title: '首页' }}].concat(matched)
}
this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
},
isDashboard(route) {
const name = route && route.name
if (!name) {
return false
}
return name.trim() === '首页'
},
pathCompile(path) {
// To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561
const { params } = this.$route
var toPath = pathToRegexp.compile(path)
return toPath(params)
},
handleLink(item) {
const { redirect, path } = item
if (redirect) {
this.$router.push(redirect)
return
}
this.$router.push(this.pathCompile(path))
}
}
}
</script>
<style lang="scss" scoped>
.app-breadcrumb.el-breadcrumb {
display: inline-block;
font-size: 14px;
line-height: 50px;
margin-left: 8px;
.no-redirect {
color: #97a8be;
cursor: text;
}
}
</style>

View File

@ -0,0 +1,466 @@
<template>
<div class="lazy-cascader" :style="{ width: width }">
<!-- 禁用状态 -->
<div
v-if="disabled"
class="el-input__inner lazy-cascader-input lazy-cascader-input-disabled"
>
<span class="lazy-cascader-placeholder" v-show="placeholderVisible">
{{ placeholder }}
</span>
<div class="lazy-cascader-tags" v-if="props.multiple">
<el-tag
class="lazy-cascader-tag"
type="info"
disable-transitions
v-for="(item, index) in labelArray"
:key="index"
closable
>
<span> {{ item.label.join(separator) }}</span>
</el-tag>
</div>
<div class="lazy-cascader-label" v-else>
<el-tooltip
placement="top-start"
:content="labelObject.label.join(separator)"
>
<span>{{ labelObject.label.join(separator) }}</span>
</el-tooltip>
</div>
</div>
<!-- 禁用状态 -->
<!-- 可选状态 -->
<el-popover v-else trigger="click" placement="bottom-start" ref="popover">
<!-- 搜索 -->
<div class="lazy-cascader-search">
<el-autocomplete
:style="{ width: searchWidth || '100%' }"
:popper-class="suggestionsPopperClass"
v-if="filterable"
class="inline-input"
prefix-icon="el-icon-search"
label="name"
v-model="keyword"
:fetch-suggestions="querySearch"
:trigger-on-focus="false"
placeholder="请输入"
@select="handleSelect"
@blur="isSearchEmpty = false"
>
<template slot-scope="{ item }">
<div class="name" :class="isChecked(item[props.value])">
{{ item[props.label].join(separator) }}
</div>
</template>
</el-autocomplete>
<div class="empty" v-show="isSearchEmpty">{{ searchEmptyText }}</div>
</div>
<!-- 搜索 -->
<!-- 级联面板 -->
<div class="lazy-cascader-panel">
<el-cascader-panel
ref="panel"
v-model="current"
:options="options"
:props="currentProps"
@change="change"
></el-cascader-panel>
</div>
<!-- 级联面板 -->
<!--内容区域-->
<div
class="el-input__inner lazy-cascader-input"
:class="disabled ? 'lazy-cascader-input-disabled' : ''"
slot="reference"
>
<span class="lazy-cascader-placeholder" v-show="placeholderVisible">
{{ placeholder }}
</span>
<div class="lazy-cascader-tags" v-if="props.multiple">
<el-tag
class="lazy-cascader-tag"
type="info"
size="small"
disable-transitions
v-for="(item, index) in labelArray"
:key="index"
closable
@close="handleClose(item)"
>
<span> {{ item.label.join(separator) }}</span>
</el-tag>
</div>
<div class="lazy-cascader-label" v-else>
<el-tooltip
placement="top-start"
:content="labelObject.label.join(separator)"
>
<span>{{ labelObject.label.join(separator) }}</span>
</el-tooltip>
</div>
<span
class="lazy-cascader-clear"
v-if="clearable && current.length > 0"
@click.stop="clearBtnClick"
>
<i class="el-icon-close"></i>
</span>
</div>
<!--内容区域-->
</el-popover>
<!-- 可选状态 -->
</div>
</template>
<script>
export default {
props: {
value: {
type: Array,
default: () => {
return [];
}
},
separator: {
type: String,
default: " > "
},
placeholder: {
type: String,
default: "请选择"
},
width: {
type: String,
default: "400px"
},
filterable: Boolean,
clearable: Boolean,
disabled: Boolean,
props: {
type: Object,
default: () => {
return {};
}
},
suggestionsPopperClass: {
type: String,
default: "suggestions-popper-class"
},
searchWidth: {
type: String
},
searchEmptyText: {
type: String,
default: "暂无数据"
}
},
data() {
return {
isSearchEmpty: false,
keyword: "",
options: [],
current: [],
labelObject: { label: [], value: [] },
labelArray: [],
currentProps: {
multiple: this.props.multiple,
checkStrictly: this.props.checkStrictly,
value: this.props.value,
label: this.props.label,
leaf: this.props.leaf,
lazy: true,
lazyLoad: this.lazyLoad
}
};
},
computed: {
placeholderVisible() {
if (this.current) {
return this.current.length == 0;
} else {
return true;
}
}
},
watch: {
current() {
this.getLabelArray();
},
value(v) {
this.current = v;
},
keyword() {
this.isSearchEmpty = false;
}
},
created() {
this.initOptions();
},
methods: {
//
isChecked(value) {
//
if (this.props.multiple) {
let index = this.current.findIndex(item => {
return item.join() == value.join();
});
if (index > -1) {
return "el-link el-link--primary";
} else {
return "";
}
} else {
if (value.join() == this.current.join()) {
return "el-link el-link--primary";
} else {
return "";
}
}
},
//
querySearch(query, callback) {
this.props.lazySearch(query, list => {
callback(list);
if (!list || !list.length) this.isSearchEmpty = true;
});
},
//
handleSelect(item) {
if (this.props.multiple) {
let index = this.current.findIndex(obj => {
return obj.join() == item[this.props.value].join();
});
if (index == -1) {
this.$refs.panel.clearCheckedNodes();
this.current.push(item[this.props.value]);
this.$emit("change", this.current);
}
} else {
//
if (
this.current == null ||
item[this.props.value].join() !== this.current.join()
) {
this.$refs.panel.activePath = [];
this.current = item[this.props.value];
this.$emit("change", this.current);
}
}
this.keyword = "";
},
//
async initOptions() {
this.props.lazyLoad(0, list => {
this.$set(this, "options", list);
if (this.props.multiple) {
this.current = [...this.value];
} else {
this.current = this.value;
}
});
},
async getLabelArray() {
if (this.props.multiple) {
let array = [];
for (let i = 0; i < this.current.length; i++) {
let obj = await this.getObject(this.current[i]);
array.push(obj);
}
this.labelArray = array;
this.$emit("input", this.current);
if (!this.disabled) {
this.$nextTick(() => {
this.$refs.popover.updatePopper();
});
}
} else {
this.labelObject = await this.getObject(this.current || []);
this.$emit("input", this.current);
}
},
/**格式化id=>object */
async getObject(id) {
try {
let options = this.options;
let nameArray = [];
for (let i = 0; i < id.length; i++) {
let index = options.findIndex(item => {
return item[this.props.value] == id[i];
});
nameArray.push(options[index][this.props.label]);
if (i < id.length - 1 && options[index].children == undefined) {
let list = new Promise(resolve => {
this.props.lazyLoad(id[i], list => {
resolve(list);
});
});
this.$set(options[index], "children", await list);
options = options[index].children;
} else {
options = options[index].children;
}
}
return { value: id, label: nameArray };
} catch (e) {
this.current = [];
return { value: [], label: [] };
}
},
//
async lazyLoad(node, resolve) {
let current = this.current;
if (this.props.multiple) {
current = [...this.current];
}
if (node.root) {
resolve();
} else if (node.data[this.props.leaf]) {
resolve();
} else if (node.data.children) {
if (this.props.multiple) {
this.current = current;
}
resolve();
} else {
this.props.lazyLoad(node.value, list => {
node.data.children = list;
if (this.props.multiple) {
this.current = current;
}
resolve(list);
});
}
},
//
/**删除**/
handleClose(item) {
let index = this.current.findIndex(obj => {
return obj.join() == item.value.join();
});
if (index > -1) {
this.$refs.panel.clearCheckedNodes();
this.current.splice(index, 1);
this.$emit("change", this.current);
}
},
//
clearBtnClick() {
this.$refs.panel.clearCheckedNodes();
this.current = [];
this.$emit("change", this.current);
},
change() {
this.$emit("change", this.current);
}
}
};
</script>
<style lang="less">
.lazy-cascader {
display: inline-block;
width: 300px;
.lazy-cascader-input {
position: relative;
width: 100%;
background: #fff;
height: auto;
min-height: 36px;
padding: 5px;
line-height: 1;
cursor: pointer;
> .lazy-cascader-placeholder {
padding: 0 2px;
line-height: 28px;
color: #999;
font-size: 14px;
}
> .lazy-cascader-label {
padding: 0 2px;
line-height: 28px;
color: #606266;
font-size: 14px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
> .lazy-cascader-clear {
position: absolute;
right: 0;
top: 0;
display: inline-block;
width: 40px;
height: 40px;
text-align: center;
line-height: 40px;
}
}
.lazy-cascader-input-disabled {
background-color: #f5f7fa;
border-color: #e4e7ed;
color: #c0c4cc;
cursor: not-allowed;
> .lazy-cascader-label {
color: #c0c4cc;
}
> .lazy-cascader-placeholder {
color: #c0c4cc;
}
}
}
.lazy-cascader-tag {
display: inline-flex;
align-items: center;
max-width: 100%;
margin: 2px;
text-overflow: ellipsis;
background: #f0f2f5;
> span {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
}
> .el-icon-close {
-webkit-box-flex: 0;
-ms-flex: none;
flex: none;
background-color: #c0c4cc;
color: #fff;
}
}
.lazy-cascader-panel {
margin-top: 10px;
display: inline-block;
}
.suggestions-popper-class {
width: auto !important;
min-width: 200px;
}
.lazy-cascader-search {
.empty {
width: calc(100% - 24px);
box-sizing: border-box;
background-color: #fff;
color: #999;
text-align: center;
position: absolute;
z-index: 999;
padding: 12px 0;
margin-top: 12px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
&:before {
content: "";
position: absolute;
top: -12px;
left: 36px;
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-top: 6px solid transparent;
border-bottom: 6px solid #fff;
filter: drop-shadow(0 -1px 2px rgba(0, 0, 0, 0.02));
}
}
}
</style>

View File

@ -0,0 +1,49 @@
<template>
<el-dialog
v-if="visible"
:append-to-body="appendToBody"
:visible.sync="visible"
:v-loading="loading"
:title="title"
width="800px"
@close="close">
<iframe :src="url" class="content-iframe" width="100%" height="600px"/>
</el-dialog>
</template>
<script>
import waves from '@/directive/waves' // waves directive
export default {
directives: { waves },
props: {
appendToBody: {
type: Boolean,
default: false
},
title: {
type: String,
default: '文件'
}
},
data() {
return {
visible: false,
url: '',
heirloom: {},
loading: false
}
},
methods: {
init(e) {
this.heirloom = e
this.url = e.url
this.visible = true
},
close() {
this.url = ''
this.visible = false
}
}
}
</script>

View File

@ -0,0 +1,44 @@
<template>
<div style="padding: 0 15px;" @click="toggleClick">
<svg
:class="{'is-active':isActive}"
class="hamburger"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
width="64"
height="64"
>
<path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" />
</svg>
</div>
</template>
<script>
export default {
name: 'Hamburger',
props: {
isActive: {
type: Boolean,
default: false
}
},
methods: {
toggleClick() {
this.$emit('toggleClick')
}
}
}
</script>
<style scoped>
.hamburger {
display: inline-block;
vertical-align: middle;
width: 20px;
height: 20px;
}
.hamburger.is-active {
transform: rotate(180deg);
}
</style>

View File

@ -0,0 +1,113 @@
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<h2>Essential Links</h2>
<ul>
<li>
<a
href="https://vuejs.org"
target="_blank"
>
Core Docs
</a>
</li>
<li>
<a
href="https://forum.vuejs.org"
target="_blank"
>
Forum
</a>
</li>
<li>
<a
href="https://chat.vuejs.org"
target="_blank"
>
Community Chat
</a>
</li>
<li>
<a
href="https://twitter.com/vuejs"
target="_blank"
>
Twitter
</a>
</li>
<br>
<li>
<a
href="http://vuejs-templates.github.io/webpack/"
target="_blank"
>
Docs for This Template
</a>
</li>
</ul>
<h2>Ecosystem</h2>
<ul>
<li>
<a
href="http://router.vuejs.org/"
target="_blank"
>
vue-router
</a>
</li>
<li>
<a
href="http://vuex.vuejs.org/"
target="_blank"
>
vuex
</a>
</li>
<li>
<a
href="http://vue-loader.vuejs.org/"
target="_blank"
>
vue-loader
</a>
</li>
<li>
<a
href="https://github.com/vuejs/awesome-vue"
target="_blank"
>
awesome-vue
</a>
</li>
</ul>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data() {
return {
msg: 'Welcome to Your Vue.js App'
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>

View File

@ -0,0 +1,239 @@
<template>
<div style="width:284px;display: inline-block;margin-left: -5px">
<!-- <div class="mask"
v-show="isShowSelect"
@click="isShowSelect = !isShowSelect"></div> -->
<el-popover
:width="width"
v-model="isShowSelect"
placement="bottom-start"
trigger="manual"
clearable
@hide="popoverHide"
@show="popoverShow">
<el-tree
ref="tree"
:data="data"
:props="defaultProps"
:node-key="nodeKey"
:check-strictly="checkStrictly"
:expand-on-click-node="false"
:check-on-click-node="true"
:default-checked-keys="defaultCheckedKeys"
:highlight-current="true"
:show-checkbox="true"
:clearable="clearable"
class="common-tree"
default-expand-all
@check-change="handleCheckChange"/>
<el-select
slot="reference"
ref="select"
:style="selectStyle"
v-model="selectedData"
:clearable="clearable"
multiple
class="tree-select"
@click.native="isShowSelect = !isShowSelect">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"/>
</el-select>
</el-popover>
</div>
</template>
<script>
export default {
name: 'TreeSelect',
// props: ["clear"],
props: {
//
data: {
type: Array,
default() {
return []
}
},
//
rootNodeChick: {
type: Boolean,
default: () => { return true }
},
//
clearable: {
type: Boolean,
default: () => { return true }
},
defaultProps: {
type: Object,
default() {
return {}
}
},
nodeKey: {
type: String,
default() {
return 'id'
}
},
//
checkStrictly: {
type: Boolean,
default() {
return false
}
},
// key
checkedKeys: {
type: Array,
default() {
return []
}
},
//
defaultCallback: {
type: Boolean,
default() {
return true
}
},
width: {
type: Number,
default() {
return 260
}
},
height: {
type: Number,
default() {
return 360
}
}
},
data() {
return {
defaultCheckedKeys: [],
isShowSelect: false, //
options: [],
selectedData: [], //
selectStyle: 'width:' + (this.width + 24) + 'px;',
checkedIds: [],
checkedData: [],
tempCheckedKeys: []
}
},
watch: {
isShowSelect(val) {
// select
this.$refs.select.blur()
},
selectedData: function(newData, oldData) {
this.popoverHide()
if (
newData == undefined ||
newData == null ||
newData == [] ||
newData.length == 0
) { this.$refs.tree.setCheckedKeys([]) }
}
},
mounted() {
if (this.checkedKeys.length > 0) {
this.defaultCheckedKeys = this.checkedKeys
this.selectedData = this.checkedKeys.map(item => {
var node = this.$refs.tree.getNode(item)
return node.label
})
}
},
methods: {
loadCheckedKeys(checkedKeys) {
if (checkedKeys.length > 0) {
if (this.defaultCallback) {
this.defaultCheckedKeys = Object.assign([], checkedKeys)
this.selectedData = checkedKeys.map(item => {
var node = this.$refs.tree.getNode(item)
return node.label
})
} else {
this.tempCheckedKeys = checkedKeys
}
}
},
handleClear() {
this.selectedData = []
this.$nextTick(() => {
this.$refs.tree.setCheckedKeys([])
})
},
popoverShow() {
if (!this.defaultCallback) {
this.defaultCheckedKeys = Object.assign([], this.tempCheckedKeys)
this.selectedData = this.tempCheckedKeys.map(item => {
var node = this.$refs.tree.getNode(item)
return node.label
})
}
},
popoverHide() {
this.checkedIds = this.$refs.tree.getCheckedKeys() // key
this.checkedData = this.$refs.tree.getCheckedNodes() //
this.$emit('handleTreeSelected', this.checkedIds, this.checkedData)
},
//
handleCheckChange() {
var checkedKeys = this.$refs.tree.getCheckedKeys() // key
this.options = []
if (!this.rootNodeChick) {
checkedKeys.forEach(item => {
var node = this.$refs.tree.getNode(item) // node
const tmpMap = {}
if (node.childNodes.length == 0) {
tmpMap.value = node.key
tmpMap.label = node.label
this.options.push(tmpMap)
}
})
} else {
this.options = checkedKeys.map(item => {
var node = this.$refs.tree.getNode(item) // node
const tmpMap = {}
tmpMap.value = node.key
tmpMap.label = node.label
return tmpMap
})
}
this.selectedData = this.options.map(item => {
return item.label
})
}
}
}
</script>
<style scoped>
.mask {
width: 100%;
height: 100%;
position: fixed;
top: 0;
left: 0;
opacity: 0;
z-index: 999;
}
.common-tree {
overflow: auto;
}
</style>
<style>
.tree-select .el-select__tags .el-tag .el-tag__close {
display: none;
}
.tree-select .el-select__tags .el-tag .el-icon-close {
display: none;
}
</style>

View File

@ -0,0 +1,102 @@
<template>
<div :class="{'hidden':hidden}" class="pagination-container">
<el-pagination
:background="background"
:current-page.sync="currentPage"
:page-size.sync="pageSize"
:layout="layout"
:page-sizes="pageSizes"
:total="total"
v-bind="$attrs"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</template>
<script>
import { scrollTo } from '@/utils/scroll-to'
export default {
name: 'Pagination',
props: {
total: {
required: true,
type: Number
},
page: {
type: Number,
default: 1
},
limit: {
type: Number,
default: 2
},
pageSizes: {
type: Array,
default() {
return [10, 20, 30, 50]
}
},
layout: {
type: String,
default: 'total, sizes, prev, pager, next, jumper'
},
background: {
type: Boolean,
default: true
},
autoScroll: {
type: Boolean,
default: true
},
hidden: {
type: Boolean,
default: false
}
},
computed: {
currentPage: {
get() {
return this.page
},
set(val) {
this.$emit('update:page', val)
}
},
pageSize: {
get() {
return this.limit
},
set(val) {
this.$emit('update:limit', val)
}
}
},
methods: {
handleSizeChange(val) {
this.$emit('pagination', { page: this.currentPage, limit: val })
if (this.autoScroll) {
scrollTo(0, 800)
}
},
handleCurrentChange(val) {
this.$emit('pagination', { page: val, limit: this.pageSize })
if (this.autoScroll) {
scrollTo(0, 800)
}
}
}
}
</script>
<style scoped>
.pagination-container {
background: #fff;
text-align: right;
padding-right: 10px;
}
.pagination-container.hidden {
display: none;
}
</style>

View File

@ -0,0 +1,145 @@
<template>
<div ref="rightPanel" :class="{show:show}" class="rightPanel-container">
<div class="rightPanel-background" />
<div class="rightPanel">
<!-- <div :style="{'top':buttonTop+'px','background-color':theme}" class="handle-button" @click="show=!show">-->
<!-- <i :class="show?'el-icon-close':'el-icon-setting'" />-->
<!-- </div>-->
<div class="rightPanel-items">
<slot />
</div>
</div>
</div>
</template>
<script>
import { addClass, removeClass } from '@/utils'
export default {
name: 'RightPanel',
props: {
clickNotClose: {
default: false,
type: Boolean
},
buttonTop: {
default: 250,
type: Number
}
},
data() {
return {
show: false
}
},
computed: {
theme() {
return this.$store.state.settings.theme
}
},
watch: {
show(value) {
if (value && !this.clickNotClose) {
this.addEventClick()
}
if (value) {
addClass(document.body, 'showRightPanel')
} else {
removeClass(document.body, 'showRightPanel')
}
}
},
mounted() {
this.insertToBody()
},
beforeDestroy() {
const elx = this.$refs.rightPanel
elx.remove()
},
methods: {
addEventClick() {
window.addEventListener('click', this.closeSidebar)
},
closeSidebar(evt) {
const parent = evt.target.closest('.rightPanel')
if (!parent) {
this.show = false
window.removeEventListener('click', this.closeSidebar)
}
},
insertToBody() {
const elx = this.$refs.rightPanel
const body = document.querySelector('body')
body.insertBefore(elx, body.firstChild)
}
}
}
</script>
<style>
.showRightPanel {
overflow: hidden;
position: relative;
width: calc(100% - 15px);
}
</style>
<style lang="scss" scoped>
.rightPanel-background {
position: fixed;
top: 0;
left: 0;
opacity: 0;
transition: opacity .3s cubic-bezier(.7, .3, .1, 1);
background: rgba(0, 0, 0, .2);
z-index: -1;
}
.rightPanel {
width: 100%;
max-width: 260px;
height: 100vh;
position: fixed;
top: 0;
right: 0;
box-shadow: 0px 0px 15px 0px rgba(0, 0, 0, .05);
transition: all .25s cubic-bezier(.7, .3, .1, 1);
transform: translate(100%);
background: #fff;
z-index: 40000;
}
.show {
transition: all .3s cubic-bezier(.7, .3, .1, 1);
.rightPanel-background {
z-index: 20000;
opacity: 1;
width: 100%;
height: 100%;
}
.rightPanel {
transform: translate(0);
}
}
.handle-button {
width: 48px;
height: 48px;
position: absolute;
left: -48px;
text-align: center;
font-size: 24px;
border-radius: 6px 0 0 6px !important;
z-index: 0;
pointer-events: auto;
cursor: pointer;
color: #fff;
line-height: 48px;
i {
font-size: 24px;
line-height: 48px;
}
}
</style>

View File

@ -0,0 +1,60 @@
<template>
<div>
<svg-icon :icon-class="isFullscreen?'exit-fullscreen':'fullscreen'" @click="click" />
</div>
</template>
<script>
import screenfull from 'screenfull'
export default {
name: 'Screenfull',
data() {
return {
isFullscreen: false
}
},
mounted() {
this.init()
},
beforeDestroy() {
this.destroy()
},
methods: {
click() {
if (!screenfull.isEnabled) {
this.$message({
message: 'you browser can not work',
type: 'warning'
})
return false
}
screenfull.toggle()
},
change() {
this.isFullscreen = screenfull.isFullscreen
},
init() {
if (screenfull.enabled) {
screenfull.on('change', this.change)
}
},
destroy() {
if (screenfull.enabled) {
screenfull.off('change', this.change)
}
}
}
}
</script>
<style scoped>
.screenfull-svg {
display: inline-block;
cursor: pointer;
fill: #5a5e66;;
width: 20px;
height: 20px;
vertical-align: 10px;
}
</style>

View File

@ -0,0 +1,175 @@
<template>
<el-select ref="elSelect" v-model="valueId" :value="valueId" :disabled="disabled" :filter-method="filterMethod" :clearable="clearable" filterable class="selectTree" @clear="clearHandle">
<el-option :value="valueId" :label="valueTitle" >
<el-tree
id="tree-option"
ref="selectTree"
:filter-node-method="filterNode"
:accordion="accordion"
:data="options"
:props="props"
:node-key="props.value"
:default-expanded-keys="defaultExpandedKey"
@node-click="handleNodeClick"/>
</el-option>
</el-select>
</template>
<script>
export default {
name: 'SelectTree',
props: {
/* 配置项 */
props: {
type: Object,
default: () => {
return {
value: 'id', // ID
label: 'label', //
children: 'children' //
}
}
},
/* 选项列表数据(树形结构的对象数组) */
options: {
type: Array,
default: () => { return [] }
},
/* 初始值 */
value: {
type: String,
default: () => { return null }
},
/* 可清空选项 */
clearable: {
type: Boolean,
default: () => { return true }
},
/* 可清空选项 */
canparent: {
type: Boolean,
default: () => { return true }
},
/* 自动收起 */
accordion: {
type: Boolean,
default: () => { return false }
},
/* 是否禁用 */
disabled: {
type: Boolean,
default: () => { return false }
}
},
data() {
return {
valueId: this.value, //
valueTitle: '',
defaultExpandedKey: []
}
},
watch: {
valueId(newValue, oldValue) {
this.valueId = newValue
this.$emit('input', newValue)
this.$emit('change', newValue)
this.initHandle()
}
},
mounted() {
this.initHandle()
},
methods: {
//
filterMethod(query) {
//
this.$refs.selectTree.filter(query)
//
return true
},
//
filterNode(value, data) {
if (!value) return true
return data.label.indexOf(value) !== -1
},
//
initHandle() {
if (this.valueId) {
this.valueTitle = this.$refs.selectTree.getNode(this.valueId).data[this.props.label] //
this.$refs.selectTree.setCurrentKey(this.valueId) //
this.defaultExpandedKey = [this.valueId] //
}
this.$nextTick(() => {
const scrollWrap = document.querySelectorAll('.el-scrollbar .el-select-dropdown__wrap')[0]
// const scrollBar = document.querySelectorAll('.el-scrollbar .el-scrollbar__bar')
scrollWrap.style.cssText = 'margin: 0px; max-height: none; overflow: hidden;'
// scrollBar.forEach(ele => ele.style.width = 0)
})
},
//
handleNodeClick(node) {
if (node.children && node.children.length > 0 && !this.canparent) {
return
}
this.valueTitle = node[this.props.label]
this.valueId = node[this.props.value]
this.$emit('input', this.valueId)
this.$emit('change', this.valueId)
this.defaultExpandedKey = []
const scrollWrap = document.querySelectorAll('.el-select-dropdown.el-popper')
scrollWrap.forEach(ele => {
ele.style.display = 'none'
ele.style.position = ''
ele.style.top = ''
ele.style.left = ''
})
this.clearSelected()
this.$refs.elSelect.blur()
},
//
clearHandle() {
this.valueTitle = ''
this.valueId = null
this.defaultExpandedKey = []
this.clearSelected()
this.$emit('input', null)
this.$emit('change', null)
},
/* 清空选中样式 */
clearSelected() {
const allNode = document.querySelectorAll('#tree-option .el-tree-node')
allNode.forEach((element) => element.classList.remove('is-current'))
}
}
}
</script>
<style scoped>
.el-scrollbar .el-scrollbar__view .el-select-dropdown__item{
height: auto;
max-height: 274px;
padding: 0;
overflow: hidden;
overflow-y: auto;
}
.el-select-dropdown__item.selected{
font-weight: normal;
}
ul li >>>.el-tree .el-tree-node__content{
height:auto;
padding: 0 20px;
}
.el-tree-node__label{
font-weight: normal;
}
.el-tree >>>.is-current .el-tree-node__label{
color: #409EFF;
font-weight: 700;
}
.el-tree >>>.is-current .el-tree-node__children .el-tree-node__label{
color:#606266;
font-weight: normal;
}
</style>

View File

@ -0,0 +1,138 @@
<template>
<el-dialog v-if="visible" :append-to-body="appendToBody" :visible.sync="visible" :v-loading="loading" :title="title" width="1600" @close="close">
<el-table v-loading="loading" ref="multipleTable" :data="list" :row-key="getRowKey" :header-cell-style="{background:'#f5f7fa','font-weight': 'bold','color': '#000'}" tooltip-effect="dark" border fit highlight-current-row>
<el-table-column :reserve-selection="true" type="selection" width="55" align="center" />
<el-table-column type="index" label="序号" width="50" align="center" />
<el-table-column prop="MAXUSE" label="新增使用人数" />
<el-table-column prop="CREATOR" label="变更人" />
<el-table-column prop="CREATTIME" label="变更时间" />
<el-table-column prop="REMAKE" label="备注" />
<el-table-column prop="CONTRACT" label="合同">
<template slot-scope="{row}" align="center" >
<el-button type="text" @click="checkPdf(row)"></el-button>
<el-divider v-if="searchFrom.isCorp === '1'" direction="vertical"/>
<el-button v-if="searchFrom.isCorp === '1'" type="text" @click="updatePdf(row)"></el-button>
</template>
</el-table-column>
</el-table>
<div style="margin-top: 10px">
<pagination :total="pageInfo.total" :page.sync="pageInfo.page" :limit.sync="pageInfo.limit" @pagination="getList" />
</div>
<div style="display: flex;justify-content: flex-end; margin-top: 10px;margin-right: 10px">
<!-- <el-button v-if="searchFrom.isCorp === '1'" type="primary" @click="addContract"></el-button>-->
<el-button @click="close"></el-button>
</div>
<glance-pdf ref="glancePdf" append-to-body/>
<!-- <add-contract ref="addContract" append-to-body @getResult="getList"/>-->
<upload-pdf ref="uploadPdf" title="编辑合同" accept=".pdf,.PDF" append-to-body @getChoose="confirm"/>
</el-dialog>
</template>
<script>
import waves from '@/directive/waves' // waves directive
import { requestFN } from '@/utils/request'
import Pagination from '@/components/Pagination'
import { upload } from '@/utils/upload'
import uploadPdf from '@/components/uploadPdf'
import glancePdf from '@/components/glancePdf'
export default {
directives: { waves },
components: { Pagination, uploadPdf, glancePdf },
props: {
appendToBody: {
type: Boolean,
default: false
},
title: {
type: String,
default: '变更记录'
}
},
data() {
return {
visible: false,
loading: false,
list: [],
pageInfo: {
total: 0,
page: 1,
limit: 10
},
heirloom: {},
searchFrom: {
ENTERPRISE_ID: '',
CORPINFO_ID: '',
isCorp: '1'
},
config: config
}
},
methods: {
init(e) {
this.visible = true
this.heirloom = e
this.searchFrom.CORPINFO_ID = e.CORPINFO_ID
this.getList()
},
getList() {
this.loading = true
requestFN(
'/expireCorpinfo/renewalList?showCount=' + this.pageInfo.limit + '&currentPage=' + this.pageInfo.page,
this.searchFrom
).then((data) => {
this.loading = false
this.list = data.varList
this.pageInfo.total = data.page.totalResult
}).catch((e) => {
this.loading = false
})
},
getRowKey(row) {
return row.CORPENTERPRISECONTACT_ID
},
checkPdf(row) {
if (row.CONTRACT) {
this.$refs.glancePdf.init({ url: config.fileUrl + row.CONTRACT })
} else {
this.$message({
message: '文件为空',
type: 'warning'
})
}
},
updatePdf(row) {
this.$refs.uploadPdf.init(row)
},
// addContract() {
// this.$refs.addContract.init(this.heirloom)
// },
confirm(e) {
const formData = new FormData()
formData.append('CONTRACT', e.info[0].raw)
formData.append('RENEWAL_ID', e.heirloom.RENEWAL_ID)
upload('/enterprises/uploadPdf', formData).then((res) => {
if (res.errorMessage) {
this.$message({
message: res.errorMessage,
type: 'error'
})
} else {
this.$message({
message: '操作成功',
type: 'success'
})
this.getList()
}
})
},
close() {
this.visible = false
this.searchFrom = {
ENTERPRISE_ID: '',
isCorp: '1'
}
}
}
}
</script>

View File

@ -0,0 +1,56 @@
<template>
<el-dropdown trigger="click" @command="handleSetSize">
<div>
<svg-icon class-name="size-icon" icon-class="size" />
</div>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item v-for="item of sizeOptions" :key="item.value" :disabled="size===item.value" :command="item.value">
{{ item.label }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
<script>
export default {
data() {
return {
sizeOptions: [
{ label: '默认', value: 'default' },
{ label: '大', value: 'medium' },
{ label: '中', value: 'small' },
{ label: '小', value: 'mini' }
]
}
},
computed: {
size() {
return this.$store.getters.size
}
},
methods: {
handleSetSize(size) {
this.$ELEMENT.size = size
this.$store.dispatch('app/setSize', size)
this.refreshView()
this.$message({
message: 'Switch Size Success',
type: 'success'
})
},
refreshView() {
// In order to make the cached page re-rendered
this.$store.dispatch('tagsView/delAllCachedViews', this.$route)
const { fullPath } = this.$route
this.$nextTick(() => {
this.$router.replace({
path: '/redirect' + fullPath
})
})
}
}
}
</script>

View File

@ -0,0 +1,62 @@
<template>
<div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
<svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
<use :xlink:href="iconName" />
</svg>
</template>
<script>
// doc: https://panjiachen.github.io/vue-element-admin-site/feature/component/svg-icon.html#usage
import { isExternal } from '@/utils/validate'
export default {
name: 'SvgIcon',
props: {
iconClass: {
type: String,
required: true
},
className: {
type: String,
default: ''
}
},
computed: {
isExternal() {
return isExternal(this.iconClass)
},
iconName() {
return `#icon-${this.iconClass}`
},
svgClass() {
if (this.className) {
return 'svg-icon ' + this.className
} else {
return 'svg-icon'
}
},
styleExternalIcon() {
return {
mask: `url(${this.iconClass}) no-repeat 50% 50%`,
'-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
}
}
}
}
</script>
<style scoped>
.svg-icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
.svg-external-icon {
background-color: currentColor;
mask-size: cover!important;
display: inline-block;
}
</style>

View File

@ -0,0 +1,175 @@
<template>
<el-color-picker
v-model="theme"
:predefine="['#409EFF', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
class="theme-picker"
popper-class="theme-picker-dropdown"
/>
</template>
<script>
const version = require('element-ui/package.json').version // element-ui version from node_modules
const ORIGINAL_THEME = '#409EFF' // default color
export default {
data() {
return {
chalk: '', // content of theme-chalk css
theme: ''
}
},
computed: {
defaultTheme() {
return this.$store.state.settings.theme
}
},
watch: {
defaultTheme: {
handler: function(val, oldVal) {
this.theme = val
},
immediate: true
},
async theme(val) {
const oldVal = this.chalk ? this.theme : ORIGINAL_THEME
if (typeof val !== 'string') return
const themeCluster = this.getThemeCluster(val.replace('#', ''))
const originalCluster = this.getThemeCluster(oldVal.replace('#', ''))
console.log(themeCluster, originalCluster)
const $message = this.$message({
message: ' Compiling the theme',
customClass: 'theme-message',
type: 'success',
duration: 0,
iconClass: 'el-icon-loading'
})
const getHandler = (variable, id) => {
return () => {
const originalCluster = this.getThemeCluster(ORIGINAL_THEME.replace('#', ''))
const newStyle = this.updateStyle(this[variable], originalCluster, themeCluster)
let styleTag = document.getElementById(id)
if (!styleTag) {
styleTag = document.createElement('style')
styleTag.setAttribute('id', id)
document.head.appendChild(styleTag)
}
styleTag.innerText = newStyle
}
}
if (!this.chalk) {
const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`
await this.getCSSString(url, 'chalk')
}
const chalkHandler = getHandler('chalk', 'chalk-style')
chalkHandler()
const styles = [].slice.call(document.querySelectorAll('style'))
.filter(style => {
const text = style.innerText
return new RegExp(oldVal, 'i').test(text) && !/Chalk Variables/.test(text)
})
styles.forEach(style => {
const { innerText } = style
if (typeof innerText !== 'string') return
style.innerText = this.updateStyle(innerText, originalCluster, themeCluster)
})
this.$emit('change', val)
$message.close()
}
},
methods: {
updateStyle(style, oldCluster, newCluster) {
let newStyle = style
oldCluster.forEach((color, index) => {
newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index])
})
return newStyle
},
getCSSString(url, variable) {
return new Promise(resolve => {
const xhr = new XMLHttpRequest()
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, '')
resolve()
}
}
xhr.open('GET', url)
xhr.send()
})
},
getThemeCluster(theme) {
const tintColor = (color, tint) => {
let red = parseInt(color.slice(0, 2), 16)
let green = parseInt(color.slice(2, 4), 16)
let blue = parseInt(color.slice(4, 6), 16)
if (tint === 0) { // when primary color is in its rgb space
return [red, green, blue].join(',')
} else {
red += Math.round(tint * (255 - red))
green += Math.round(tint * (255 - green))
blue += Math.round(tint * (255 - blue))
red = red.toString(16)
green = green.toString(16)
blue = blue.toString(16)
return `#${red}${green}${blue}`
}
}
const shadeColor = (color, shade) => {
let red = parseInt(color.slice(0, 2), 16)
let green = parseInt(color.slice(2, 4), 16)
let blue = parseInt(color.slice(4, 6), 16)
red = Math.round((1 - shade) * red)
green = Math.round((1 - shade) * green)
blue = Math.round((1 - shade) * blue)
red = red.toString(16)
green = green.toString(16)
blue = blue.toString(16)
return `#${red}${green}${blue}`
}
const clusters = [theme]
for (let i = 0; i <= 9; i++) {
clusters.push(tintColor(theme, Number((i / 10).toFixed(2))))
}
clusters.push(shadeColor(theme, 0.1))
return clusters
}
}
}
</script>
<style>
.theme-message,
.theme-picker-dropdown {
z-index: 99999 !important;
}
.theme-picker .el-color-picker__trigger {
height: 26px !important;
width: 26px !important;
padding: 2px;
}
.theme-picker-dropdown .el-color-dropdown__link-btn {
display: none;
}
</style>

View File

@ -0,0 +1,111 @@
<template>
<div class="upload-container">
<!-- <el-button :style="{background:color,borderColor:color}" icon="el-icon-upload" size="mini" type="primary" @click=" dialogVisible=true">-->
<!-- upload-->
<!-- </el-button>-->
<el-dialog :visible.sync="dialogVisible">
<el-upload
:multiple="true"
:file-list="fileList"
:show-file-list="true"
:on-remove="handleRemove"
:on-success="handleSuccess"
:before-upload="beforeUpload"
class="editor-slide-upload"
action="https://httpbin.org/post"
list-type="picture-card"
>
<el-button size="small" type="primary">
Click upload
</el-button>
</el-upload>
<el-button @click="dialogVisible = false">
关闭
</el-button>
<el-button type="primary" @click="handleSubmit">
提交
</el-button>
</el-dialog>
</div>
</template>
<script>
// import { getToken } from 'api/qiniu'
export default {
name: 'EditorSlideUpload',
props: {
color: {
type: String,
default: '#1890ff'
}
},
data() {
return {
dialogVisible: false,
listObj: {},
fileList: []
}
},
methods: {
checkAllSuccess() {
return Object.keys(this.listObj).every(item => this.listObj[item].hasSuccess)
},
handleSubmit() {
const arr = Object.keys(this.listObj).map(v => this.listObj[v])
if (!this.checkAllSuccess()) {
this.$message('请等待所有图片上传成功。如果出现网络问题,请刷新页面并重新上传!')
return
}
this.$emit('successCBK', arr)
this.listObj = {}
this.fileList = []
this.dialogVisible = false
},
handleSuccess(response, file) {
const uid = file.uid
const objKeyArr = Object.keys(this.listObj)
for (let i = 0, len = objKeyArr.length; i < len; i++) {
if (this.listObj[objKeyArr[i]].uid === uid) {
this.listObj[objKeyArr[i]].url = response.files.file
this.listObj[objKeyArr[i]].hasSuccess = true
return
}
}
},
handleRemove(file) {
const uid = file.uid
const objKeyArr = Object.keys(this.listObj)
for (let i = 0, len = objKeyArr.length; i < len; i++) {
if (this.listObj[objKeyArr[i]].uid === uid) {
delete this.listObj[objKeyArr[i]]
return
}
}
},
beforeUpload(file) {
const _self = this
const _URL = window.URL || window.webkitURL
const fileName = file.uid
this.listObj[fileName] = {}
return new Promise((resolve, reject) => {
const img = new Image()
img.src = _URL.createObjectURL(file)
img.onload = function() {
_self.listObj[fileName] = { hasSuccess: false, uid: file.uid, width: this.width, height: this.height }
}
resolve(true)
})
}
}
}
</script>
<style lang="scss" scoped>
.editor-slide-upload {
margin-bottom: 20px;
::v-deep .el-upload--picture-card {
width: 100%;
}
}
</style>

View File

@ -0,0 +1,59 @@
let callbacks = []
function loadedTinymce() {
// to fixed https://github.com/PanJiaChen/vue-element-admin/issues/2144
// check is successfully downloaded script
return window.tinymce
}
const dynamicLoadScript = (src, callback) => {
const existingScript = document.getElementById(src)
const cb = callback || function() {}
if (!existingScript) {
const script = document.createElement('script')
script.src = src // src url for the third-party library being loaded.
script.id = src
document.body.appendChild(script)
callbacks.push(cb)
const onEnd = 'onload' in script ? stdOnEnd : ieOnEnd
onEnd(script)
}
if (existingScript && cb) {
if (loadedTinymce()) {
cb(null, existingScript)
} else {
callbacks.push(cb)
}
}
function stdOnEnd(script) {
script.onload = function() {
// this.onload = null here is necessary
// because even IE9 works not like others
this.onerror = this.onload = null
for (const cb of callbacks) {
cb(null, script)
}
callbacks = null
}
script.onerror = function() {
this.onerror = this.onload = null
cb(new Error('Failed to load ' + src), script)
}
}
function ieOnEnd(script) {
script.onreadystatechange = function() {
if (this.readyState !== 'complete' && this.readyState !== 'loaded') return
this.onreadystatechange = null
for (const cb of callbacks) {
cb(null, script) // there is no way to catch loading errors in IE8
}
callbacks = null
}
}
}
export default dynamicLoadScript

View File

@ -0,0 +1,250 @@
<template>
<div :class="{fullscreen:fullscreen}" class="tinymce-container" >
<textarea :id="tinymceId" class="tinymce-textarea" />
<div class="editor-custom-btn-container">
<editorImage color="#1890ff" class="editor-upload-btn" @successCBK="imageSuccessCBK" />
</div>
</div>
</template>
<script>
/**
* docs:
* https://panjiachen.github.io/vue-element-admin-site/feature/component/rich-editor.html#tinymce
*/
import editorImage from './components/EditorImage'
import plugins from './plugins'
import toolbar from './toolbar'
import load from './dynamicLoadScript'
// why use this cdn, detail see https://github.com/PanJiaChen/tinymce-all-in-one
const tinymceCDN = 'https://cdn.jsdelivr.net/npm/tinymce-all-in-one@4.9.3/tinymce.min.js'
export default {
name: 'Tinymce',
components: { editorImage },
props: {
id: {
type: String,
default: function() {
return 'vue-tinymce-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '')
}
},
value: {
type: String,
default: ''
},
toolbar: {
type: Array,
required: false,
default() {
return []
}
},
menubar: {
type: String,
default: 'file edit insert view format table'
},
height: {
type: [Number, String],
required: false,
default: 360
},
width: {
type: [Number, String],
required: false,
default: 'auto'
}
},
data() {
return {
hasChange: false,
hasInit: false,
tinymceId: this.id,
fullscreen: false,
languageTypeList: {
'en': 'en',
'zh': 'zh_CN',
'es': 'es_MX',
'ja': 'ja'
}
}
},
computed: {
containerWidth() {
const width = this.width
if (/^[\d]+(\.[\d]+)?$/.test(width)) { // matches `100`, `'100'`
return `${width}px`
}
return width
}
},
watch: {
value(val) {
if (!this.hasChange && this.hasInit) {
this.$nextTick(() =>
window.tinymce.get(this.tinymceId).setContent(val || ''))
}
}
},
mounted() {
this.init()
},
activated() {
if (window.tinymce) {
this.initTinymce()
}
},
deactivated() {
this.destroyTinymce()
},
destroyed() {
this.destroyTinymce()
},
methods: {
init() {
// dynamic load tinymce from cdn
load(tinymceCDN, (err) => {
if (err) {
this.$message.error(err.message)
return
}
this.initTinymce()
})
},
initTinymce() {
const _this = this
window.tinymce.init({
selector: `#${this.tinymceId}`,
language: this.languageTypeList['zh'],
height: this.height,
body_class: 'panel-body ',
object_resizing: false,
toolbar: this.toolbar.length > 0 ? this.toolbar : toolbar,
// menubar: this.menubar,
menubar: false,
// statusbar: false,
branding: false,
plugins: plugins,
end_container_on_empty_block: true,
powerpaste_word_import: 'clean',
code_dialog_height: 450,
code_dialog_width: 1000,
advlist_bullet_styles: 'square',
advlist_number_styles: 'default',
imagetools_cors_hosts: ['www.tinymce.com', 'codepen.io'],
default_link_target: '_blank',
link_title: false,
nonbreaking_force_tab: true, // inserting nonbreaking space &nbsp; need Nonbreaking Space Plugin
init_instance_callback: editor => {
if (_this.value) {
editor.setContent(_this.value)
}
_this.hasInit = true
editor.on('NodeChange Change KeyUp SetContent', () => {
this.hasChange = true
this.$emit('input', editor.getContent())
})
},
setup(editor) {
editor.on('FullscreenStateChanged', (e) => {
_this.fullscreen = e.state
})
},
// it will try to keep these URLs intact
// https://www.tiny.cloud/docs-3x/reference/configuration/Configuration3x@convert_urls/
// https://stackoverflow.com/questions/5196205/disable-tinymce-absolute-to-relative-url-conversions
convert_urls: false
//
// images_dataimg_filter(img) {
// setTimeout(() => {
// const $image = $(img);
// $image.removeAttr('width');
// $image.removeAttr('height');
// if ($image[0].height && $image[0].width) {
// $image.attr('data-wscntype', 'image');
// $image.attr('data-wscnh', $image[0].height);
// $image.attr('data-wscnw', $image[0].width);
// $image.addClass('wscnph');
// }
// }, 0);
// return img
// },
// images_upload_handler(blobInfo, success, failure, progress) {
// progress(0);
// const token = _this.$store.getters.token;
// getToken(token).then(response => {
// const url = response.data.qiniu_url;
// const formData = new FormData();
// formData.append('token', response.data.qiniu_token);
// formData.append('key', response.data.qiniu_key);
// formData.append('file', blobInfo.blob(), url);
// upload(formData).then(() => {
// success(url);
// progress(100);
// })
// }).catch(err => {
// failure('')
// console.log(err);
// });
// },
})
},
destroyTinymce() {
const tinymce = window.tinymce.get(this.tinymceId)
if (this.fullscreen) {
tinymce.execCommand('mceFullScreen')
}
if (tinymce) {
tinymce.destroy()
}
},
setContent(value) {
window.tinymce.get(this.tinymceId).setContent(value)
},
getContent() {
window.tinymce.get(this.tinymceId).getContent()
},
imageSuccessCBK(arr) {
arr.forEach(v => window.tinymce.get(this.tinymceId).insertContent(`<img class="wscnph" src="${v.url}" >`))
}
}
}
</script>
<style lang="scss" scoped>
.tinymce-container {
position: relative;
line-height: normal;
}
.tinymce-container {
::v-deep {
.mce-fullscreen {
z-index: 10000;
}
}
}
.tinymce-textarea {
visibility: hidden;
z-index: -1;
}
.editor-custom-btn-container {
position: absolute;
right: 4px;
top: 4px;
/*z-index: 2005;*/
}
.fullscreen .editor-custom-btn-container {
z-index: 10000;
position: fixed;
}
.editor-upload-btn {
display: inline-block;
}
</style>

View File

@ -0,0 +1,7 @@
// Any plugins you want to use has to be imported
// Detail plugins list see https://www.tinymce.com/docs/plugins/
// Custom builds see https://www.tinymce.com/download/custom-builds/
const plugins = ['advlist anchor autolink autosave code codesample colorpicker colorpicker contextmenu directionality emoticons fullscreen hr image imagetools insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textcolor textpattern visualblocks visualchars wordcount']
export default plugins

View File

@ -0,0 +1,6 @@
// Here is a list of the toolbar
// Detail list see https://www.tinymce.com/docs/advanced/editor-control-identifiers/#toolbarcontrols
const toolbar = ['searchreplace bold italic underline strikethrough alignleft aligncenter alignright outdent indent blockquote undo redo removeformat subscript superscript code codesample', 'hr bullist numlist link image charmap preview anchor pagebreak insertdatetime media table emoticons forecolor backcolor fullscreen']
export default toolbar

View File

@ -0,0 +1,90 @@
<template>
<div>
<el-upload
ref="uploadFile"
:auto-upload="false"
:file-list="fileList"
:on-change="onChange"
:on-remove="onRemove"
:limit="limit"
:on-exceed="handleExceed"
:accept="accept"
action="#">
<el-button slot="trigger" size="small" type="primary">选取文件</el-button>
<div slot="tip" class="el-upload__tip">{{ info }}</div>
</el-upload>
</div>
</template>
<script>
export default {
name: 'UploadImg',
props: {
//
fileList: {
type: Array,
default() {
return []
}
},
//
limit: {
type: Number,
default: 1
},
//
fileSize: {
type: Number,
default: 500
},
//
accept: {
type: String,
default: ''
},
//
info: {
type: String,
default: '文件大小不超过500MB'
}
},
data() {
return {
dialogImageUrl: '',
dialogVisible: false,
disabled: false
}
},
methods: {
handleRemove(file) {
this.fileList.splice(this.fileList.findIndex(item => item.uid === file.uid), 1)
},
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url
this.dialogVisible = true
},
onChange(file, fileList) {
if (!file) {
this.$message.error('请上传文件')
return
}
this.file = file
this.file_name = file.name
const isLt2M = file.size / 1024 / 1024 < this.fileSize
if (!isLt2M) {
this.$message.error('上传视频大小不能超过 ' + this.fileSize + 'MB!')
this.$refs.uploadFile.clearFiles()
return false
}
this.$emit('update:fileList', fileList)
},
onRemove(file, fileList) {
this.$emit('update:fileList', fileList)
},
handleExceed(files, fileList) {
this.$message.warning(`当前限制选择 ${this.limit} 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`)
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,84 @@
<template>
<el-dialog
v-if="visible"
:visible.sync="visible"
:before-close="handleClose"
:title="title"
:append-to-body="appendToBody"
width="60%">
<UploadFile :file-list.sync = "files" :accept="accept"/>
<span slot="footer" class="dialog-footer">
<el-button @click="closeWindow"> </el-button>
<el-button type="primary" @click="confirm"> </el-button>
</span>
</el-dialog>
</template>
<script>
import Pagination from '@/components/Pagination' // el-pagination
import waves from '@/directive/waves' // waves directive
import UploadFile from '@/components/UploadFile'
export default {
components: { Pagination, UploadFile },
directives: { waves },
props: {
title: {
type: String,
default: ''
},
appendToBody: {
type: Boolean,
default: false
},
limit: {
type: Number,
default: 1
},
accept: {
type: String,
default: '.pdf'
}
},
data() {
return {
visible: false,
files: [],
heirloom: {}
}
},
methods: {
init(e) {
this.visible = true
this.heirloom = e
},
handleClose() {
this.visible = false
this.files = []
},
closeWindow() {
this.handleClose()
},
confirm() {
if (this.files.length <= 0) {
this.$message.error('未选择文件')
return
}
const str = this.files[0].name
if (str.substr(str.indexOf('.') + 1, str.length) !== 'pdf') {
this.$message.error('导入类型与模板类型不一致')
return
}
this.$emit('getChoose', { heirloom: this.heirloom, info: this.files, name: 'uploadPdf' })
this.visible = false
}
}
}
</script>
<style scoped>
.information >>> .el-scrollbar__wrap {
overflow-x: hidden;
}
</style>

View File

@ -0,0 +1,203 @@
<template>
<el-dialog :visible.sync="dialogFormVisible" :before-close="close" title="培训类型" top="80px" width="1040px" append-to-body>
<el-form :model="form" class="appformwith">
<div class="type_field_box">
<div class="type_field_item">
<div class="type_field_top">培训类型</div>
<div class="type_field_content type_pa">
<div
v-for="(item,i) in trainingList"
:key="i"
:class="form.TRAINTYPE == item.TRAININGTYPE_ID ? 'type_li_active' : ''"
class="type_li"
@click="checkTrain(item)">
{{ item.NAME }}
</div>
</div>
</div>
<div class="type_field_item">
<div class="type_field_top">岗位类型</div>
<div class="type_field_content type_pa">
<div
v-for="(item,i) in postList"
:key="i"
:class="form.POSTTYPE == item.POSTTYPE_ID ? 'type_li_active' : ''"
class="type_li"
@click="checkPost(item)">
{{ item.NAME }}
</div>
</div>
</div>
<div class="type_field_item" style="width:320px">
<div class="type_field_top">行业类型</div>
<div class="type_field_content m-scroll-style">
<div class="type_field_search">
<el-input
v-model="filterText"
placeholder="请输入关键字进行过滤..."
prefix-icon="el-icon-search"
size="mini"
clearable/>
</div>
<el-tree
v-loading="treeLoading"
ref="tree"
:data="industryTreeData"
:props="industryProps"
:filter-node-method="filterNode"
:highlight-current="true"
class="type_tree"
@node-click="handleNodeClick"/>
</div>
</div>
<div class="type_field_item">
<div class="type_field_top">培训级别</div>
<div class="type_field_content type_pa">
<div
v-for="(item,i) in trainLevelList"
:key="i"
:class="form.TRAINLEVEL == item.TRAINLEVEL_ID ? 'type_li_active' : ''"
class="type_li"
@click="checkTrainLevel(item)">
{{ item.NAME }}
</div>
</div>
</div>
</div>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="close"> </el-button>
<el-button type="primary" @click="selectIndustry"> </el-button>
</div>
</el-dialog>
</template>
<script>
import { requestFN } from '@/utils/request'
export default {
props: {
dialogFormVisible: {
type: Boolean,
default: false
}
},
data() {
return {
form: {
TRAINTYPE: '',
TRAINTYPE_NAME: '',
POSTTYPE: '',
POSTTYPE_NAME: '',
TRAINLEVEL: '',
TRAINLEVEL_NAME: '',
INDUSTRY_END_ID: '',
INDUSTRY_END_ID_NAME: '',
trainAllName: ''
},
treeLoading: false,
trainingList: [],
postList: [],
filterText: '',
industryTreeData: [],
industryProps: {
children: 'nodes',
label: 'NAME'
},
trainLevelList: []
}
},
created() {
this.getTrainingList()
this.getTreeList()
},
methods: {
getTrainingList() {
requestFN(
'/trainingtype/listAll',
{}
).then((data) => {
this.trainingList = data.varList
}).catch((e) => {
})
},
getPostList(TRAININGTYPE_ID) {
requestFN(
'/posttype/listAll',
{ TRAININGTYPE_ID }
).then((data) => {
this.postList = data.varList
}).catch((e) => {
})
},
getTreeList() {
this.treeLoading = true
requestFN(
'/industrytype/getIndustryTree'
).then((data) => {
this.treeLoading = false
this.industryTreeData = data.zTreeNodes
}).catch((e) => {
this.treeLoading = false
})
},
getTrainLevelList(TRAININGTYPE_ID) {
requestFN(
'/trainleveltype/listAll',
{ TRAININGTYPE_ID }
).then((data) => {
this.trainLevelList = data.varList
}).catch((e) => {
})
},
checkTrain(item) {
this.form.TRAINTYPE = item.TRAININGTYPE_ID
this.form.TRAINTYPE_NAME = item.NAME
this.form.POSTTYPE = ''
this.form.POSTTYPE_NAME = ''
this.form.INDUSTRY_END_ID = ''
this.form.INDUSTRY_END_ID_NAME = ''
this.form.TRAINLEVEL = ''
this.form.TRAINLEVEL_NAME = ''
this.getPostList(item.TRAININGTYPE_ID)
this.getTrainLevelList(item.TRAININGTYPE_ID)
},
checkPost(item) {
this.form.POSTTYPE = item.POSTTYPE_ID
this.form.POSTTYPE_NAME = item.NAME
this.form.INDUSTRY_END_ID = ''
this.form.INDUSTRY_END_ID_NAME = ''
},
filterNode(value, data) {
if (!value) return true
return data.name.indexOf(value) !== -1
},
handleNodeClick(node, data, value) {
if (data.isLeaf) { //
this.form.INDUSTRY_END_ID = node.INDUSTRYTYPE_ID
this.form.INDUSTRY_END_ID_NAME = node.NAME
}
},
checkTrainLevel(item) {
this.form.TRAINLEVEL = item.TRAINLEVEL_ID
this.form.TRAINLEVEL_NAME = item.NAME
},
selectIndustry() {
const pn = this.form.POSTTYPE_NAME ? '-' + this.form.POSTTYPE_NAME : ''
const iname = this.form.INDUSTRY_END_ID_NAME ? '-' + this.form.INDUSTRY_END_ID_NAME : ''
const tlName = this.form.TRAINLEVEL_NAME ? '-' + this.form.TRAINLEVEL_NAME : ''
this.form.trainAllName = this.form.TRAINTYPE_NAME + pn + iname + tlName
this.$nextTick(() => {
this.$emit('confirm', this.form)
this.close()
})
},
close() {
this.$emit('update:dialogFormVisible', false)
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,13 @@
import waves from './waves'
const install = function(Vue) {
Vue.directive('waves', waves)
}
if (window.Vue) {
window.waves = waves
Vue.use(install); // eslint-disable-line
}
waves.install = install
export default waves

View File

@ -0,0 +1,26 @@
.waves-ripple {
position: absolute;
border-radius: 100%;
background-color: rgba(0, 0, 0, 0.15);
background-clip: padding-box;
pointer-events: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-transform: scale(0);
-ms-transform: scale(0);
transform: scale(0);
opacity: 1;
}
.waves-ripple.z-active {
opacity: 0;
-webkit-transform: scale(2);
-ms-transform: scale(2);
transform: scale(2);
-webkit-transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
transition: opacity 1.2s ease-out, transform 0.6s ease-out;
transition: opacity 1.2s ease-out, transform 0.6s ease-out, -webkit-transform 0.6s ease-out;
}

View File

@ -0,0 +1,72 @@
import './waves.css'
const context = '@@wavesContext'
function handleClick(el, binding) {
function handle(e) {
const customOpts = Object.assign({}, binding.value)
const opts = Object.assign({
ele: el, // 波纹作用元素
type: 'hit', // hit 点击位置扩散 center中心点扩展
color: 'rgba(0, 0, 0, 0.15)' // 波纹颜色
},
customOpts
)
const target = opts.ele
if (target) {
target.style.position = 'relative'
target.style.overflow = 'hidden'
const rect = target.getBoundingClientRect()
let ripple = target.querySelector('.waves-ripple')
if (!ripple) {
ripple = document.createElement('span')
ripple.className = 'waves-ripple'
ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px'
target.appendChild(ripple)
} else {
ripple.className = 'waves-ripple'
}
switch (opts.type) {
case 'center':
ripple.style.top = rect.height / 2 - ripple.offsetHeight / 2 + 'px'
ripple.style.left = rect.width / 2 - ripple.offsetWidth / 2 + 'px'
break
default:
ripple.style.top =
(e.pageY - rect.top - ripple.offsetHeight / 2 - document.documentElement.scrollTop ||
document.body.scrollTop) + 'px'
ripple.style.left =
(e.pageX - rect.left - ripple.offsetWidth / 2 - document.documentElement.scrollLeft ||
document.body.scrollLeft) + 'px'
}
ripple.style.backgroundColor = opts.color
ripple.className = 'waves-ripple z-active'
return false
}
}
if (!el[context]) {
el[context] = {
removeHandle: handle
}
} else {
el[context].removeHandle = handle
}
return handle
}
export default {
bind(el, binding) {
el.addEventListener('click', handleClick(el, binding), false)
},
update(el, binding) {
el.removeEventListener('click', el[context].removeHandle, false)
el.addEventListener('click', handleClick(el, binding), false)
},
unbind(el) {
el.removeEventListener('click', el[context].removeHandle, false)
el[context] = null
delete el[context]
}
}

9
src/icons/index.js Normal file
View File

@ -0,0 +1,9 @@
import Vue from 'vue'
import SvgIcon from '@/components/SvgIcon'// svg component
// register globally
Vue.component('svg-icon', SvgIcon)
const req = require.context('./svg', false, /\.svg$/)
const requireAll = requireContext => requireContext.keys().map(requireContext)
requireAll(req)

10
src/icons/svg-icons.js Normal file
View File

@ -0,0 +1,10 @@
const req = require.context('../../icons/svg', false, /\.svg$/)
const requireAll = requireContext => requireContext.keys()
const re = /\.\/(.*)\.svg/
const svgIcons = requireAll(req).map(i => {
return i.match(re)[1]
})
export default svgIcons

1
src/icons/svg/404.svg Normal file
View File

@ -0,0 +1 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M121.718 73.272v9.953c3.957-7.584 6.199-16.05 6.199-24.995C127.917 26.079 99.273 0 63.958 0 28.644 0 0 26.079 0 58.23c0 .403.028.806.028 1.21l22.97-25.953h13.34l-19.76 27.187h6.42V53.77l13.728-19.477v49.361H22.998V73.272H2.158c5.951 20.284 23.608 36.208 45.998 41.399-1.44 3.3-5.618 11.263-12.565 12.674-8.607 1.764 23.358.428 46.163-13.178 17.519-4.611 31.938-15.849 39.77-30.513h-13.506V73.272H85.02V59.464l22.998-25.977h13.008l-19.429 27.187h6.421v-7.433l13.727-19.402v39.433h-.027zm-78.24 2.822a10.516 10.516 0 0 1-.996-4.535V44.548c0-1.613.332-3.124.996-4.535a11.66 11.66 0 0 1 2.713-3.68c1.134-1.032 2.49-1.864 4.04-2.468 1.55-.605 3.21-.908 4.982-.908h11.292c1.77 0 3.431.303 4.981.908 1.522.604 2.85 1.41 3.986 2.418l-12.26 16.303v-2.898a1.96 1.96 0 0 0-.665-1.512c-.443-.403-.996-.604-1.66-.604-.665 0-1.218.201-1.661.604a1.96 1.96 0 0 0-.664 1.512v9.071L44.364 77.606a10.556 10.556 0 0 1-.886-1.512zm35.73-4.535c0 1.613-.332 3.124-.997 4.535a11.66 11.66 0 0 1-2.712 3.68c-1.134 1.032-2.49 1.864-4.04 2.469-1.55.604-3.21.907-4.982.907H55.185c-1.77 0-3.431-.303-4.981-.907-1.55-.605-2.906-1.437-4.041-2.47a12.49 12.49 0 0 1-1.384-1.512l13.727-18.217v6.375c0 .605.222 1.109.665 1.512.442.403.996.604 1.66.604.664 0 1.218-.201 1.66-.604a1.96 1.96 0 0 0 .665-1.512V53.87L75.97 36.838c.913.932 1.66 1.99 2.214 3.175.664 1.41.996 2.922.996 4.535v27.011h.028z"/></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

11
src/icons/svg/app.svg Normal file
View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 200 200" style="enable-background:new 0 0 200 200;" xml:space="preserve">
<path d="M50.2,123.3l4.4,11.6H71L45.8,67.8l0-0.1H29.3l0,0.1L4.1,134.9h16.5l4.4-11.6L50.2,123.3L50.2,123.3z M45.2,110.2H29.9
l7.7-20.4L45.2,110.2z M83.7,67.5v67.4h16.4v-16h9c14.1,0,25.7-11.5,25.7-25.7s-11.5-25.7-25.7-25.7L83.7,67.5L83.7,67.5z
M118.3,93.2c0,5-4.2,9.2-9.2,9.2h-9V84h9C114.1,84,118.3,88.2,118.3,93.2z M174.3,67.5h-25.4v67.4h16.4v-16h9
c14.1,0,25.7-11.5,25.7-25.7S188.5,67.5,174.3,67.5L174.3,67.5z M174.3,102.5h-9V84h9c5,0,9.2,4.2,9.2,9.2
C183.6,98.2,179.3,102.5,174.3,102.5z M38,26.5h127v31.7h16.4V19.9c0-5.4-4.6-9.9-10.2-9.9H31.8c-5.6,0-10.2,4.4-10.2,9.9v38.2H38
V26.5z M165,176.3H38v-31.7H21.6v38.2c0,5.4,4.6,9.9,10.2,9.9h139.5c5.6,0,10.2-4.4,10.2-9.9v-38.2H165L165,176.3L165,176.3z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

1
src/icons/svg/books.svg Normal file
View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1636790062702" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="23163" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M956.8 828.7c3.2 20-0.8 38-12 54-11.1 16-26.4 25.7-45.5 29l-115.1 19c-18.5 3.3-35.7-0.9-51.3-12.5-15.6-11.6-25.1-27.5-28.3-47.5l-97.8-646c-1.3-10-0.8-19.5 1.4-28.5s6-17.4 11-25c5.1-7.7 11.7-14 19.7-19s16.8-8.5 26.4-10.5l114.1-19c19.2-3.3 36.4 1 51.8 13 15.4 12 24.6 28 27.8 48l97.8 645zM510 99.6c19.2 0 35.5 7 48.9 21 13.4 14 20.1 31 20.1 51v667.9c0 20-6.7 37-20.1 51-13.4 14-29.7 21-48.9 21h-99.7c-19.2 0-35.5-7-48.9-21-13.4-14-20.1-31-20.1-51V171.6c0-20 5.1-37 15.4-51s25.3-21 45-21H510z m23.4 504c6.4 0 11.8-3.1 16.3-9.5 4.5-6.3 6.7-13.9 6.7-22.5 0-9.4-2.3-17-6.7-23-4.5-6-9.9-9-16.3-9h-99.7c-6.4 0-11.8 3-16.3 9s-6.7 13.7-6.7 23c0 8.7 2.2 16.2 6.7 22.5 4.5 6.4 9.9 9.5 16.3 9.5h99.7z m0-127.1c6.4 0 11.8-3.1 16.3-9.5 4.5-6.3 6.7-14.2 6.7-23.5s-2.3-17-6.7-23c-4.5-6.1-9.9-9-16.3-9h-99.7c-6.4 0-11.8 3-16.3 9s-6.7 13.7-6.7 23 2.2 17.2 6.7 23.5c4.5 6.3 9.9 9.5 16.3 9.5h99.7z m-301-376.9c19.2 0 35.7 7 49.3 21 13.7 14 20.6 31 20.6 51v667.9c0 20-6.8 37-20.6 51s-30.2 21-49.3 21h-99.7c-19.2 0-35.7-7-49.3-21-13.8-14-20.6-31-20.6-51V171.6c0-20 6.8-37 20.6-51s30.2-21 49.3-21h99.7z m-95.9 250c-7 0-12.8 3-17.2 9-4.5 6-6.7 13.7-6.7 23 0 8.7 2.2 16.2 6.7 22.5 4.5 6.2 10.2 9.5 17.2 9.5h92c7 0 12.6-3.1 16.8-9.5s6.3-13.9 6.3-22.5c0-9.4-2.1-17-6.3-23-4.1-6-9.7-9-16.8-9h-92z m95.9 313.9c7 0 12.6-3 16.8-9 4.1-6 6.3-13.4 6.3-22 0-9.4-2.1-16.8-6.3-22.5s-9.7-8.5-16.8-8.5h-95.9c-7 0-12.8 2.8-17.2 8.5-4.4 5.7-6.7 13.2-6.7 22.5 0 8.7 2.2 16 6.7 22s10.2 9 17.2 9h95.9z m0-122.9c7 0 12.6-3 16.8-9 4.1-6 6.3-13.7 6.3-23 0-9.4-2.1-17-6.3-23-4.1-6-9.7-9-16.8-9h-95.9c-7 0-12.8 3-17.2 9-4.5 6-6.7 13.7-6.7 23 0 9.4 2.2 17 6.7 23 4.5 5.9 10.2 9 17.2 9h95.9z" p-id="23164"></path></svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

1
src/icons/svg/bug.svg Normal file
View File

@ -0,0 +1 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M127.88 73.143c0 1.412-.506 2.635-1.518 3.669-1.011 1.033-2.209 1.55-3.592 1.55h-17.887c0 9.296-1.783 17.178-5.35 23.645l16.609 17.044c1.011 1.034 1.517 2.257 1.517 3.67 0 1.412-.506 2.635-1.517 3.668-.958 1.033-2.155 1.55-3.593 1.55-1.438 0-2.635-.517-3.593-1.55l-15.811-16.063a15.49 15.49 0 0 1-1.196 1.06c-.532.434-1.65 1.208-3.353 2.322a50.104 50.104 0 0 1-5.192 2.974c-1.758.87-3.94 1.658-6.546 2.364-2.607.706-5.189 1.06-7.748 1.06V47.044H58.89v73.062c-2.716 0-5.417-.367-8.106-1.102-2.688-.734-5.003-1.631-6.945-2.692a66.769 66.769 0 0 1-5.268-3.179c-1.571-1.057-2.73-1.94-3.476-2.65L33.9 109.34l-14.611 16.877c-1.066 1.14-2.344 1.711-3.833 1.711-1.277 0-2.422-.434-3.434-1.304-1.012-.978-1.557-2.187-1.635-3.627-.079-1.44.333-2.705 1.236-3.794l16.129-18.51c-3.087-6.197-4.63-13.644-4.63-22.342H5.235c-1.383 0-2.58-.517-3.592-1.55S.125 74.545.125 73.132c0-1.412.506-2.635 1.518-3.668 1.012-1.034 2.21-1.55 3.592-1.55h17.887V43.939L9.308 29.833c-1.012-1.033-1.517-2.256-1.517-3.669 0-1.412.505-2.635 1.517-3.668 1.012-1.034 2.21-1.55 3.593-1.55s2.58.516 3.593 1.55l13.813 14.106h67.396l13.814-14.106c1.012-1.034 2.21-1.55 3.592-1.55 1.384 0 2.581.516 3.593 1.55 1.012 1.033 1.518 2.256 1.518 3.668 0 1.413-.506 2.636-1.518 3.67l-13.814 14.105v23.975h17.887c1.383 0 2.58.516 3.593 1.55 1.011 1.033 1.517 2.256 1.517 3.668l-.005.01zM89.552 26.175H38.448c0-7.23 2.489-13.386 7.466-18.469C50.892 2.623 56.92.082 64 .082c7.08 0 13.108 2.541 18.086 7.624 4.977 5.083 7.466 11.24 7.466 18.469z"/></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

1
src/icons/svg/chart.svg Normal file
View File

@ -0,0 +1 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M0 54.857h36.571V128H0V54.857zM91.429 27.43H128V128H91.429V27.429zM45.714 0h36.572v128H45.714V0z"/></svg>

After

Width:  |  Height:  |  Size: 179 B

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1636791278015" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="48187" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M293.5 463.9H767c44.2 0 61.4 106 61.6 224 0.2 118-44.3 224-79.6 224H640.9c-4.1 0-6.9-4.1-5.4-7.9 5.1-13 13.7-39.6 9.9-63-5.3-32.4-16.5-58.8-16.5-58.8s8.3 23.9-25.8 68.7c-31.2 41-58.9 55.7-68.1 59.7-1.9 0.8-3.9 1.3-6 1.3H184.2c-24.3 0-44-20.2-43-44.8 0.3-7.4 2.6-14.7 6.5-21l48.7-81.2c35.5-59.1 54.2-126.8 54.2-195.7V507c-0.1-23.8 19.2-43.1 42.9-43.1z m213.7-158.1V155.1c0-23.8 19.3-43.1 43.1-43.1s43.1 19.3 43.1 43.1v150.7h160.8c23.8 0 43.1 19.3 43.1 43.1V392c0 23.8-19.3 43.1-43.1 43.1H323.5c-23.8 0-43.1-19.3-43.1-43.1v-43.1c0-23.8 19.3-43.1 43.1-43.1h183.7z" p-id="48188"></path></svg>

After

Width:  |  Height:  |  Size: 966 B

View File

@ -0,0 +1 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M54.857 118.857h64V73.143H89.143c-1.902 0-3.52-.668-4.855-2.002-1.335-1.335-2.002-2.954-2.002-4.855V36.57H54.857v82.286zM73.143 16v-4.571a2.2 2.2 0 0 0-.677-1.61 2.198 2.198 0 0 0-1.609-.676H20.571c-.621 0-1.158.225-1.609.676a2.198 2.198 0 0 0-.676 1.61V16a2.2 2.2 0 0 0 .676 1.61c.451.45.988.676 1.61.676h50.285c.622 0 1.158-.226 1.61-.677.45-.45.676-.987.676-1.609zm18.286 48h21.357L91.43 42.642V64zM128 73.143v48c0 1.902-.667 3.52-2.002 4.855-1.335 1.335-2.953 2.002-4.855 2.002H52.57c-1.901 0-3.52-.667-4.854-2.002-1.335-1.335-2.003-2.953-2.003-4.855v-11.429H6.857c-1.902 0-3.52-.667-4.855-2.002C.667 106.377 0 104.759 0 102.857v-96c0-1.902.667-3.52 2.002-4.855C3.337.667 4.955 0 6.857 0h77.714c1.902 0 3.52.667 4.855 2.002 1.335 1.335 2.003 2.953 2.003 4.855V30.29c1 .622 1.856 1.29 2.569 2.003l29.147 29.147c1.335 1.335 2.478 3.145 3.429 5.43.95 2.287 1.426 4.383 1.426 6.291v-.018z"/></svg>

After

Width:  |  Height:  |  Size: 971 B

View File

@ -0,0 +1 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h54.857v54.857H0V0zm0 73.143h54.857V128H0V73.143zm73.143 0H128V128H73.143V73.143zm27.428-18.286C115.72 54.857 128 42.577 128 27.43 128 12.28 115.72 0 100.571 0 85.423 0 73.143 12.28 73.143 27.429c0 15.148 12.28 27.428 27.428 27.428z"/></svg>

After

Width:  |  Height:  |  Size: 319 B

1
src/icons/svg/dable.svg Normal file
View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1637050800027" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="21861" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M341.312 341.312v-243.84C341.312 43.776 385.024 0 438.848 0h487.68C980.224 0 1024 43.648 1024 97.536v487.616c0 53.824-43.648 97.536-97.536 97.536h-243.84v243.84c0 53.76-43.648 97.472-97.472 97.472h-487.68A97.536 97.536 0 0 1 0 926.464V438.848c0-53.824 43.648-97.536 97.536-97.536h243.84z m0 0v243.84c0 53.824 43.712 97.536 97.536 97.536h243.84v-243.84c0-53.824-43.712-97.536-97.536-97.536h-243.84z" fill="#666666" p-id="21862"></path></svg>

After

Width:  |  Height:  |  Size: 818 B

1
src/icons/svg/danger.svg Normal file
View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1636796096311" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="136730" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M963.555556 856.888889a55.978667 55.978667 0 0 1-55.978667 56.007111c-0.284444 0-0.540444-0.085333-0.824889-0.085333l-0.056889 0.085333H110.734222l-0.654222-1.137778A55.409778 55.409778 0 0 1 56.888889 856.462222c0-9.756444 2.730667-18.773333 7.139555-26.737778l-3.726222-6.599111L453.461333 156.302222A59.335111 59.335111 0 0 1 510.236444 113.777778c26.936889 0 49.436444 18.005333 56.803556 42.552889l389.973333 661.447111-3.669333 6.997333c6.4 9.102222 10.211556 20.138667 10.211556 32.113778z m-497.777778-541.326222l16.014222 312.888889h56.888889l16.014222-312.888889h-88.917333z m44.458666 398.222222a56.888889 56.888889 0 1 0-0.028444 113.749333 56.888889 56.888889 0 0 0 0.028444-113.749333z" p-id="136731"></path></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1 @@
<svg width="128" height="100" xmlns="http://www.w3.org/2000/svg"><path d="M27.429 63.638c0-2.508-.893-4.65-2.679-6.424-1.786-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.465 2.662-1.785 1.774-2.678 3.916-2.678 6.424 0 2.508.893 4.65 2.678 6.424 1.786 1.775 3.94 2.662 6.465 2.662 2.524 0 4.678-.887 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zm13.714-31.801c0-2.508-.893-4.65-2.679-6.424-1.785-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zM71.714 65.98l7.215-27.116c.285-1.23.107-2.378-.536-3.443-.643-1.064-1.56-1.762-2.75-2.094-1.19-.33-2.333-.177-3.429.462-1.095.639-1.81 1.573-2.143 2.804l-7.214 27.116c-2.857.237-5.405 1.266-7.643 3.088-2.238 1.822-3.738 4.152-4.5 6.992-.952 3.644-.476 7.098 1.429 10.364 1.905 3.265 4.69 5.37 8.357 6.317 3.667.947 7.143.474 10.429-1.42 3.285-1.892 5.404-4.66 6.357-8.305.762-2.84.619-5.607-.429-8.305-1.047-2.697-2.762-4.85-5.143-6.46zm47.143-2.342c0-2.508-.893-4.65-2.678-6.424-1.786-1.775-3.94-2.662-6.465-2.662-2.524 0-4.678.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.786 1.775 3.94 2.662 6.464 2.662 2.524 0 4.679-.887 6.465-2.662 1.785-1.775 2.678-3.916 2.678-6.424zm-45.714-45.43c0-2.509-.893-4.65-2.679-6.425C68.68 10.01 66.524 9.122 64 9.122c-2.524 0-4.679.887-6.464 2.661-1.786 1.775-2.679 3.916-2.679 6.425 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zm32 13.629c0-2.508-.893-4.65-2.679-6.424-1.785-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zM128 63.638c0 12.351-3.357 23.78-10.071 34.286-.905 1.372-2.19 2.058-3.858 2.058H13.93c-1.667 0-2.953-.686-3.858-2.058C3.357 87.465 0 76.037 0 63.638c0-8.613 1.69-16.847 5.071-24.703C8.452 31.08 13 24.312 18.714 18.634c5.715-5.68 12.524-10.199 20.429-13.559C47.048 1.715 55.333.035 64 .035c8.667 0 16.952 1.68 24.857 5.04 7.905 3.36 14.714 7.88 20.429 13.559 5.714 5.678 10.262 12.446 13.643 20.301 3.38 7.856 5.071 16.09 5.071 24.703z"/></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1,2 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1653277811444" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2100" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); }
</style></defs><path d="M886.67 256.13H137.35c-5.2 0-9.41-4.21-9.41-9.41v-45.18c0-5.2 4.21-9.41 9.41-9.41h749.32c5.2 0 9.41 4.21 9.41 9.41v45.18c0.01 5.19-4.21 9.41-9.41 9.41zM886.67 545.22H137.35c-5.2 0-9.41-4.21-9.41-9.41v-45.18c0-5.2 4.21-9.41 9.41-9.41h749.32c5.2 0 9.41 4.21 9.41 9.41v45.18c0.01 5.2-4.21 9.41-9.41 9.41zM886.67 832.32H137.35c-5.2 0-9.41-4.21-9.41-9.41v-45.18c0-5.2 4.21-9.41 9.41-9.41h749.32c5.2 0 9.41 4.21 9.41 9.41v45.18c0.01 5.2-4.21 9.41-9.41 9.41z"></path></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,2 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1653277827707" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2248" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); }
</style></defs><path d="M405.62 480.99H106.33c-5.66 0-10.25-4.59-10.25-10.25V171.45c0-5.66 4.59-10.25 10.25-10.25h299.29c5.66 0 10.25 4.59 10.25 10.25v299.29c0.01 5.66-4.59 10.25-10.25 10.25z m-245.54-64h191.8v-191.8h-191.8v191.8zM405.62 865.25H106.33c-5.66 0-10.25-4.59-10.25-10.25V555.71c0-5.66 4.59-10.25 10.25-10.25h299.29c5.66 0 10.25 4.59 10.25 10.25V855c0.01 5.66-4.59 10.25-10.25 10.25z m-245.54-64h191.8v-191.8h-191.8v191.8zM917.85 257.24H490.27c-5.66 0-10.25-4.59-10.25-10.25V203.5c0-5.66 4.59-10.25 10.25-10.25h427.58c5.66 0 10.25 4.59 10.25 10.25v43.49c0.01 5.66-4.58 10.25-10.25 10.25zM917.85 449.08h-426.9c-5.66 0-10.25-4.59-10.25-10.25v-43.49c0-5.66 4.59-10.25 10.25-10.25h426.9c5.66 0 10.25 4.59 10.25 10.25v43.49c0.01 5.66-4.58 10.25-10.25 10.25zM917.85 641.44H490.27c-5.66 0-10.25-4.59-10.25-10.25V587.7c0-5.66 4.59-10.25 10.25-10.25h427.58c5.66 0 10.25 4.59 10.25 10.25v43.49c0.01 5.65-4.58 10.25-10.25 10.25zM917.85 833.27h-426.9c-5.66 0-10.25-4.59-10.25-10.25v-43.49c0-5.66 4.59-10.25 10.25-10.25h426.9c5.66 0 10.25 4.59 10.25 10.25v43.49c0.01 5.66-4.58 10.25-10.25 10.25z"></path></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M71.984 44.815H115.9L71.984 9.642v35.173zM16.094.05h63.875l47.906 38.37v76.74c0 3.392-1.682 6.645-4.677 9.044-2.995 2.399-7.056 3.746-11.292 3.746H16.094c-4.236 0-8.297-1.347-11.292-3.746-2.995-2.399-4.677-5.652-4.677-9.044V12.84C.125 5.742 7.23.05 16.094.05zm71.86 102.32V89.58h-71.86v12.79h71.86zm23.952-25.58V64H16.094v12.79h95.812z"/></svg>

After

Width:  |  Height:  |  Size: 418 B

1
src/icons/svg/drag.svg Normal file
View File

@ -0,0 +1 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M73.137 29.08h-9.209 29.7L63.886.093 34.373 29.08h20.49v27.035H27.238v17.948h27.625v27.133h18.274V74.063h27.41V56.115h-27.41V29.08zm-9.245 98.827l27.518-26.711H36.59l27.302 26.71zM.042 64.982l27.196 27.029V38.167L.042 64.982zm100.505-26.815V92.01l27.41-27.029-27.41-26.815z"/></svg>

After

Width:  |  Height:  |  Size: 356 B

1
src/icons/svg/edit.svg Normal file
View File

@ -0,0 +1 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M106.133 67.2a4.797 4.797 0 0 0-4.8 4.8c0 .187.014.36.027.533h-.027V118.4H9.6V26.667h50.133c2.654 0 4.8-2.147 4.8-4.8 0-2.654-2.146-4.8-4.8-4.8H9.6a9.594 9.594 0 0 0-9.6 9.6V118.4c0 5.307 4.293 9.6 9.6 9.6h91.733c5.307 0 9.6-4.293 9.6-9.6V72.533h-.026c.013-.173.026-.346.026-.533 0-2.653-2.146-4.8-4.8-4.8z"/><path d="M125.16 13.373L114.587 2.8c-3.747-3.747-9.854-3.72-13.6.027l-52.96 52.96a4.264 4.264 0 0 0-.907 1.36L33.813 88.533c-.746 1.76-.226 3.534.907 4.68 1.133 1.147 2.92 1.667 4.693.92l31.4-13.293c.507-.213.96-.52 1.36-.907l52.96-52.96c3.747-3.746 3.774-9.853.027-13.6zM66.107 72.4l-18.32 7.76 7.76-18.32L92.72 24.667l10.56 10.56L66.107 72.4zm52.226-52.227l-8.266 8.267-10.56-10.56 8.266-8.267.027-.026 10.56 10.56-.027.026z"/></svg>

After

Width:  |  Height:  |  Size: 818 B

View File

@ -0,0 +1 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M88.883 119.565c-7.284 0-19.434 2.495-21.333 8.25v.127c-4.232.13-5.222 0-7.108 0-1.895-5.76-14.045-8.256-21.333-8.256H0V0h42.523c9.179 0 17.109 5.47 21.47 13.551C68.352 5.475 76.295 0 85.478 0H128v119.57l-39.113-.005h-.004zM60.442 24.763c0-9.651-8.978-16.507-17.777-16.507H7.108V111.43H39.11c7.054-.14 18.177.082 21.333 6.12v-4.628c-.134-5.722-.004-13.522 0-13.832V27.413l.004-2.655-.004.005zm60.442-16.517h-35.55c-8.802 0-17.78 6.856-17.78 16.493v74.259c.004.32.138 8.115 0 13.813v4.627c3.155-6.022 14.279-6.26 21.333-6.114h32V8.25l-.003-.005z"/></svg>

After

Width:  |  Height:  |  Size: 627 B

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1636795297685" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="127058" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M128 64h768a32 32 0 0 1 32 32v832a32 32 0 0 1-32 32H128a32 32 0 0 1-32-32V96a32 32 0 0 1 32-32z m342.016 416L352 661.696l160 44-82.88 183.872L672 642.912l-160-26.176L605.12 480h-135.104zM864 131.84L160 131.52V384h704V131.84zM296 192h64v128h-64V192z m192 0h64v128h-64V192z m192 0h64v128h-64V192z" p-id="127059"></path></svg>

After

Width:  |  Height:  |  Size: 702 B

1
src/icons/svg/email.svg Normal file
View File

@ -0,0 +1 @@
<svg width="128" height="96" xmlns="http://www.w3.org/2000/svg"><path d="M64.125 56.975L120.188.912A12.476 12.476 0 0 0 115.5 0h-103c-1.588 0-3.113.3-4.513.838l56.138 56.137z"/><path d="M64.125 68.287l-62.3-62.3A12.42 12.42 0 0 0 0 12.5v71C0 90.4 5.6 96 12.5 96h103c6.9 0 12.5-5.6 12.5-12.5v-71a12.47 12.47 0 0 0-1.737-6.35L64.125 68.287z"/></svg>

After

Width:  |  Height:  |  Size: 347 B

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1636787671916" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="13402" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M660 375.6v417.5h-70.4v-639c0-10.6-10-18.3-20.2-15.6L172 241.7c-7.1 1.8-12.1 8.3-12.1 15.6v590.1c0 8.9 7.2 16.1 16.1 16.1h673.5c8.9 0 16.1-7.2 16.1-16.1V412.6c0-7.6-5.3-14.2-12.8-15.8l-173.3-37c-10-2.1-19.5 5.5-19.5 15.8zM506 607.8c0 8.8-7.1 15.9-15.9 15.9H277.9c-8.8 0-15.9-7.1-15.9-15.9v-38.6c0-8.8 7.1-15.9 15.9-15.9h212.2c8.8 0 15.9 7.1 15.9 15.9v38.6z m0-195.1c0 8.8-7.1 15.9-15.9 15.9H277.9c-8.8 0-15.9-7.1-15.9-15.9v-38.6c0-8.8 7.1-15.9 15.9-15.9h212.2c8.8 0 15.9 7.1 15.9 15.9v38.6z" fill="#231815" p-id="13403"></path></svg>

After

Width:  |  Height:  |  Size: 911 B

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1636792351286" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="53071" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M144.84489 0m27.459832 0l677.491251 0q27.459832 0 27.459832 27.459832l0 55.056962q0 27.459832-27.459832 27.459831l-677.491251 0q-27.459832 0-27.459832-27.459831l0-55.056962q0-27.459832 27.459832-27.459832Z" fill="#333333" p-id="53072"></path><path d="M980.493329 519.917585l-55.846432-313.19082a73.226217 73.226217 0 0 0-72.082058-60.377305H169.85622a73.226217 73.226217 0 0 0-72.150707 60.731994L43.438021 520.203625a73.226217 73.226217 0 0 0 18.398087 62.219401l395.570314 427.78985a73.409283 73.409283 0 0 0 17.299694 13.787124V581.461932a146.452435 146.452435 0 1 1 73.123243-0.102974v442.526626a73.340633 73.340633 0 0 0 17.002213-13.558292L962.060918 582.606092a73.226217 73.226217 0 0 0 18.432411-62.688507z" fill="#333333" p-id="53073"></path></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M96.258 57.462h31.421C124.794 27.323 100.426 2.956 70.287.07v31.422a32.856 32.856 0 0 1 25.971 25.97zm-38.796-25.97V.07C27.323 2.956 2.956 27.323.07 57.462h31.422a32.856 32.856 0 0 1 25.97-25.97zm12.825 64.766v31.421c30.46-2.885 54.507-27.253 57.713-57.712H96.579c-2.886 13.466-13.146 23.726-26.292 26.291zM31.492 70.287H.07c2.886 30.46 27.253 54.507 57.713 57.713V96.579c-13.466-2.886-23.726-13.146-26.291-26.292z"/></svg>

After

Width:  |  Height:  |  Size: 497 B

1
src/icons/svg/excel.svg Normal file
View File

@ -0,0 +1 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M78.208 16.576v8.384h38.72v5.376h-38.72v8.704h38.72v5.376h-38.72v8.576h38.72v5.376h-38.72v8.576h38.72v5.376h-38.72v8.576h38.72v5.376h-38.72v8.512h38.72v5.376h-38.72v11.136H128v-94.72H78.208zM0 114.368L72.128 128V0L0 13.632v100.736z"/><path d="M28.672 82.56h-11.2l14.784-23.488-14.08-22.592h11.52l8.192 14.976 8.448-14.976h11.136l-14.08 22.208L58.368 82.56H46.656l-8.768-15.68z"/></svg>

After

Width:  |  Height:  |  Size: 459 B

Some files were not shown because too many files have changed in this diff Show More