feat: fes design for vue3

This commit is contained in:
bac-joker 2020-09-30 19:08:37 +08:00
parent 7ea0e8b438
commit 560df66b33
110 changed files with 15841 additions and 4419 deletions

View File

@ -17,6 +17,9 @@ module.exports = {
'no-param-reassign': 'off',
'func-names': 'off',
'global-require': 'off',
'class-methods-use-this': 'off'
'class-methods-use-this': 'off',
'no-restricted-syntax': 'off',
'import/prefer-default-export': 'off',
'import/no-unresolved': 'off'
}
};

View File

@ -35,14 +35,6 @@ commander.command('route')
route(config);
});
commander.command('components')
.description('预编译 src/components 里面的组件')
.action(() => {
const components = require('../build/tasks/components');
const config = generateConfig('components');
components(config);
});
commander.command('dev')
.description('开发调试, 默认 local')
.action(() => {

View File

@ -1,7 +1,7 @@
const autoprefixer = require('autoprefixer');
const browsers = require('../helpers/browser');
module.exports = {
module.ex = {
plugins: [
autoprefixer({ browsers })
]

View File

@ -2,7 +2,7 @@ const path = require('path');
const fs = require('fs');
const merge = require('webpack-merge');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const { VueLoaderPlugin } = require('vue-loader');
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
const FriendlyErrorsPlugin = require('@soda/friendly-errors-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
@ -27,7 +27,7 @@ function handleGzipCompress(compress) {
module.exports = function webpackConfig(configs, webpack, mode) {
let template = path.resolve(
configs.folders.PROJECT_DIR,
'./src/index.html'
'./publish/index.html'
);
if (!fs.existsSync(template)) {
template = path.resolve(configs.folders.FES_DIR, './src/index.html');
@ -44,10 +44,10 @@ module.exports = function webpackConfig(configs, webpack, mode) {
]
];
const plugins = [
[require.resolve('@vue/babel-plugin-jsx')],
[
require.resolve('@babel/plugin-transform-runtime'), {
corejs: 3,
proposals: true
corejs: 3
}
],
require.resolve('@babel/plugin-proposal-object-rest-spread'),
@ -96,21 +96,16 @@ module.exports = function webpackConfig(configs, webpack, mode) {
entry: {
app: [
path.resolve(configs.folders.FES_DIR, './src/app.js')
path.resolve(configs.folders.PROJECT_DIR, './src/app.js')
]
},
resolve: {
extensions: ['.js', '.fes', '.vue', '.json'],
extensions: ['.js', '.jsx', '.vue', '.json'],
alias: {
projectRoot: configs.folders.PROJECT_DIR,
'@': path.resolve(configs.folders.PROJECT_DIR, 'src'),
'@@': path.resolve(configs.folders.FES_DIR, 'src'),
assets: path.resolve(
configs.folders.PROJECT_DIR,
'./src/assets/'
),
vue$: 'vue/dist/vue.esm.js'
assets: path.resolve(configs.folders.PROJECT_DIR, './src/assets/')
}
},
@ -128,7 +123,7 @@ module.exports = function webpackConfig(configs, webpack, mode) {
/* config.module.rule('vue') */
{
test: /\.vue|fes$/,
test: /\.vue$/,
use: [
{
loader: require.resolve('cache-loader'),
@ -139,10 +134,9 @@ module.exports = function webpackConfig(configs, webpack, mode) {
{
loader: require.resolve('vue-loader'),
options: {
compilerOptions: {
preserveWhitespace: false
},
cacheDirectory: path.resolve(configs.folders.PROJECT_DIR, 'node_modules/.cache/vue-loader')
shadowMode: true,
cacheDirectory: path.resolve(configs.folders.PROJECT_DIR, 'node_modules/.cache/vue-loader'),
babelParserPlugins: ['jsx', 'classProperties', 'decorators-legacy']
}
}
]
@ -288,7 +282,18 @@ module.exports = function webpackConfig(configs, webpack, mode) {
/* config.module.rule('js') */
{
test: /\.m?jsx?$/,
exclude: /(node_modules|bower_components)/,
include(filePath) {
if (filePath.startsWith(path.resolve(process.cwd(), 'src'))) {
return true;
}
if (/fes-core.?src/.test(filePath)) {
return true;
}
if (/fes-plugin-[a-z-]+.?(src|index)/.test(filePath)) {
return true;
}
return false;
},
use: [
{
loader: require.resolve('cache-loader'),
@ -324,10 +329,10 @@ module.exports = function webpackConfig(configs, webpack, mode) {
/* config.plugin('define') */
new webpack.DefinePlugin({
'process.privateFesEnv': {
env: `"${configs.env}"`
},
__VUE_OPTIONS_API__: true,
__VUE_PROD_DEVTOOLS__: false,
'process.env': {
// NODE_ENV: isDev ? 'development' : 'production',
env: JSON.stringify(configs.env),
command: JSON.stringify(configs.command)
}
@ -427,7 +432,21 @@ module.exports = function webpackConfig(configs, webpack, mode) {
baseConfig.optimization = {
minimizer: [
new TerserPlugin({
test: /\.m?js(\?.*)?$/i,
chunkFilter: () => true,
warningsFilter: () => true,
extractComments: false,
sourceMap: true,
cache: true,
cacheKeys: defaultCacheKeys => defaultCacheKeys,
parallel: true,
include: undefined,
exclude: undefined,
minify: undefined,
terserOptions: {
output: {
comments: /^\**!|@preserve|@license|@cc_on/i
},
compress: {
arrows: false,
collapse_vars: false,
@ -456,11 +475,7 @@ module.exports = function webpackConfig(configs, webpack, mode) {
mangle: {
safari10: true
}
},
sourceMap: true,
cache: true,
parallel: true,
extractComments: false
}
})
],
splitChunks: {

View File

@ -1,6 +1,5 @@
const path = require('path');
const fs = require('fs');
const log = require('./log');
function generateConfig(command, env) {
// cli目录
@ -21,10 +20,7 @@ function generateConfig(command, env) {
const config = {
command,
env,
ports: {
server: 5000,
liveReload: 35729
},
port: 5000,
projectName,
folders: {
CLI_DIR,
@ -37,28 +33,9 @@ function generateConfig(command, env) {
PROJECT_CPN_DIR
}
};
if (fs.existsSync(fesConfigFile)) {
try {
// eslint-disable-next-line
const fesCofig = require(path.join(config.folders.PROJECT_DIR, 'fes.config.js'));
config.CDN = fesCofig.env[config.env].cdn;
config.needCDN = !!config.CDN;
config.compress = fesCofig.compress;
config.lazyRouter = fesCofig.lazyRouter;
} catch (e) {
config.needCDN = false;
const fesCofig = require(fesConfigFile);
return Object.assign({}, config, fesCofig);
}
}
if (!config.needCDN) {
if (config.command === 'dev' || config.command === 'build') {
log.warn('项目没有配置cdn打包之后将不会请求cdn的地址请开发者注意');
}
}
return config;
}
module.exports = generateConfig;

View File

@ -2,7 +2,7 @@ const
http = require('http');
const webpack = require('webpack');
const express = require('express');
const opn = require('opn');
const open = require('open');
const path = require('path');
const webpackHotMiddleware = require('webpack-hot-middleware');
const webpackDevMiddleware = require('webpack-dev-middleware');
@ -43,7 +43,7 @@ module.exports = function createDevServer(port, defaultConfig) {
// 初始化Mock数据
initMock(app);
opn(`http://localhost:${port}`);
defaultConfig.open && open(`http://localhost:${port}`);
http.createServer(app).listen(port);
};

View File

@ -14,6 +14,8 @@ const log = require('../helpers/log');
const main = {
init(app, argv, cwd) {
const defaultCgiMockFile = path.join(process.cwd(), 'mock.js');
if (fs.existsSync(defaultCgiMockFile)) {
this.app = app;
this.argv = argv;
this.cwd = cwd;
@ -27,6 +29,7 @@ const main = {
app.use(cookieParser());
this.customRoute();
}
},
customRoute() {

View File

@ -1,26 +0,0 @@
// 全局注册common目录下的组件
const fs = require('fs');
const Path = require('path');
const stringUtil = require('node-plus-string');
function addComp(path, outputCommonDir, components) {
const dirList = fs.readdirSync(path);
dirList.forEach((item) => {
if (fs.statSync(`${path}/${item}`).isFile()
&& item[0] !== '.'
&& ['.fes', '.vue'].indexOf(Path.extname(item)) !== -1) {
const fileName = Path.basename(item, Path.extname(item));
const tagName = stringUtil.capitalize(fileName);
components.push({
tagName,
path: Path.resolve(outputCommonDir, item).replace(/\\/g, '\\\\')
});
}
});
}
module.exports = function genComponents(commonDir, outputCommonDir) {
const components = [];
addComp(commonDir, outputCommonDir, components);
return components;
};

View File

@ -19,7 +19,7 @@ function checkHasLayout(path) {
let hasLayout = false;
dirList.forEach((item) => {
if (fs.statSync(`${path}/${item}`).isFile()
&& item[0] !== '.' && ['.fes', '.vue'].indexOf(Path.extname(item)) !== -1
&& item[0] !== '.' && ['.vue', '.jsx'].indexOf(Path.extname(item)) !== -1
&& Path.basename(item, Path.extname(item)) === 'layout') {
hasLayout = true;
}
@ -46,7 +46,7 @@ function genRoute(path, prePathUrl, preRoutes) {
}
dirList.forEach((item) => {
if (fs.statSync(`${path}/${item}`).isFile()
&& item[0] !== '.' && ['.fes', '.vue'].indexOf(Path.extname(item)) !== -1) {
&& item[0] !== '.' && ['.jsx', '.vue'].indexOf(Path.extname(item)) !== -1) {
const fileName = Path.basename(item, Path.extname(item));
const preRouteName = path.slice(pagesDir.length + 1);
let routePath = Path.posix.join(preRouteUrl, (fileName === 'index' ? '' : fileName.replace(/@/g, ':')));

View File

@ -3,12 +3,10 @@ const log = require('../helpers/log');
const createProdConfig = require('../configs/webpack.config');
const generateRoute = require('./route');
const generateComponent = require('./components');
function startBuild(config) {
try {
generateRoute(config);
generateComponent(config);
const webpackConfig = createProdConfig(config, webpack, 'build');
webpack(webpackConfig, (err) => {
if (err) {

View File

@ -1,45 +0,0 @@
const render = require('json-templater/string');
const path = require('path');
const endOfLine = require('os').EOL;
const fs = require('fs-extra');
const getCommonComponent = require('../preComplie/components');
function generateComponent(config) {
const OUTPUT_PATH = path.resolve(config.folders.PROJECT_CACHE_DIR, 'commonComp.js');
const IMPORT_TEMPLATE = 'import {{name}} from \'{{path}}\';';
const LIST_TEMPLATE = ' {{name}}';
const MAIN_TEMPLATE = `
/**
* 全局组件配置输出
*/
{{include}}
export default {
{{list}}
};
`;
const components = getCommonComponent(config.folders.PROJECT_CPN_DIR, config.folders.PROJECT_CPN_DIR);
const componentsTemplate = [];
const listTemplate = [];
components.forEach((item) => {
componentsTemplate.push(render(IMPORT_TEMPLATE, {
name: item.tagName,
path: item.path
}));
listTemplate.push(render(LIST_TEMPLATE, {
name: item.tagName
}));
});
const template = render(MAIN_TEMPLATE, {
include: componentsTemplate.join(endOfLine),
list: listTemplate.join(`,${endOfLine}`)
});
fs.outputFileSync(OUTPUT_PATH, template);
}
module.exports = generateComponent;

View File

@ -7,8 +7,6 @@ const log = require('../helpers/log');
const createDevConfig = require('../configs/webpack.config');
const generateRoute = require('./route');
const generateComponent = require('./components');
function routeHandle(config) {
generateRoute(config);
@ -27,30 +25,12 @@ function routeHandle(config) {
});
}
function globalComponentHandle(config) {
generateComponent(config);
// 监听components变化重新生成组件注入文件
const compWatcher = chokidar.watch(path.resolve(config.folders.PROJECT_DIR, './src/components'));
compWatcher.on('ready', () => {
compWatcher.on('add', (filePath) => {
if (path.extname(filePath) === '.fes' || path.extname(filePath) === '.vue') {
generateComponent(config);
}
}).on('unlink', (filePath) => {
if (path.extname(filePath) === '.fes' || path.extname(filePath) === '.vue') {
generateComponent(config);
}
});
});
}
function startDev(config) {
routeHandle(config);
globalComponentHandle(config);
const webpackConfig = createDevConfig(config, webpack, 'dev');
if (!webpackConfig) return;
getPort(config.ports.server)
getPort(config.port)
.then((port) => {
log.message(`------------ find port success. port: ${port}`);
createDevServer(port, webpackConfig);

View File

@ -1,6 +1,5 @@
const init = require('./init.js');
const route = require('./route.js');
const components = require('./components.js');
const build = require('./build.js');
const dev = require('./dev.js');
const update = require('./update.js');
@ -8,7 +7,6 @@ const update = require('./update.js');
module.exports = {
init,
route,
components,
build,
dev,
update

View File

@ -13,9 +13,9 @@ function createProject(config, projectName) {
log.error('该项目已存在,请重新输入!');
return Promise.reject();
}
return new Promise((resolve, reject) => {
return new Promise((resolve) => {
const productDir = `${config.folders.PROJECT_DIR}/${projectName}`;
const stdout = execSync(`npm pack @webank/fes-template`, { encoding: 'utf8', stdio: [null]});
const stdout = execSync('npm pack @webank/fes-template', { encoding: 'utf8', stdio: [null] });
const filePath = path.resolve(config.folders.PROJECT_DIR, stdout.replace('\n', ''));
fs.mkdirSync(projectDir);
fs.createReadStream(filePath).pipe(

View File

@ -1,6 +1,6 @@
{
"name": "@webank/fes-cli",
"version": "0.2.3",
"version": "0.2.2",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -480,6 +480,14 @@
"@babel/helper-plugin-utils": "^7.8.0"
}
},
"@babel/plugin-syntax-jsx": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.10.4.tgz",
"integrity": "sha512-KCg9mio9jwiARCB7WAcQ7Y1q+qicILjoK8LP/VkPkEKaf5dkaZZK1EcTe91a3JJlZ3qy6L5s9X52boEYi8DM9g==",
"requires": {
"@babel/helper-plugin-utils": "^7.10.4"
}
},
"@babel/plugin-syntax-logical-assignment-operators": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz",
@ -1128,48 +1136,105 @@
}
}
},
"@vue/component-compiler-utils": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.2.0.tgz",
"integrity": "sha512-lejBLa7xAMsfiZfNp7Kv51zOzifnb29FwdnMLa96z26kXErPFioSf9BMcePVIQ6/Gc6/mC0UrPpxAWIHyae0vw==",
"@vue/babel-helper-vue-transform-on": {
"version": "1.0.0-rc.2",
"resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.0.0-rc.2.tgz",
"integrity": "sha512-1+7CwjQ0Kasml6rHoNQUmbISwqLNNfFVBUcZl6QBremUl296ZmLrVQPqJP5pyAAWjZke5bpI1hlj+LVVuT7Jcg=="
},
"@vue/babel-plugin-jsx": {
"version": "1.0.0-rc.3",
"resolved": "https://registry.npmjs.org/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.0.0-rc.3.tgz",
"integrity": "sha512-/Ibq0hoKsidnHWPhgRpjcjYhYcHpqEm2fiKVAPO88OXZNHGwaGgS4yXkC6TDEvlZep4mBDo+2S5T81wpbVh90Q==",
"requires": {
"consolidate": "^0.15.1",
"hash-sum": "^1.0.2",
"lru-cache": "^4.1.2",
"merge-source-map": "^1.1.0",
"postcss": "^7.0.14",
"postcss-selector-parser": "^6.0.2",
"prettier": "^1.18.2",
"source-map": "~0.6.1",
"vue-template-es2015-compiler": "^1.9.0"
"@babel/helper-module-imports": "^7.0.0",
"@babel/plugin-syntax-jsx": "^7.0.0",
"@babel/traverse": "^7.0.0",
"@babel/types": "^7.0.0",
"@vue/babel-helper-vue-transform-on": "^1.0.0-rc.2",
"camelcase": "^6.0.0",
"html-tags": "^3.1.0",
"svg-tags": "^1.0.0"
},
"dependencies": {
"hash-sum": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz",
"integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ="
},
"lru-cache": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
"integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
"requires": {
"pseudomap": "^1.0.2",
"yallist": "^2.1.2"
"camelcase": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.0.0.tgz",
"integrity": "sha512-8KMDF1Vz2gzOq54ONPJS65IvTUaB1cHJ2DMM7MbPmLZljDH1qpzzLsWdiN9pHh6qvkRVDTi/07+eNGch/oLU4w=="
}
}
},
"@vue/compiler-core": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.0.0.tgz",
"integrity": "sha512-XqPC7vdv4rFE77S71oCHmT1K4Ks3WE2Gi6Lr4B5wn0Idmp+NyQQBUHsCNieMDRiEpgtJrw+yOHslrsV0AfAsfQ==",
"requires": {
"@babel/parser": "^7.11.5",
"@babel/types": "^7.11.5",
"@vue/shared": "3.0.0",
"estree-walker": "^2.0.1",
"source-map": "^0.6.1"
},
"dependencies": {
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
}
}
},
"yallist": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
"@vue/compiler-dom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.0.0.tgz",
"integrity": "sha512-ukDEGOP8P7lCPyStuM3F2iD5w2QPgUu2xwCW2XNeqPjFKIlR2xMsWjy4raI/cLjN6W16GtlMFaZdK8tLj5PRog==",
"requires": {
"@vue/compiler-core": "3.0.0",
"@vue/shared": "3.0.0"
}
},
"@vue/compiler-sfc": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.0.0.tgz",
"integrity": "sha512-1Bn4L5jNRm6tlb79YwqYUGGe+Yc9PRoRSJi67NJX6icdhf84+tRMtESbx1zCLL9QixQXu2+7aLkXHxvh4RpqAA==",
"requires": {
"@babel/parser": "^7.11.5",
"@babel/types": "^7.11.5",
"@vue/compiler-core": "3.0.0",
"@vue/compiler-dom": "3.0.0",
"@vue/compiler-ssr": "3.0.0",
"@vue/shared": "3.0.0",
"consolidate": "^0.16.0",
"estree-walker": "^2.0.1",
"hash-sum": "^2.0.0",
"lru-cache": "^5.1.1",
"magic-string": "^0.25.7",
"merge-source-map": "^1.1.0",
"postcss": "^7.0.32",
"postcss-modules": "^3.2.2",
"postcss-selector-parser": "^6.0.2",
"source-map": "^0.6.1"
},
"dependencies": {
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
}
}
},
"@vue/compiler-ssr": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.0.0.tgz",
"integrity": "sha512-Er41F9ZFyKB3YnNbE6JSTIGCVWve3NAQimgDOk4uP42OnckxBYKGBTutDeFNeqUZBMu/9vRHYrxlGFC9Z5jBVQ==",
"requires": {
"@vue/compiler-dom": "3.0.0",
"@vue/shared": "3.0.0"
}
},
"@vue/shared": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.0.0.tgz",
"integrity": "sha512-4XWL/avABGxU2E2ZF1eZq3Tj7fvksCMssDZUHOykBIMmh5d+KcAnQMC5XHMhtnA0NAvktYsA2YpdsVwVmhWzvA=="
},
"@webassemblyjs/ast": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz",
@ -2692,11 +2757,11 @@
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
},
"consolidate": {
"version": "0.15.1",
"resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz",
"integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==",
"version": "0.16.0",
"resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.16.0.tgz",
"integrity": "sha512-Nhl1wzCslqXYTJVDyJCu3ODohy9OfBMB5uD2BiBTzd7w+QY0lBzafkR8y8755yMYHAaMD4NuzbAw03/xzfw+eQ==",
"requires": {
"bluebird": "^3.1.1"
"bluebird": "^3.7.2"
}
},
"constants-browserify": {
@ -3639,6 +3704,11 @@
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="
},
"estree-walker": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.1.tgz",
"integrity": "sha512-tF0hv+Yi2Ot1cwj9eYHtxC0jB9bmjacjQs6ZBTj82H8JwUywFuc+7E83NWfNMwHXZc11mjfFcVXPe9gEP4B8dg=="
},
"esutils": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
@ -4482,6 +4552,14 @@
"globule": "^1.0.0"
}
},
"generic-names": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/generic-names/-/generic-names-2.0.1.tgz",
"integrity": "sha512-kPCHWa1m9wGG/OwQpeweTwM/PYiQLrUIxXbt/P4Nic3LbGjCP0YwrALHW1uNLKZ0LIMg+RF+XRlj2ekT9ZlZAQ==",
"requires": {
"loader-utils": "^1.1.0"
}
},
"gensync": {
"version": "1.0.0-beta.1",
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz",
@ -4840,6 +4918,11 @@
}
}
},
"html-tags": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz",
"integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg=="
},
"html-webpack-plugin": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz",
@ -4966,6 +5049,11 @@
"safer-buffer": ">= 2.1.2 < 3"
}
},
"icss-replace-symbols": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz",
"integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0="
},
"icss-utils": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz",
@ -5167,6 +5255,11 @@
"resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz",
"integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE="
},
"is-docker": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz",
"integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw=="
},
"is-dotfile": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz",
@ -5614,6 +5707,11 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
},
"lodash.camelcase": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
"integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY="
},
"lodash.clonedeep": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
@ -5666,6 +5764,14 @@
}
}
},
"magic-string": {
"version": "0.25.7",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz",
"integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==",
"requires": {
"sourcemap-codec": "^1.4.4"
}
},
"make-dir": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
@ -6494,13 +6600,23 @@
"wrappy": "1"
}
},
"opn": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/opn/-/opn-4.0.2.tgz",
"integrity": "sha1-erwi5kTf9jsKltWrfyeQwPAavJU=",
"open": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/open/-/open-7.3.0.tgz",
"integrity": "sha512-mgLwQIx2F/ye9SmbrUkurZCnkoXyXyu9EbHtJZrICjVAJfyMArdHp3KkixGdZx1ZHFPNIwl0DDM1dFFqXbTLZw==",
"requires": {
"object-assign": "^4.0.1",
"pinkie-promise": "^2.0.0"
"is-docker": "^2.0.0",
"is-wsl": "^2.1.1"
},
"dependencies": {
"is-wsl": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
"integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
"requires": {
"is-docker": "^2.0.0"
}
}
}
},
"os-browserify": {
@ -7087,6 +7203,22 @@
}
}
},
"postcss-modules": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-3.2.2.tgz",
"integrity": "sha512-JQ8IAqHELxC0N6tyCg2UF40pACY5oiL6UpiqqcIFRWqgDYO8B0jnxzoQ0EOpPrWXvcpu6BSbQU/3vSiq7w8Nhw==",
"requires": {
"generic-names": "^2.0.1",
"icss-replace-symbols": "^1.1.0",
"lodash.camelcase": "^4.3.0",
"postcss": "^7.0.32",
"postcss-modules-extract-imports": "^2.0.0",
"postcss-modules-local-by-default": "^3.0.2",
"postcss-modules-scope": "^2.2.0",
"postcss-modules-values": "^3.0.0",
"string-hash": "^1.1.1"
}
},
"postcss-modules-extract-imports": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz",
@ -7369,12 +7501,6 @@
"resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
"integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks="
},
"prettier": {
"version": "1.19.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz",
"integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==",
"optional": true
},
"pretty-error": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz",
@ -8675,6 +8801,11 @@
"resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
"integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM="
},
"sourcemap-codec": {
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA=="
},
"spawn-sync": {
"version": "1.0.15",
"resolved": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz",
@ -8831,6 +8962,11 @@
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
"integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM="
},
"string-hash": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz",
"integrity": "sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs="
},
"string-replace-loader": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/string-replace-loader/-/string-replace-loader-2.3.0.tgz",
@ -9017,6 +9153,11 @@
"has-flag": "^3.0.0"
}
},
"svg-tags": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz",
"integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q="
},
"svgo": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz",
@ -9725,27 +9866,25 @@
"resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
"integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ=="
},
"vue-hot-reload-api": {
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz",
"integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog=="
},
"vue-loader": {
"version": "15.9.3",
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.9.3.tgz",
"integrity": "sha512-Y67VnGGgVLH5Voostx8JBZgPQTlDQeOVBLOEsjc2cXbCYBKexSKEpOA56x0YZofoDOTszrLnIShyOX1p9uCEHA==",
"version": "16.0.0-beta.8",
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.0.0-beta.8.tgz",
"integrity": "sha512-oouKUQWWHbSihqSD7mhymGPX1OQ4hedzAHyvm8RdyHh6m3oIvoRF+NM45i/bhNOlo8jCnuJhaSUf/6oDjv978g==",
"requires": {
"@vue/component-compiler-utils": "^3.1.0",
"hash-sum": "^1.0.2",
"loader-utils": "^1.1.0",
"vue-hot-reload-api": "^2.3.0",
"vue-style-loader": "^4.1.0"
"chalk": "^4.1.0",
"hash-sum": "^2.0.0",
"loader-utils": "^2.0.0"
},
"dependencies": {
"hash-sum": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz",
"integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ="
"loader-utils": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
"integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^2.1.2"
}
}
}
},
@ -9774,11 +9913,6 @@
"he": "^1.1.0"
}
},
"vue-template-es2015-compiler": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz",
"integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw=="
},
"watchpack": {
"version": "1.7.4",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.4.tgz",

View File

@ -1,6 +1,6 @@
{
"name": "@webank/fes-cli",
"version": "0.2.3",
"version": "0.2.2",
"description": "一个好用的前端管理台快速开发框架",
"preferGlobal": true,
"scripts": {
@ -35,6 +35,9 @@
"@babel/runtime-corejs3": "^7.11.2",
"@intervolga/optimize-cssnano-plugin": "^1.0.6",
"@soda/friendly-errors-webpack-plugin": "^1.7.1",
"@vue/babel-plugin-jsx": "^1.0.0-rc.3",
"@vue/compiler-sfc": "^3.0.0",
"@webank/fes-core": "^0.2.1",
"autoprefixer": "^8.1.0",
"babel-loader": "^8.0.6",
"body-parser": "^1.5.2",
@ -72,7 +75,7 @@
"node-sass": "^4.14.1",
"normalize-path": "^1.0.0",
"on-finished": "^2.3.0",
"opn": "^4.0.2",
"open": "^7.3.0",
"path": "^0.12.7",
"postcss": "^7.0.32",
"postcss-loader": "^4.0.1",
@ -91,7 +94,7 @@
"terser-webpack-plugin": "^2.2.1",
"thread-loader": "^2.1.3",
"url-loader": "^2.2.0",
"vue-loader": "^15.7.2",
"vue-loader": "^16.0.0-beta.8",
"vue-style-loader": "^4.1.2",
"vue-template-compiler": "^2.6.10",
"webpack": "^4.41.2",

View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2020-present webank
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,8 +0,0 @@
# fes-core
`fes-core`是框架核心对Vue的API做了一些增强。建议先阅读学习[Vue2.0](https://cn.vuejs.org/v2/guide/)。
## 安装:
npm install @webank/fes-core --save
## 文档
详细使用请查看[文档](https://webankfintech.github.io/fes.js/)

446
packages/fes-core/package-lock.json generated Normal file
View File

@ -0,0 +1,446 @@
{
"name": "@webank/fes-core",
"version": "0.2.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@babel/helper-validator-identifier": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz",
"integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw=="
},
"@babel/parser": {
"version": "7.11.5",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.5.tgz",
"integrity": "sha512-X9rD8qqm695vgmeaQ4fvz/o3+Wk4ZzQvSHkDBgpYKxpD4qTAUm88ZKtHkVqIOsYFFbIQ6wQYhC6q7pjqVK0E0Q=="
},
"@babel/runtime-corejs3": {
"version": "7.11.2",
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.11.2.tgz",
"integrity": "sha512-qh5IR+8VgFz83VBa6OkaET6uN/mJOhHONuy3m1sgF0CV6mXdPSEBdA7e1eUbVvyNtANjMbg22JUv71BaDXLY6A==",
"requires": {
"core-js-pure": "^3.0.0",
"regenerator-runtime": "^0.13.4"
}
},
"@babel/types": {
"version": "7.11.5",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.5.tgz",
"integrity": "sha512-bvM7Qz6eKnJVFIn+1LPtjlBFPVN5jNDc1XmN15vWe7Q3DPBufWWsLiIvUu7xW87uTG6QoggpIDnUgLQvPheU+Q==",
"requires": {
"@babel/helper-validator-identifier": "^7.10.4",
"lodash": "^4.17.19",
"to-fast-properties": "^2.0.0"
}
},
"@vue/compiler-core": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.0.0.tgz",
"integrity": "sha512-XqPC7vdv4rFE77S71oCHmT1K4Ks3WE2Gi6Lr4B5wn0Idmp+NyQQBUHsCNieMDRiEpgtJrw+yOHslrsV0AfAsfQ==",
"requires": {
"@babel/parser": "^7.11.5",
"@babel/types": "^7.11.5",
"@vue/shared": "3.0.0",
"estree-walker": "^2.0.1",
"source-map": "^0.6.1"
}
},
"@vue/compiler-dom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.0.0.tgz",
"integrity": "sha512-ukDEGOP8P7lCPyStuM3F2iD5w2QPgUu2xwCW2XNeqPjFKIlR2xMsWjy4raI/cLjN6W16GtlMFaZdK8tLj5PRog==",
"requires": {
"@vue/compiler-core": "3.0.0",
"@vue/shared": "3.0.0"
}
},
"@vue/compiler-sfc": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.0.0.tgz",
"integrity": "sha512-1Bn4L5jNRm6tlb79YwqYUGGe+Yc9PRoRSJi67NJX6icdhf84+tRMtESbx1zCLL9QixQXu2+7aLkXHxvh4RpqAA==",
"requires": {
"@babel/parser": "^7.11.5",
"@babel/types": "^7.11.5",
"@vue/compiler-core": "3.0.0",
"@vue/compiler-dom": "3.0.0",
"@vue/compiler-ssr": "3.0.0",
"@vue/shared": "3.0.0",
"consolidate": "^0.16.0",
"estree-walker": "^2.0.1",
"hash-sum": "^2.0.0",
"lru-cache": "^5.1.1",
"magic-string": "^0.25.7",
"merge-source-map": "^1.1.0",
"postcss": "^7.0.32",
"postcss-modules": "^3.2.2",
"postcss-selector-parser": "^6.0.2",
"source-map": "^0.6.1"
}
},
"@vue/compiler-ssr": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.0.0.tgz",
"integrity": "sha512-Er41F9ZFyKB3YnNbE6JSTIGCVWve3NAQimgDOk4uP42OnckxBYKGBTutDeFNeqUZBMu/9vRHYrxlGFC9Z5jBVQ==",
"requires": {
"@vue/compiler-dom": "3.0.0",
"@vue/shared": "3.0.0"
}
},
"@vue/reactivity": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.0.0.tgz",
"integrity": "sha512-mEGkztGQrAPZRhV7C6PorrpT3+NtuA4dY2QjMzzrW31noKhssWTajRZTwpLF39NBRrF5UU6cp9+1I0FfavMgEQ==",
"requires": {
"@vue/shared": "3.0.0"
}
},
"@vue/runtime-core": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.0.0.tgz",
"integrity": "sha512-3ABMLeA0ZbeVNLbGGLXr+pNUwqXILOqz8WCVGfDWwQb+jW114Cm8djOHVVDoqdvRETQvDf8yHSUmpKHZpQuTkA==",
"requires": {
"@vue/reactivity": "3.0.0",
"@vue/shared": "3.0.0"
}
},
"@vue/runtime-dom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.0.0.tgz",
"integrity": "sha512-f312n5w9gK6mVvkDSj6/Xnot1XjlKXzFBYybmoy6ahAVC8ExbQ+LOWti1IZM/adU8VMNdKaw7Q53Hxz3y5jX8g==",
"requires": {
"@vue/runtime-core": "3.0.0",
"@vue/shared": "3.0.0",
"csstype": "^2.6.8"
}
},
"@vue/shared": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.0.0.tgz",
"integrity": "sha512-4XWL/avABGxU2E2ZF1eZq3Tj7fvksCMssDZUHOykBIMmh5d+KcAnQMC5XHMhtnA0NAvktYsA2YpdsVwVmhWzvA=="
},
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"requires": {
"color-convert": "^1.9.0"
}
},
"big.js": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
"integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ=="
},
"bluebird": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
},
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
},
"dependencies": {
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"requires": {
"color-name": "1.1.3"
}
},
"color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
},
"consolidate": {
"version": "0.16.0",
"resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.16.0.tgz",
"integrity": "sha512-Nhl1wzCslqXYTJVDyJCu3ODohy9OfBMB5uD2BiBTzd7w+QY0lBzafkR8y8755yMYHAaMD4NuzbAw03/xzfw+eQ==",
"requires": {
"bluebird": "^3.7.2"
}
},
"core-js-pure": {
"version": "3.6.5",
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.6.5.tgz",
"integrity": "sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA=="
},
"cssesc": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="
},
"csstype": {
"version": "2.6.13",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.13.tgz",
"integrity": "sha512-ul26pfSQTZW8dcOnD2iiJssfXw0gdNVX9IJDH/X3K5DGPfj+fUYe3kB+swUY6BF3oZDxaID3AJt+9/ojSAE05A=="
},
"emojis-list": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
"integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q=="
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
},
"estree-walker": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.1.tgz",
"integrity": "sha512-tF0hv+Yi2Ot1cwj9eYHtxC0jB9bmjacjQs6ZBTj82H8JwUywFuc+7E83NWfNMwHXZc11mjfFcVXPe9gEP4B8dg=="
},
"generic-names": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/generic-names/-/generic-names-2.0.1.tgz",
"integrity": "sha512-kPCHWa1m9wGG/OwQpeweTwM/PYiQLrUIxXbt/P4Nic3LbGjCP0YwrALHW1uNLKZ0LIMg+RF+XRlj2ekT9ZlZAQ==",
"requires": {
"loader-utils": "^1.1.0"
}
},
"has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
},
"hash-sum": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz",
"integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg=="
},
"icss-replace-symbols": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz",
"integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0="
},
"icss-utils": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz",
"integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==",
"requires": {
"postcss": "^7.0.14"
}
},
"indexes-of": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz",
"integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc="
},
"json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"requires": {
"minimist": "^1.2.0"
}
},
"loader-utils": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
"integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^1.0.1"
}
},
"lodash": {
"version": "4.17.20",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
},
"lodash.camelcase": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
"integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY="
},
"lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
"requires": {
"yallist": "^3.0.2"
}
},
"magic-string": {
"version": "0.25.7",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz",
"integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==",
"requires": {
"sourcemap-codec": "^1.4.4"
}
},
"merge-source-map": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz",
"integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==",
"requires": {
"source-map": "^0.6.1"
}
},
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
},
"postcss": {
"version": "7.0.35",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz",
"integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==",
"requires": {
"chalk": "^2.4.2",
"source-map": "^0.6.1",
"supports-color": "^6.1.0"
}
},
"postcss-modules": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-3.2.2.tgz",
"integrity": "sha512-JQ8IAqHELxC0N6tyCg2UF40pACY5oiL6UpiqqcIFRWqgDYO8B0jnxzoQ0EOpPrWXvcpu6BSbQU/3vSiq7w8Nhw==",
"requires": {
"generic-names": "^2.0.1",
"icss-replace-symbols": "^1.1.0",
"lodash.camelcase": "^4.3.0",
"postcss": "^7.0.32",
"postcss-modules-extract-imports": "^2.0.0",
"postcss-modules-local-by-default": "^3.0.2",
"postcss-modules-scope": "^2.2.0",
"postcss-modules-values": "^3.0.0",
"string-hash": "^1.1.1"
}
},
"postcss-modules-extract-imports": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz",
"integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==",
"requires": {
"postcss": "^7.0.5"
}
},
"postcss-modules-local-by-default": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz",
"integrity": "sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==",
"requires": {
"icss-utils": "^4.1.1",
"postcss": "^7.0.32",
"postcss-selector-parser": "^6.0.2",
"postcss-value-parser": "^4.1.0"
}
},
"postcss-modules-scope": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz",
"integrity": "sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==",
"requires": {
"postcss": "^7.0.6",
"postcss-selector-parser": "^6.0.0"
}
},
"postcss-modules-values": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz",
"integrity": "sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==",
"requires": {
"icss-utils": "^4.0.0",
"postcss": "^7.0.6"
}
},
"postcss-selector-parser": {
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.4.tgz",
"integrity": "sha512-gjMeXBempyInaBqpp8gODmwZ52WaYsVOsfr4L4lDQ7n3ncD6mEyySiDtgzCT+NYC0mmeOLvtsF8iaEf0YT6dBw==",
"requires": {
"cssesc": "^3.0.0",
"indexes-of": "^1.0.1",
"uniq": "^1.0.1",
"util-deprecate": "^1.0.2"
}
},
"postcss-value-parser": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz",
"integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ=="
},
"regenerator-runtime": {
"version": "0.13.7",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz",
"integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew=="
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
},
"sourcemap-codec": {
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA=="
},
"string-hash": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz",
"integrity": "sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs="
},
"supports-color": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
"integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
"requires": {
"has-flag": "^3.0.0"
}
},
"to-fast-properties": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
"integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4="
},
"uniq": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",
"integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8="
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"vue": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/vue/-/vue-3.0.0.tgz",
"integrity": "sha512-ZMrAARZ32sGIaYKr7Fk2GZEBh/VhulSrGxcGBiAvbN4fhjl3tuJyNFbbbLFqGjndbLoBW66I2ECq8ICdvkKdJw==",
"requires": {
"@vue/compiler-dom": "3.0.0",
"@vue/runtime-dom": "3.0.0",
"@vue/shared": "3.0.0"
}
},
"vue-router": {
"version": "4.0.0-beta.12",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.0.0-beta.12.tgz",
"integrity": "sha512-prbqAs2hSlKGt3U/Iyq8G62q/oprwmEd//a6x5M1uqP1aZxwjq0s27ZG8hfUSOOPB7SYg4NOydwy6zi/b3S2Ww=="
},
"yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
}
}
}

View File

@ -1,10 +1,11 @@
{
"name": "@webank/fes-core",
"version": "0.2.3",
"version": "0.2.1",
"description": "一个好用的前端管理台快速开发框架",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"main": "src/index.js",
"author": "harrywan,qlin",
"repository": {
"type": "git",
@ -18,15 +19,13 @@
"easy",
"strong"
],
"dependencies": {
"axios": "^0.16.2",
"lodash": "^4.17.15",
"vue": "^2.6.10",
"vue-i18n": "^8.4.0",
"vue-router": "^2.6.0",
"vue-template-compiler": "^2.6.10"
},
"peerDependencies": {
"@webank/fes-ui": "^0.1.0"
"vue": "^3.0.0"
},
"dependencies": {
"@babel/runtime-corejs3": "^7.11.2",
"@vue/compiler-sfc": "^3.0.0",
"vue": "^3.0.0",
"vue-router": "^4.0.0-beta.12"
}
}

View File

@ -0,0 +1,3 @@
import { defineComponent } from 'vue';
export default defineComponent(() => () => (<RouterView></RouterView>));

View File

@ -1,395 +0,0 @@
/**
* 操作Api
*/
import axios from 'axios';
import util from '../util';
import env from '../env';
import storage from '../storage';
const trim = function (obj) {
Object.keys(obj).forEach((p) => {
if (util.isString(obj[p])) {
obj[p] = obj[p].trim();
} else if (util.isPlainObject(obj[p])) {
trim(obj[p]);
} else if (util.isArray(obj[p])) {
trim(obj[p]);
}
});
};
const requsetLog = {
data: storage.get('FES_AJAX_LOG') || [],
importantApi: {},
creatLog(url, data, status) {
let _data;
if (data) {
_data = JSON.stringify(data);
}
if (_data && _data.length > 1000) {
data = _data.slice(0, 1000); // 大约1K
}
const now = new Date().getTime();
const obj = {
url,
data,
timestamp: now,
status: status || 'send'
};
if (this.data.length >= 500) {
this.data.shift();
}
this.data.push(obj);
try {
storage.set('FES_AJAX_LOG', this.data);
} catch (e) {
storage.remove('FES_AJAX_LOG');
this.data = [obj];
storage.set('FES_AJAX_LOG', this.data);
}
return obj;
},
changeLogStatus(log, newStatus) {
const logs = this.data.filter(obj => obj.timestamp === log.timestamp);
if (logs.length > 0) {
logs[0].status = newStatus;
storage.set('FES_AJAX_LOG', this.data);
}
},
getLogByURL(url, data) {
return this.data.filter(obj => obj.url === url && JSON.stringify(data) === JSON.stringify(obj.data));
}
};
const instance = axios.create({
method: 'post',
baseURL: env.api,
timeout: 10000,
withCredentials: true
});
const api = {
instance,
error: {},
constructionOfResponse: {
codePath: 'code',
successCode: '0',
messagePath: 'msg',
resultPath: 'result'
}
};
const getData = function (data, resultFormat) {
const _arr = ['codePath', 'messagePath', 'resultPath'];
const arr = []; const
rst = {};
for (let i = 0; i < _arr.length; i++) {
const pathArray = resultFormat[_arr[i]].split('.');
const pathLength = pathArray.length;
let result;
if (pathLength === 1 && pathArray[0] === '*') {
result = data;
} else {
result = data[pathArray[0]];
}
for (let j = 1; j < pathLength; j++) {
result = result[pathArray[j]];
if (!result) {
if (j < pathLength - 1) {
console.error(`【FEX】ConstructionOfResponse配置错误${_arr[i]}拿到的值是undefined请检查配置`);
}
break;
}
}
arr.push(result);
}
rst.code = arr[0];
rst.message = arr[1];
rst.result = arr[2];
return rst;
};
const success = function (response) {
// 响应结构
const resultFormat = (response.config && response.config.resultFormat) || api.constructionOfResponse;
// 哪些code不处理错误
const ignoreCode = (response.config && response.config.ignoreCode) || [];
if (util.isNull(resultFormat.codePath) || util.isNull(resultFormat.successCode)
|| util.isNull(resultFormat.messagePath) || util.isNull(resultFormat.resultPath)) {
console.error('【FEX】Api配置错误: 请调用setConstructionOfResponse来设置API的响应结构');
return null;
}
let data;
if (util.isString(response.data)) {
data = JSON.parse(response.data);
} else if (util.isObject(response.data)) {
data = response.data;
} else {
throw new Error(util.format('fesMessages.defaultError'));
}
const { code, message, result } = getData(data, resultFormat);
if (code !== resultFormat.successCode) {
let _message = '';
if (api.error[code]) {
api.error[code].forEach(fn => fn(response));
} else if (!ignoreCode.includes(code) && ignoreCode !== '*') {
_message = message || util.format('fesMessages.defaultError');
}
const error = new Error(_message);
error.response = response;
throw error;
}
return result || {};
};
const fail = function (error) {
let _message = '';
const response = error.response;
if (response && api.error[response.status]) {
api.error[response.status].forEach(fn => fn(response));
} else {
_message = util.format('fesMessages.defaultError');
try {
if (response && response.data) {
let data;
if (util.isString(response.data)) {
data = JSON.parse(response.data);
} else if (util.isObject(response.data)) {
data = response.data;
}
if (data) {
const { message } = getData(data, (response.config && response.config.resultFormat) || api.constructionOfResponse);
_message = message;
}
}
} catch (e) {
// 可以啥都不做
}
}
error.message = _message;
throw error;
};
const param = function (url, data, option) {
const method = instance.defaults.method || 'post';
if (util.isNull(url)) {
return console.error('请传入URL');
} if (!util.isNull(url) && util.isNull(data) && util.isNull(option)) {
option = {
method
};
} else if (!util.isNull(url) && !util.isNull(data) && util.isNull(option)) {
option = {
method
};
if (util.isString(data)) {
option.method = data;
} else if (util.isObject(data)) {
option.data = data;
}
} else if (!util.isNull(url) && !util.isNull(data) && !util.isNull(option)) {
if (!util.isObject(data)) {
data = {};
}
if (util.isString(option)) {
option = {
method: option
};
} else if (util.isObject(option)) {
option.method = option.method || method;
} else {
option = {
method
};
}
if (option.method === 'get' || option.method === 'delete' || option.method === 'head' || option.method === 'options') {
option.params = data;
}
if (option.method === 'post' || option.method === 'put' || option.method === 'patch') {
option.data = data;
}
}
// 过滤参数中的空格
const _data = option.params || option.data;
if (_data && util.isObject(_data) && option.trim !== false) {
trim(_data);
}
option.url = url;
// 如果传了button
if (option.button) {
option.button.currentDisabled = true;
}
return instance.request(option);
};
const action = function (url, data, option) {
// 记录日志
const log = requsetLog.creatLog(url, data);
return param(url, data, option)
.then(success, fail)
.then((response) => {
requsetLog.changeLogStatus(log, 'success');
if (option && option.button) {
option.button.currentDisabled = false;
}
return response;
})
.catch((error) => {
requsetLog.changeLogStatus(log, 'fail');
if (option && option.button) {
option.button.currentDisabled = false;
}
error.message && window.Toast.error(error.message);
throw error;
});
};
api.fetch = function (url, data, option) {
if (requsetLog.importantApi[url]) {
const logs = requsetLog.getLogByURL(url, data);
if (logs.length > 0) {
const compareLog = logs[logs.length - 1];
if (compareLog.status === 'compare') {
requsetLog.creatLog(url, data, 'notAllowed');
return {
then: () => {}
};
}
const importantApiOption = requsetLog.importantApi[url];
const control = importantApiOption.control || 10000;
const message = importantApiOption.message || util.format('fesMessages.importInterfaceTip', { s: control / 1000 });
if (new Date().getTime() - compareLog.timestamp < control) {
const oldStatus = compareLog.status;
requsetLog.changeLogStatus(compareLog, 'compare');
return new Promise(((resolve, reject) => {
window.Message.confirm(util.format('fesMessages.tip'), message).then((index) => {
if (compareLog.status === 'compare') {
requsetLog.changeLogStatus(compareLog, oldStatus);
}
if (index === 0) {
resolve(action(url, data, option));
} else {
reject(new Error('不允许相同操作间隔过小'));
}
});
}));
}
return action(url, data, option);
}
return action(url, data, option);
}
return action(url, data, option);
};
/**
* 设置 request Header
* @param headers Object
*/
api.setHeader = function (headers = {}) {
Object.keys(headers).forEach((p) => {
if (['delete', 'get', 'head', 'post', 'put', 'patch', 'common'].includes(p)) {
instance.defaults.headers[p] = Object.assign({}, instance.defaults.headers[p], headers[p]);
} else {
instance.defaults.headers.common[p] = headers[p];
}
});
};
/**
* 配置ajax请求参数
* @param option
*/
api.option = function (option = {}) {
const {
root,
baseURL,
timeout,
headers,
config,
...others
} = option;
if (root || baseURL) {
instance.defaults.baseURL = root || baseURL;
}
if (timeout && util.isNumber(timeout)) {
instance.defaults.timeout = timeout;
}
if (headers) {
api.setHeader(headers);
}
const otherPropertys = Object.assign({}, others, config);
Object.keys(otherPropertys).forEach((p) => {
instance.defaults[p] = otherPropertys[p];
});
};
/**
* 请求拦截器
* @param before function 请求之前的拦截器
*/
api.setReqInterceptor = function (before, error) {
if (Array.isArray(before)) {
return instance.interceptors.request.use(...before);
}
return instance.interceptors.request.use(before, error);
};
api.ejectReqInterceptor = function (interceptor) {
return instance.interceptors.request.eject(interceptor);
};
/**
* 响应拦截器
* @param after function 响应之后的拦截器
*/
api.setResInterceptor = function (after, error) {
if (Array.isArray(after)) {
return instance.interceptors.response.use(...after);
}
return instance.interceptors.response.use(after, error);
};
api.ejectResInterceptor = function (interceptor) {
return instance.interceptors.response.eject(interceptor);
};
/**
* 配置错误响应
* @param option
*/
api.setError = function (option) {
if (option && util.isObject(option)) {
Object.keys(option).forEach((key) => {
if (!util.isArray(api.error[key])) {
api.error[key] = [];
}
api.error[key].push(option[key]);
});
}
};
/**
* 设置响应结构
* @param constructionOfResponse
*/
api.setResponse = function (constructionOfResponse) {
this.constructionOfResponse = constructionOfResponse;
};
/**
* 配置重要请求
*/
api.setImportant = function (option) {
if (option && util.isObject(option)) {
requsetLog.importantApi = option;
} else {
console.error('【FEX】ImportantApi配置错误: 参数必须是对象{"/get": { message:"xxx", control: 10000 } }');
}
};
export default api;

View File

@ -1,9 +0,0 @@
import './polyfill';
// eslint-disable-next-line
import '@webank/fes-ui/dist/styles/fes-ui.css';
import './views/styles/index.scss';
// eslint-disable-next-line
import init from 'projectRoot/src/app.js';
import App from './instance/app';
App.init(init);

View File

@ -1,61 +0,0 @@
// eslint-disable-next-line
import fesConfig from 'projectRoot/fes.config.js';
// 设置默认
if (!fesConfig.mode) {
fesConfig.mode = 'vertical';
}
if (!fesConfig.theme) {
fesConfig.theme = 'blue';
}
if (!fesConfig.env) {
fesConfig.env = {};
}
if (!fesConfig.roles) {
fesConfig.roles = {};
}
if (!fesConfig.menu) {
fesConfig.menu = [];
}
if (!fesConfig.i18n) {
fesConfig.i18n = {
locale: 'zh-cn',
messages: {
}
};
}
if (!fesConfig.i18n.locale) {
fesConfig.i18n.locale = 'zh-cn';
}
if (!fesConfig.i18n.messages) {
fesConfig.i18n.messages = {};
}
if (!fesConfig.i18n.messages['zh-cn']) {
fesConfig.i18n.messages['zh-cn'] = {};
}
if (!fesConfig.i18n.messages.en) {
fesConfig.i18n.messages.en = {};
}
Object.assign(fesConfig.i18n.messages['zh-cn'], {
fesMessages: {
defaultError: '后台接口异常,请联系开发处理!',
importInterfaceTip: '两个相同请求间隔小于 {s} 秒,是否继续?',
tip: '提示',
noPermission: '您没有访问当前路径的权限'
}
});
Object.assign(fesConfig.i18n.messages.en, {
fesMessages: {
defaultError: 'Server-end API error, please contact the admin.',
importInterfaceTip: 'Repetitive request in {s} seconds, continue anyway?',
tip: 'Tips',
noPermission: 'You dont have the authority to access.'
}
});
export default fesConfig;

View File

@ -1,22 +0,0 @@
// TODO runtime 实例和具体功能解耦
/*eslint-disable */
import app from '../instance/app';
/**
* 常用的指令
*/
export const permission = {
bind(el, binding) {
const dispaly = el.style.display;
const setDispaly = () => {
const urls = app.getAllowPage() || [];
if (urls.indexOf(binding.value) === -1) {
el.style.display = 'none';
} else {
el.style.display = dispaly;
}
};
setDispaly();
app.FesUtil.event.on('fes_allowPage_change', setDispaly);
}
};

View File

@ -1,3 +0,0 @@
import fesConfig from '../config';
export default fesConfig.env[process.privateFesEnv.env] || {};

View File

@ -1,4 +0,0 @@
import FesxClass from './fesx';
const insideName = `inside_${window.location.pathname.replace(/\//g, '_')}`;
export default new FesxClass(insideName);

View File

@ -1,56 +0,0 @@
/**
* 全局状态管理
*/
import Vue from 'vue';
import storage from '../storage';
import util from '../util';
class Fesx {
constructor(name) {
Object.defineProperty(this, 'name', {
value: name,
enumerable: false
});
Object.defineProperty(this, 'pre', {
value: `FesFesx_${this.name}_`,
enumerable: false
});
const keys = Object.keys(sessionStorage);
const len = keys.length;
for (let i = 0; i < len; i++) {
const key = keys[i];
if (key.indexOf(this.pre) === 0) {
Vue.set(this, key.slice(this.pre.length), storage.get(key));
}
}
}
get(prop) {
if (!this[prop]) {
this.set(prop, storage.get(this.pre + prop));
}
return this[prop];
}
set(prop, value) {
Vue.set(this, prop, value);
if (!util.isFunction(value)) {
storage.set(this.pre + prop, value);
}
return this;
}
clear() {
const keys = Object.keys(sessionStorage);
const len = keys.length;
for (let i = 0; i < len; i++) {
const key = keys[i];
if (key.indexOf(this.pre) === 0) {
storage.remove(key);
Vue.set(this, key.slice(this.pre.length), undefined);
}
}
}
}
export default Fesx;

View File

@ -1,9 +0,0 @@
/**
* 全局状态管理
*/
import Fesx from './fesx';
const collection = new Fesx('outside');
export default collection;

View File

@ -1,154 +0,0 @@
/**
* 常用的过滤器
*/
import util from '../util';
/**
* 日期格式化
* @param _date
* @param format
* @returns {*}
*/
export function date(timestap, format) {
if (!timestap) return '';
format = format || 'yyyy-MM-dd hh:mm:ss';
timestap = Number(timestap);
const time = new Date(timestap);
const obj = {
'y+': time.getFullYear(),
'M+': time.getMonth() + 1,
'd+': time.getDate(),
'h+': time.getHours(),
'm+': time.getMinutes(),
's+': time.getSeconds()
};
if (new RegExp('(y+)').test(format)) {
format = format.replace(RegExp.$1, obj['y+']);
}
Object.keys(obj).forEach((j) => {
if (new RegExp(`(${j})`).test(format)) {
format = format.replace(RegExp.$1, (RegExp.$1.length === 1) ? (obj[j]) : ((`00${obj[j]}`).substr((`${obj[j]}`).length)));
}
});
return format;
}
/**
* 资金格式化插件
* @param value
* @returns {string|*}
*/
export function money(value) {
const m = [];
value = Number(value).toFixed(2);
// 获取小数部分
const decimals = value.match(/\.[0-9]*/g);
// 获取整数部分
const integer = parseInt(value, 10).toString();
const temp = integer.split('');
const length = temp.length;
// 添加","分隔符
function formart() {
let count = 0;
for (let n = length; n > 0; n--, count++) {
if (count && count % 3 === 0) {
m.unshift(',');
count = 0;
}
m.unshift(temp.pop());
}
const result = m.join('');
return decimals ? result.concat(decimals) : result;
}
return length > 3 ? formart() : value;
}
/**
* 银行卡四位加一空格
* @param value
* @returns {*}
*/
export function card(value) {
value = `${value}`;
const reg = /([0-9]{4})/g;
if (value) {
value = value.replace(reg, '$1 ');
}
return value;
}
/**
* 给字符串中间加***
* @param value
* @param frontLen
* @param backLen
* @returns {*}
*/
export function safety(value, frontLen, backLen) {
if (value) {
const len = value.length;
let front = '';
let back = '';
if (frontLen && len > frontLen) {
front = value.slice(0, frontLen);
}
if (backLen && len > (frontLen + backLen)) {
back = value.slice(len - backLen);
}
return `${front}***${back}`;
}
return '';
}
/**
* 把数据字典中的值转换成text
* @param value
* @param arr
* @returns {string}
*/
export function map(value, arr) {
let name = '';
if (arr && util.isArray(arr)) {
arr.forEach((item) => {
if (item.value === value) {
name = item.text;
}
});
}
return name;
}
/**
* 过滤掉数据中的值
* @param value
* @param arr
* @returns {string}
*/
export function allow(value, arr) {
const _arr = [];
if (util.isArray(value)) {
value.forEach((obj) => {
if (util.isArray(arr)) {
if (arr.indexOf(obj.value) !== -1) {
_arr.push(obj);
}
}
});
}
return _arr;
}
export function capitalize(text) {
return text[0].toUpperCase() + text.slice(1);
}
export function uppercase(text) {
return text.toUpperCase();
}
export function lowercase(text) {
return text.toLowerCase();
}

View File

@ -0,0 +1,4 @@
const hasSymbol = typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol';
/** @internal */
export const makeSymbol = name => (hasSymbol ? Symbol(name) : name);

View File

@ -11,6 +11,7 @@
<meta http-equiv="expires" content="0">
</head>
<body>
<div id="app"></div>
<div id="app">
</div>
</body>
</html>

View File

@ -0,0 +1,58 @@
import {
createApp,
inject,
reactive
} from 'vue';
import createRouter from './router';
import DefaultLayout from './DefaultLayout';
import { makeSymbol } from './helpers';
const __FES_PLUGIN_DATA_SYMBOL__ = makeSymbol('fes-plugin-data');
// const __FES_PLUGIN_METHOD_SYMBOL__ = makeSymbol('fes-plugin-method');
// 写入这里的方法和函数,将会通过 useFesContext 导出
// 用于共享 plugins 之间的数据和方法
const fesContext = {
layout: DefaultLayout
};
const plugins = [];
export function addPlugin(plugin, options) {
if (typeof plugin === 'function') {
plugins.push([{
install: plugin
}, options]);
} else {
// TODO 非 plugin 校验
plugins.push(plugin, options);
}
}
const _installPlugins = (app) => {
for (const plugin of plugins) {
const [pluginInstance, options] = plugin;
pluginInstance.install(app, options, fesContext);
}
};
export function useFesContext() {
return inject(__FES_PLUGIN_DATA_SYMBOL__);
}
export async function createFesApp(options = {}) {
Object.assign(fesContext, options);
const router = await createRouter(fesContext);
// TODO dependencies plugin 实现
const app = createApp(fesContext.layout);
app.use(router);
fesContext.router = router;
_installPlugins(app);
app.provide(__FES_PLUGIN_DATA_SYMBOL__, reactive(fesContext));
app.mount('#app');
return app;
}

View File

@ -1,325 +0,0 @@
import Vue from 'vue';
import VueRouter from 'vue-router';
import VueI18n from 'vue-i18n';
// eslint-disable-next-line
import UiWebank from '@webank/fes-ui';
// eslint-disable-next-line
import routerConfig from 'projectRoot/.cache/routeConfig.js';
// eslint-disable-next-line
import commonCompConfig from 'projectRoot/.cache/commonComp.js';
import Page from './page';
import fesComponents from '../views/components';
import root from '../views/layout/root.vue';
import * as filters from '../filter';
// eslint-disable-next-line
import * as directives from '../directive';
import util from '../util';
import _fesx from '../fesx/_fesx';
import storage from '../storage';
import api from '../api';
import map from '../map';
import fesx from '../fesx';
import fesConfig from '../config';
import env from '../env';
import permission from './permission';
if (process.privateFesEnv.env !== 'prod') {
Vue.config.debug = true;
Vue.config.devtools = true;
}
const rolesConfig = fesConfig.roles;
class App {
constructor() {
this.FesApp = this;
this.FesApi = api;
this.FesStorage = storage;
this.FesMap = map;
this.FesFesx = fesx;
this.FesUtil = util;
this.FesEnv = env;
// 允许的路由
// 默认可以访问所有路由第一次addAllowPage的时候需要删除'*'
this._roleId = _fesx.get('FesRoleId');
if (this._roleId) {
permission.set(rolesConfig[this._roleId] || ['*']);
} else {
permission.set(_fesx.get('FesAllowPageList') || ['*']);
}
this.router = null;
this.beforeRouter = null;
this.afterRouter = null;
this.i18n = null;
}
init(func) {
window.Vue = Vue;
// ======================安装插件====================
Vue.use(VueRouter);
Vue.use(UiWebank);
Vue.use(VueI18n);
Vue.use(fesComponents);
Vue.use(Page, this);
// =====================注册全局过滤器================
Object.keys(filters).forEach((p) => {
Vue.filter(p, filters[p]);
});
// =====================注册全局组件==================
Object.keys(commonCompConfig).forEach((p) => {
Vue.component(p, commonCompConfig[p]);
});
// =====================注册全局指令==================
Object.keys(directives).forEach((p) => {
Vue.directive(p, directives[p]);
});
// 设置系统名称
if (fesConfig.fesName) {
this.set('FesName', fesConfig.fesName);
}
// 设置系统名称
if (fesConfig.favicon) {
this.setFavicon(fesConfig.favicon);
}
if (util.isFunction(func)) {
func.call(this);
}
this.run();
}
run() {
this.creatRouter();
this.creatI18n();
// eslint-disable-next-line
new Vue({
el: '#app',
extends: root,
router: this.router,
i18n: this.i18n
});
}
creatI18n() {
this.i18n = new VueI18n(fesConfig.i18n);
this.setLocale(fesConfig.i18n.locale);
}
creatRouter() {
this.router = new VueRouter({
routes: routerConfig,
scrollBehavior(to, from, savedPosition) {
if (savedPosition) {
return savedPosition;
}
return {
x: 0,
y: 0
};
}
});
this.handleRouter();
}
handleRouter() {
this.router.beforeEach(async (to, from, next) => {
util.history.record(to.path);
let path;
if (to.matched.length === 1) {
path = to.matched[0].path;
} else {
path = to.path;
}
// 只有允许的路由才能进
const canRoute = await permission.match(path);
if (canRoute) {
if (this.beforeRouter && util.isFunction(this.beforeRouter)) {
this.beforeRouter(to, from, next);
} else {
next();
}
} else {
window.Toast.error(util.format('fesMessages.noPermission'));
if (from.path) {
next(false);
} else {
next('/');
}
}
});
this.router.afterEach((route) => {
// 更新页面的title
let title;
fesConfig.menu.forEach((parent) => {
if (parent.path === route.path) {
title = parent.title;
} else if (parent.subMenu && parent.subMenu.length > 0) {
parent.subMenu.forEach((son) => {
if (son.path === route.path) {
title = son.title;
}
});
}
});
// 设置切换路由时页面的标题
let fesName = this.get('FesName');
if (fesName.slice(0, 6) === '$i18n.') {
fesName = util.format(fesName.slice(6));
}
document.title = title ? `${fesName} | ${title}` : fesName;
if (this.afterRouter && util.isFunction(this.afterRouter)) {
this.afterRouter(route);
}
});
this.setDefaultPage();
}
async getDefaultPage(update) {
// 如果router已初始化通过当前链接来找路由返回当前链接对应的路由
if (this.router && !update) {
const currentPath = this.router.history.getCurrentLocation();
const isMatchCurrentPath = await permission.match(currentPath);
if (isMatchCurrentPath) {
return currentPath;
}
}
// 返回权限列表第一个 > 路由表第一个
const allAllowedRoute = await permission.get();
return allAllowedRoute.length > 0 ? allAllowedRoute[0] : routerConfig[0];
}
async setDefaultPage() {
const defaultPage = await this.getDefaultPage(false);
this.router.push(defaultPage);
}
async setRole(roleId, redirect = true, update = true) {
if (_fesx.get('FesRoleId') !== roleId) {
if (rolesConfig[roleId] instanceof Array) {
permission.set(rolesConfig[roleId]);
this.set('FesRoleId', roleId);
if (this.router && redirect) {
const defaultPage = await this.getDefaultPage(update);
this.router.push(defaultPage);
}
util.event.trigger('fes_allowPage_change');
} else {
console.error(`rolesConfig配置错误不存在角色${roleId}`);
}
}
return this;
}
async setAllowPage(pageList, redirect = true, update = true) {
if (pageList instanceof Array) {
permission.set(pageList);
this.set('FesRoleId', ''); // 通过角色控制权限和通过路由控制权限互斥,只能使用一种
this.set('FesAllowPageList', pageList);
if (this.router && redirect) {
const defaultPage = await this.getDefaultPage(update);
this.router.push(defaultPage);
}
util.event.trigger('fes_allowPage_change');
}
return this;
}
// 废弃 API
getAllowPage() {
// 异步的这里会造成 break;
return permission.getSync();
}
getAllowPageAsync() {
return permission.get();
}
get(prop) {
return _fesx.get(prop);
}
set(prop, value) {
_fesx.set(prop, value);
return this;
}
// 添加过滤器
addFilter(name, func) {
Vue.filter(name, func);
return this;
}
// 添加指令
addDirective(name, option) {
Vue.directive(name, option);
return this;
}
// 添加组件
addComponent(name, c) {
Vue.component(name, c);
return this;
}
// 第三方插件
addThrid(name, option) {
Vue.use(name, option);
return this;
}
setBeforeRouter(beforeRouter) {
this.beforeRouter = beforeRouter;
return this;
}
setAfterRouter(afterRouter) {
this.afterRouter = afterRouter;
return this;
}
// 添加favicon
setFavicon(url) {
let favicon = document.querySelector('#favicon');
if (!favicon) {
favicon = document.createElement('link');
favicon.id = 'favicon';
favicon.rel = 'shortcut icon';
favicon.type = 'image/png';
favicon.href = url;
document.head.appendChild(favicon);
} else {
favicon.href = url;
}
return this;
}
setLocale(lang) {
// 修改vue-i18n的语言
this.i18n.locale = lang;
// 修改组件库的语言
UiWebank.i18n.setLocale(lang);
return this;
}
}
util.merge(App.prototype, util.event);
// 暂时去掉package.json引入安全检测不通过
// App.prototype.version = packageConfig.version;
App.prototype.engine = 'Vue';
export default new App();

View File

@ -1,136 +0,0 @@
import util from '../util';
import storage from '../storage';
import api from '../api';
import map from '../map';
import fesx from '../fesx';
import env from '../env';
import fesConfig from '../config';
const fesDataCache = {};
const certainConfig = function (matchPages, prop, n = 1) {
const length = matchPages.length;
if (n > length) {
return matchPages[0].components.default[prop];
}
const matchPage = matchPages[length - n].components.default;
if (typeof matchPage[prop] === 'boolean') {
return matchPage[prop];
}
return certainConfig(matchPages, prop, n + 1);
};
const Page = {
install(Vue, App) {
Vue.mixin({
data() {
const data = {
FesMap: map,
FesFesx: fesx
};
// 如果存在页面缓存
const cacheName = this.$options.FesDataCache;
if (cacheName && fesDataCache[cacheName] && util.history.current.type !== 'forward') {
return fesDataCache[cacheName];
}
if (this.$options.FesSyncData) {
Object.keys(this.$options.FesSyncData).forEach((p) => {
data[p] = null;
});
}
let fesData;
if (util.isFunction(this.$options.FesData)) {
this.FesFesx = fesx;
this.FesMap = map;
fesData = this.$options.FesData.call(this);
} else {
// 直接等于是对象的引用会导致下次进入页面FesData的值没变
fesData = this.$options.FesData;
}
if (fesData) {
Object.keys(fesData).forEach((p) => {
data[p] = fesData[p];
});
}
return data;
},
created() {
const defaultHeader = fesConfig.FesHeader === undefined ? false : fesConfig.FesHeader;
const defaultLeft = fesConfig.FesLeft === undefined ? true : fesConfig.FesLeft;
// route切换时重新设置为初始值
const comp = (this.$route && this.$route.matched) || [];
if (comp.length > 0) {
const matchPage = comp[comp.length - 1].components.default;
if (this.$options.__file === matchPage.__file) {
const header = certainConfig(comp, 'FesHeader');
if (typeof header === 'boolean') {
this.$root.header = header;
} else {
this.$root.header = defaultHeader;
}
const left = certainConfig(comp, 'FesLeft');
if (typeof left === 'boolean') {
this.$root.left = left;
} else {
this.$root.left = defaultLeft;
}
}
}
const syncData = this.$options.FesSyncData;
if (syncData) {
const arr = [];
Object.keys(syncData).forEach((p) => {
if (util.isArray(syncData[p])) {
arr.push([p, syncData[p][0], syncData[p][1]]);
} else {
console.error(`【FEX】异步参数【${p}】配置错误:值不是数组`, syncData[p]);
}
});
const requests = [];
for (let i = 0; i < arr.length; i++) {
requests.push(api.fetch(arr[i][1], util.merge({}, this.$route.params, this.$route.query, arr[i][2])));
}
Promise.all(requests).then((values) => {
values.forEach((value, index) => {
this[arr[index][0]] = value;
});
});
}
if (this.$options.FesCreated && util.isFunction(this.$options.FesCreated)) {
this.$options.FesCreated.call(this);
}
},
mounted() {
if (this.$options.FesReady && util.isFunction(this.$options.FesReady)) {
this.$options.FesReady.call(this);
}
},
beforeDestroy() {
const cacheName = this.$options.FesDataCache;
if (cacheName) {
fesDataCache[cacheName] = this.$data;
}
if (this.$options.FesBeforeDestroy && util.isFunction(this.$options.FesBeforeDestroy)) {
this.$options.FesBeforeDestroy.call(this);
}
},
destroyed() {
if (this.$options.FesDestroy && util.isFunction(this.$options.FesDestroy)) {
this.$options.FesDestroy.call(this);
}
}
});
// 注入自己的对象
Vue.prototype.FesApp = App;
Vue.prototype.FesUtil = util;
Vue.prototype.FesStorage = storage;
Vue.prototype.FesApi = api;
Vue.prototype.FesEnv = env;
}
};
export default Page;

View File

@ -1,34 +0,0 @@
/**
* 用户路由控制
*/
import util from '../util';
const permission = {
allowRoutesSync: [], // 兼容老的 API 请勿使用
allowRoutes: [],
format(allowRoutes) {
if (Array.isArray(allowRoutes)) {
return allowRoutes.map(allow => Promise.resolve(allow));
}
return [Promise.resolve(allowRoutes)];
},
set(data) {
this.allowRoutesSync = data;
this.allowRoutes = this.format(data);
},
getSync() {
return this.allowRoutesSync;
},
get() {
return Promise.all(this.allowRoutes).then(data => data.reduce((merge, cur) => merge.concat(cur), []));
},
merge(data) {
this.allowRoutes = this.allowRoutes.concat(this.format(data));
},
async match(path) {
const mergedAllowRoutes = await this.get();
return util.canRoute(path, mergedAllowRoutes);
}
};
export default permission;

View File

@ -1,42 +0,0 @@
/**
* 数据字典管理
*/
import util from '../util';
import fesConfig from '../config';
const data = fesConfig.map;
const $Map = Object.create({
getValueByName(name, text) {
// TODO 不确定这里是否需要 ===
// eslint-disable-next-line
const arr = this[name].filter(item => item.text == text);
return arr[0] ? arr[0].value : '';
},
getNameByValue(name, value) {
// TODO 不确定这里是否需要 ===
// eslint-disable-next-line
const arr = this[name].filter(item => item.value == value);
return arr[0] ? arr[0].text : '';
}
});
Object.keys(data).forEach((name) => {
$Map[name] = [];
if (util.isArray(data[name])) {
data[name].forEach((item) => {
if (item.length >= 2) {
$Map[name].push({
value: item[0],
text: item[1]
});
} else {
console.error(`【FEX】Map配置错误Name${name}的值必输是数组,类似['1', '成功']`, item);
}
});
} else {
console.error('【FEX】Map配置错误后面的值必须是数组', data[name]);
}
});
export default $Map;

View File

@ -1,48 +0,0 @@
/* eslint-disable */
class File {
toString() {
console.log('compatible File');
return 'function File() { [native code] }';
}
}
if (window.File === undefined) {
window.File = File;
}
// el remove
(function (arr) {
arr.forEach((item) => {
if (item.hasOwnProperty('remove')) {
return;
}
Object.defineProperty(item, 'remove', {
configurable: true,
enumerable: true,
writable: true,
value: function remove() {
if (this.parentNode !== null) this.parentNode.removeChild(this);
}
});
});
}([Element.prototype, CharacterData.prototype, DocumentType.prototype]));
// Function.bind
if (!Function.prototype.bind) {
Function.prototype.bind = function (oThis) {
if (typeof this !== 'function') {
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
}
const aArgs = Array.prototype.slice.call(arguments, 1);
const fToBind = this;
const fNOP = function () {};
const fBound = function () {
return fToBind.apply(this instanceof fNOP && oThis ? this : oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}

View File

@ -0,0 +1,14 @@
import { createRouter, createWebHashHistory } from 'vue-router';
export default async (options) => {
let routes = options.routes;
if (!routes) {
const automaticRoutes = await import('projectRoot/.cache/routeConfig.js');
routes = automaticRoutes.default;
}
return createRouter({
history: createWebHashHistory(),
routes
});
};

View File

@ -1,183 +0,0 @@
/* \
|*|
|*| :: cookies.js ::
|*|
|*| A complete cookies reader/writer framework with full unicode support.
|*|
|*| https://developer.mozilla.org/en-US/docs/DOM/document.cookie
|*|
|*| This framework is released under the GNU Public License, version 3 or later.
|*| http://www.gnu.org/licenses/gpl-3.0-standalone.html
|*|
|*| Syntaxes:
|*|
|*| * docCookies.setItem(name, value[, end[, path[, domain[, secure]]]])
|*| * docCookies.getItem(name)
|*| * docCookies.removeItem(name[, path], domain)
|*| * docCookies.hasItem(name)
|*| * docCookies.keys()
|*|
\ */
const docCookies = {
getItem(sKey) {
return decodeURIComponent(document.cookie.replace(new RegExp(`(?:(?:^|.*;)\\s*${encodeURIComponent(sKey).replace(/[-.+*]/g, '\\$&')}\\s*\\=\\s*([^;]*).*$)|^.*$`), '$1')) || null;
},
setItem(sKey, sValue, vEnd, sPath, sDomain, bSecure) {
if (!sKey || /^(?:expires|max-age|path|domain|secure)$/i.test(sKey)) {
return false;
}
let sExpires = '';
if (vEnd) {
switch (vEnd.constructor) {
case Number:
sExpires = vEnd === Infinity ? '; expires=Fri, 31 Dec 9999 23:59:59 GMT' : `; max-age=${vEnd}`;
break;
case String:
sExpires = `; expires=${vEnd}`;
break;
case Date:
sExpires = `; expires=${vEnd.toUTCString()}`;
break;
default: break;
}
}
document.cookie = `${encodeURIComponent(sKey)}=${encodeURIComponent(sValue)}${sExpires}${sDomain ? `; domain=${sDomain}` : ''}${sPath ? `; path=${sPath}` : ''}${bSecure ? '; secure' : ''}`;
return true;
},
removeItem(sKey, sPath, sDomain) {
if (!sKey || !this.hasItem(sKey)) {
return false;
}
document.cookie = `${encodeURIComponent(sKey)}=; expires=Thu, 01 Jan 1970 00:00:00 GMT${sDomain ? `; domain=${sDomain}` : ''}${sPath ? `; path=${sPath}` : ''}`;
return true;
},
hasItem(sKey) {
return (new RegExp(`(?:^|;\\s*)${encodeURIComponent(sKey).replace(/[-.+*]/g, '\\$&')}\\s*\\=`)).test(document.cookie);
},
// eslint-disable-next-line
keys: /* optional method: you can safely remove it! */ function () {
const aKeys = document.cookie.replace(/((?:^|\s*;)[^=]+)(?=;|$)|^\s*|\s*(?:=[^;]*)?(?:\1|$)/g, '').split(/\s*(?:=[^;]*)?;\s*/);
for (let nIdx = 0; nIdx < aKeys.length; nIdx++) {
aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]);
}
return aKeys;
}
};
const isProd = process.env.NODE_ENV === 'production';
export const storageManager = {
set(key, value, storage) {
try {
window[storage].setItem(key, JSON.stringify(value));
} catch (e) {
!isProd && console.error(e);
}
},
get(key, storage) {
try {
if (window[storage].getItem(key)) {
return JSON.parse(window[storage].getItem(key));
}
return window[storage].getItem(key);
} catch (e) {
!isProd && console.error(e, key);
return null;
}
},
clear(storage) {
window[storage].clear();
},
remove(key, storage) {
window[storage].removeItem(key);
}
};
export const cookieManager = {
set(key, value, expired) {
if (expired) docCookies.setItem(key, value, expired);
else docCookies.setItem(key, value);
},
get(key) {
return docCookies.getItem(key);
},
clear() {
docCookies.keys().forEach((key) => {
docCookies.removeItem(key);
});
},
remove(key) {
docCookies.removeItem(key);
}
};
/**
* 操作cookiesessionStoragelocalStorage缓存
*/
const
SESSION = 'session';
const LOCAL = 'local';
const COOKIE = 'cookie';
export default {
set(key, value, category = SESSION, expired) {
const { storage, isWebStorage = true } = this._map(category);
if (isWebStorage) {
storageManager.set(key, value, storage);
} else {
cookieManager.set(key, value, expired);
}
},
get(key, category = SESSION) {
const { storage, isWebStorage = true } = this._map(category);
if (isWebStorage) {
return storageManager.get(key, storage);
}
return cookieManager.get(key);
},
clear(category = SESSION) {
const { storage, isWebStorage = true } = this._map(category);
if (isWebStorage) {
storageManager.clear(storage);
} else {
cookieManager.clear();
}
},
remove(key, category = SESSION) {
const { storage, isWebStorage = true } = this._map(category);
if (isWebStorage) {
storageManager.remove(key, storage);
} else {
cookieManager.remove(key);
}
},
_map(category) {
let isWebStorage = true; let
storage;
switch (true) {
case category === SESSION:
storage = 'sessionStorage';
break;
case category === LOCAL:
storage = 'localStorage';
break;
case category === COOKIE:
storage = 'cookie';
isWebStorage = false;
break;
default:
storage = 'sessionStorage';
}
return { isWebStorage, storage };
}
};

View File

@ -1,106 +0,0 @@
const inBrowser = typeof window !== 'undefined'
&& Object.prototype.toString.call(window) !== '[object Object]';
export const UA = inBrowser && window.navigator.userAgent.toLowerCase();
export const isIE = UA && UA.indexOf('trident') > 0;
export const isIE9 = UA && UA.indexOf('msie 9.0') > 0;
/**
* For IE9 compat: when both class and :class are present
* getAttribute('class') returns wrong value...
*
* @param {Element} el
* @return {String}
*/
export function getClass(el) {
let classname = el.className;
if (typeof classname === 'object') {
classname = classname.baseVal || '';
}
return classname;
}
/**
* 判断dom节点是否有某样式
*
* @param {Element} el
* @return {String}
* @returns {boolean}
*/
export function hasClass(el, name) {
if (!el) return null;
const className = getClass(el);
const classes = className.split(' ');
return classes.indexOf(name) !== -1;
}
/**
* In IE9, setAttribute('class') will result in empty class
* if the element also has the :class attribute; However in
* PhantomJS, setting `className` does not work on SVG elements...
* So we have to do a conditional check here.
*
* @param {Element} el
* @param {String} cls
*/
export function setClass(el, cls) {
/* istanbul ignore if */
if (isIE9 && !/svg$/.test(el.namespaceURI)) {
el.className = cls;
} else {
el.setAttribute('class', cls);
}
}
/**
* Add class with compatibility for IE & SVG
*
* @param {Element} el
* @param {String} cls
*/
export function addClass(el, cls) {
if (el.classList) {
el.classList.add(cls);
} else {
const cur = ` ${getClass(el)} `;
if (cur.indexOf(` ${cls} `) < 0) {
setClass(el, (cur + cls).trim());
}
}
}
/**
* Remove class with compatibility for IE & SVG
*
* @param {Element} el
* @param {String} cls
*/
export function removeClass(el, cls) {
if (el.classList) {
el.classList.remove(cls);
} else {
let cur = ` ${getClass(el)} `;
const tar = ` ${cls} `;
while (cur.indexOf(tar) >= 0) {
cur = cur.replace(tar, ' ');
}
setClass(el, cur.trim());
}
if (!el.className) {
el.removeAttribute('class');
}
}
/**
* 从jquery扣过来的递归去算
*
* @param {Element} a
* @param {Element} b
* @returns {boolean}
*/
export function contains(a, b) {
const adown = a.nodeType === 9 ? a.documentElement : a;
const bup = b && b.parentNode;
return a === bup || !!(bup && bup.nodeType === 1 && adown.contains(bup));
}

View File

@ -1,51 +0,0 @@
const eventProxy = {
onObj: {},
oneObj: {},
on(key, fn) {
if (fn && typeof (fn) === 'function') {
if (this.onObj[key] === undefined) {
this.onObj[key] = [];
}
this.onObj[key].push(fn);
} else {
throw new Error('请传入正确的回调函数');
}
},
one(key, fn) {
if (this.oneObj[key] === undefined) {
this.oneObj[key] = [];
}
this.oneObj[key].push(fn);
},
off(key) {
this.onObj[key] = [];
this.oneObj[key] = [];
},
trigger(...args) {
if (args.length === 0) {
return false;
}
const key = args[0];
args = [].concat(Array.prototype.slice.call(args, 1));
if (this.onObj[key] !== undefined
&& this.onObj[key].length > 0) {
Object.keys(this.onObj[key]).forEach((i) => {
this.onObj[key][i].apply(null, args);
});
}
if (this.oneObj[key] !== undefined
&& this.oneObj[key].length > 0) {
Object.keys(this.oneObj[key]).forEach((i) => {
this.oneObj[key][i].apply(null, args);
this.oneObj[key][i] = undefined;
});
this.oneObj[key] = [];
}
return null;
}
};
export default eventProxy;

View File

@ -1,46 +0,0 @@
import fesConfig from '../config';
const hasOwnProperty = Object.prototype.hasOwnProperty;
const hasOwn = function (obj, key) {
return hasOwnProperty.call(obj, key);
};
const RE_NARGS = /(%|)\{([0-9a-zA-Z_]+)\}/g;
const template = function (string, ...args) {
if (args.length === 1 && typeof args[0] === 'object') {
args = args[0];
}
if (!args || !args.hasOwnProperty) {
args = {};
}
return string.replace(RE_NARGS, (match, prefix, i, index) => {
if (string[index - 1] === '{' && string[index + match.length] === '}') {
return i;
}
const result = hasOwn(args, i) ? args[i] : null;
if (result === null || result === undefined) {
return '';
}
return result;
});
};
export default function (path, options) {
const array = path.split('.');
let current = fesConfig.i18n.messages[fesConfig.i18n.locale];
if (!current) {
current = fesConfig.i18n.messages['zh-cn'];
}
let value;
for (let i = 0, j = array.length; i < j; i++) {
const property = array[i];
value = current[property];
if (i === j - 1) return template(value, options);
if (!value) return '';
current = value;
}
return '';
}

View File

@ -1,38 +0,0 @@
import storage from '../storage';
const history = {
data: storage.get('Fes_History') || [],
current: null
};
history.record = function (href) {
const length = history.data.length;
const obj = {
href,
type: ''
};
if (length === 0) {
obj.type = 'forward';
} else if (length > 0 && length <= 1) {
if (history.data[length - 1].href === href) {
obj.type = 'refresh';
} else {
obj.type = 'forward';
}
} else if (length > 1) {
const first = history.data[length - 1];
const second = history.data[length - 2];
if (first.href === href) {
obj.type = 'refresh';
} else if (second.href === href) {
obj.type = 'back';
} else {
obj.type = 'forward';
}
}
history.data.push(obj);
history.current = obj;
storage.set('Fes_History', history.data);
};
export default history;

View File

@ -1,88 +0,0 @@
import _ from 'lodash';
import * as domUtil from './dom';
import * as objectUtil from './object';
import * as typeUtil from './type';
import format from './format';
import event from './event';
import history from './history';
const util = {
// 验证一个path是否可以访问, 空的allowPage可以访问任何路由
canRoute(path, allowPage) {
path = path.split('?')[0];
if (Array.isArray(allowPage) && allowPage.length > 0) {
if (path === '' && allowPage.includes('/')) return true;
if (path) {
for (let i = 0; i < allowPage.length; i++) {
if (path === allowPage[i]) {
return true;
}
// 支持*匹配
const reg = new RegExp(`^${allowPage[i].replace('*', '.+')}$`);
if (reg.test(path)) {
return true;
}
}
}
}
return false;
},
getUrlParam(name) {
const reg = new RegExp(`(^|&)${name}=([^&]*)(&|$)`);
let r = window.location.search.substr(1).match(reg);
const hashQuery = window.location.hash.split('?')[1];
if (r != null) {
return decodeURIComponent(r[2]);
} if (hashQuery) {
r = hashQuery.match(reg);
return r && decodeURIComponent(r[2]);
}
return null;
},
removeParam(name, content) {
if (typeof name !== 'string') return false;
const prefix = encodeURIComponent(`${name}=`);
const pars = content.split(/[&;]/g);
let i = 0; const
len = pars.length;
let value = '';
for (; i < len; i++) {
if (encodeURIComponent(pars[i]).lastIndexOf(prefix, 0) !== -1) {
pars.splice(i, 1);
}
}
value = (pars.length > 0 ? `?${pars.join('&')}` : '');
return value;
},
proxyFn(proxy, prop, apiArr) {
proxy[prop] = {};
const cache = {};
if (window.Proxy) {
proxy[prop] = new Proxy(proxy[prop], {
get(target, name) {
cache[name] = cache[name] ? cache[name] : [];
if (!target[name]) {
target[name] = function (...args) {
cache[name].push(args);
};
}
return target[name];
}
});
} else {
apiArr.forEach((api) => {
if (!proxy[prop][api]) {
proxy[prop][api] = function (...args) {
cache[api] = cache[api] ? cache[api] : [];
cache[api].push(args);
};
}
});
}
return cache;
},
_
};
objectUtil.merge(util, domUtil, objectUtil, typeUtil, { format }, { event }, { history });
export default util;

View File

@ -1,27 +0,0 @@
export function merge(...args) {
const base = args[0];
if (!base) return null;
[].forEach.call(args, (item, index) => {
if (index > 0) {
Object.keys(item).forEach((attrname) => {
base[attrname] = item[attrname];
});
}
});
return base;
}
export function extend(...args) {
const base = args[0];
if (!base) return null;
[].forEach.call(args, (item, index) => {
if (index > 0) {
Object.keys(item).forEach((attrname) => {
if (base[attrname] !== undefined) {
base[attrname] = item[attrname];
}
});
}
});
return base;
}

View File

@ -1,36 +0,0 @@
const objectToString = Object.prototype.toString;
const OBJECT_STRING = '[object Object]';
export function isPlainObject(obj) {
return objectToString.call(obj) === OBJECT_STRING;
}
export function isNumber(value) { return typeof value === 'number'; }
export function isDate(value) {
return objectToString.call(value) === '[object Date]';
}
export function isFunction(value) { return typeof value === 'function'; }
export function isObject(value) {
const type = typeof value;
return !!value && (type === 'object' || type === 'function');
}
export function isArray(value) {
return Array.isArray(value);
}
export function isObjectLike(value) {
return !!value && typeof value === 'object';
}
export function isString(value) {
return typeof value === 'string'
|| (!isArray(value) && isObjectLike(value) && objectToString.call(value) === '[object String]');
}
export function isNull(value) {
return value === undefined || value === null || value === '';
}

View File

@ -1,29 +0,0 @@
/* !
* fes-components v1.0.0
* (c) 2017 fanniehuang
* Released under the MIT License.
*/
import FesRouteMenu from './routeMenu.vue';
import FesSearchPanel from './searchPanel.vue';
import FesListPanel from './listPanel.vue';
const fesComp = {
FesRouteMenu,
FesSearchPanel,
FesListPanel
};
const install = function (Vue) {
Object.keys(fesComp).forEach((key) => {
Vue.component(key, fesComp[key]);
});
};
if (typeof window !== 'undefined' && window.Vue) {
install(window.Vue);
}
export default {
install,
version: '2.0.0'
}; // eslint-disable-line no-undef

View File

@ -1,11 +0,0 @@
<template>
<div class="query-page">
<div class="query-page-table">
<slot />
</div>
</div>
</template>
<script>
export default {
};
</script>

View File

@ -1,91 +0,0 @@
<template>
<route-menu :menu="authMenu" :width="width" :type="type" :mode="mode" :auto-close="autoClose" />
</template>
<script>
import util from '../../util/index';
export default {
props: {
mode: {
type: String,
default: 'vertical' //
},
width: {
type: [String, Number],
default: undefined
},
menu: {
type: Array,
default() {
return [];
}
},
type: {
type: String,
default: 'light'
},
autoClose: {
type: Boolean,
default: false
}
},
data() {
return {
allowPage: ['*']
};
},
computed: {
authMenu() {
return this.filterMenu(this.menu, this.allowPage);
}
},
created() {
this.allowPage = this.FesApp.getAllowPage();
util.event.on('fes_allowPage_change', () => {
this.allowPage = this.FesApp.getAllowPage();
});
},
methods: {
// menu
filterMenu(menu, allowPage) {
if (allowPage && menu) {
const menuData = [];
// menu访
for (let i = 0; i < menu.length; i++) {
const item = menu[i];
if (
item.path
&& (!item.subMenu || item.subMenu.length === 0)
) {
if (util.canRoute(item.path, allowPage)) {
menuData.push(item);
}
} else if (item.subMenu && item.subMenu.length > 0) {
const subMenu = [];
for (let j = 0; j < item.subMenu.length; j++) {
const subItem = item.subMenu[j];
if (
(subItem.path
&& util.canRoute(subItem.path, allowPage))
|| !subItem.path
) {
subMenu.push(subItem);
}
}
if (subMenu.length > 0) {
menuData.push({
...item,
subMenu
});
}
} else {
menuData.push(item);
}
}
return menuData;
}
return menu;
}
}
};
</script>

View File

@ -1,14 +0,0 @@
<template>
<div class="query-page">
<div class="query-page-search">
<slot />
<div class="query-page-search-buttons">
<slot name="button" />
</div>
</div>
</div>
</template>
<script>
export default {
};
</script>

View File

@ -1,108 +0,0 @@
<template>
<div class="layout-left-body">
<div v-if="!fesFesx.FesHideLeftLogo" :class="{ 'hasLogoEvent': fesFesx.FesLogoEvent }" @click="LogoClick" class="layout-left-logo">
<img src="~assets/images/logo.png">
<p>{{fesName}}</p>
</div>
<div class="layout-left-menu">
<fes-route-menu :menu="fesMenu" :type="menuTheme" :mode="menuMode" :auto-close="true" />
</div>
<fes-left ref="commonleft" />
<div v-if="!showCommonLeft" class="layout-left-user">
<div class="layout-left-user-name">
<p>{{fesFesx.FesUserName}}</p>
<p>{{fesFesx.FesRoleName}}</p>
</div>
<div class="layout-left-user-logout">
<Icon @click="logout" type="md-log-out" size="28" />
</div>
</div>
</div>
</template>
<script>
import fesConfig from '../../config';
import _fes from '../../fesx/_fesx';
export default {
data() {
//
const obj = {
light: 'light',
blue: 'dark',
dark: 'dark'
};
return {
fesFesx: _fes,
menuData: fesConfig.menu || [],
menuMode: this.$parent.mode,
menuTheme: obj[this.$parent.theme],
showCommonLeft: false
};
},
computed: {
fesName() {
const fesName = _fes.get('FesName');
if (fesName.slice(0, 6) === '$i18n.') {
return this.$t(fesName.slice(6));
}
return fesName;
},
fesMenu() {
const menu = this.menuData;
// title
menu.forEach((element) => {
if (!element.__title) {
element.__title = element.title;
}
if (element.__title.slice(0, 6) === '$i18n.') {
element.title = this.$t(element.__title.slice(6));
}
//
if (element.subMenu) {
element.subMenu.forEach((son) => {
if (!son.__title) {
son.__title = son.title;
}
if (son.__title.slice(0, 6) === '$i18n.') {
son.title = this.$t(son.__title.slice(6));
}
});
}
});
return menu;
}
},
mounted() {
this.showCommonLeft = this.$refs.commonleft
&& this.$refs.commonleft.$el
&& this.$refs.commonleft.$el.innerHTML
&& this.$refs.commonleft.$el.innerHTML.trim() !== '';
this.FesApp.on('fes_logout', () => {
// FesName
const fesName = _fes.get('FesName');
_fes.clear();
_fes.set('FesName', fesName);
});
},
methods: {
logout() {
this.FesApp.set('FesRoleId', null);
const FesLogoutFn = this.FesApp.get('FesLogout');
if (this.FesUtil.isFunction(FesLogoutFn)) {
FesLogoutFn.call(this.FesApp);
}
this.FesApp.trigger('fes_logout', this.FesApp);
},
LogoClick() {
const logoClick = this.fesFesx.get('FesLogoEvent');
if (this.FesUtil.isFunction(logoClick)) {
logoClick.call(this);
}
this.FesApp.trigger('fes_logo_click', this.FesApp);
}
}
};
</script>

View File

@ -1,73 +0,0 @@
<template>
<div :class="getRootClass()" class="layout">
<div v-if="left" class="layout-left">
<left />
<span v-if="mode === 'vertical'" @click="toggleMenu" class="layout-left-fold-menu">
<span v-show="!leftHidden">
<Icon type="ios-arrow-back" />
<Icon type="ios-arrow-back" />
</span>
<span v-show="leftHidden">
<Icon type="ios-arrow-forward" />
<Icon type="ios-arrow-forward" />
</span>
</span>
</div>
<div class="layout-right">
<div v-if="header" class="layout-right-header">
<fes-header />
</div>
<div class="layout-right-body">
<router-view ref="pageview" />
</div>
</div>
</div>
</template>
<script>
import fesConfig from '../../config';
import left from './left.vue';
export default {
components: {
left
},
data() {
return {
mode: fesConfig.mode,
theme: fesConfig.theme,
leftHidden: false,
header: false,
left: true,
animate: false
};
},
methods: {
getRootClass() {
const arr = [
`layout-mode-${this.mode}`,
`layout-theme-${this.theme}`
];
if (!this.left) {
arr.push('layout-left-hide');
}
if (this.leftHidden) {
arr.push('layout-left-hidden');
}
if (!this.header) {
arr.push('layout-header-hide');
}
if (this.animate) {
arr.push('layout-animate');
}
return arr;
},
toggleMenu() {
this.animate = true;
setTimeout(() => {
this.animate = false;
}, 300);
this.leftHidden = !this.leftHidden;
}
}
};
</script>

View File

@ -1,48 +0,0 @@
.query-page {
.query-page-search {
position: relative;
background-color: #f7f7f7;
.query-page-search-buttons {
position: absolute;
margin-bottom: 16px;
margin-left: 50px;
height: 32px;
line-height: 32px;
bottom: 0;
right: 40px;
.ui-button+.ui-button {
margin-left: 8px;
}
}
.ui-form {
width: 75%;
}
.ui-form-item {
display: inline-block;
width: 33.33%;
}
}
.query-page-table {
.ui-page {
margin: 20px;
text-align: center;
}
}
.ui-modal-dialog {
overflow: auto;
}
.ui-modal-body {
width: 500px;
padding-right: 30px;
}
.link {
color: #3399ff;
cursor: pointer;
}
.link:hover {
color: #5cadff;
}
.link:active {
color: #3091f2;
}
}

View File

@ -0,0 +1,16 @@
{
"name": "@webank/fes-plugin-layout",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "MIT",
"peerDependencies": {
"vue": "^3.0.0",
"@webank/fes-core": "^0.2.4"
}
}

View File

@ -0,0 +1 @@
export const noop = () => { };

View File

@ -0,0 +1,12 @@
import generateLayout from './views/layout';
import './views/styles/index.scss';
export function createLayout() {
return {
install(app, options, ctx) {
ctx.layout = generateLayout(options);
}
};
}

View File

@ -0,0 +1,89 @@
import { defineComponent, computed } from 'vue';
import { useFesContext } from '@webank/fes-core';
import RightRender from './RightRender';
import RouteMenu from './RouteMenu.vue';
const DEFAULT_THEME = {
light: 'light',
blue: 'dark',
dark: 'dark'
};
function useMenu(menu) {
// 根据当前权限控制,显示 隐藏菜单
const { useI18n, accessibleElementTags, accessibleValidator } = useFesContext();
const accessibleMenu = computed(() => {
if (accessibleElementTags) {
const menuData = [];
// 循环menu可以访问页面才放入新对象中
for (let i = 0; i < menu.length; i++) {
const item = menu[i];
if (item.path && (!item.subMenu || item.subMenu.length === 0)) {
if (accessibleValidator(item.path)) {
menuData.push(item);
}
} else if (item.subMenu && item.subMenu.length > 0) {
const subMenu = [];
for (let j = 0; j < item.subMenu.length; j++) {
const subItem = item.subMenu[j];
if ((subItem.path && accessibleValidator(subItem.path)) || !subItem.path) {
subMenu.push(subItem);
}
}
if (subMenu.length > 0) {
menuData.push({
...item,
subMenu
});
}
} else {
menuData.push(item);
}
}
return menuData;
}
return menu;
});
const localeMenu = computed(() => {
if (useI18n) {
const { t } = useI18n();
// 给菜单title搞国际化
return accessibleMenu.map((element) => {
const copyElement = { ...element };
copyElement.title = t(element.title);
// 子菜单
if (copyElement.subMenu) {
copyElement.subMenu = element.subMenu.map((son) => {
const copySon = { ...son };
copySon.title = t(son.title);
return copySon;
});
}
return copyElement;
});
}
return accessibleMenu;
});
return localeMenu;
}
export default defineComponent((props) => {
const clickLogo = () => props.clickLogo && props.clickLogo;
const menuTheme = computed(() => DEFAULT_THEME[props.theme] || DEFAULT_THEME.light);
const menu = useMenu(props.menu);
return () => (
<div class="layout-left-body">
<div class={['layout-left-logo', 'has-logo-event' && props.clickLogo]} onClick={clickLogo}>
<img src="~assets/images/logo.png" />
<p>{props.projectName}</p>
</div>
<div class="layout-left-menu">
<RouteMenu menu={menu} type={menuTheme} mode={props.menuMode} auto-close={true} />
</div>
<RightRender rightRender={props.rightRender} layout={props.layout} />
</div>
);
});

View File

@ -0,0 +1,12 @@
import { defineComponent } from 'vue';
import { noop } from '../../helpers';
export default defineComponent(props => () => {
if (props.rightRender) return props.rightRender;
return (<div class="layout-left-user">
<div class="layout-left-user-logout">
<Icon onClick={props.logout || noop} type="md-log-out" size="28" />
</div>
</div>);
});

View File

@ -0,0 +1,43 @@
<template>
<route-menu
:menu="props.menu"
:width="props.width"
:type="props.type"
:mode="props.mode"
:auto-close="props.autoClose"
/>
</template>
<script>
export default {
props: {
mode: {
type: String,
default: 'vertical' //
},
width: {
type: [String, Number],
default: undefined
},
menu: {
type: Array,
default() {
return [];
}
},
type: {
type: String,
default: 'light'
},
autoClose: {
type: Boolean,
default: false
}
},
setup(props) {
return {
props
};
}
};
</script>

View File

@ -0,0 +1,73 @@
import {
defineComponent,
computed,
readonly,
ref
} from 'vue';
import LayoutNav from './LayoutNav';
export default function generateLayout(config) {
return defineComponent(() => {
const menu = readonly(config.menu);
const themeRef = ref(config.theme);
const modeRef = ref(config.mode || 'vertical');
const animateRef = ref(false);
const leftHiddenRef = ref(false);
const headerRef = ref(false);
const rootCls = computed(() => {
const arr = [
'layout',
`layout-mode-${modeRef.value}`,
`layout-theme-${themeRef.value}`
];
if (leftHiddenRef.value) {
arr.push('layout-left-hidden');
}
if (!headerRef.value) {
arr.push('layout-header-hide');
}
if (animateRef.value) {
arr.push('layout-animate');
}
return arr;
});
function toggleMenu() {
animateRef.value = true;
setTimeout(() => {
animateRef.value = false;
}, 300);
leftHiddenRef.value = !leftHiddenRef.value;
}
return () => (
<div class={rootCls}>
<div class="layout-left">
<LayoutNav
menuMode={modeRef.value}
menu={menu}
theme={themeRef.value}
/>
{
modeRef.value === 'vertical' && (<span onClick={toggleMenu} class="layout-left-fold-menu">
<span>
<Icon type={`ios-arrow-${leftHiddenRef.value ? 'forward' : 'back'}`} />
<Icon type={`ios-arrow-${leftHiddenRef.value ? 'forward' : 'back'}`} />
</span>
</span>)
}
</div>
<div class="layout-right">
{
headerRef.value && (<div class="layout-right-header">
<fes-header />
</div>)
}
<div class="layout-right-body">
<router-view />
</div>
</div>
</div >
);
});
}

View File

@ -1,3 +1,2 @@
@import "layout.scss";
@import "components.scss";
@import "polyfill.scss";

View File

@ -0,0 +1,14 @@
import { createI18n, useI18n } from 'vue-i18n';
// 注入 i18n 上下文
// 动态变更 local
// 其他组件能拿到 t 函数
// local 变更后,能通知到其他函数
export default {
install(app, options, ctx) {
const i18n = createI18n(options);
ctx.useI18n = useI18n;
app.use(i18n);
}
};

View File

@ -0,0 +1,13 @@
{
"name": "@webank/fes-plugin-locale",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"vue-i18n": {
"version": "9.0.0-beta.2",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.0.0-beta.2.tgz",
"integrity": "sha512-fvpf+LjXFdcSxKWYDaYetto3hnLwLzkPfKUmkzhG/AqgaIi+ZaVf+fLsQUmOaXzqp0l/4orjXjhHUIjhYsBLhA=="
}
}
}

View File

@ -0,0 +1,15 @@
{
"name": "@webank/fes-plugin-locale",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "MIT",
"dependencies": {
"vue-i18n": "^9.0.0-beta.2"
}
}

View File

@ -0,0 +1,78 @@
import { reactive } from 'vue';
let accessibleElementTags = null;
// TODO 支持异步函数
export const addAccessibleElementTags = (elementTags) => {
if (accessibleElementTags) {
if (typeof elementTags === 'string') {
accessibleElementTags.push(elementTags);
} else {
accessibleElementTags.push(...elementTags);
}
}
};
// TODO 移除权限 + 支持异步函数
export const delAccessibleElementTags = () => {
console.log('todo');
};
// 验证一个资源是否可以访问
export const accessibleValidator = (elementTag) => {
elementTag = elementTag.split('?')[0];
if (Array.isArray(accessibleElementTags) && accessibleElementTags.length > 0) {
if (elementTag === '' && accessibleElementTags.includes('/')) return true;
if (elementTag) {
for (let i = 0; i < accessibleElementTags.length; i++) {
if (elementTag === accessibleElementTags[i]) {
return true;
}
// 支持*匹配
const reg = new RegExp(`^${accessibleElementTags[i].replace('*', '.+')}$`);
if (reg.test(elementTag)) {
return true;
}
}
}
}
return true;
};
export const createPermissionHandler = () => ({
async install(app, options, ctx) {
try {
if (typeof options.accessibleElementTags === 'function') {
const elementTags = await options.accessibleElementTags(ctx);
accessibleElementTags = reactive(elementTags || []);
} else {
accessibleElementTags = reactive(options.accessibleElementTags || []);
}
const elWeakMap = new WeakMap();
app.directive('permission', (el, binding) => {
// TODO 当 accessibleElementTags 变更的时候调用 forceUpdate 更新组件
if (!elWeakMap.has(el)) {
elWeakMap.set(el, {
display: el.style.display
});
}
const elementTags = Array.isArray(binding.value) ? binding.value : binding.value;
if (elementTags.some(elementTag => accessibleValidator(elementTag))) {
el.style.display = elWeakMap.get(el).display;
} else {
el.style.display = 'none';
}
});
// TODO 异步权限
ctx.router.beforeEach(to => accessibleValidator(to.path));
ctx.accessibleValidator = accessibleValidator;
ctx.accessibleElementTags = accessibleElementTags;
} catch (err) {
console.error(err);
}
}
});

View File

@ -0,0 +1,12 @@
{
"name": "@webank/fes-plugin-permission",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "MIT"
}

View File

@ -0,0 +1,26 @@
{
"name": "@webank/fes-plugin-request",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"axios": {
"version": "0.20.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.20.0.tgz",
"integrity": "sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA==",
"requires": {
"follow-redirects": "^1.10.0"
}
},
"follow-redirects": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz",
"integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA=="
},
"throttle-debounce": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-2.3.0.tgz",
"integrity": "sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ=="
}
}
}

View File

@ -0,0 +1,17 @@
{
"name": "@webank/fes-plugin-request",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"type": "module",
"license": "MIT",
"dependencies": {
"axios": "^0.20.0",
"throttle-debounce": "^2.3.0"
}
}

View File

@ -0,0 +1,88 @@
/**
*判断类型
* @param {*} obj 需要判断的对象
*/
export function typeOf(obj) {
const map = {
'[object Boolean]': 'boolean',
'[object Number]': 'number',
'[object String]': 'string',
'[object Function]': 'function',
'[object Array]': 'array',
'[object Date]': 'date',
'[object RegExp]': 'regExp',
'[object Undefined]': 'undefined',
'[object Null]': 'null',
'[object Object]': 'object'
};
return map[Object.prototype.toString.call(obj)];
}
export function isFunction(obj) {
return typeOf(obj) === 'function';
}
export function isDate(obj) {
return typeOf(obj) === 'date';
}
export function isString(obj) {
return typeOf(obj) === 'string';
}
export function isArray(obj) {
return typeOf(obj) === 'array';
}
export function isObject(obj) {
return typeOf(obj) === 'object';
}
export function isHtmlElement(node) {
return node && node.nodeType === Node.ELEMENT_NODE;
}
export const isUndefined = val => val === undefined;
export const isDefined = val => val !== undefined && val !== null;
export function checkHttpRequestHasBody(method) {
method = method.toUpperCase();
const HTTP_METHOD = {
GET: {
request_body: false
},
POST: {
request_body: true
},
PUT: {
request_body: true
},
DELETE: {
request_body: true
},
HEAD: {
request_body: false
},
OPTIONS: {
request_body: false
},
PATCH: {
request_body: true
}
};
return HTTP_METHOD[method].request_body;
}
export function trimObj(obj) {
Object.entries(obj).forEach(([key, value]) => {
if (isString(value)) {
obj[key] = value.trim();
} else if (isObject(value)) {
trimObj(value);
} else if (Array.isArray(value)) {
trimObj(value);
}
});
}

View File

@ -0,0 +1,29 @@
import { debounce } from 'throttle-debounce';
import initAxiosInstance from './request';
let request;
function _advanceRequest({ url, debounce: waitTime, options = {} }) {
return debounce((data, specialCaseOptions) => {
request(url, data, Object.assign(options, specialCaseOptions));
}, true, waitTime || 0);
}
export const requestWrap = (interfaces) => {
const obj = {};
Object.entries(interfaces).forEach(([key, value]) => {
if (value.url) {
obj[key] = _advanceRequest(value);
} else {
obj[key] = requestWrap(value);
}
});
return obj;
};
export const createRequest = () => ({
install(app, options, ctx) {
request = initAxiosInstance(options, { router: ctx.router });
ctx.request = request;
}
});

View File

@ -0,0 +1,19 @@
import { checkHttpRequestHasBody, trimObj } from './helpers';
export default function reqInterceptors(instance) {
// 将 http method 转换为大写
instance.interceptors.request.use((config) => {
config.method = config.method.toUpperCase();
return config;
});
// 清理请求值中的空格
instance.interceptors.request.use((config) => {
if (checkHttpRequestHasBody(config.method)) {
config.data = trimObj(config.data);
} else {
config.params = trimObj(config.params);
}
return config;
});
}

View File

@ -0,0 +1,91 @@
import axios from 'axios';
import reqInterceptors from './reqInterceptors';
import resInterceptors from './resInterceptors';
import { checkHttpRequestHasBody, isObject } from './helpers';
// TODO
// 响应体控制
// formData 控制
// 段时间内不能重复发送的请求
// 错误控制
// 跳错误页面 || 或者重新登录
let instance;
export function requestUse(before, error) {
return this.instance.interceptors.request.use(before, error);
}
export function requestEject(interceptor) {
this.instance.interceptors.request.eject(interceptor);
}
export function responseUse(after, error) {
return instance.interceptors.response.use(after, error);
}
export function responseEject(interceptor) {
instance.interceptors.response.eject(interceptor);
}
export function getRequestInstance() {
return instance;
}
function _failedHandler(error, customerErrorHandler) {
if (error.response) {
const status = error.response.status;
if (typeof customerErrorHandler[status] === 'function') {
customerErrorHandler(error);
}
} else if (error.request) {
// TODO 请求异常
} else {
console.error(error);
}
return Promise.reject(error);
}
function _successedHandler(response, responseDataStruct) {
const responseData = response.data;
if (responseDataStruct && isObject(responseData)) {
// TODO 响应体解构解析
return responseData;
}
return responseData;
}
function initAxiosInstance({ options: internalOptions, responseDataStruct, errorHandler }) {
const customerErrorHandler = errorHandler || {};
instance = axios.create(Object.assign({
timeout: 10000,
withCredentials: true
}, internalOptions));
// 设置请求拦截器
reqInterceptors(instance);
// 设置响应拦截器
resInterceptors(instance);
return (url, data, options = {}) => {
options.url = url;
options.method = options.method || 'post';
if (checkHttpRequestHasBody(options.method)) {
options.data = data;
} else {
options.params = data;
}
// 请求内容可能是一个json
// 一个 query
// formdata
// 响应内容可能是一个文件流
// 一个文本
// 一个 json
// eslint-disable-next-line
return this.instance.request(options).then(response => _successedHandler(response, responseDataStruct)).catch(error => _failedHandler(error, customerErrorHandler));
};
}
export default initAxiosInstance;

View File

@ -0,0 +1,4 @@
export default function resInterceptors() {
}

View File

@ -1,17 +0,0 @@
module.exports = {
extends: [
'@webank/eslint-config-webank/vue',
],
globals: {
// 这里填入你的项目需要的全局变量
// 这里值为 false 表示这个全局变量不允许被重新赋值,比如:
//
// Vue: false
},
rules: {
'no-plusplus': 'off',
'no-bitwise': 'off',
'vue/comment-directive': 'off'
}
};

View File

@ -1,8 +0,0 @@
.DS_Store
.idea
.git
.vscode
.cache
/dist
.history
/node_modules

View File

@ -1,13 +0,0 @@
# 项目名称
## 运行
```bash
npm run dev
```
## 编译
```bash
npm run build
```

View File

@ -1,25 +0,0 @@
#!/usr/bin/env sh
# 确保脚本抛出遇到的错误
set -e
# 生成静态文件
npm run build
# 进入生成的文件夹
cd dist
# 如果是发布到自定义域名
# echo 'www.example.com' > CNAME
git init
git add -A
git commit -m 'deploy'
# 如果发布到 https://<USERNAME>.github.io
# git push -f git@github.com:<USERNAME>/<USERNAME>.github.io.git master
# 如果发布到 https://<USERNAME>.github.io/<REPO>
git push -f https://gitee.com/WeBank/fes-pro.git master:gh-pages
cd -

View File

@ -1,112 +1,6 @@
// fes.config.js 只负责管理和 cli 相关的配置
module.exports = {
// 可选有vertical、horizontal默认vertical
mode: 'vertical',
// 可选有blue、dark默认blue
theme: 'blue',
// 项目名称
fesName: 'Fes.js 运营平台',
favicon: 'static/favicon.ico', // 图标
lazyRouter: true,
// 环境变量配置, 默认使用local环境
env: {
// 本地开发环境
local: {
api: ''
},
// 测试环境 --env=sit 触发使用
develop: {
api: 'http://test.xxx.com'
},
// 生产环境 --env=sit 触发使用
prod: {
api: 'http://xxx.com'
}
},
// 配置角色-路由访问权限使用FesApp.setRole('unLogin')来修改当前用户的角色,控制路由访问权限
roles: {
unLogin: ['/'],
admin: ['/dashboard/console', '*']
},
// map
map: {
level: [['1', '青铜'], ['2', '白银'], ['3', '黄金'], ['4', '铂金']]
},
// 左侧菜单配置
menu: [
{
title: '工作台',
subMenu: [
{
title: '工作台',
path: '/dashboard/console'
}
]
},
{
title: '列表页',
subMenu: [
{
title: '查询列表',
path: '/list'
}
]
},
{
title: '表单页',
subMenu: [
{
title: '基础表单',
path: '/form/base'
},
{
title: '分步表单',
path: '/form/step'
}
]
},
{
title: '功能演示',
path: '/layout',
subMenu: [
{
title: '$i18n.menu.internationalization',
path: '/layout/i18n'
},
{
title: '静态资源',
path: '/layout/static'
}
]
}
],
i18n: {
// default zh-cn
locale: 'zh-cn',
messages: {
'zh-cn': {
menu: {
internationalization: '国际化'
},
overview: '概述',
i18n: {
internationalization: '国际化,基于',
achieve: '实现。',
ui: 'UI组件'
},
title: 'Fes.js 运营平台'
},
en: {
menu: {
internationalization: 'internationalization'
},
overview: 'Overview',
i18n: {
internationalization: 'internationalizationbase on',
achieve: 'to achieve.',
ui: 'UI components'
},
title: 'Fes.js Admin'
}
}
}
open: false,
port: 5000
};

View File

@ -1,113 +0,0 @@
module.exports = (cgiMock, Mock) => {
const { Random } = Mock;
// 前缀,全局(可选)
// cgiMock.prefix = '';
// 返回一个数字
cgiMock('/number', 123);
// 返回一个json
cgiMock({
url: '/json',
result: {
code: '400101', msg: "不合法的请求:Missing cookie 'wb_app_id' for method parameter of type String", transactionTime: '20170309171146', success: false
}
});
// 利用mock.js 产生随机文本
cgiMock('/text', Random.cparagraph());
// 返回一个字符串 利用mock.js 产生随机字符
cgiMock('/string', Mock.mock({
'string|1-10': '★'
}));
// 正则匹配url, 返回一个字符串
// cgiMock(/\/abc|\/xyz/, 'regexp test!');
// option.result 参数如果是一个函数, 可以实现自定义返回内容, 接收的参数是是经过 express 封装的 req 和 res 对象.
// cgiMock(/\/function$/, function (req, res) {
// res.send('function test');
// });
// 返回文本 fs.readFileSync
// cgiMock('/file', cgiMock.file('./test.json'));
// 更复杂的规则配置
cgiMock({
url: /\/who/,
method: 'GET',
result(req, res) {
if (req.query.name === 'kwan') {
res.json({ kwan: '孤独患者' });
} else {
res.send('Nooooooooooo');
}
},
headers: {
'Content-Type': 'text/plain',
'Content-Length': '123',
ETag: '12345'
},
cookies: [
{
name: 'myname', value: 'kwan', maxAge: 900000, httpOnly: true
}
],
// 接口随机延迟
timeout: Mock.mock({
'number|1000-5000': 1000
}).number
});
// 登录
cgiMock('/login', (req, res) => {
res.send(JSON.stringify({
code: '0',
msg: '',
result: {
username: '万纯harrywan',
roleName: '管理员'
}
}));
});
cgiMock('/getTestList', (req, res) => {
const list = [];
for (let i = 0; i < req.body.pageSize; i++) {
list.push({
a: i
});
}
res.send(JSON.stringify({
code: '0',
msg: 'this is message',
result: {
list,
page: {
pageSize: req.body.pageSize,
currentPage: req.body.currentPage,
totalPage: 1000
}
}
}));
});
cgiMock('/getNumber', (req, res) => {
res.send(JSON.stringify({
code: '0',
msg: 'this is message',
result: 4
}));
});
cgiMock('/getRoleName', (req, res) => {
res.send(JSON.stringify({
code: '0',
msg: 'this is message',
result: 'admin'
}));
});
};

View File

@ -1,6 +1,6 @@
{
"name": "@webank/fes-template",
"version": "0.2.3",
"version": "0.2.1",
"description": "fes项目模版",
"main": "index.js",
"scripts": {
@ -29,14 +29,14 @@
"author": "harrywan qlin",
"license": "MIT",
"devDependencies": {
"@vue/compiler-sfc": "^3.0.0",
"@webank/eslint-config-webank": "^0.1.4",
"csp-html-webpack-plugin": "^4.0.0"
},
"dependencies": {
"@antv/data-set": "^0.11.7",
"@antv/g2": "^4.0.15",
"@babel/runtime-corejs3": "^7.11.2",
"@webank/fes-core": "^0.2.3",
"@webank/fes-ui": "^0.2.3"
"@webank/fes-core": "^0.2.1",
"vue": "^3.0.0",
"vue-router": "^4.0.0-beta.12"
}
}

View File

@ -1,42 +1,41 @@
import './assets/styles/main.scss';
export default function () {
this.FesApp.set('FesName', '$i18n.title');
import { createFesApp } from '@webank/fes-core';
// import LayoutPlugin from '@webank/fes-plugin-layout';
// import { createRequest } from '@webank/fes-plugin-request';
// 设置退出逻辑
this.on('fes_logout', () => {
this.FesApp.setRole('unLogin');
this.FesStorage.set('userLogin', false);
// addPlugin(LayoutPlugin);
// addPlugin(createRequest({
// options: {
// baseURL: ''
// },
// // some options
// responseDataStruct: {
// },
// errorHandler: {
// 404: () => {
// },
// 403: (ctx) => {
// ctx.router.push('/login');
// },
// 401: () => {
// },
// 502: () => {
// },
// otherCode: (error) => {
// window.Toast(error.message);
// }
// }
// }));
createFesApp({
// routes: [
// { path: '/', component: Home }
// ]
// some options
});
// 设置logo点击事件
this.on('fes_logo_click', () => {
window.Toast('你点击了LOGO');
});
// 设置路由钩子
this.FesApp.setBeforeRouter((from, to, next) => {
next();
});
this.FesApp.setAfterRouter((route) => {
console.log(`您浏览到了${route.path}`);
});
// 设置当前角色
if (!this.FesStorage.get('userLogin') === true) {
this.setRole('unLogin');
}
// 设置AJAX配置
this.FesApi.option({
});
// 设置响应结构
this.FesApi.setResponse({
successCode: '0',
codePath: 'code',
messagePath: 'msg',
resultPath: 'result'
});
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

View File

@ -1,104 +0,0 @@
@import "variables";
.article {
padding: 20px;
h1 {
font-size: 26px;
font-weight: 400;
margin: 12px 0;
}
h2 {
margin: 25px 0 12px;
font-size: 20px;
font-weight: 400;
}
h3 {
font-size: 16px;
font-weight: 400;
}
p {
font-size: 14px;
margin: 5px;
}
ul {
padding-left: 40px;
}
li {
list-style-type: disc;
margin-bottom: 5px;
font-size: 14px;
}
table{
border-collapse: collapse;
border-spacing: 0;
empty-cells: show;
border: 1px solid #e9e9e9;
width: 500px;
margin-bottom: 24px;
}
th,td {
border: 1px solid #e9e9e9;
padding: 8px 16px;
text-align: left;
}
}
.ml-8{
margin-left: 8px;
}
.ml-16{
margin-left: 16px;
}
.mt-16{
margin-top: 16px;
}
.pr-16{
padding-right: 16px;
}
// 修复问题
.ui-modal .ui-modal-dialog{
overflow: visible;
}
.query-page .query-page-table .ui-page {
margin: 20px;
text-align: center;
justify-content: center;
}
.page {
display: flex;
flex-direction: column;
background: #f0f2f5;
min-height: 100%;
.page-header{
padding: 16px 32px 0;
background: #fff;
border-bottom: 1px solid $border-color-split ;
.page-header-title{
color: $title-color;
font-weight: 500;
font-size: 16px;
margin-bottom: 16px;
}
.page-header-desc{
margin-bottom: 16px;
}
}
.page-body{
flex: auto;
min-height: 0;
margin: 24px 24px;
background: #fff;
border: 1px solid $border-color-split ;
}
}

View File

@ -1,90 +0,0 @@
// Color
$primary-color : #3399ff;
$info-color : #2db7f5;
$success-color : #00cc66;
$warning-color : #ff9900;
$error-color : #ff5500;
$link-color : #3399ff;
$link-hover-color : #5cadff;
$link-focus-color : rgba(51,153,255, .2);
$link-active-color : #3091f2;
$selected-color : rgba($primary-color, .9);
$tooltip-color : #fff;
//辅助/图标
$subsidiary-color : #9ea7b4;
$disabled-color : #f3f3f3;
// Base
$body-background : #fff;
$component-background : #fff;
$font-family : "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif;
$code-family : Consolas,Menlo,Courier,monospace;
$title-color : #464c5b;
$text-color : #657180;
$black-text-color : #333333;
$sub-text-color : #999;
$dark-color : #333;
//失效 Disabled
$tip-color : #c3cbd6;
$font-size-lg : 16px;
$font-size-base : 14px;
$font-size-small : 12px;
$line-height-base : 1.5;
$line-height-computed : floor(($font-size-base * $line-height-base));
$border-radius-base : 6px;
$border-radius-small : 4px;
$cursor-disabled : not-allowed;
// Border color
$border-color-base : #d7dde4; // outside
$border-color-split : #e3e8ee; // inside
// Background color
$background-color-base : #f7f7f7; // base
$background-color-select-hover: #f3f3f3;
$tooltip-bg : rgba(70, 76, 91, .9);
$head-bg : #f9fafc;
$table-thead-bg : #f5f7f9;
$table-td-stripe-bg : #f5f7f9;
$table-td-hover-bg : #ebf7ff;
$table-td-highlight-bg : #ebf7ff;
// Z-index
$zindex-spin : 8;
$zindex-affix : 10;
$zindex-back-top : 10;
$zindex-select : 900;
$zindex-modal : 1000;
$zindex-message : 1010;
$zindex-notification : 1010;
$zindex-tooltip : 1060;
$zindex-loading-bar : 2000;
// Animation
$animation-time : .3s;
$transition-time : .2s;
$ease-out : cubic-bezier(0.215, 0.61, 0.355, 1);
$ease-in : cubic-bezier(0.55, 0.055, 0.675, 0.19);
$ease-in-out : cubic-bezier(0.645, 0.045, 0.355, 1);
$ease-out-back : cubic-bezier(0.12, 0.4, 0.29, 1.46);
$ease-in-back : cubic-bezier(0.71, -0.46, 0.88, 0.6);
$ease-in-out-back : cubic-bezier(0.71, -0.46, 0.29, 1.46);
$ease-out-circ : cubic-bezier(0.08, 0.82, 0.17, 1);
$ease-in-circ : cubic-bezier(0.6, 0.04, 0.98, 0.34);
$ease-in-out-circ : cubic-bezier(0.78, 0.14, 0.15, 0.86);
$ease-out-quint : cubic-bezier(0.23, 1, 0.32, 1);
$ease-in-quint : cubic-bezier(0.755, 0.05, 0.855, 0.06);
$ease-in-out-quint : cubic-bezier(0.86, 0, 0.07, 1);
// Shadow
$shadow-color : rgba(0, 0, 0, .2);
$shadow-1-up : 0 -1px 6px $shadow-color;
$shadow-1-down : 0 1px 6px $shadow-color;
$shadow-1-left : -1px 0 6px $shadow-color;
$shadow-1-right : 1px 0 6px $shadow-color;
$shadow-2 : 0 2px 8px $shadow-color;
$box-shadow-base : $shadow-1-down;
$mask-color: rgba(55, 55, 55, .6);

View File

@ -0,0 +1,24 @@
import { requestWrap } from '@webank/fes-plugin-request';
// TODO
// 响应体控制
// formData 控制
// 错误控制
// 跳错误页面 || 或者重新登录
// 段时间内不能重复发送的请求
// request(url, data, option).then(() => {
// });
// or
export default requestWrap({
login: {
url: '',
throttle: 300,
options: {
method: 'get'
}
}
});

View File

@ -1,54 +0,0 @@
<template>
<div class="card">
<div class="card-header">
{{title}}
<div class="card-header-extra"><slot name="extra"></slot></div>
</div>
<div class="card-body">
<slot name="body"></slot>
</div>
</div>
</template>
<script>
export default {
props: {
title: {
type: String,
required: true
}
}
};
</script>
<style lang="scss" scoped>
@import "~@/assets/styles/variables";
.card {
box-sizing: border-box;
position: relative;
background: rgb(255, 255, 255);
border-radius: 2px;
color: $text-color;
.card-header {
min-height: 48px;
margin-bottom: -1px;
padding: 0px 24px;
color: $title-color;
font-weight: 500;
font-size: 16px;
background: transparent;
border-bottom: 1px solid rgb(240, 240, 240);
border-radius: 2px 2px 0px 0px;
display: flex;
justify-content: space-between;
align-items: center;
.card-header-extra {
color: $title-color;
font-weight: normal;
font-size: 14px;
}
}
.card-body {
margin: -1px 0px 0px -1px;
padding: 0px;
}
}
</style>

View File

@ -1,81 +0,0 @@
<template>
<div ref="chart"></div>
</template>
<script>
import { Chart } from '@antv/g2';
export default {
props: {
data: {
type: Array,
required: true
},
options: {
type: Object,
required: true
}
},
watch: {
data() {
if (this.chart) {
this.chart.changeData(this.data);
this.chart.render();
}
}
},
mounted() {
const chart = new Chart({
container: this.$refs.chart,
autoFit: true,
height: 300
});
this.chart = chart;
Object.keys(this.options).forEach((p) => {
const option = this.options[p];
switch (p) {
case 'scale':
chart.scale(option);
break;
case 'coordinate':
chart.coordinate(option);
break;
case 'tooltip':
chart.tooltip(option);
break;
case 'axis':
Object.keys(option).forEach((pp) => {
chart.axis(pp, option[pp]);
});
break;
default:
}
});
if (this.options.line) {
const lineGeometry = chart.line();
Object.keys(this.options.line).forEach((pp) => {
lineGeometry[pp](this.options.line[pp]);
});
}
if (this.options.point) {
const pointGeometry = chart.point();
Object.keys(this.options.point).forEach((pp) => {
pointGeometry[pp](this.options.point[pp]);
});
}
if (this.data.length === 0) {
return;
}
chart.data(this.data);
chart.render();
},
beforeDestroy() {
this.chart && this.chart.destroy();
}
};
</script>
<style lang="scss" scoped>
</style>

View File

@ -1,14 +0,0 @@
<template>
<div style="text-align: center">
我是头部
</div>
</template>
<script>
// components*.fes使
// fesHeader.fes
export default {
FesReady() {
// do something
}
};
</script>

View File

@ -1,9 +0,0 @@
<template>
<div />
</template>
<script>
//
// fesLeft.fes
export default {
};
</script>

View File

@ -1,449 +0,0 @@
<template>
<div class="page page-console">
<div class="page-header">
<div class="page-header-title">工作台</div>
<div class="page-hader-content">
<img
class="avatar"
src="https://gw.alipayobjects.com/zos/rmsportal/WhxKECPNujWoWEFNdnJE.png"
/>
<div class="user">
<div class="user-wellcome">早安Harry祝你开心每一天</div>
<div class="user-role">
前端开发工程师 | 某某公司-某某部门-某某科室
</div>
</div>
<div class="report">
<div class="report-item">
<span class="report-item-name">项目数量</span>
<span class="report-item-score">56</span>
</div>
<div class="report-item">
<span class="report-item-name">团队内排名</span>
<span class="report-item-score">8 / 24</span>
</div>
<div class="report-item">
<span class="report-item-name">项目访问</span>
<span class="report-item-score">2,223</span>
</div>
</div>
</div>
</div>
<div class="page-body">
<Row>
<Cell span="16" class="pr-16">
<Card title="进行中的项目">
<a slot="extra" href="">全部项目</a>
<div slot="body" class="grid-project">
<div v-for="(item, i) in projects" :key="i" class="grid-project-item">
<div class="grid-project-title">
<img :src="item.icon" />
<span>{{item.title}}</span>
</div>
<div class="grid-project-desc">{{item.desc}}</div>
<div class="grid-project-content">
<span>{{item.group}}</span>
<span class="grid-project-time">{{item.time}}</span>
</div>
</div>
</div>
</Card>
<Card class="mt-16" title="动态">
<div slot="body" class="list-dynamic">
<div v-for="(item, i) in projects" :key="i" class="list-dynamic-item">
<img
class="list-dynamic-logo"
src="https://gw.alipayobjects.com/zos/rmsportal/WhxKECPNujWoWEFNdnJE.png"
/>
<div class="list-dynamic-content">
曲丽丽 <a>高逼格设计天团</a> 新建项目 <a>六月迭代</a>
<div class="list-dynamic-desc">3 小时前</div>
</div>
</div>
</div>
</Card>
</Cell>
<Cell span="8">
<Card title="快速开始 / 便捷导航">
<div slot="body" class="grid-nav">
<div v-for="(item, i) in navs" :key="i" class="grid-nav-item">
{{item}}
</div>
<div>
<Wb-button icon="md-add" type="ghost">添加</Wb-button>
</div>
</div>
</Card>
<Card class="mt-16" title="幸运指数">
<div slot="body" class="card-chart">
<Chart :data="chartData" :options="chartOptions"></Chart>
</div>
</Card>
<Card class="mt-16" title="团队">
<div slot="body" class="grid-group">
<div v-for="(item, i) in projects" :key="i" class="grid-group-item">
<img :src="item.icon" class="grid-group-icon" />
<span class="grid-group-name">{{item.group}}</span>
</div>
</div>
</Card>
</Cell>
</Row>
</div>
</div>
</template>
<script>
import DataSet from '@antv/data-set';
export default {
FesData() {
return {
projects: [
{
icon: 'https://cn.vuejs.org/images/logo.png',
title: 'Vue',
desc: '那是一种内在的东西,他们到达不了,也无法触及的',
group: '科学搬砖组',
time: '2 小时前'
},
{
icon:
'https://gw.alipayobjects.com/zos/rmsportal/zOsKZmFRdUtvpqCImOVY.png',
title: 'Angular',
desc: '希望是一个好东西,也许是最好的,好东西是不会消亡的',
group: '中二少女团',
time: '3 年前'
},
{
icon:
'https://gw.alipayobjects.com/zos/rmsportal/kZzEzemZyKLKFsojXItE.png',
title: 'React',
desc: '城镇中有那么多的酒馆,她却偏偏走进了我的酒馆',
group: 'javascript',
time: '2 小时前'
},
{
icon:
'https://gw.alipayobjects.com/zos/rmsportal/siCrBXXhmvTQGWPNLBow.png',
title: 'Bootstrap',
desc: '那时候我只会想自己想要什么,从不想自己拥有什么',
group: 'java',
time: '2 小时前'
},
{
icon:
'https://s.cn.bing.net/th?id=OJ.wjuHWOYyiQYnjw&pid=MsnJVFeeds&w=16&h=16',
title: 'Wechat',
desc: '凛冬将至',
group: '部落',
time: '2 小时前'
},
{
icon:
'https://gw.alipayobjects.com/zos/rmsportal/WdGqmHpayyMjiEhcKoVE.png',
title: 'Alipay',
desc: '生命就像一盒巧克力,结果往往出人意料',
group: '联盟',
time: '2 小时前'
}
],
navs: ['操作一', '操作二', '操作三', '操作四', '操作五', '操作六'],
chartData: [],
chartOptions: {
scale: {
score: {
min: 0,
max: 100
}
},
coordinate: {
type: 'polar',
cfg: {
radius: 0.85
}
},
tooltip: {
shared: true,
showCrosshairs: true,
crosshairs: {
line: {
style: {
lineDash: [4, 4],
stroke: '#333'
}
}
}
},
axis: {
item: {
line: null,
tickLine: null,
grid: {
line: {
style: {
lineDash: null
}
}
}
},
score: {
line: null,
tickLine: null,
grid: {
line: {
type: 'line',
style: {
lineDash: null
}
}
}
}
},
line: {
position: 'item*score',
color: 'user',
size: 2
},
point: {
position: 'item*score',
color: 'user',
shape: 'circle',
size: 4,
style: {
stroke: '#fff',
lineWidth: 1,
fillOpacity: 1
}
}
}
};
},
FesReady() {
const data = [
{
item: '热度',
a: 70,
b: 10,
c: 70
},
{
item: '引用',
a: 100,
b: 30,
c: 40
},
{
item: '口碑',
a: 80,
b: 90,
c: 10
},
{
item: '产出',
a: 40,
b: 60,
c: 60
},
{
item: '贡献',
a: 50,
b: 30,
c: 60
}
];
const { DataView } = DataSet;
const dv = new DataView().source(data);
dv.transform({
type: 'rename',
map: {
a: '个人',
b: '团队',
c: '部门'
}
});
dv.transform({
type: 'fold',
fields: ['个人', '团队', '部门'], //
key: 'user', // key
value: 'score' // value
});
this.chartData = dv.rows;
},
FesBeforeDestroy() {
},
methods: {}
};
</script>
<style lang="scss">
@import "~@/assets/styles/variables";
.page.page-console{
font-size: 14px;
.page-header {
.page-hader-content {
display: flex;
align-items: center;
margin-bottom: 24px;
.avatar {
width: 60px;
height: 60px;
margin-right: 16px;
}
.user {
flex: 1;
.user-wellcome {
font-size: 18px;
color: $title-color;
}
.user-role {
margin-top: 8px;
}
}
.report {
min-width: 420px;
margin-left: 88px;
display: flex;
.report-item {
flex: 1;
display: flex;
padding: 0 32px;
flex-direction: column;
align-items: flex-end;
position: relative;
&:not(:last-child):before{
content: "";
position: absolute;
right: 0;
top: 6px;
bottom: 6px;
width: 1px;
background: $border-color-split;
}
&:last-child{
padding-right: 0;
}
.report-item-name {
margin-bottom: 4px;
}
.report-item-score {
font-size: 24px;
font-weight: 500;
}
}
}
}
}
.page-body {
background: #f0f2f5;
border: none;
.grid-project {
display: grid;
grid-template-columns: repeat(3, 33.33%);
.grid-project-item {
padding: 24px;
border: 0px;
box-shadow: rgb(240, 240, 240) 1px 0px 0px 0px,
rgb(240, 240, 240) 0px 1px 0px 0px, rgb(240, 240, 240) 1px 1px 0px 0px,
rgb(240, 240, 240) 1px 0px 0px 0px inset,
rgb(240, 240, 240) 0px 1px 0px 0px inset;
transition: all 0.3s ease 0s;
&:hover {
position: relative;
z-index: 1;
box-shadow: 0 1px 2px -2px rgba(0, 0, 0, 0.16),
0 3px 6px 0 rgba(0, 0, 0, 0.12), 0 5px 12px 4px rgba(0, 0, 0, 0.09);
}
}
.grid-project-title {
display: flex;
align-items: center;
margin-bottom: 8px;
font-size: 16px;
img {
width: 24px;
height: auto;
}
span {
margin-left: 8px;
}
}
.grid-project-desc {
height: 44px;
overflow: hidden;
color: $sub-text-color;
line-height: 22px;
font-size: 14px;
}
.grid-project-content {
margin-top: 8px;
display: flex;
align-items: center;
justify-content: space-between;
.grid-project-time {
color: rgba($sub-text-color, 0.85);
}
}
}
.grid-nav {
display: grid;
padding: 20px;
row-gap: 20px;
grid-template-columns: repeat(4, 25%);
.grid-nav-item {
line-height: 24px;
}
.ui-button {
padding: 2px 8px;
}
}
.card-chart {
padding: 20px;
}
.grid-group {
display: grid;
padding: 20px;
row-gap: 20px;
grid-template-columns: repeat(2, 50%);
.grid-group-item {
display: flex;
align-items: center;
}
.grid-group-icon {
width: 24px;
height: auto;
}
.grid-group-name {
margin-left: 8px;
}
}
.list-dynamic {
padding: 8px 24px 8px 24px;
.list-dynamic-item {
padding: 16px 24px;
border-bottom: 1px solid #f0f0f0;
display: flex;
&:last-child {
border: 0;
}
.list-dynamic-logo {
margin-right: 16px;
width: 24px;
height: 24px;
}
.list-dynamic-content {
flex: 1;
.list-dynamic-desc {
margin-top: 4px;
color: $sub-text-color;
}
}
}
}
}
}
</style>

View File

@ -1,136 +0,0 @@
<template>
<div class="page">
<div class="page-header">
<div class="page-header-title">
基础表单
</div>
<div class="page-header-desc">
表单页用于向用户收集或验证信息基础表单常见于数据项较少的表单场景
</div>
</div>
<div class="page-body">
<Row>
<Cell offset="5" span="12">
<Wb-form ref="formValidate" :rule="ruleValidate" :label-width="150">
<Form-item label="是否需要标题:" prop="hasTitle">
<Radio-group v-model="form.hasTitle">
<Radio value="1">
</Radio>
<Radio value="2">
</Radio>
</Radio-group>
</Form-item>
<Form-item label="标题:" prop="title">
<wb-input v-model="form.title" placeholder="请输入标题"></wb-input>
</Form-item>
<Form-item label="城市:" prop="city">
<wb-select v-model="form.city" placeholder="请选择城市">
<wb-option :value="1">北京市</wb-option>
<wb-option :value="2">上海市</wb-option>
<wb-option :value="3">深圳市</wb-option>
<wb-option :value="4">杭州市</wb-option>
<wb-option :value="5">南京市</wb-option>
<wb-option :value="6">重庆市</wb-option>
</wb-select>
</Form-item>
<Form-item label="娱乐活动:" prop="active">
<Checkbox-group v-model="form.active">
<Checkbox value="1">
吃饭
</Checkbox>
<Checkbox value="2">
睡觉
</Checkbox>
<Checkbox value="3">
跑步
</Checkbox>
</Checkbox-group>
</Form-item>
<Form-item label="日期范围:" prop="date">
<Wb-input-date-picker v-model="form.date" model="range" />
</Form-item>
<Form-item label="目标描述:" prop="desc">
<wb-input v-model="form.desc" :autosize="true" type="textarea" placeholder="请输入目标描述"></wb-input>
</Form-item>
<Form-item :value="form.pics" label="图片上传" prop="pics">
<Upload :accept="accpetType" :action="handleUpload">
</Upload>
<div class="img-list">
<img v-for="(item, index) in form.pics" :key="index" :src="converToURL(item)" />
</div>
</Form-item>
<Form-item>
<Wb-button @click="click" type="primary">提交</Wb-button>
<Wb-button @click="reset" type="ghost" class="ml-8">重置</Wb-button>
</Form-item>
</Wb-form>
</Cell>
</Row>
</div>
</div>
</template>
<script>
export default {
FesData() {
const self = this;
return {
form: {
hasTitle: '',
title: '',
city: '',
active: [],
date: [],
desc: '',
pics: []
},
ruleValidate: {
hasTitle: [
{ required: true, message: '请选择是否需要标题' }
],
title: [
{ required: self.form && self.form.hasTitle === '1', message: '请输入标题' }
],
city: [
{ required: true, message: '请选择城市' }
],
active: [
{
required: true, message: '请至少选择一个活动', type: 'array', min: 1
}
],
pics: [
{
required: true, message: '请至少上传一张图片', type: 'array', min: 1
}
]
},
accpetType: ['jpg', 'png']
};
},
methods: {
click() {
this.$refs.formValidate.validate((valid, errors) => {
if (valid) {
console.log(this.form);
//
} else {
console.log(errors);
}
});
},
reset() {
this.$refs.formValidate.resetFields();
},
handleUpload(valid, formData) {
if (valid) {
this.form.pics.push(formData.get('upFiles'));
}
},
converToURL(item) {
return URL.createObjectURL(item);
}
}
};
</script>

View File

@ -1,139 +0,0 @@
<template>
<div class="page">
<div class="page-header">
<div class="page-header-title">分步表单</div>
<div class="page-header-desc">将一个冗长或用户不熟悉的表单任务分成多个步骤指导用户完成</div>
</div>
<div class="page-body">
<Steps :current="current" class="step">
<Step title="填写转账信息"></Step>
<Step title="确认转账信息"></Step>
<Step title="完成"></Step>
</Steps>
<Wb-form v-show="current === 1" class="step-form">
<Form-item label="付款账户:">
<wb-select v-model="form.payNo" placeholder="请选择付款账户">
<wb-option value="fes@alipay.com">fes@alipay.com</wb-option>
<wb-option value="fes@wepay.com">fes@wepay.com</wb-option>
</wb-select>
</Form-item>
<Form-item label="收款账户:">
<Wb-input v-model="form.accountNo" placeholder="请输入收款账户" />
</Form-item>
<Form-item label="收款人姓名:">
<Wb-input v-model="form.name" placeholder="请输入收款人姓名" />
</Form-item>
<Form-item label="转账金额:">
<Wb-input v-model="form.amount" placeholder="请输入转账金额">
</Wb-input>
</Form-item>
<Form-item>
<Wb-button @click="next" type="primary">提交</Wb-button>
</Form-item>
</Wb-form>
<Wb-form v-show="current === 2" class="step-form">
<Form-item label="付款账户:">
<span class="text">{{form.payNo}}</span>
</Form-item>
<Form-item label="收款账户:">
<span class="text">{{form.accountNo | card}}</span>
</Form-item>
<Form-item label="收款人姓名:">
<span class="text">{{form.name}}</span>
</Form-item>
<Form-item label="转账金额:">
<span class="text big">{{form.amount}}</span>
</Form-item>
<Form-item label="支付密码:" class="line">
<Wb-input v-model="form.password" type="password" placeholder="请输入支付密码" />
</Form-item>
<Form-item>
<Wb-button @click="next" type="primary">提交</Wb-button>
<Wb-button @click="last" class="ml-16" type="primary">上一步</Wb-button>
</Form-item>
</Wb-form>
<div v-show="current === 3" class="step-form">
<div class="result-icon">
<Process-circle :percent="100" stroke-color="#00cc66" stroke-type="round">
<Icon type="md-checkmark" size="50" color="#00cc66"></Icon>
</Process-circle>
</div>
<div class="result-title">操作成功</div>
<div class="result-subtitle">预计两小时内到账</div>
<div class="result-extra">
<Wb-button @click="reset" type="primary">再转一笔</Wb-button>
<Wb-button class="ml-16">查看账单</Wb-button>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
FesData() {
return {
current: 1,
form: {
payNo: 'fes@wepay.com',
accountNo: '622000011876188',
name: 'Hali',
amount: 500,
password: '11212'
}
};
},
methods: {
next() {
this.current += 1;
},
last() {
this.current -= 1;
},
reset() {
this.current = 1;
}
}
};
</script>
<style lang="scss" scoped>
@import "@/assets/styles/variables";
.step {
margin: 40px auto 0;
width: 800px;
transform: translateX(12%);
}
.step-form {
margin: 20px auto;
width: 500px;
.text {
line-height: 32px;
&.big {
font-size: 16px;
}
}
.line {
padding-top: 30px;
border-top: 1px solid $border-color-split;
}
.result-icon {
text-align: center;
margin-bottom: 24px;
}
.result-title {
color: $title-color;
font-size: $font-size-lg;
line-height: 1.8;
text-align: center;
}
.result-subtitle {
color: $sub-text-color;
font-size: $font-size-small;
line-height: 1.6;
text-align: center;
}
.result-extra{
margin: 24px 0 0 0;
text-align: center;
}
}
</style>

View File

@ -1,241 +1,18 @@
<template>
<div class="login-panel">
<div class="login-panel-swap">
<div class="login-project">
<div class="title">
<!-- <img class="logo" src="~@/assets/images/favicon.png" /> -->
<span class="text">Fes.js 运营平台</span>
</div>
<div class="desc">fes.js是一个优秀的中台应用前端解决方案</div>
</div>
<div class="login-form">
<div :class="{ focus: currentFoucs === 'userFocus' }" class="input-swap">
<Icon class="icon" type="md-person" />
<input
ref="username"
v-model="username"
@input="input"
@keydown.enter="login"
@focus="focusHandler('userFocus')"
@blur="blurHandler('userFocus')"
class="input"
type="text"
name="username"
autocomplete="off"
autofocus
placeholder="用户名: 符合邮箱规则即可"
/>
</div>
<div :class="{ focus: currentFoucs === 'passwordFocus' }" class="input-swap">
<Icon class="icon" type="md-eye-off" />
<input
ref="password"
v-model="password"
@input="input"
@keydown.enter="login"
@focus="focusHandler('passwordFocus')"
@blur="blurHandler('passwordFocus')"
class="input"
type="password"
name="password"
autocomplete="off"
placeholder="密码:任意"
/>
</div>
<div class="help">
<Checkbox value="1">
记住密码
</Checkbox>
<a>忘记密码</a>
</div>
<button @click="login" class="button">登录</button>
<div v-show="error" class="error">
<Icon type="md-warning" />
{{error}}
</div>
</div>
</div>
<div>
fes & 拉夫德鲁
</div>
</template>
<script>
import { ref } from 'vue';
export default {
FesLeft: false,
FesData() {
setup() {
const fes = ref('fes upgrade to vue3');
return {
currentFoucs: '',
username: '',
password: '',
error: '' // 8-16
fes
};
},
FesReady() {
this.$nextTick(() => {
this.$refs.username.focus();
this.currentFoucs = 'userFocus';
});
if (this.FesStorage.get('userLogin') === true) {
this.getRole();
}
},
methods: {
login() {
if (this.validate()) {
//
this.FesApp.set('FesUserName', 'harrywan');
this.FesApp.set('FesRoleName', '管理员');
this.FesStorage.set('userLogin', true);
this.getRole();
}
},
getRole() {
this.FesApp.setRole('admin');
},
input() {
this.error = '';
},
focusHandler(type) {
this.currentFoucs = type;
},
blurHandler() {
this.currentFoucs = '';
},
validate() {
const { username } = this;
const { password } = this;
if (username === '' || username == null) {
this.error = '请输入用户名';
return false;
}
if (
!/^[a-zA-Z0-9]+([._\\-]*[a-zA-Z0-9])*@([a-zA-Z0-9]+[-a-zA-Z0-9]*[a-zA-Z0-9]+.){1,63}[a-zA-Z0-9]+$/.test(
username
)
) {
this.error = '请输入正确邮箱账号';
return false;
}
if (password === '' || password == null) {
this.error = '请输入密码';
return false;
}
return true;
}
}
};
</script>
<style lang="scss">
@import "~@/assets/styles/variables";
.login-panel {
display: flex;
flex-direction: column;
height: 100vh;
overflow: auto;
background: #f0f2f5;
background-image: url("~@/assets/images/bg.png");
background-position: left bottom;
background-repeat: no-repeat;
background-size: 100% auto;
}
.login-panel .login-panel-swap {
width: 350px;
margin: auto;
text-align: center;
.login-project {
.title {
display: flex;
align-items: center;
justify-content: center;
font-weight: 600;
font-size: 33px;
color: $black-text-color;
.logo {
margin-right: 20px;
}
}
.desc {
margin-top: 12px;
margin-bottom: 40px;
color: $sub-text-color;
font-size: 14px;
}
}
.login-form {
height: 270px;
.input-swap {
position: relative;
display: flex;
align-items: center;
min-height: 32px;
padding: 6px 11px;
font-size: 14px;
border-radius: 2px;
border: 1px solid $border-color-base;
background: #ffffff;
transition: all 0.3s;
&:not(:first-child) {
margin-top: 12px;
}
&:hover,&.focus {
border-color: $link-hover-color;
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
}
.icon {
margin-right: 4px;
color: $primary-color;
}
.input {
padding: 0;
border: none;
outline: none;
box-sizing: border-box;
margin: 0;
padding: 0;
font-variant: tabular-nums;
list-style: none;
font-feature-settings: "tnum", "tnum";
position: relative;
width: 100%;
min-width: 0;
padding: 2px 11px;
color: rgba(0, 0, 0, 0.85);
font-size: 14px;
}
}
.button {
margin-top: 24px;
width: 100%;
border: 0;
outline: 0;
height: 40px;
line-height: 40px;
background: $primary-color;
color: #ffffff;
border-radius: 2px;
text-align: center;
font-size: 14px;
cursor: pointer;
transition: all 0.3s;
&:hover{
background: rgba($primary-color, 0.85);
}
}
.error {
margin-top: 10px;
width: 350px;
color: $error-color;
font-size: 14px;
text-align: left;
.ui-icon {
margin-right: 6px;
}
}
}
.help{
margin-top: 20px;
display: flex;
align-items: center;
justify-content: space-between;
}
}
</style>

View File

@ -1,48 +0,0 @@
<template>
<div class="article">
<h2>{{$t('overview')}}</h2>
<p>
{{$t('i18n.internationalization')}}<a target="_blank" href="https://kazupon.github.io/vue-i18n">
vue-i18n
</a>{{$t('i18n.achieve')}}
<Wb-select v-model="locale" @on-change="change" class="select">
<wb-option value="zh-cn">
zh-cn
</wb-option>
<wb-option value="en">
en
</wb-option>
</Wb-select>
</p>
<h2>{{$t('i18n.ui')}}</h2>
<Date-picker :value="value" />
</div>
</template>
<script type="text/ecmascript-6">
export default {
FesData() {
const local = this.FesApp.i18n.locale;
return {
locale: local,
value: +new Date()
};
},
FesReady() {
// do something
},
methods: {
change() {
this.FesApp.setLocale(this.locale);
}
}
};
</script>
<style>
.select{
width: 200px;
}
.article ul{
padding: 0;
}
</style>

View File

@ -1,17 +0,0 @@
<template>
<div class="page">
<div class="page-header">
<div class="page-header-title">公共路由</div>
</div>
<div class="page-body">
<router-view />
</div>
</div>
</template>
<script>
export default {
FesReady() {
// do something
}
};
</script>

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