mirror of
https://github.com/cloudreve/frontend.git
synced 2025-12-25 19:52:48 +00:00
init
This commit is contained in:
commit
a341a4558b
|
|
@ -0,0 +1,21 @@
|
|||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- '10.13.0'
|
||||
before_script: npm install
|
||||
script: npm run-script build
|
||||
after_success:
|
||||
- zip -r -q -o pack.zip ./build
|
||||
- curl -F "token=$TOKEN" -F "commit=$TRAVIS_COMMIT" -F "source=frontend" -F "filename=@pack.zip" -H "Expect:" http://cloudreve.org/deploy.php
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2018 AaronLiu
|
||||
|
||||
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.
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
cloudreve-frontend [](https://travis-ci.org/HFO4/cloudreve-frontend)
|
||||
=========================
|
||||
|
||||
Build:
|
||||
|
||||
```
|
||||
npm install
|
||||
npm run-script build
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const paths = require('./paths');
|
||||
|
||||
// Make sure that including paths.js after env.js will read .env variables.
|
||||
delete require.cache[require.resolve('./paths')];
|
||||
|
||||
const NODE_ENV = process.env.NODE_ENV;
|
||||
if (!NODE_ENV) {
|
||||
throw new Error(
|
||||
'The NODE_ENV environment variable is required but was not specified.'
|
||||
);
|
||||
}
|
||||
|
||||
// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
|
||||
var dotenvFiles = [
|
||||
`${paths.dotenv}.${NODE_ENV}.local`,
|
||||
`${paths.dotenv}.${NODE_ENV}`,
|
||||
// Don't include `.env.local` for `test` environment
|
||||
// since normally you expect tests to produce the same
|
||||
// results for everyone
|
||||
NODE_ENV !== 'test' && `${paths.dotenv}.local`,
|
||||
paths.dotenv,
|
||||
].filter(Boolean);
|
||||
|
||||
// Load environment variables from .env* files. Suppress warnings using silent
|
||||
// if this file is missing. dotenv will never modify any environment variables
|
||||
// that have already been set. Variable expansion is supported in .env files.
|
||||
// https://github.com/motdotla/dotenv
|
||||
// https://github.com/motdotla/dotenv-expand
|
||||
dotenvFiles.forEach(dotenvFile => {
|
||||
if (fs.existsSync(dotenvFile)) {
|
||||
require('dotenv-expand')(
|
||||
require('dotenv').config({
|
||||
path: dotenvFile,
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// We support resolving modules according to `NODE_PATH`.
|
||||
// This lets you use absolute paths in imports inside large monorepos:
|
||||
// https://github.com/facebook/create-react-app/issues/253.
|
||||
// It works similar to `NODE_PATH` in Node itself:
|
||||
// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
|
||||
// Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored.
|
||||
// Otherwise, we risk importing Node.js core modules into an app instead of Webpack shims.
|
||||
// https://github.com/facebook/create-react-app/issues/1023#issuecomment-265344421
|
||||
// We also resolve them to make sure all tools using them work consistently.
|
||||
const appDirectory = fs.realpathSync(process.cwd());
|
||||
process.env.NODE_PATH = (process.env.NODE_PATH || '')
|
||||
.split(path.delimiter)
|
||||
.filter(folder => folder && !path.isAbsolute(folder))
|
||||
.map(folder => path.resolve(appDirectory, folder))
|
||||
.join(path.delimiter);
|
||||
|
||||
// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
|
||||
// injected into the application via DefinePlugin in Webpack configuration.
|
||||
const REACT_APP = /^REACT_APP_/i;
|
||||
|
||||
function getClientEnvironment(publicUrl) {
|
||||
const raw = Object.keys(process.env)
|
||||
.filter(key => REACT_APP.test(key))
|
||||
.reduce(
|
||||
(env, key) => {
|
||||
env[key] = process.env[key];
|
||||
return env;
|
||||
},
|
||||
{
|
||||
// Useful for determining whether we’re running in production mode.
|
||||
// Most importantly, it switches React into the correct mode.
|
||||
NODE_ENV: process.env.NODE_ENV || 'development',
|
||||
// Useful for resolving the correct path to static assets in `public`.
|
||||
// For example, <img src={process.env.PUBLIC_URL + '/img/logo.png'} />.
|
||||
// This should only be used as an escape hatch. Normally you would put
|
||||
// images into the `src` and `import` them in code to get their paths.
|
||||
PUBLIC_URL: publicUrl,
|
||||
}
|
||||
);
|
||||
// Stringify all values so we can feed into Webpack DefinePlugin
|
||||
const stringified = {
|
||||
'process.env': Object.keys(raw).reduce((env, key) => {
|
||||
env[key] = JSON.stringify(raw[key]);
|
||||
return env;
|
||||
}, {}),
|
||||
};
|
||||
|
||||
return { raw, stringified };
|
||||
}
|
||||
|
||||
module.exports = getClientEnvironment;
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
'use strict';
|
||||
|
||||
// This is a custom Jest transformer turning style imports into empty objects.
|
||||
// http://facebook.github.io/jest/docs/en/webpack.html
|
||||
|
||||
module.exports = {
|
||||
process() {
|
||||
return 'module.exports = {};';
|
||||
},
|
||||
getCacheKey() {
|
||||
// The output is always the same.
|
||||
return 'cssTransform';
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
|
||||
// This is a custom Jest transformer turning file imports into filenames.
|
||||
// http://facebook.github.io/jest/docs/en/webpack.html
|
||||
|
||||
module.exports = {
|
||||
process(src, filename) {
|
||||
const assetFilename = JSON.stringify(path.basename(filename));
|
||||
|
||||
if (filename.match(/\.svg$/)) {
|
||||
return `module.exports = {
|
||||
__esModule: true,
|
||||
default: ${assetFilename},
|
||||
ReactComponent: (props) => ({
|
||||
$$typeof: Symbol.for('react.element'),
|
||||
type: 'svg',
|
||||
ref: null,
|
||||
key: null,
|
||||
props: Object.assign({}, props, {
|
||||
children: ${assetFilename}
|
||||
})
|
||||
}),
|
||||
};`;
|
||||
}
|
||||
|
||||
return `module.exports = ${assetFilename};`;
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const url = require('url');
|
||||
|
||||
// Make sure any symlinks in the project folder are resolved:
|
||||
// https://github.com/facebook/create-react-app/issues/637
|
||||
const appDirectory = fs.realpathSync(process.cwd());
|
||||
const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
|
||||
|
||||
const envPublicUrl = process.env.PUBLIC_URL;
|
||||
|
||||
function ensureSlash(inputPath, needsSlash) {
|
||||
const hasSlash = inputPath.endsWith('/');
|
||||
if (hasSlash && !needsSlash) {
|
||||
return inputPath.substr(0, inputPath.length - 1);
|
||||
} else if (!hasSlash && needsSlash) {
|
||||
return `${inputPath}/`;
|
||||
} else {
|
||||
return inputPath;
|
||||
}
|
||||
}
|
||||
|
||||
const getPublicUrl = appPackageJson =>
|
||||
envPublicUrl || require(appPackageJson).homepage;
|
||||
|
||||
// We use `PUBLIC_URL` environment variable or "homepage" field to infer
|
||||
// "public path" at which the app is served.
|
||||
// Webpack needs to know it to put the right <script> hrefs into HTML even in
|
||||
// single-page apps that may serve index.html for nested URLs like /todos/42.
|
||||
// We can't use a relative path in HTML because we don't want to load something
|
||||
// like /todos/42/static/js/bundle.7289d.js. We have to know the root.
|
||||
function getServedPath(appPackageJson) {
|
||||
const publicUrl = getPublicUrl(appPackageJson);
|
||||
const servedUrl =
|
||||
envPublicUrl || (publicUrl ? url.parse(publicUrl).pathname : '/');
|
||||
return ensureSlash(servedUrl, true);
|
||||
}
|
||||
|
||||
// config after eject: we're in ./config/
|
||||
module.exports = {
|
||||
dotenv: resolveApp('.env'),
|
||||
appPath: resolveApp('.'),
|
||||
appBuild: resolveApp('build'),
|
||||
appPublic: resolveApp('public'),
|
||||
appHtml: resolveApp('public/index.html'),
|
||||
appIndexJs: resolveApp('src/index.js'),
|
||||
appPackageJson: resolveApp('package.json'),
|
||||
appSrc: resolveApp('src'),
|
||||
yarnLockFile: resolveApp('yarn.lock'),
|
||||
testsSetup: resolveApp('src/setupTests.js'),
|
||||
proxySetup: resolveApp('src/setupProxy.js'),
|
||||
appNodeModules: resolveApp('node_modules'),
|
||||
publicUrl: getPublicUrl(resolveApp('package.json')),
|
||||
servedPath: getServedPath(resolveApp('package.json')),
|
||||
};
|
||||
|
|
@ -0,0 +1,463 @@
|
|||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const PnpWebpackPlugin = require('pnp-webpack-plugin');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
|
||||
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
|
||||
const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin');
|
||||
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
|
||||
const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent');
|
||||
const getClientEnvironment = require('./env');
|
||||
const paths = require('./paths');
|
||||
const ManifestPlugin = require('webpack-manifest-plugin');
|
||||
const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin');
|
||||
|
||||
|
||||
// Webpack uses `publicPath` to determine where the app is being served from.
|
||||
// In development, we always serve from the root. This makes config easier.
|
||||
const publicPath = '/';
|
||||
// `publicUrl` is just like `publicPath`, but we will provide it to our app
|
||||
// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
|
||||
// Omit trailing slash as %PUBLIC_PATH%/xyz looks better than %PUBLIC_PATH%xyz.
|
||||
const publicUrl = '';
|
||||
// Get environment variables to inject into our app.
|
||||
const env = getClientEnvironment(publicUrl);
|
||||
|
||||
// style files regexes
|
||||
const cssRegex = /\.css$/;
|
||||
const cssModuleRegex = /\.module\.css$/;
|
||||
const sassRegex = /\.(scss|sass)$/;
|
||||
const sassModuleRegex = /\.module\.(scss|sass)$/;
|
||||
|
||||
// common function to get style loaders
|
||||
const getStyleLoaders = (cssOptions, preProcessor) => {
|
||||
const loaders = [
|
||||
require.resolve('style-loader'),
|
||||
{
|
||||
loader: require.resolve('css-loader'),
|
||||
options: cssOptions,
|
||||
},
|
||||
{
|
||||
// Options for PostCSS as we reference these options twice
|
||||
// Adds vendor prefixing based on your specified browser support in
|
||||
// package.json
|
||||
loader: require.resolve('postcss-loader'),
|
||||
options: {
|
||||
// Necessary for external CSS imports to work
|
||||
// https://github.com/facebook/create-react-app/issues/2677
|
||||
ident: 'postcss',
|
||||
plugins: () => [
|
||||
require('postcss-flexbugs-fixes'),
|
||||
require('postcss-preset-env')({
|
||||
autoprefixer: {
|
||||
flexbox: 'no-2009',
|
||||
},
|
||||
stage: 3,
|
||||
}),
|
||||
],
|
||||
},
|
||||
},
|
||||
];
|
||||
if (preProcessor) {
|
||||
loaders.push(require.resolve(preProcessor));
|
||||
}
|
||||
return loaders;
|
||||
};
|
||||
|
||||
// This is the development configuration.
|
||||
// It is focused on developer experience and fast rebuilds.
|
||||
// The production configuration is different and lives in a separate file.
|
||||
module.exports = {
|
||||
mode: 'development',
|
||||
// You may want 'eval' instead if you prefer to see the compiled output in DevTools.
|
||||
// See the discussion in https://github.com/facebook/create-react-app/issues/343
|
||||
devtool: 'cheap-module-source-map',
|
||||
// These are the "entry points" to our application.
|
||||
// This means they will be the "root" imports that are included in JS bundle.
|
||||
entry: {
|
||||
// Include an alternative client for WebpackDevServer. A client's job is to
|
||||
// connect to WebpackDevServer by a socket and get notified about changes.
|
||||
// When you save a file, the client will either apply hot updates (in case
|
||||
// of CSS changes), or refresh the page (in case of JS changes). When you
|
||||
// make a syntax error, this client will display a syntax error overlay.
|
||||
// Note: instead of the default WebpackDevServer client, we use a custom one
|
||||
// to bring better experience for Create React App users. You can replace
|
||||
// the line below with these two lines if you prefer the stock client:
|
||||
// require.resolve('webpack-dev-server/client') + '?/',
|
||||
// require.resolve('webpack/hot/dev-server'),
|
||||
hot:require.resolve('react-dev-utils/webpackHotDevClient'),
|
||||
// Finally, this is your app's code:
|
||||
index:paths.appIndexJs,
|
||||
video:'./src/pages/video.js',
|
||||
markdown:'./src/pages/markdown.js',
|
||||
folderShare:'./src/pages/folderShare.js',
|
||||
lock:'./src/pages/lock.js',
|
||||
fileShare:'./src/pages/fileShare.js',
|
||||
setting:'./src/pages/setting.js',
|
||||
profile:'./src/pages/profile.js',
|
||||
myShare:'./src/pages/myShare.js',
|
||||
search:'./src/pages/search.js',
|
||||
download:'./src/pages/download.js',
|
||||
login:'./src/pages/login.js',
|
||||
// We include the app code last so that if there is a runtime error during
|
||||
// initialization, it doesn't blow up the WebpackDevServer client, and
|
||||
// changing JS code would still trigger a refresh.
|
||||
},
|
||||
output: {
|
||||
// Add /* filename */ comments to generated require()s in the output.
|
||||
pathinfo: true,
|
||||
// This does not produce a real file. It's just the virtual path that is
|
||||
// served by WebpackDevServer in development. This is the JS bundle
|
||||
// containing code from all our entry points, and the Webpack runtime.
|
||||
filename: 'static/js/[name].bundle.js',
|
||||
// There are also additional JS chunk files if you use code splitting.
|
||||
chunkFilename: 'static/js/[name].chunk.js',
|
||||
// This is the URL that app is served from. We use "/" in development.
|
||||
publicPath: publicPath,
|
||||
// Point sourcemap entries to original disk location (format as URL on Windows)
|
||||
devtoolModuleFilenameTemplate: info =>
|
||||
path.resolve(info.absoluteResourcePath).replace(/\\/g, '/'),
|
||||
},
|
||||
optimization: {
|
||||
// Automatically split vendor and commons
|
||||
// https://twitter.com/wSokra/status/969633336732905474
|
||||
// https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366
|
||||
splitChunks: {
|
||||
chunks: 'all',
|
||||
name: false,
|
||||
},
|
||||
// Keep the runtime chunk seperated to enable long term caching
|
||||
// https://twitter.com/wSokra/status/969679223278505985
|
||||
runtimeChunk: true,
|
||||
},
|
||||
resolve: {
|
||||
// This allows you to set a fallback for where Webpack should look for modules.
|
||||
// We placed these paths second because we want `node_modules` to "win"
|
||||
// if there are any conflicts. This matches Node resolution mechanism.
|
||||
// https://github.com/facebook/create-react-app/issues/253
|
||||
modules: ['node_modules'].concat(
|
||||
// It is guaranteed to exist because we tweak it in `env.js`
|
||||
process.env.NODE_PATH.split(path.delimiter).filter(Boolean)
|
||||
),
|
||||
// These are the reasonable defaults supported by the Node ecosystem.
|
||||
// We also include JSX as a common component filename extension to support
|
||||
// some tools, although we do not recommend using it, see:
|
||||
// https://github.com/facebook/create-react-app/issues/290
|
||||
// `web` extension prefixes have been added for better support
|
||||
// for React Native Web.
|
||||
extensions: ['.mjs', '.web.js', '.js', '.json', '.web.jsx', '.jsx'],
|
||||
alias: {
|
||||
// Support React Native Web
|
||||
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
|
||||
'react-native': 'react-native-web',
|
||||
},
|
||||
plugins: [
|
||||
// Adds support for installing with Plug'n'Play, leading to faster installs and adding
|
||||
// guards against forgotten dependencies and such.
|
||||
PnpWebpackPlugin,
|
||||
// Prevents users from importing files from outside of src/ (or node_modules/).
|
||||
// This often causes confusion because we only process files within src/ with babel.
|
||||
// To fix this, we prevent you from importing files out of src/ -- if you'd like to,
|
||||
// please link the files into your node_modules/ and let module-resolution kick in.
|
||||
// Make sure your source files are compiled, as they will not be processed in any way.
|
||||
new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson]),
|
||||
],
|
||||
},
|
||||
resolveLoader: {
|
||||
plugins: [
|
||||
// Also related to Plug'n'Play, but this time it tells Webpack to load its loaders
|
||||
// from the current package.
|
||||
PnpWebpackPlugin.moduleLoader(module),
|
||||
],
|
||||
},
|
||||
module: {
|
||||
strictExportPresence: true,
|
||||
rules: [
|
||||
// Disable require.ensure as it's not a standard language feature.
|
||||
{ parser: { requireEnsure: false } },
|
||||
|
||||
// First, run the linter.
|
||||
// It's important to do this before Babel processes the JS.
|
||||
{
|
||||
test: /\.(js|mjs|jsx)$/,
|
||||
enforce: 'pre',
|
||||
use: [
|
||||
{
|
||||
options: {
|
||||
formatter: require.resolve('react-dev-utils/eslintFormatter'),
|
||||
eslintPath: require.resolve('eslint'),
|
||||
|
||||
},
|
||||
loader: require.resolve('eslint-loader'),
|
||||
},
|
||||
],
|
||||
include: paths.appSrc,
|
||||
},
|
||||
{
|
||||
// "oneOf" will traverse all following loaders until one will
|
||||
// match the requirements. When no loader matches it will fall
|
||||
// back to the "file" loader at the end of the loader list.
|
||||
oneOf: [
|
||||
// "url" loader works like "file" loader except that it embeds assets
|
||||
// smaller than specified limit in bytes as data URLs to avoid requests.
|
||||
// A missing `test` is equivalent to a match.
|
||||
{
|
||||
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
|
||||
loader: require.resolve('url-loader'),
|
||||
options: {
|
||||
limit: 10000,
|
||||
name: 'static/media/[name].[hash:8].[ext]',
|
||||
},
|
||||
},
|
||||
// Process application JS with Babel.
|
||||
// The preset includes JSX, Flow, and some ESnext features.
|
||||
{
|
||||
test: /\.(js|mjs|jsx)$/,
|
||||
include: paths.appSrc,
|
||||
loader: require.resolve('babel-loader'),
|
||||
options: {
|
||||
customize: require.resolve(
|
||||
'babel-preset-react-app/webpack-overrides'
|
||||
),
|
||||
|
||||
plugins: [
|
||||
[
|
||||
require.resolve('babel-plugin-named-asset-import'),
|
||||
{
|
||||
loaderMap: {
|
||||
svg: {
|
||||
ReactComponent: '@svgr/webpack?-prettier,-svgo![path]',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
// This is a feature of `babel-loader` for webpack (not Babel itself).
|
||||
// It enables caching results in ./node_modules/.cache/babel-loader/
|
||||
// directory for faster rebuilds.
|
||||
cacheDirectory: true,
|
||||
// Don't waste time on Gzipping the cache
|
||||
cacheCompression: false,
|
||||
},
|
||||
},
|
||||
// Process any JS outside of the app with Babel.
|
||||
// Unlike the application JS, we only compile the standard ES features.
|
||||
{
|
||||
test: /\.(js|mjs)$/,
|
||||
exclude: /@babel(?:\/|\\{1,2})runtime/,
|
||||
loader: require.resolve('babel-loader'),
|
||||
options: {
|
||||
babelrc: false,
|
||||
configFile: false,
|
||||
compact: false,
|
||||
presets: [
|
||||
[
|
||||
require.resolve('babel-preset-react-app/dependencies'),
|
||||
{ helpers: true },
|
||||
],
|
||||
],
|
||||
cacheDirectory: true,
|
||||
// Don't waste time on Gzipping the cache
|
||||
cacheCompression: false,
|
||||
|
||||
// If an error happens in a package, it's possible to be
|
||||
// because it was compiled. Thus, we don't want the browser
|
||||
// debugger to show the original code. Instead, the code
|
||||
// being evaluated would be much more helpful.
|
||||
sourceMaps: false,
|
||||
},
|
||||
},
|
||||
// "postcss" loader applies autoprefixer to our CSS.
|
||||
// "css" loader resolves paths in CSS and adds assets as dependencies.
|
||||
// "style" loader turns CSS into JS modules that inject <style> tags.
|
||||
// In production, we use a plugin to extract that CSS to a file, but
|
||||
// in development "style" loader enables hot editing of CSS.
|
||||
// By default we support CSS Modules with the extension .module.css
|
||||
{
|
||||
test: cssRegex,
|
||||
exclude: cssModuleRegex,
|
||||
use: getStyleLoaders({
|
||||
importLoaders: 1,
|
||||
}),
|
||||
},
|
||||
// Adds support for CSS Modules (https://github.com/css-modules/css-modules)
|
||||
// using the extension .module.css
|
||||
{
|
||||
test: cssModuleRegex,
|
||||
use: getStyleLoaders({
|
||||
importLoaders: 1,
|
||||
modules: true,
|
||||
getLocalIdent: getCSSModuleLocalIdent,
|
||||
}),
|
||||
},
|
||||
// Opt-in support for SASS (using .scss or .sass extensions).
|
||||
// Chains the sass-loader with the css-loader and the style-loader
|
||||
// to immediately apply all styles to the DOM.
|
||||
// By default we support SASS Modules with the
|
||||
// extensions .module.scss or .module.sass
|
||||
{
|
||||
test: sassRegex,
|
||||
exclude: sassModuleRegex,
|
||||
use: getStyleLoaders({ importLoaders: 2 }, 'sass-loader'),
|
||||
},
|
||||
// Adds support for CSS Modules, but using SASS
|
||||
// using the extension .module.scss or .module.sass
|
||||
{
|
||||
test: sassModuleRegex,
|
||||
use: getStyleLoaders(
|
||||
{
|
||||
importLoaders: 2,
|
||||
modules: true,
|
||||
getLocalIdent: getCSSModuleLocalIdent,
|
||||
},
|
||||
'sass-loader'
|
||||
),
|
||||
},
|
||||
// "file" loader makes sure those assets get served by WebpackDevServer.
|
||||
// When you `import` an asset, you get its (virtual) filename.
|
||||
// In production, they would get copied to the `build` folder.
|
||||
// This loader doesn't use a "test" so it will catch all modules
|
||||
// that fall through the other loaders.
|
||||
{
|
||||
// Exclude `js` files to keep "css" loader working as it injects
|
||||
// its runtime that would otherwise be processed through "file" loader.
|
||||
// Also exclude `html` and `json` extensions so they get processed
|
||||
// by webpacks internal loaders.
|
||||
exclude: [/\.(js|mjs|jsx)$/, /\.html$/, /\.json$/],
|
||||
loader: require.resolve('file-loader'),
|
||||
options: {
|
||||
name: 'static/media/[name].[hash:8].[ext]',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
// ** STOP ** Are you adding a new loader?
|
||||
// Make sure to add the new loader(s) before the "file" loader.
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
// Generates an `index.html` file with the <script> injected.
|
||||
new HtmlWebpackPlugin({
|
||||
inject: true,
|
||||
filename:"index.html",
|
||||
chunks:['index'],
|
||||
template: paths.appHtml,
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
inject: true,
|
||||
chunks:['video'],
|
||||
filename:"video.html",
|
||||
template: './public/video.html',
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
inject: true,
|
||||
chunks:['markdown'],
|
||||
filename:"markdown.html",
|
||||
template: './public/markdown.html',
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
inject: true,
|
||||
chunks:['folderShare'],
|
||||
filename:"folderShare.html",
|
||||
template: './public/folderShare.html',
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
inject: true,
|
||||
chunks:['fileShare'],
|
||||
filename:"fileShare.html",
|
||||
template: './public/fileShare.html',
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
inject: true,
|
||||
chunks:['lock'],
|
||||
filename:"lock.html",
|
||||
template: './public/lock.html',
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
inject: true,
|
||||
chunks:['setting'],
|
||||
filename:"setting.html",
|
||||
template: './public/setting.html',
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
inject: true,
|
||||
chunks:['profile'],
|
||||
filename:"profile.html",
|
||||
template: './public/profile.html',
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
inject: true,
|
||||
chunks:['myShare'],
|
||||
filename:"myShare.html",
|
||||
template: './public/myShare.html',
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
inject: true,
|
||||
chunks:['search'],
|
||||
filename:"search.html",
|
||||
template: './public/explore/result.html',
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
inject: true,
|
||||
chunks:['download'],
|
||||
filename:"download.html",
|
||||
template: './public/home/download.html',
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
inject: true,
|
||||
chunks:['login'],
|
||||
filename:"login.html",
|
||||
template: './public/member/login.html',
|
||||
}),
|
||||
// Makes some environment variables available in index.html.
|
||||
// The public URL is available as %PUBLIC_URL% in index.html, e.g.:
|
||||
// <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
// In development, this will be an empty string.
|
||||
new InterpolateHtmlPlugin(HtmlWebpackPlugin, env.raw),
|
||||
// This gives some necessary context to module not found errors, such as
|
||||
// the requesting resource.
|
||||
new ModuleNotFoundPlugin(paths.appPath),
|
||||
// Makes some environment variables available to the JS code, for example:
|
||||
// if (process.env.NODE_ENV === 'development') { ... }. See `./env.js`.
|
||||
new webpack.DefinePlugin(env.stringified),
|
||||
// This is necessary to emit hot updates (currently CSS only):
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
// Watcher doesn't work well if you mistype casing in a path so we use
|
||||
// a plugin that prints an error when you attempt to do this.
|
||||
// See https://github.com/facebook/create-react-app/issues/240
|
||||
new CaseSensitivePathsPlugin(),
|
||||
// If you require a missing module and then `npm install` it, you still have
|
||||
// to restart the development server for Webpack to discover it. This plugin
|
||||
// makes the discovery automatic so you don't have to restart.
|
||||
// See https://github.com/facebook/create-react-app/issues/186
|
||||
new WatchMissingNodeModulesPlugin(paths.appNodeModules),
|
||||
// Moment.js is an extremely popular library that bundles large locale files
|
||||
// by default due to how Webpack interprets its code. This is a practical
|
||||
// solution that requires the user to opt into importing specific locales.
|
||||
// https://github.com/jmblog/how-to-optimize-momentjs-with-webpack
|
||||
// You can remove this if you don't use Moment.js:
|
||||
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
|
||||
// Generate a manifest file which contains a mapping of all asset filenames
|
||||
// to their corresponding output file so that tools can pick it up without
|
||||
// having to parse `index.html`.
|
||||
new ManifestPlugin({
|
||||
fileName: 'asset-manifest.json',
|
||||
publicPath: publicPath,
|
||||
}),
|
||||
],
|
||||
|
||||
// Some libraries import Node modules but don't use them in the browser.
|
||||
// Tell Webpack to provide empty mocks for them so importing them works.
|
||||
node: {
|
||||
dgram: 'empty',
|
||||
fs: 'empty',
|
||||
net: 'empty',
|
||||
tls: 'empty',
|
||||
child_process: 'empty',
|
||||
},
|
||||
// Turn off performance processing because we utilize
|
||||
// our own hints via the FileSizeReporter
|
||||
performance: false,
|
||||
};
|
||||
|
|
@ -0,0 +1,714 @@
|
|||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const PnpWebpackPlugin = require('pnp-webpack-plugin');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin');
|
||||
const TerserPlugin = require('terser-webpack-plugin');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
|
||||
const safePostCssParser = require('postcss-safe-parser');
|
||||
const ManifestPlugin = require('webpack-manifest-plugin');
|
||||
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
|
||||
const WorkboxWebpackPlugin = require('workbox-webpack-plugin');
|
||||
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
|
||||
const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent');
|
||||
const paths = require('./paths');
|
||||
const getClientEnvironment = require('./env');
|
||||
const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin');
|
||||
|
||||
|
||||
// Webpack uses `publicPath` to determine where the app is being served from.
|
||||
// It requires a trailing slash, or the file assets will get an incorrect path.
|
||||
const publicPath = paths.servedPath;
|
||||
// Some apps do not use client-side routing with pushState.
|
||||
// For these, "homepage" can be set to "." to enable relative asset paths.
|
||||
const shouldUseRelativeAssetPaths = publicPath === './';
|
||||
// Source maps are resource heavy and can cause out of memory issue for large source files.
|
||||
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';
|
||||
// Some apps do not need the benefits of saving a web request, so not inlining the chunk
|
||||
// makes for a smoother build process.
|
||||
const shouldInlineRuntimeChunk = process.env.INLINE_RUNTIME_CHUNK !== 'false';
|
||||
// `publicUrl` is just like `publicPath`, but we will provide it to our app
|
||||
// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
|
||||
// Omit trailing slash as %PUBLIC_URL%/xyz looks better than %PUBLIC_URL%xyz.
|
||||
const publicUrl = publicPath.slice(0, -1);
|
||||
// Get environment variables to inject into our app.
|
||||
const env = getClientEnvironment(publicUrl);
|
||||
|
||||
// Assert this just to be safe.
|
||||
// Development builds of React are slow and not intended for production.
|
||||
if (env.stringified['process.env'].NODE_ENV !== '"production"') {
|
||||
throw new Error('Production builds must have NODE_ENV=production.');
|
||||
}
|
||||
|
||||
// style files regexes
|
||||
const cssRegex = /\.css$/;
|
||||
const cssModuleRegex = /\.module\.css$/;
|
||||
const sassRegex = /\.(scss|sass)$/;
|
||||
const sassModuleRegex = /\.module\.(scss|sass)$/;
|
||||
|
||||
// common function to get style loaders
|
||||
const getStyleLoaders = (cssOptions, preProcessor) => {
|
||||
const loaders = [
|
||||
{
|
||||
loader: MiniCssExtractPlugin.loader,
|
||||
options: Object.assign(
|
||||
{},
|
||||
shouldUseRelativeAssetPaths ? { publicPath: '../../' } : undefined
|
||||
),
|
||||
},
|
||||
{
|
||||
loader: require.resolve('css-loader'),
|
||||
options: cssOptions,
|
||||
},
|
||||
{
|
||||
// Options for PostCSS as we reference these options twice
|
||||
// Adds vendor prefixing based on your specified browser support in
|
||||
// package.json
|
||||
loader: require.resolve('postcss-loader'),
|
||||
options: {
|
||||
// Necessary for external CSS imports to work
|
||||
// https://github.com/facebook/create-react-app/issues/2677
|
||||
ident: 'postcss',
|
||||
plugins: () => [
|
||||
require('postcss-flexbugs-fixes'),
|
||||
require('postcss-preset-env')({
|
||||
autoprefixer: {
|
||||
flexbox: 'no-2009',
|
||||
},
|
||||
stage: 3,
|
||||
}),
|
||||
],
|
||||
sourceMap: shouldUseSourceMap,
|
||||
},
|
||||
},
|
||||
];
|
||||
if (preProcessor) {
|
||||
loaders.push({
|
||||
loader: require.resolve(preProcessor),
|
||||
options: {
|
||||
sourceMap: shouldUseSourceMap,
|
||||
},
|
||||
});
|
||||
}
|
||||
return loaders;
|
||||
};
|
||||
|
||||
// This is the production configuration.
|
||||
// It compiles slowly and is focused on producing a fast and minimal bundle.
|
||||
// The development configuration is different and lives in a separate file.
|
||||
module.exports = {
|
||||
mode: 'production',
|
||||
// Don't attempt to continue if there are any errors.
|
||||
bail: true,
|
||||
// We generate sourcemaps in production. This is slow but gives good results.
|
||||
// You can exclude the *.map files from the build during deployment.
|
||||
devtool: shouldUseSourceMap ? 'source-map' : false,
|
||||
// In production, we only want to load the app code.
|
||||
entry: {
|
||||
index:paths.appIndexJs,
|
||||
download:'./src/pages/download.js',
|
||||
search:'./src/pages/search.js',
|
||||
login:'./src/pages/login.js',
|
||||
video:'./src/pages/video.js',
|
||||
markdown:'./src/pages/markdown.js',
|
||||
profile:'./src/pages/profile.js',
|
||||
setting:'./src/pages/setting.js',
|
||||
folderShare:'./src/pages/folderShare.js',
|
||||
lock:'./src/pages/lock.js',
|
||||
fileShare:'./src/pages/fileShare.js',
|
||||
myShare:'./src/pages/myShare.js',
|
||||
},
|
||||
output: {
|
||||
// The build folder.
|
||||
path: paths.appBuild,
|
||||
// Generated JS file names (with nested folders).
|
||||
// There will be one main bundle, and one file per asynchronous chunk.
|
||||
// We don't currently advertise code splitting but Webpack supports it.
|
||||
filename: 'static/js/[name].js',
|
||||
chunkFilename: 'static/js/[name].chunk.js',
|
||||
// We inferred the "public path" (such as / or /my-project) from homepage.
|
||||
publicPath: publicPath,
|
||||
// Point sourcemap entries to original disk location (format as URL on Windows)
|
||||
devtoolModuleFilenameTemplate: info =>
|
||||
path
|
||||
.relative(paths.appSrc, info.absoluteResourcePath)
|
||||
.replace(/\\/g, '/'),
|
||||
},
|
||||
optimization: {
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
terserOptions: {
|
||||
parse: {
|
||||
// we want terser to parse ecma 8 code. However, we don't want it
|
||||
// to apply any minfication steps that turns valid ecma 5 code
|
||||
// into invalid ecma 5 code. This is why the 'compress' and 'output'
|
||||
// sections only apply transformations that are ecma 5 safe
|
||||
// https://github.com/facebook/create-react-app/pull/4234
|
||||
ecma: 8,
|
||||
},
|
||||
compress: {
|
||||
ecma: 5,
|
||||
warnings: false,
|
||||
// Disabled because of an issue with Uglify breaking seemingly valid code:
|
||||
// https://github.com/facebook/create-react-app/issues/2376
|
||||
// Pending further investigation:
|
||||
// https://github.com/mishoo/UglifyJS2/issues/2011
|
||||
comparisons: false,
|
||||
// Disabled because of an issue with Terser breaking valid code:
|
||||
// https://github.com/facebook/create-react-app/issues/5250
|
||||
// Pending futher investigation:
|
||||
// https://github.com/terser-js/terser/issues/120
|
||||
inline: 2,
|
||||
},
|
||||
mangle: {
|
||||
safari10: true,
|
||||
},
|
||||
output: {
|
||||
ecma: 5,
|
||||
comments: false,
|
||||
// Turned on because emoji and regex is not minified properly using default
|
||||
// https://github.com/facebook/create-react-app/issues/2488
|
||||
ascii_only: true,
|
||||
},
|
||||
},
|
||||
// Use multi-process parallel running to improve the build speed
|
||||
// Default number of concurrent runs: os.cpus().length - 1
|
||||
parallel: true,
|
||||
// Enable file caching
|
||||
cache: true,
|
||||
sourceMap: shouldUseSourceMap,
|
||||
}),
|
||||
new OptimizeCSSAssetsPlugin({
|
||||
cssProcessorOptions: {
|
||||
parser: safePostCssParser,
|
||||
map: shouldUseSourceMap
|
||||
? {
|
||||
// `inline: false` forces the sourcemap to be output into a
|
||||
// separate file
|
||||
inline: false,
|
||||
// `annotation: true` appends the sourceMappingURL to the end of
|
||||
// the css file, helping the browser find the sourcemap
|
||||
annotation: true,
|
||||
}
|
||||
: false,
|
||||
},
|
||||
}),
|
||||
],
|
||||
// Automatically split vendor and commons
|
||||
// https://twitter.com/wSokra/status/969633336732905474
|
||||
// https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366
|
||||
splitChunks: {
|
||||
chunks: 'all',
|
||||
name: false,
|
||||
},
|
||||
// Keep the runtime chunk seperated to enable long term caching
|
||||
// https://twitter.com/wSokra/status/969679223278505985
|
||||
runtimeChunk: true,
|
||||
},
|
||||
resolve: {
|
||||
// This allows you to set a fallback for where Webpack should look for modules.
|
||||
// We placed these paths second because we want `node_modules` to "win"
|
||||
// if there are any conflicts. This matches Node resolution mechanism.
|
||||
// https://github.com/facebook/create-react-app/issues/253
|
||||
modules: ['node_modules'].concat(
|
||||
// It is guaranteed to exist because we tweak it in `env.js`
|
||||
process.env.NODE_PATH.split(path.delimiter).filter(Boolean)
|
||||
),
|
||||
// These are the reasonable defaults supported by the Node ecosystem.
|
||||
// We also include JSX as a common component filename extension to support
|
||||
// some tools, although we do not recommend using it, see:
|
||||
// https://github.com/facebook/create-react-app/issues/290
|
||||
// `web` extension prefixes have been added for better support
|
||||
// for React Native Web.
|
||||
extensions: ['.mjs', '.web.js', '.js', '.json', '.web.jsx', '.jsx'],
|
||||
alias: {
|
||||
// Support React Native Web
|
||||
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
|
||||
'react-native': 'react-native-web',
|
||||
},
|
||||
plugins: [
|
||||
// Adds support for installing with Plug'n'Play, leading to faster installs and adding
|
||||
// guards against forgotten dependencies and such.
|
||||
PnpWebpackPlugin,
|
||||
// Prevents users from importing files from outside of src/ (or node_modules/).
|
||||
// This often causes confusion because we only process files within src/ with babel.
|
||||
// To fix this, we prevent you from importing files out of src/ -- if you'd like to,
|
||||
// please link the files into your node_modules/ and let module-resolution kick in.
|
||||
// Make sure your source files are compiled, as they will not be processed in any way.
|
||||
new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson]),
|
||||
],
|
||||
},
|
||||
resolveLoader: {
|
||||
plugins: [
|
||||
// Also related to Plug'n'Play, but this time it tells Webpack to load its loaders
|
||||
// from the current package.
|
||||
PnpWebpackPlugin.moduleLoader(module),
|
||||
],
|
||||
},
|
||||
module: {
|
||||
strictExportPresence: true,
|
||||
rules: [
|
||||
// Disable require.ensure as it's not a standard language feature.
|
||||
{ parser: { requireEnsure: false } },
|
||||
|
||||
// First, run the linter.
|
||||
// It's important to do this before Babel processes the JS.
|
||||
{
|
||||
test: /\.(js|mjs|jsx)$/,
|
||||
enforce: 'pre',
|
||||
use: [
|
||||
{
|
||||
options: {
|
||||
formatter: require.resolve('react-dev-utils/eslintFormatter'),
|
||||
eslintPath: require.resolve('eslint'),
|
||||
|
||||
},
|
||||
loader: require.resolve('eslint-loader'),
|
||||
},
|
||||
],
|
||||
include: paths.appSrc,
|
||||
},
|
||||
{
|
||||
// "oneOf" will traverse all following loaders until one will
|
||||
// match the requirements. When no loader matches it will fall
|
||||
// back to the "file" loader at the end of the loader list.
|
||||
oneOf: [
|
||||
// "url" loader works just like "file" loader but it also embeds
|
||||
// assets smaller than specified size as data URLs to avoid requests.
|
||||
{
|
||||
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
|
||||
loader: require.resolve('url-loader'),
|
||||
options: {
|
||||
limit: 10000,
|
||||
name: 'static/media/[name].[hash:8].[ext]',
|
||||
},
|
||||
},
|
||||
// Process application JS with Babel.
|
||||
// The preset includes JSX, Flow, and some ESnext features.
|
||||
{
|
||||
test: /\.(js|mjs|jsx)$/,
|
||||
include: paths.appSrc,
|
||||
|
||||
loader: require.resolve('babel-loader'),
|
||||
options: {
|
||||
customize: require.resolve(
|
||||
'babel-preset-react-app/webpack-overrides'
|
||||
),
|
||||
|
||||
plugins: [
|
||||
[
|
||||
require.resolve('babel-plugin-named-asset-import'),
|
||||
{
|
||||
loaderMap: {
|
||||
svg: {
|
||||
ReactComponent: '@svgr/webpack?-prettier,-svgo![path]',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
cacheDirectory: true,
|
||||
// Save disk space when time isn't as important
|
||||
cacheCompression: true,
|
||||
compact: true,
|
||||
},
|
||||
},
|
||||
// Process any JS outside of the app with Babel.
|
||||
// Unlike the application JS, we only compile the standard ES features.
|
||||
{
|
||||
test: /\.(js|mjs)$/,
|
||||
exclude: /@babel(?:\/|\\{1,2})runtime/,
|
||||
loader: require.resolve('babel-loader'),
|
||||
options: {
|
||||
babelrc: false,
|
||||
configFile: false,
|
||||
compact: false,
|
||||
presets: [
|
||||
[
|
||||
require.resolve('babel-preset-react-app/dependencies'),
|
||||
{ helpers: true },
|
||||
],
|
||||
],
|
||||
cacheDirectory: true,
|
||||
// Save disk space when time isn't as important
|
||||
cacheCompression: true,
|
||||
|
||||
// If an error happens in a package, it's possible to be
|
||||
// because it was compiled. Thus, we don't want the browser
|
||||
// debugger to show the original code. Instead, the code
|
||||
// being evaluated would be much more helpful.
|
||||
sourceMaps: false,
|
||||
},
|
||||
},
|
||||
// "postcss" loader applies autoprefixer to our CSS.
|
||||
// "css" loader resolves paths in CSS and adds assets as dependencies.
|
||||
// `MiniCSSExtractPlugin` extracts styles into CSS
|
||||
// files. If you use code splitting, async bundles will have their own separate CSS chunk file.
|
||||
// By default we support CSS Modules with the extension .module.css
|
||||
{
|
||||
test: cssRegex,
|
||||
exclude: cssModuleRegex,
|
||||
loader: getStyleLoaders({
|
||||
importLoaders: 1,
|
||||
sourceMap: shouldUseSourceMap,
|
||||
}),
|
||||
// Don't consider CSS imports dead code even if the
|
||||
// containing package claims to have no side effects.
|
||||
// Remove this when webpack adds a warning or an error for this.
|
||||
// See https://github.com/webpack/webpack/issues/6571
|
||||
sideEffects: true,
|
||||
},
|
||||
// Adds support for CSS Modules (https://github.com/css-modules/css-modules)
|
||||
// using the extension .module.css
|
||||
{
|
||||
test: cssModuleRegex,
|
||||
loader: getStyleLoaders({
|
||||
importLoaders: 1,
|
||||
sourceMap: shouldUseSourceMap,
|
||||
modules: true,
|
||||
getLocalIdent: getCSSModuleLocalIdent,
|
||||
}),
|
||||
},
|
||||
// Opt-in support for SASS. The logic here is somewhat similar
|
||||
// as in the CSS routine, except that "sass-loader" runs first
|
||||
// to compile SASS files into CSS.
|
||||
// By default we support SASS Modules with the
|
||||
// extensions .module.scss or .module.sass
|
||||
{
|
||||
test: sassRegex,
|
||||
exclude: sassModuleRegex,
|
||||
loader: getStyleLoaders(
|
||||
{
|
||||
importLoaders: 2,
|
||||
sourceMap: shouldUseSourceMap,
|
||||
},
|
||||
'sass-loader'
|
||||
),
|
||||
// Don't consider CSS imports dead code even if the
|
||||
// containing package claims to have no side effects.
|
||||
// Remove this when webpack adds a warning or an error for this.
|
||||
// See https://github.com/webpack/webpack/issues/6571
|
||||
sideEffects: true,
|
||||
},
|
||||
// Adds support for CSS Modules, but using SASS
|
||||
// using the extension .module.scss or .module.sass
|
||||
{
|
||||
test: sassModuleRegex,
|
||||
loader: getStyleLoaders(
|
||||
{
|
||||
importLoaders: 2,
|
||||
sourceMap: shouldUseSourceMap,
|
||||
modules: true,
|
||||
getLocalIdent: getCSSModuleLocalIdent,
|
||||
},
|
||||
'sass-loader'
|
||||
),
|
||||
},
|
||||
// "file" loader makes sure assets end up in the `build` folder.
|
||||
// When you `import` an asset, you get its filename.
|
||||
// This loader doesn't use a "test" so it will catch all modules
|
||||
// that fall through the other loaders.
|
||||
{
|
||||
loader: require.resolve('file-loader'),
|
||||
// Exclude `js` files to keep "css" loader working as it injects
|
||||
// it's runtime that would otherwise be processed through "file" loader.
|
||||
// Also exclude `html` and `json` extensions so they get processed
|
||||
// by webpacks internal loaders.
|
||||
exclude: [/\.(js|mjs|jsx)$/, /\.html$/, /\.json$/],
|
||||
options: {
|
||||
name: 'static/media/[name].[hash:8].[ext]',
|
||||
},
|
||||
},
|
||||
// ** STOP ** Are you adding a new loader?
|
||||
// Make sure to add the new loader(s) before the "file" loader.
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
// Generates an `index.html` file with the <script> injected.
|
||||
new HtmlWebpackPlugin({
|
||||
inject: true,
|
||||
filename:"explore/result.html",
|
||||
chunks:['search'],
|
||||
template: "public/explore/result.html",
|
||||
minify: {
|
||||
removeComments: true,
|
||||
collapseWhitespace: true,
|
||||
removeRedundantAttributes: true,
|
||||
useShortDoctype: true,
|
||||
removeEmptyAttributes: true,
|
||||
removeStyleLinkTypeAttributes: true,
|
||||
keepClosingSlash: true,
|
||||
minifyJS: true,
|
||||
minifyCSS: true,
|
||||
minifyURLs: true,
|
||||
},
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
inject: true,
|
||||
filename:"member/login.html",
|
||||
chunks:['login'],
|
||||
template: "public/member/login.html",
|
||||
minify: {
|
||||
removeComments: true,
|
||||
collapseWhitespace: true,
|
||||
removeRedundantAttributes: true,
|
||||
useShortDoctype: true,
|
||||
removeEmptyAttributes: true,
|
||||
removeStyleLinkTypeAttributes: true,
|
||||
keepClosingSlash: true,
|
||||
minifyJS: true,
|
||||
minifyCSS: true,
|
||||
minifyURLs: true,
|
||||
},
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
inject: true,
|
||||
filename:"member/setting.html",
|
||||
chunks:['setting'],
|
||||
template: "public/member/setting.html",
|
||||
minify: {
|
||||
removeComments: true,
|
||||
collapseWhitespace: true,
|
||||
removeRedundantAttributes: true,
|
||||
useShortDoctype: true,
|
||||
removeEmptyAttributes: true,
|
||||
removeStyleLinkTypeAttributes: true,
|
||||
keepClosingSlash: true,
|
||||
minifyJS: true,
|
||||
minifyCSS: true,
|
||||
minifyURLs: true,
|
||||
},
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
inject: true,
|
||||
filename:"profile/profile.html",
|
||||
chunks:['profile'],
|
||||
template: "public/profile/profile.html",
|
||||
minify: {
|
||||
removeComments: true,
|
||||
collapseWhitespace: true,
|
||||
removeRedundantAttributes: true,
|
||||
useShortDoctype: true,
|
||||
removeEmptyAttributes: true,
|
||||
removeStyleLinkTypeAttributes: true,
|
||||
keepClosingSlash: true,
|
||||
minifyJS: true,
|
||||
minifyCSS: true,
|
||||
minifyURLs: true,
|
||||
},
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
inject: true,
|
||||
filename:"share/share_home.html",
|
||||
chunks:['myShare'],
|
||||
template: "public/share/share_home.html",
|
||||
minify: {
|
||||
removeComments: true,
|
||||
collapseWhitespace: true,
|
||||
removeRedundantAttributes: true,
|
||||
useShortDoctype: true,
|
||||
removeEmptyAttributes: true,
|
||||
removeStyleLinkTypeAttributes: true,
|
||||
keepClosingSlash: true,
|
||||
minifyJS: true,
|
||||
minifyCSS: true,
|
||||
minifyURLs: true,
|
||||
},
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
inject: true,
|
||||
filename:"share/share_single.html",
|
||||
chunks:['fileShare'],
|
||||
template: "public/share/share_single.html",
|
||||
minify: {
|
||||
removeComments: true,
|
||||
collapseWhitespace: true,
|
||||
removeRedundantAttributes: true,
|
||||
useShortDoctype: true,
|
||||
removeEmptyAttributes: true,
|
||||
removeStyleLinkTypeAttributes: true,
|
||||
keepClosingSlash: true,
|
||||
minifyJS: true,
|
||||
minifyCSS: true,
|
||||
minifyURLs: true,
|
||||
},
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
inject: true,
|
||||
filename:"share/share_lock.html",
|
||||
chunks:['lock'],
|
||||
template: "public/share/share_lock.html",
|
||||
minify: {
|
||||
removeComments: true,
|
||||
collapseWhitespace: true,
|
||||
removeRedundantAttributes: true,
|
||||
useShortDoctype: true,
|
||||
removeEmptyAttributes: true,
|
||||
removeStyleLinkTypeAttributes: true,
|
||||
keepClosingSlash: true,
|
||||
minifyJS: true,
|
||||
minifyCSS: true,
|
||||
minifyURLs: true,
|
||||
},
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
inject: true,
|
||||
filename:"share/share_dir.html",
|
||||
chunks:['folderShare'],
|
||||
template: "public/share/share_dir.html",
|
||||
minify: {
|
||||
removeComments: true,
|
||||
collapseWhitespace: true,
|
||||
removeRedundantAttributes: true,
|
||||
useShortDoctype: true,
|
||||
removeEmptyAttributes: true,
|
||||
removeStyleLinkTypeAttributes: true,
|
||||
keepClosingSlash: true,
|
||||
minifyJS: true,
|
||||
minifyCSS: true,
|
||||
minifyURLs: true,
|
||||
},
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
inject: true,
|
||||
filename:"viewer/video.html",
|
||||
chunks:['video'],
|
||||
template: "public/viewer/video.html",
|
||||
minify: {
|
||||
removeComments: true,
|
||||
collapseWhitespace: true,
|
||||
removeRedundantAttributes: true,
|
||||
useShortDoctype: true,
|
||||
removeEmptyAttributes: true,
|
||||
removeStyleLinkTypeAttributes: true,
|
||||
keepClosingSlash: true,
|
||||
minifyJS: true,
|
||||
minifyCSS: true,
|
||||
minifyURLs: true,
|
||||
},
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
inject: true,
|
||||
filename:"viewer/markdown.html",
|
||||
chunks:['markdown'],
|
||||
template: "public/viewer/markdown.html",
|
||||
minify: {
|
||||
removeComments: true,
|
||||
collapseWhitespace: true,
|
||||
removeRedundantAttributes: true,
|
||||
useShortDoctype: true,
|
||||
removeEmptyAttributes: true,
|
||||
removeStyleLinkTypeAttributes: true,
|
||||
keepClosingSlash: true,
|
||||
minifyJS: true,
|
||||
minifyCSS: true,
|
||||
minifyURLs: true,
|
||||
},
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
inject: true,
|
||||
filename:"home/home.html",
|
||||
chunks:['index'],
|
||||
template: paths.appHtml,
|
||||
minify: {
|
||||
removeComments: true,
|
||||
collapseWhitespace: true,
|
||||
removeRedundantAttributes: true,
|
||||
useShortDoctype: true,
|
||||
removeEmptyAttributes: true,
|
||||
removeStyleLinkTypeAttributes: true,
|
||||
keepClosingSlash: true,
|
||||
minifyJS: true,
|
||||
minifyCSS: true,
|
||||
minifyURLs: true,
|
||||
},
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
inject: true,
|
||||
filename:"home/download.html",
|
||||
chunks:['download'],
|
||||
template: "public/home/download.html",
|
||||
minify: {
|
||||
removeComments: true,
|
||||
collapseWhitespace: true,
|
||||
removeRedundantAttributes: true,
|
||||
useShortDoctype: true,
|
||||
removeEmptyAttributes: true,
|
||||
removeStyleLinkTypeAttributes: true,
|
||||
keepClosingSlash: true,
|
||||
minifyJS: true,
|
||||
minifyCSS: true,
|
||||
minifyURLs: true,
|
||||
},
|
||||
}),
|
||||
|
||||
// Inlines the webpack runtime script. This script is too small to warrant
|
||||
// a network request.
|
||||
shouldInlineRuntimeChunk && new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime~.+[.]js/]),
|
||||
// Makes some environment variables available in index.html.
|
||||
// The public URL is available as %PUBLIC_URL% in index.html, e.g.:
|
||||
// <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
// In production, it will be an empty string unless you specify "homepage"
|
||||
// in `package.json`, in which case it will be the pathname of that URL.
|
||||
new InterpolateHtmlPlugin(HtmlWebpackPlugin, env.raw),
|
||||
// This gives some necessary context to module not found errors, such as
|
||||
// the requesting resource.
|
||||
new ModuleNotFoundPlugin(paths.appPath),
|
||||
// Makes some environment variables available to the JS code, for example:
|
||||
// if (process.env.NODE_ENV === 'production') { ... }. See `./env.js`.
|
||||
// It is absolutely essential that NODE_ENV was set to production here.
|
||||
// Otherwise React will be compiled in the very slow development mode.
|
||||
new webpack.DefinePlugin(env.stringified),
|
||||
new MiniCssExtractPlugin({
|
||||
// Options similar to the same options in webpackOptions.output
|
||||
// both options are optional
|
||||
filename: 'static/css/[name].css',
|
||||
chunkFilename: 'static/css/[name].chunk.css',
|
||||
}),
|
||||
// Generate a manifest file which contains a mapping of all asset filenames
|
||||
// to their corresponding output file so that tools can pick it up without
|
||||
// having to parse `index.html`.
|
||||
new ManifestPlugin({
|
||||
fileName: 'asset-manifest.json',
|
||||
publicPath: publicPath,
|
||||
}),
|
||||
// Moment.js is an extremely popular library that bundles large locale files
|
||||
// by default due to how Webpack interprets its code. This is a practical
|
||||
// solution that requires the user to opt into importing specific locales.
|
||||
// https://github.com/jmblog/how-to-optimize-momentjs-with-webpack
|
||||
// You can remove this if you don't use Moment.js:
|
||||
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
|
||||
// Generate a service worker script that will precache, and keep up to date,
|
||||
// the HTML & assets that are part of the Webpack build.
|
||||
new WorkboxWebpackPlugin.GenerateSW({
|
||||
clientsClaim: true,
|
||||
exclude: [/\.map$/, /asset-manifest\.json$/],
|
||||
importWorkboxFrom: 'cdn',
|
||||
navigateFallback: publicUrl + '/index.html',
|
||||
navigateFallbackBlacklist: [
|
||||
// Exclude URLs starting with /_, as they're likely an API call
|
||||
new RegExp('^/_'),
|
||||
// Exclude URLs containing a dot, as they're likely a resource in
|
||||
// public/ and not a SPA route
|
||||
new RegExp('/[^/]+\\.[^/]+$'),
|
||||
],
|
||||
}),
|
||||
].filter(Boolean),
|
||||
// Some libraries import Node modules but don't use them in the browser.
|
||||
// Tell Webpack to provide empty mocks for them so importing them works.
|
||||
node: {
|
||||
dgram: 'empty',
|
||||
fs: 'empty',
|
||||
net: 'empty',
|
||||
tls: 'empty',
|
||||
child_process: 'empty',
|
||||
},
|
||||
// Turn off performance processing because we utilize
|
||||
// our own hints via the FileSizeReporter
|
||||
performance: false,
|
||||
};
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
'use strict';
|
||||
|
||||
const errorOverlayMiddleware = require('react-dev-utils/errorOverlayMiddleware');
|
||||
const evalSourceMapMiddleware = require('react-dev-utils/evalSourceMapMiddleware');
|
||||
const noopServiceWorkerMiddleware = require('react-dev-utils/noopServiceWorkerMiddleware');
|
||||
const ignoredFiles = require('react-dev-utils/ignoredFiles');
|
||||
const config = require('./webpack.config.dev');
|
||||
const paths = require('./paths');
|
||||
const fs = require('fs');
|
||||
|
||||
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
|
||||
const host = process.env.HOST || '0.0.0.0';
|
||||
|
||||
module.exports = function(proxy, allowedHost) {
|
||||
return {
|
||||
// WebpackDevServer 2.4.3 introduced a security fix that prevents remote
|
||||
// websites from potentially accessing local content through DNS rebinding:
|
||||
// https://github.com/webpack/webpack-dev-server/issues/887
|
||||
// https://medium.com/webpack/webpack-dev-server-middleware-security-issues-1489d950874a
|
||||
// However, it made several existing use cases such as development in cloud
|
||||
// environment or subdomains in development significantly more complicated:
|
||||
// https://github.com/facebook/create-react-app/issues/2271
|
||||
// https://github.com/facebook/create-react-app/issues/2233
|
||||
// While we're investigating better solutions, for now we will take a
|
||||
// compromise. Since our WDS configuration only serves files in the `public`
|
||||
// folder we won't consider accessing them a vulnerability. However, if you
|
||||
// use the `proxy` feature, it gets more dangerous because it can expose
|
||||
// remote code execution vulnerabilities in backends like Django and Rails.
|
||||
// So we will disable the host check normally, but enable it if you have
|
||||
// specified the `proxy` setting. Finally, we let you override it if you
|
||||
// really know what you're doing with a special environment variable.
|
||||
disableHostCheck:
|
||||
!proxy || process.env.DANGEROUSLY_DISABLE_HOST_CHECK === 'true',
|
||||
// Enable gzip compression of generated files.
|
||||
compress: true,
|
||||
// Silence WebpackDevServer's own logs since they're generally not useful.
|
||||
// It will still show compile warnings and errors with this setting.
|
||||
clientLogLevel: 'none',
|
||||
// By default WebpackDevServer serves physical files from current directory
|
||||
// in addition to all the virtual build products that it serves from memory.
|
||||
// This is confusing because those files won’t automatically be available in
|
||||
// production build folder unless we copy them. However, copying the whole
|
||||
// project directory is dangerous because we may expose sensitive files.
|
||||
// Instead, we establish a convention that only files in `public` directory
|
||||
// get served. Our build script will copy `public` into the `build` folder.
|
||||
// In `index.html`, you can get URL of `public` folder with %PUBLIC_URL%:
|
||||
// <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
// In JavaScript code, you can access it with `process.env.PUBLIC_URL`.
|
||||
// Note that we only recommend to use `public` folder as an escape hatch
|
||||
// for files like `favicon.ico`, `manifest.json`, and libraries that are
|
||||
// for some reason broken when imported through Webpack. If you just want to
|
||||
// use an image, put it in `src` and `import` it from JavaScript instead.
|
||||
contentBase: paths.appPublic,
|
||||
// By default files from `contentBase` will not trigger a page reload.
|
||||
watchContentBase: true,
|
||||
// Enable hot reloading server. It will provide /sockjs-node/ endpoint
|
||||
// for the WebpackDevServer client so it can learn when the files were
|
||||
// updated. The WebpackDevServer client is included as an entry point
|
||||
// in the Webpack development configuration. Note that only changes
|
||||
// to CSS are currently hot reloaded. JS changes will refresh the browser.
|
||||
hot: true,
|
||||
// It is important to tell WebpackDevServer to use the same "root" path
|
||||
// as we specified in the config. In development, we always serve from /.
|
||||
publicPath: config.output.publicPath,
|
||||
// WebpackDevServer is noisy by default so we emit custom message instead
|
||||
// by listening to the compiler events with `compiler.hooks[...].tap` calls above.
|
||||
quiet: true,
|
||||
// Reportedly, this avoids CPU overload on some systems.
|
||||
// https://github.com/facebook/create-react-app/issues/293
|
||||
// src/node_modules is not ignored to support absolute imports
|
||||
// https://github.com/facebook/create-react-app/issues/1065
|
||||
watchOptions: {
|
||||
ignored: ignoredFiles(paths.appSrc),
|
||||
},
|
||||
// Enable HTTPS if the HTTPS environment variable is set to 'true'
|
||||
https: protocol === 'https',
|
||||
host,
|
||||
overlay: false,
|
||||
historyApiFallback: {
|
||||
// Paths with dots should still use the history fallback.
|
||||
// See https://github.com/facebook/create-react-app/issues/387.
|
||||
disableDotRule: true,
|
||||
},
|
||||
public: allowedHost,
|
||||
proxy,
|
||||
before(app, server) {
|
||||
if (fs.existsSync(paths.proxySetup)) {
|
||||
// This registers user provided middleware for proxy reasons
|
||||
require(paths.proxySetup)(app);
|
||||
}
|
||||
|
||||
// This lets us fetch source contents from webpack for the error overlay
|
||||
app.use(evalSourceMapMiddleware(server));
|
||||
// This lets us open files from the runtime error overlay.
|
||||
app.use(errorOverlayMiddleware());
|
||||
|
||||
// This service worker file is effectively a 'no-op' that will reset any
|
||||
// previous service worker registered for the same host:port combination.
|
||||
// We do this in development to avoid hitting the production cache if
|
||||
// it used the same host and port.
|
||||
// https://github.com/facebook/create-react-app/issues/2272#issuecomment-302832432
|
||||
app.use(noopServiceWorkerMiddleware());
|
||||
},
|
||||
};
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,126 @@
|
|||
{
|
||||
"name": "my-app",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@babel/core": "7.1.0",
|
||||
"@material-ui/core": "^3.9.2",
|
||||
"@material-ui/icons": "^3.0.2",
|
||||
"@material-ui/lab": "^3.0.0-alpha.30",
|
||||
"@svgr/webpack": "2.4.1",
|
||||
"axios": "^0.18.0",
|
||||
"babel-core": "7.0.0-bridge.0",
|
||||
"babel-eslint": "9.0.0",
|
||||
"babel-jest": "23.6.0",
|
||||
"babel-loader": "8.0.4",
|
||||
"babel-plugin-named-asset-import": "^0.2.3",
|
||||
"babel-preset-react-app": "^5.0.4",
|
||||
"bfj": "6.1.1",
|
||||
"case-sensitive-paths-webpack-plugin": "2.1.2",
|
||||
"chalk": "2.4.1",
|
||||
"css-loader": "1.0.0",
|
||||
"dotenv": "6.0.0",
|
||||
"dotenv-expand": "4.2.0",
|
||||
"eslint": "5.6.0",
|
||||
"eslint-config-react-app": "^3.0.7",
|
||||
"eslint-loader": "2.1.1",
|
||||
"eslint-plugin-flowtype": "2.50.1",
|
||||
"eslint-plugin-import": "2.14.0",
|
||||
"eslint-plugin-jsx-a11y": "6.1.2",
|
||||
"eslint-plugin-react": "7.11.1",
|
||||
"file-loader": "2.0.0",
|
||||
"fs-extra": "7.0.0",
|
||||
"html-webpack-plugin": "4.0.0-alpha.2",
|
||||
"identity-obj-proxy": "3.0.0",
|
||||
"jest": "23.6.0",
|
||||
"jest-pnp-resolver": "1.0.1",
|
||||
"jest-resolve": "23.6.0",
|
||||
"material-ui": "^0.20.2",
|
||||
"mdi-material-ui": "^5.10.0",
|
||||
"mini-css-extract-plugin": "0.4.3",
|
||||
"node-sass": "^4.11.0",
|
||||
"optimize-css-assets-webpack-plugin": "5.0.1",
|
||||
"pnp-webpack-plugin": "1.1.0",
|
||||
"postcss-flexbugs-fixes": "4.1.0",
|
||||
"postcss-loader": "3.0.0",
|
||||
"postcss-preset-env": "6.0.6",
|
||||
"postcss-safe-parser": "4.0.1",
|
||||
"react": "^16.8.3",
|
||||
"react-app-polyfill": "^0.1.3",
|
||||
"react-async-script-loader": "^0.3.0",
|
||||
"react-content-loader": "^4.0.1",
|
||||
"react-dev-utils": "^6.1.1",
|
||||
"react-dom": "^16.8.3",
|
||||
"react-lazy-load-image-component": "^1.3.2",
|
||||
"react-photoswipe": "^1.3.0",
|
||||
"react-redux": "^6.0.1",
|
||||
"redux": "^4.0.1",
|
||||
"resolve": "1.8.1",
|
||||
"sass-loader": "^7.1.0",
|
||||
"style-loader": "0.23.0",
|
||||
"terser-webpack-plugin": "1.1.0",
|
||||
"url-loader": "1.1.1",
|
||||
"webpack": "4.19.1",
|
||||
"webpack-dev-server": "3.1.9",
|
||||
"webpack-manifest-plugin": "2.0.4",
|
||||
"workbox-webpack-plugin": "3.6.2"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node scripts/start.js",
|
||||
"build": "node scripts/build.js",
|
||||
"test": "node scripts/test.js"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "react-app"
|
||||
},
|
||||
"browserslist": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not ie <= 11",
|
||||
"not op_mini all"
|
||||
],
|
||||
"jest": {
|
||||
"collectCoverageFrom": [
|
||||
"src/**/*.{js,jsx}"
|
||||
],
|
||||
"resolver": "jest-pnp-resolver",
|
||||
"setupFiles": [
|
||||
"react-app-polyfill/jsdom"
|
||||
],
|
||||
"testMatch": [
|
||||
"<rootDir>/src/**/__tests__/**/*.{js,jsx}",
|
||||
"<rootDir>/src/**/?(*.)(spec|test).{js,jsx}"
|
||||
],
|
||||
"testEnvironment": "jsdom",
|
||||
"testURL": "http://localhost",
|
||||
"transform": {
|
||||
"^.+\\.(js|jsx)$": "<rootDir>/node_modules/babel-jest",
|
||||
"^.+\\.css$": "<rootDir>/config/jest/cssTransform.js",
|
||||
"^(?!.*\\.(js|jsx|css|json)$)": "<rootDir>/config/jest/fileTransform.js"
|
||||
},
|
||||
"transformIgnorePatterns": [
|
||||
"[/\\\\]node_modules[/\\\\].+\\.(js|jsx)$",
|
||||
"^.+\\.module\\.(css|sass|scss)$"
|
||||
],
|
||||
"moduleNameMapper": {
|
||||
"^react-native$": "react-native-web",
|
||||
"^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy"
|
||||
},
|
||||
"moduleFileExtensions": [
|
||||
"web.js",
|
||||
"js",
|
||||
"json",
|
||||
"web.jsx",
|
||||
"jsx",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"babel": {
|
||||
"presets": [
|
||||
"react-app"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"react-dplayer": "^0.2.3"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-cn">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="shortcut icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="theme-color" content="{$options.themeColor}" />
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
|
||||
<title>“{$keyWords}”搜索结果 - {$options.siteName}</title>
|
||||
<script type="text/javascript">
|
||||
colorTheme = {:json_encode($options["themeConfig"])};
|
||||
isHomePage = false;
|
||||
isSharePage = false;
|
||||
pageId="shareLock";
|
||||
list = {$list};
|
||||
userInfo = {
|
||||
uid: {$userData.uid},
|
||||
nick: "{$userData.userNick}",
|
||||
email: "{$userData.userMail}",
|
||||
group: "{$userData.groupData.group_name}",
|
||||
groupId: {$userData.groupData.id},
|
||||
groupColor: "{$userData.groupData.color}",
|
||||
};
|
||||
siteInfo = {
|
||||
mainTitle: "{$options.siteName}",
|
||||
};
|
||||
uploadConfig = {
|
||||
allowSource: false,
|
||||
allowShare: false,
|
||||
allowRemoteDownload: "0",
|
||||
allowTorrentDownload: "0",
|
||||
};
|
||||
isMobile = window.innerWidth < 600;
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.8 KiB |
|
|
@ -0,0 +1,60 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is added to the
|
||||
homescreen on Android. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
<script type="text/javascript">
|
||||
uploadConfig={
|
||||
saveType : "onedrive",
|
||||
maxSize : "20000mb",
|
||||
allowedType: [
|
||||
],
|
||||
allowSource : "0",
|
||||
upUrl : "/Upload",
|
||||
allowShare:"1",
|
||||
allowRemoteDownload:"1",
|
||||
allowTorrentDownload:"1",
|
||||
};
|
||||
</script>
|
||||
<!-- <script src="http://lite.aoaoao.me/dev/moxie.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/plupload.dev.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/i18n/zh_CN.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/ui.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/qiniu.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/main.js"></script> -->
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is added to the
|
||||
homescreen on Android. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
<script type="text/javascript">
|
||||
uploadConfig={
|
||||
saveType : "onedrive",
|
||||
maxSize : "20000mb",
|
||||
allowedType: [
|
||||
],
|
||||
allowSource : "0",
|
||||
upUrl : "/Upload",
|
||||
allowShare:"1",
|
||||
allowRemoteDownload:"1",
|
||||
allowTorrentDownload:"1",
|
||||
};
|
||||
</script>
|
||||
<!-- <script src="http://lite.aoaoao.me/dev/moxie.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/plupload.dev.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/i18n/zh_CN.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/ui.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/qiniu.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/main.js"></script> -->
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-cn">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="shortcut icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="theme-color" content="{$options.themeColor}" />
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
<title>离线下载管理- {$options.siteName}</title>
|
||||
<script type="text/javascript">
|
||||
colorTheme = {:json_encode($options["themeConfig"])};
|
||||
isHomePage = false;
|
||||
isSharePage = false;
|
||||
pageId="shareLock";
|
||||
userInfo = {
|
||||
uid: {$userInfo.uid},
|
||||
nick: "{$userInfo.userNick}",
|
||||
email: "{$userInfo.userMail}",
|
||||
group: "{$userInfo.groupData.group_name}",
|
||||
groupId: {$userInfo.groupData.id},
|
||||
groupColor: "{$userInfo.groupData.color}",
|
||||
};
|
||||
siteInfo = {
|
||||
mainTitle: "离线下载",
|
||||
};
|
||||
uploadConfig = {
|
||||
allowSource: false,
|
||||
allowShare: false,
|
||||
allowRemoteDownload: "0",
|
||||
allowTorrentDownload: "0",
|
||||
};
|
||||
isMobile = window.innerWidth < 600;
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-cn">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="shortcut icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="theme-color" content="{$options.themeColor}" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is added to the
|
||||
homescreen on Android. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>我的文件 - {$options.siteName}</title>
|
||||
<script type="text/javascript">
|
||||
colorTheme = {:json_encode($options["themeConfig"])};
|
||||
isHomePage = true;
|
||||
pageId="";
|
||||
isSharePage = false;
|
||||
uploadConfig = {
|
||||
saveType: "{$policyData.policy_type}",
|
||||
maxSize: "{$policyData.max_size}mb",
|
||||
allowedType: [{$extLimit}],
|
||||
allowSource: "{$policyData.origin_link}",
|
||||
upUrl: "{$policyData.server}",
|
||||
allowShare: "{$groupData.allow_share}",
|
||||
allowRemoteDownload: "{:explode(",",$groupData.aria2)[0]}",
|
||||
allowTorrentDownload: "{:explode(",",$groupData.aria2)[1]}",
|
||||
};
|
||||
apiURL = {
|
||||
imgThumb: "/File/Thumb",
|
||||
preview: "/File/Preview",
|
||||
download: "/File/Download",
|
||||
docPreiview: '/File/DocPreview',
|
||||
listFile:"/File/ListFile"
|
||||
};
|
||||
userInfo = {
|
||||
uid: {$userInfo.uid},
|
||||
nick: "{$userInfo.userNick}",
|
||||
email: "{$userInfo.userMail}",
|
||||
group: "{$userInfo.groupData.group_name}",
|
||||
groupId: {$userInfo.groupData.id},
|
||||
groupColor: "{$userInfo.groupData.color}",
|
||||
};
|
||||
siteInfo = {
|
||||
mainTitle: "{$options.siteName}",
|
||||
};
|
||||
pathCache = {};
|
||||
path = "{$path}";
|
||||
mediaType = {},
|
||||
isMobile = window.innerWidth < 600;
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
<script src="http://192.168.123.19:3000/static/js/runtime~index.bundle.js"></script>
|
||||
<script src="http://192.168.123.19:3000/static/js/0.chunk.js"></script>
|
||||
<script src="http://192.168.123.19:3000/static/js/2.chunk.js"></script>
|
||||
<script src="http://192.168.123.19:3000/static/js/3.chunk.js"></script>
|
||||
<script src="http://192.168.123.19:3000/static/js/4.chunk.js"></script>
|
||||
<script src="http://192.168.123.19:3000/static/js/5.chunk.js"></script>
|
||||
<script src="http://192.168.123.19:3000/static/js/6.chunk.js"></script>
|
||||
<script src="http://192.168.123.19:3000/static/js/9.chunk.js"></script>
|
||||
<script src="http://192.168.123.19:3000/static/js/1.chunk.js"></script>
|
||||
<script src="http://192.168.123.19:3000/static/js/8.chunk.js"></script>
|
||||
<script src="http://192.168.123.19:3000/static/js/12.chunk.js"></script>
|
||||
<script src="http://192.168.123.19:3000/static/js/index.chunk.js"></script>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-cn">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="shortcut icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="theme-color" content="{$options.themeColor}" />
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
<title>我的文件 - {$options.siteName}</title>
|
||||
<script type="text/javascript">
|
||||
colorTheme = {:json_encode($options["themeConfig"])};
|
||||
isHomePage = true;
|
||||
pageId="";
|
||||
isSharePage = false;
|
||||
uploadConfig = {
|
||||
saveType: "{$policyData.policy_type}",
|
||||
maxSize: "{$policyData.max_size}mb",
|
||||
allowedType: [{$extLimit}],
|
||||
allowSource: "{$policyData.origin_link}",
|
||||
upUrl: "{$policyData.server}",
|
||||
allowShare: "{$groupData.allow_share}",
|
||||
allowRemoteDownload: "{:explode(",",$groupData.aria2)[0]}",
|
||||
allowTorrentDownload: "{:explode(",",$groupData.aria2)[1]}",
|
||||
};
|
||||
if(uploadConfig.saveType == "oss" || uploadConfig.saveType == "upyun" || uploadConfig.saveType == "s3"){
|
||||
ChunkSize = "0";
|
||||
}else if(uploadConfig.saveType == "qiniu" ){
|
||||
ChunkSize = 4*1024*1024;
|
||||
}else{
|
||||
ChunkSize = {$chunkSize};
|
||||
}
|
||||
apiURL = {
|
||||
imgThumb: "/File/Thumb",
|
||||
preview: "/File/Preview",
|
||||
download: "/File/Download",
|
||||
docPreiview: '/File/DocPreview',
|
||||
listFile:"/File/ListFile"
|
||||
};
|
||||
userInfo = {
|
||||
uid: {$userInfo.uid},
|
||||
nick: "{$userInfo.userNick}",
|
||||
email: "{$userInfo.userMail}",
|
||||
group: "{$userInfo.groupData.group_name}",
|
||||
groupId: {$userInfo.groupData.id},
|
||||
groupColor: "{$userInfo.groupData.color}",
|
||||
};
|
||||
siteInfo = {
|
||||
mainTitle: "{$options.siteName}",
|
||||
};
|
||||
pathCache = {};
|
||||
path = "{$path}";
|
||||
mediaType = {},
|
||||
isMobile = window.innerWidth < 600;
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is added to the
|
||||
homescreen on Android. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
<script type="text/javascript">
|
||||
uploadConfig={
|
||||
saveType : "onedrive",
|
||||
maxSize : "20000mb",
|
||||
allowedType: [
|
||||
],
|
||||
allowSource : "0",
|
||||
upUrl : "/Upload",
|
||||
allowShare:"1",
|
||||
allowRemoteDownload:"1",
|
||||
allowTorrentDownload:"1",
|
||||
};
|
||||
</script>
|
||||
<!-- <script src="http://lite.aoaoao.me/dev/moxie.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/plupload.dev.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/i18n/zh_CN.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/ui.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/qiniu.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/main.js"></script> -->
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"short_name": "React App",
|
||||
"name": "Create React App Sample",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is added to the
|
||||
homescreen on Android. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
<script type="text/javascript">
|
||||
uploadConfig={
|
||||
saveType : "onedrive",
|
||||
maxSize : "20000mb",
|
||||
allowedType: [
|
||||
],
|
||||
allowSource : "0",
|
||||
upUrl : "/Upload",
|
||||
allowShare:"1",
|
||||
allowRemoteDownload:"1",
|
||||
allowTorrentDownload:"1",
|
||||
};
|
||||
</script>
|
||||
<!-- <script src="http://lite.aoaoao.me/dev/moxie.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/plupload.dev.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/i18n/zh_CN.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/ui.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/qiniu.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/main.js"></script> -->
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-cn">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="shortcut icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="theme-color" content="{$options.themeColor}" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is added to the
|
||||
homescreen on Android. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>{eq name="pageId" value="resetPwdForm"}找回密码{/eq}{eq name="pageId" value="resetPwd"}找回密码{/eq}{eq name="pageId" value="emailActivate"}激活成功{/eq}{eq name="pageId" value="login"}登录{/eq}{eq name="pageId" value="register"}注册{/eq}{eq name="pageId" value="TwoStep"}二步验证{/eq} - {$options.siteName}</title>
|
||||
<script type="text/javascript">
|
||||
colorTheme = {:json_encode($options["themeConfig"])};
|
||||
isHomePage = false;
|
||||
isSharePage = false;
|
||||
captcha = "{$RegOptions.login_captcha}";
|
||||
regCaptcha = "{$RegOptions.reg_captcha}";
|
||||
findPwdCaptcha = "{$RegOptions.forget_captcha}";
|
||||
{if isset($key)}
|
||||
resetKey = '{$key}';
|
||||
{/if}
|
||||
pageId="{$pageId}";
|
||||
userInfo = {
|
||||
uid: -1,
|
||||
};
|
||||
siteInfo = {
|
||||
mainTitle: "{$options.siteName}",
|
||||
};
|
||||
uploadConfig = {
|
||||
allowSource: false,
|
||||
allowShare: false,
|
||||
allowRemoteDownload: "0",
|
||||
allowTorrentDownload: "0",
|
||||
};
|
||||
isMobile = window.innerWidth < 600;
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-cn">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="shortcut icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="theme-color" content="{$options.themeColor}" />
|
||||
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
|
||||
<title>用户设置- {$options.siteName}</title>
|
||||
<script type="text/javascript">
|
||||
colorTheme = {:json_encode($options["themeConfig"])};
|
||||
colorThemeOptions = {$options["themes"]};
|
||||
isHomePage = false;
|
||||
isSharePage = false;
|
||||
pageId="userSetting";
|
||||
siteUrl = "{$options.siteURL}";
|
||||
userInfo = {
|
||||
uid: {$userInfo.uid},
|
||||
nick: "{$userInfo.userNick}",
|
||||
email: "{$userInfo.userMail}",
|
||||
group: "{$userInfo.groupData.group_name}",
|
||||
groupId: {$userInfo.groupData.id},
|
||||
groupColor: "{$userInfo.groupData.color}",
|
||||
regTime: "{$userSQL.user_date}",
|
||||
homePage: "{$userSQL.profile}",
|
||||
twoFactor: "{$userSQL.two_step}",
|
||||
webdav:"{$userInfo.groupData.webdav}",
|
||||
};
|
||||
siteInfo = {
|
||||
mainTitle: "{$options.siteName}",
|
||||
};
|
||||
uploadConfig = {
|
||||
allowSource: false,
|
||||
allowShare: false,
|
||||
allowRemoteDownload: "0",
|
||||
allowTorrentDownload: "0",
|
||||
};
|
||||
isMobile = window.innerWidth < 600;
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="root"></div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is added to the
|
||||
homescreen on Android. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
<script type="text/javascript">
|
||||
uploadConfig={
|
||||
saveType : "onedrive",
|
||||
maxSize : "20000mb",
|
||||
allowedType: [
|
||||
],
|
||||
allowSource : "0",
|
||||
upUrl : "/Upload",
|
||||
allowShare:"1",
|
||||
allowRemoteDownload:"1",
|
||||
allowTorrentDownload:"1",
|
||||
};
|
||||
</script>
|
||||
<!-- <script src="http://lite.aoaoao.me/dev/moxie.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/plupload.dev.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/i18n/zh_CN.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/ui.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/qiniu.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/main.js"></script> -->
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is added to the
|
||||
homescreen on Android. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
<script type="text/javascript">
|
||||
uploadConfig={
|
||||
saveType : "onedrive",
|
||||
maxSize : "20000mb",
|
||||
allowedType: [
|
||||
],
|
||||
allowSource : "0",
|
||||
upUrl : "/Upload",
|
||||
allowShare:"1",
|
||||
allowRemoteDownload:"1",
|
||||
allowTorrentDownload:"1",
|
||||
};
|
||||
</script>
|
||||
<!-- <script src="http://lite.aoaoao.me/dev/moxie.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/plupload.dev.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/i18n/zh_CN.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/ui.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/qiniu.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/main.js"></script> -->
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-cn">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="shortcut icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="theme-color" content="{$options.themeColor}" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is added to the
|
||||
homescreen on Android. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>用户主页 - {$options.siteName}</title>
|
||||
<script type="text/javascript">
|
||||
colorTheme = {:json_encode($options["themeConfig"])};
|
||||
isHomePage = false;
|
||||
isSharePage = false;
|
||||
pageId="profile";
|
||||
taegetUserInfo = {
|
||||
uid:{$targetUserInfo.id},
|
||||
nickname:"{$targetUserInfo.user_nick}",
|
||||
regDate:"{$targetUserInfo.user_date}",
|
||||
shareCount:"{$shareCount}",
|
||||
group:"{$groupData.group_name}",
|
||||
};
|
||||
userInfo = {
|
||||
uid: {$userInfo.uid},
|
||||
nick: "{$userInfo.userNick}",
|
||||
email: "{$userInfo.userMail}",
|
||||
group: "{$userInfo.groupData.group_name}",
|
||||
groupId: {$userInfo.groupData.id},
|
||||
groupColor: "{$userInfo.groupData.color}",
|
||||
regTime: "{$userSQL.user_date}",
|
||||
homePage: "{$userSQL.profile}",
|
||||
twoFactor: "{$userSQL.two_step}",
|
||||
webdav:"{$userInfo.groupData.webdav}",
|
||||
};
|
||||
siteInfo = {
|
||||
mainTitle: "{$options.siteName}",
|
||||
};
|
||||
uploadConfig = {
|
||||
allowSource: false,
|
||||
allowShare: false,
|
||||
allowRemoteDownload: "0",
|
||||
allowTorrentDownload: "0",
|
||||
};
|
||||
isMobile = window.innerWidth < 600;
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is added to the
|
||||
homescreen on Android. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
<script type="text/javascript">
|
||||
uploadConfig={
|
||||
saveType : "onedrive",
|
||||
maxSize : "20000mb",
|
||||
allowedType: [
|
||||
],
|
||||
allowSource : "0",
|
||||
upUrl : "/Upload",
|
||||
allowShare:"1",
|
||||
allowRemoteDownload:"1",
|
||||
allowTorrentDownload:"1",
|
||||
};
|
||||
</script>
|
||||
<!-- <script src="http://lite.aoaoao.me/dev/moxie.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/plupload.dev.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/i18n/zh_CN.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/ui.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/qiniu.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/main.js"></script> -->
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-cn">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="shortcut icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="theme-color" content="{$options.themeColor}" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is added to the
|
||||
homescreen on Android. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>{$dirData.folder_name} - {$options.siteName}</title>
|
||||
<script type="text/javascript">
|
||||
colorTheme = {:json_encode($options["themeConfig"])};
|
||||
isHomePage = false;
|
||||
isSharePage = true;
|
||||
pageId="";
|
||||
apiURL = {
|
||||
imgThumb: "/Share/Thumb/{$shareData.share_key}",
|
||||
preview: "/Share/Preview/{$shareData.share_key}",
|
||||
download: "/Share/Download/{$shareData.share_key}",
|
||||
docPreiview: '/Share/DocPreview/{$shareData.share_key}',
|
||||
listFile:'/Share/ListFile/{$shareData.share_key}'
|
||||
};
|
||||
userInfo = {
|
||||
uid: {$userData.uid},
|
||||
nick: "{$userData.userNick}",
|
||||
email: "{$userData.userMail}",
|
||||
group: "{$userData.groupData.group_name}",
|
||||
groupId: {$userData.groupData.id},
|
||||
groupColor: "{$userData.groupData.color}",
|
||||
};
|
||||
siteInfo = {
|
||||
mainTitle: "{$dirData.folder_name}",
|
||||
};
|
||||
path = "{$path}";
|
||||
uploadConfig = {
|
||||
allowSource: false,
|
||||
allowShare: false,
|
||||
allowRemoteDownload: "0",
|
||||
allowTorrentDownload: "0",
|
||||
};
|
||||
shareInfo={
|
||||
shareDate : "{$shareData.share_time}",
|
||||
ownerUid:"{$userInfo.id}",
|
||||
ownerNick:"{$userInfo.user_nick}",
|
||||
downloadNum:"{$shareData.download_num}",
|
||||
ViewNum:"{$shareData.view_num}",
|
||||
shareId:"{$shareData.share_key}",
|
||||
dirName:"{$dirData.folder_name}",
|
||||
groupName:"{$groupData.group_name}",
|
||||
color:"{$groupData.color}",
|
||||
{eq name="$loginStatus" value="1"}
|
||||
allowPreview:true,
|
||||
{else/}
|
||||
allowPreview:{$allowPreview},
|
||||
{/eq}
|
||||
};
|
||||
mediaType = {},
|
||||
isMobile = window.innerWidth < 600;
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-cn">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="shortcut icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="theme-color" content="{$options.themeColor}" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is added to the
|
||||
homescreen on Android. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>我的分享- {$options.siteName}</title>
|
||||
<script type="text/javascript">
|
||||
colorTheme = {:json_encode($options["themeConfig"])};
|
||||
isHomePage = false;
|
||||
isSharePage = false;
|
||||
pageId="shareLock";
|
||||
userInfo = {
|
||||
uid: {$userData.uid},
|
||||
nick: "{$userData.userNick}",
|
||||
email: "{$userData.userMail}",
|
||||
group: "{$userData.groupData.group_name}",
|
||||
groupId: {$userData.groupData.id},
|
||||
groupColor: "{$userData.groupData.color}",
|
||||
};
|
||||
siteInfo = {
|
||||
mainTitle: "{$options.siteName}",
|
||||
};
|
||||
uploadConfig = {
|
||||
allowSource: false,
|
||||
allowShare: false,
|
||||
allowRemoteDownload: "0",
|
||||
allowTorrentDownload: "0",
|
||||
};
|
||||
isMobile = window.innerWidth < 600;
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-cn">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="shortcut icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="theme-color" content="{$options.themeColor}" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is added to the
|
||||
homescreen on Android. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>私密分享 - {$options.siteName}</title>
|
||||
<script type="text/javascript">
|
||||
colorTheme = {:json_encode($options["themeConfig"])};
|
||||
isHomePage = false;
|
||||
isSharePage = false;
|
||||
pageId="shareLock";
|
||||
userInfo = {
|
||||
uid: {$userData.uid},
|
||||
nick: "{$userData.userNick}",
|
||||
email: "{$userData.userMail}",
|
||||
group: "{$userData.groupData.group_name}",
|
||||
groupId: {$userData.groupData.id},
|
||||
groupColor: "{$userData.groupData.color}",
|
||||
};
|
||||
siteInfo = {
|
||||
mainTitle: "{$options.siteName}",
|
||||
};
|
||||
uploadConfig = {
|
||||
allowSource: false,
|
||||
allowShare: false,
|
||||
allowRemoteDownload: "0",
|
||||
allowTorrentDownload: "0",
|
||||
};
|
||||
shareInfo={
|
||||
shareDate : "{$shareData.share_time}",
|
||||
shareId : "{$shareData.share_key}",
|
||||
ownerUid:"{$userInfo.id}",
|
||||
ownerNick:"{$userInfo.user_nick}",
|
||||
};
|
||||
isMobile = window.innerWidth < 600;
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-cn">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="shortcut icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="theme-color" content="{$options.themeColor}" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is added to the
|
||||
homescreen on Android. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>{$fileData.orign_name} - {$options.siteName}</title>
|
||||
<script type="text/javascript">
|
||||
colorTheme = {:json_encode($options["themeConfig"])};
|
||||
isHomePage = false;
|
||||
isSharePage = true;
|
||||
pageId="fileShare";
|
||||
apiURL = {
|
||||
imgThumb: "/Share/Thumb/{$shareData.share_key}",
|
||||
preview: "/Share/Preview/{$shareData.share_key}",
|
||||
download: "/Share/Download/{$shareData.share_key}",
|
||||
docPreiview: '/Share/DocPreview/{$shareData.share_key}',
|
||||
listFile:'/Share/ListFile/{$shareData.share_key}'
|
||||
};
|
||||
userInfo = {
|
||||
uid: {$userData.uid},
|
||||
nick: "{$userData.userNick}",
|
||||
email: "{$userData.userMail}",
|
||||
group: "{$userData.groupData.group_name}",
|
||||
groupId: {$userData.groupData.id},
|
||||
groupColor: "{$userData.groupData.color}",
|
||||
};
|
||||
siteInfo = {
|
||||
mainTitle: "{$fileData.orign_name}",
|
||||
};
|
||||
path = "{$path}";
|
||||
uploadConfig = {
|
||||
allowSource: false,
|
||||
allowShare: false,
|
||||
allowRemoteDownload: "0",
|
||||
allowTorrentDownload: "0",
|
||||
};
|
||||
shareInfo={
|
||||
fileSize : "{$fileData.size}",
|
||||
shareDate : "{$shareData.share_time}",
|
||||
ownerUid:"{$userInfo.id}",
|
||||
ownerNick:"{$userInfo.user_nick}",
|
||||
downloadNum:"{$shareData.download_num}",
|
||||
ViewNum:"{$shareData.view_num}",
|
||||
shareId:"{$shareData.share_key}",
|
||||
fileName:"{$fileData.orign_name}",
|
||||
picSize:"{$fileData.pic_info}",
|
||||
{eq name="$loginStatus" value="1"}
|
||||
allowPreview:true,
|
||||
{else/}
|
||||
allowPreview:{$allowPreview},
|
||||
{/eq}
|
||||
};
|
||||
mediaType = {},
|
||||
isMobile = window.innerWidth < 600;
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is added to the
|
||||
homescreen on Android. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
<script type="text/javascript">
|
||||
uploadConfig={
|
||||
saveType : "onedrive",
|
||||
maxSize : "20000mb",
|
||||
allowedType: [
|
||||
],
|
||||
allowSource : "0",
|
||||
upUrl : "/Upload",
|
||||
allowShare:"1",
|
||||
allowRemoteDownload:"1",
|
||||
allowTorrentDownload:"1",
|
||||
};
|
||||
</script>
|
||||
<!-- <script src="http://lite.aoaoao.me/dev/moxie.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/plupload.dev.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/i18n/zh_CN.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/ui.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/qiniu.js"></script>
|
||||
<script src="http://lite.aoaoao.me/dev/main.js"></script> -->
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-cn">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="shortcut icon" href="/favicon.ico">
|
||||
<link rel="stylesheet" href="/static/css/mdeditor/editormd.min.css" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="theme-color" content="{$options.themeColor}" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is added to the
|
||||
homescreen on Android. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>{$fileName} - {$options.siteName}</title>
|
||||
<script type="text/javascript">
|
||||
colorTheme = {:json_encode($options["themeConfig"])};
|
||||
isHomePage = false;
|
||||
isSharePage = false;
|
||||
pageId="";
|
||||
apiURL={
|
||||
imgThumb:"/File/Thumb",
|
||||
preview:"/File/Preview",
|
||||
download:"/File/Download",
|
||||
docPreiview:'/File/DocPreview',
|
||||
};
|
||||
userInfo={
|
||||
uid:{$userInfo.uid},
|
||||
nick:"{$userInfo.userNick}",
|
||||
email:"{$userInfo.userMail}",
|
||||
group:"{$userInfo.groupData.group_name}",
|
||||
groupId:{$userInfo.groupData.id},
|
||||
groupColor:"{$userInfo.groupData.color}",
|
||||
};
|
||||
siteInfo = {
|
||||
mainTitle:"{$fileName}",
|
||||
};
|
||||
fileInfo={
|
||||
url:"{$url}",
|
||||
name:"{$fileName}",
|
||||
path:"{$path}",
|
||||
};
|
||||
mediaType = {},
|
||||
isMobile = window.innerWidth<600;
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
<script src="/static/js/jquery.min.js"></script>
|
||||
<script src="/static/js/mdeditor/editormd.min.js"></script>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-cn">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="shortcut icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="theme-color" content="{$options.themeColor}" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is added to the
|
||||
homescreen on Android. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>{$fileName} - {$options.siteName}</title>
|
||||
<script type="text/javascript">
|
||||
colorTheme = {:json_encode($options["themeConfig"])};
|
||||
isHomePage = false;
|
||||
isSharePage = false;
|
||||
pageId="";
|
||||
apiURL={
|
||||
imgThumb:"/File/Thumb",
|
||||
preview:"/File/Preview",
|
||||
download:"/File/Download",
|
||||
docPreiview:'/File/DocPreview',
|
||||
};
|
||||
userInfo={
|
||||
uid:{$userInfo.uid},
|
||||
nick:"{$userInfo.userNick}",
|
||||
email:"{$userInfo.userMail}",
|
||||
group:"{$userInfo.groupData.group_name}",
|
||||
groupId:{$userInfo.groupData.id},
|
||||
groupColor:"{$userInfo.groupData.color}",
|
||||
};
|
||||
siteInfo = {
|
||||
mainTitle:"{$fileName}",
|
||||
};
|
||||
videoInfo={
|
||||
url:"{$url}",
|
||||
name:"{$fileName}"
|
||||
};
|
||||
mediaType = {},
|
||||
isMobile = window.innerWidth<600;
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,189 @@
|
|||
'use strict';
|
||||
|
||||
// Do this as the first thing so that any code reading it knows the right env.
|
||||
process.env.BABEL_ENV = 'production';
|
||||
process.env.NODE_ENV = 'production';
|
||||
|
||||
// Makes the script crash on unhandled rejections instead of silently
|
||||
// ignoring them. In the future, promise rejections that are not handled will
|
||||
// terminate the Node.js process with a non-zero exit code.
|
||||
process.on('unhandledRejection', err => {
|
||||
throw err;
|
||||
});
|
||||
|
||||
// Ensure environment variables are read.
|
||||
require('../config/env');
|
||||
|
||||
|
||||
const path = require('path');
|
||||
const chalk = require('chalk');
|
||||
const fs = require('fs-extra');
|
||||
const webpack = require('webpack');
|
||||
const bfj = require('bfj');
|
||||
const config = require('../config/webpack.config.prod');
|
||||
const paths = require('../config/paths');
|
||||
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
|
||||
const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');
|
||||
const printHostingInstructions = require('react-dev-utils/printHostingInstructions');
|
||||
const FileSizeReporter = require('react-dev-utils/FileSizeReporter');
|
||||
const printBuildError = require('react-dev-utils/printBuildError');
|
||||
|
||||
const measureFileSizesBeforeBuild =
|
||||
FileSizeReporter.measureFileSizesBeforeBuild;
|
||||
const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild;
|
||||
const useYarn = fs.existsSync(paths.yarnLockFile);
|
||||
|
||||
// These sizes are pretty large. We'll warn for bundles exceeding them.
|
||||
const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024;
|
||||
const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024;
|
||||
|
||||
const isInteractive = process.stdout.isTTY;
|
||||
|
||||
// Warn and crash if required files are missing
|
||||
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Process CLI arguments
|
||||
const argv = process.argv.slice(2);
|
||||
const writeStatsJson = argv.indexOf('--stats') !== -1;
|
||||
|
||||
// We require that you explictly set browsers and do not fall back to
|
||||
// browserslist defaults.
|
||||
const { checkBrowsers } = require('react-dev-utils/browsersHelper');
|
||||
checkBrowsers(paths.appPath, isInteractive)
|
||||
.then(() => {
|
||||
// First, read the current file sizes in build directory.
|
||||
// This lets us display how much they changed later.
|
||||
return measureFileSizesBeforeBuild(paths.appBuild);
|
||||
})
|
||||
.then(previousFileSizes => {
|
||||
// Remove all content but keep the directory so that
|
||||
// if you're in it, you don't end up in Trash
|
||||
fs.emptyDirSync(paths.appBuild);
|
||||
// Merge with the public folder
|
||||
copyPublicFolder();
|
||||
// Start the webpack build
|
||||
return build(previousFileSizes);
|
||||
})
|
||||
.then(
|
||||
({ stats, previousFileSizes, warnings }) => {
|
||||
if (warnings.length) {
|
||||
console.log(chalk.yellow('Compiled with warnings.\n'));
|
||||
console.log(warnings.join('\n\n'));
|
||||
console.log(
|
||||
'\nSearch for the ' +
|
||||
chalk.underline(chalk.yellow('keywords')) +
|
||||
' to learn more about each warning.'
|
||||
);
|
||||
console.log(
|
||||
'To ignore, add ' +
|
||||
chalk.cyan('// eslint-disable-next-line') +
|
||||
' to the line before.\n'
|
||||
);
|
||||
} else {
|
||||
console.log(chalk.green('Compiled successfully.\n'));
|
||||
}
|
||||
|
||||
console.log('File sizes after gzip:\n');
|
||||
printFileSizesAfterBuild(
|
||||
stats,
|
||||
previousFileSizes,
|
||||
paths.appBuild,
|
||||
WARN_AFTER_BUNDLE_GZIP_SIZE,
|
||||
WARN_AFTER_CHUNK_GZIP_SIZE
|
||||
);
|
||||
console.log();
|
||||
|
||||
const appPackage = require(paths.appPackageJson);
|
||||
const publicUrl = paths.publicUrl;
|
||||
const publicPath = config.output.publicPath;
|
||||
const buildFolder = path.relative(process.cwd(), paths.appBuild);
|
||||
printHostingInstructions(
|
||||
appPackage,
|
||||
publicUrl,
|
||||
publicPath,
|
||||
buildFolder,
|
||||
useYarn
|
||||
);
|
||||
},
|
||||
err => {
|
||||
console.log(chalk.red('Failed to compile.\n'));
|
||||
printBuildError(err);
|
||||
process.exit(1);
|
||||
}
|
||||
)
|
||||
.catch(err => {
|
||||
if (err && err.message) {
|
||||
console.log(err.message);
|
||||
}
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
// Create the production build and print the deployment instructions.
|
||||
function build(previousFileSizes) {
|
||||
console.log('Creating an optimized production build...');
|
||||
|
||||
let compiler = webpack(config);
|
||||
return new Promise((resolve, reject) => {
|
||||
compiler.run((err, stats) => {
|
||||
let messages;
|
||||
if (err) {
|
||||
if (!err.message) {
|
||||
return reject(err);
|
||||
}
|
||||
messages = formatWebpackMessages({
|
||||
errors: [err.message],
|
||||
warnings: [],
|
||||
});
|
||||
} else {
|
||||
messages = formatWebpackMessages(
|
||||
stats.toJson({ all: false, warnings: true, errors: true })
|
||||
);
|
||||
}
|
||||
if (messages.errors.length) {
|
||||
// Only keep the first error. Others are often indicative
|
||||
// of the same problem, but confuse the reader with noise.
|
||||
if (messages.errors.length > 1) {
|
||||
messages.errors.length = 1;
|
||||
}
|
||||
return reject(new Error(messages.errors.join('\n\n')));
|
||||
}
|
||||
if (
|
||||
process.env.CI &&
|
||||
(typeof process.env.CI !== 'string' ||
|
||||
process.env.CI.toLowerCase() !== 'false') &&
|
||||
messages.warnings.length
|
||||
) {
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
'\nTreating warnings as errors because process.env.CI = true.\n' +
|
||||
'Most CI servers set it automatically.\n'
|
||||
)
|
||||
);
|
||||
return reject(new Error(messages.warnings.join('\n\n')));
|
||||
}
|
||||
|
||||
const resolveArgs = {
|
||||
stats,
|
||||
previousFileSizes,
|
||||
warnings: messages.warnings,
|
||||
};
|
||||
if (writeStatsJson) {
|
||||
return bfj
|
||||
.write(paths.appBuild + '/bundle-stats.json', stats.toJson())
|
||||
.then(() => resolve(resolveArgs))
|
||||
.catch(error => reject(new Error(error)));
|
||||
}
|
||||
|
||||
return resolve(resolveArgs);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function copyPublicFolder() {
|
||||
fs.copySync(paths.appPublic, paths.appBuild, {
|
||||
dereference: true,
|
||||
filter: file => file !== paths.appHtml,
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
'use strict';
|
||||
|
||||
// Do this as the first thing so that any code reading it knows the right env.
|
||||
process.env.BABEL_ENV = 'development';
|
||||
process.env.NODE_ENV = 'development';
|
||||
|
||||
// Makes the script crash on unhandled rejections instead of silently
|
||||
// ignoring them. In the future, promise rejections that are not handled will
|
||||
// terminate the Node.js process with a non-zero exit code.
|
||||
process.on('unhandledRejection', err => {
|
||||
throw err;
|
||||
});
|
||||
|
||||
// Ensure environment variables are read.
|
||||
require('../config/env');
|
||||
|
||||
|
||||
const fs = require('fs');
|
||||
const chalk = require('chalk');
|
||||
const webpack = require('webpack');
|
||||
const WebpackDevServer = require('webpack-dev-server');
|
||||
const clearConsole = require('react-dev-utils/clearConsole');
|
||||
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
|
||||
const {
|
||||
choosePort,
|
||||
createCompiler,
|
||||
prepareProxy,
|
||||
prepareUrls,
|
||||
} = require('react-dev-utils/WebpackDevServerUtils');
|
||||
const openBrowser = require('react-dev-utils/openBrowser');
|
||||
const paths = require('../config/paths');
|
||||
const config = require('../config/webpack.config.dev');
|
||||
const createDevServerConfig = require('../config/webpackDevServer.config');
|
||||
|
||||
const useYarn = fs.existsSync(paths.yarnLockFile);
|
||||
const isInteractive = process.stdout.isTTY;
|
||||
|
||||
// Warn and crash if required files are missing
|
||||
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Tools like Cloud9 rely on this.
|
||||
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000;
|
||||
const HOST = process.env.HOST || '0.0.0.0';
|
||||
|
||||
if (process.env.HOST) {
|
||||
console.log(
|
||||
chalk.cyan(
|
||||
`Attempting to bind to HOST environment variable: ${chalk.yellow(
|
||||
chalk.bold(process.env.HOST)
|
||||
)}`
|
||||
)
|
||||
);
|
||||
console.log(
|
||||
`If this was unintentional, check that you haven't mistakenly set it in your shell.`
|
||||
);
|
||||
console.log(
|
||||
`Learn more here: ${chalk.yellow('http://bit.ly/CRA-advanced-config')}`
|
||||
);
|
||||
console.log();
|
||||
}
|
||||
|
||||
// We require that you explictly set browsers and do not fall back to
|
||||
// browserslist defaults.
|
||||
const { checkBrowsers } = require('react-dev-utils/browsersHelper');
|
||||
checkBrowsers(paths.appPath, isInteractive)
|
||||
.then(() => {
|
||||
// We attempt to use the default port but if it is busy, we offer the user to
|
||||
// run on a different port. `choosePort()` Promise resolves to the next free port.
|
||||
return choosePort(HOST, DEFAULT_PORT);
|
||||
})
|
||||
.then(port => {
|
||||
if (port == null) {
|
||||
// We have not found a port.
|
||||
return;
|
||||
}
|
||||
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
|
||||
const appName = require(paths.appPackageJson).name;
|
||||
const urls = prepareUrls(protocol, HOST, port);
|
||||
// Create a webpack compiler that is configured with custom messages.
|
||||
const compiler = createCompiler(webpack, config, appName, urls, useYarn);
|
||||
// Load proxy config
|
||||
const proxySetting = require(paths.appPackageJson).proxy;
|
||||
const proxyConfig = prepareProxy(proxySetting, paths.appPublic);
|
||||
// Serve webpack assets generated by the compiler over a web server.
|
||||
const serverConfig = createDevServerConfig(
|
||||
proxyConfig,
|
||||
urls.lanUrlForConfig
|
||||
);
|
||||
const devServer = new WebpackDevServer(compiler, serverConfig);
|
||||
// Launch WebpackDevServer.
|
||||
devServer.listen(port, HOST, err => {
|
||||
if (err) {
|
||||
return console.log(err);
|
||||
}
|
||||
if (isInteractive) {
|
||||
clearConsole();
|
||||
}
|
||||
console.log(chalk.cyan('Starting the development server...\n'));
|
||||
openBrowser(urls.localUrlForBrowser);
|
||||
});
|
||||
|
||||
['SIGINT', 'SIGTERM'].forEach(function(sig) {
|
||||
process.on(sig, function() {
|
||||
devServer.close();
|
||||
process.exit();
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
if (err && err.message) {
|
||||
console.log(err.message);
|
||||
}
|
||||
process.exit(1);
|
||||
});
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
'use strict';
|
||||
|
||||
// Do this as the first thing so that any code reading it knows the right env.
|
||||
process.env.BABEL_ENV = 'test';
|
||||
process.env.NODE_ENV = 'test';
|
||||
process.env.PUBLIC_URL = '';
|
||||
|
||||
// Makes the script crash on unhandled rejections instead of silently
|
||||
// ignoring them. In the future, promise rejections that are not handled will
|
||||
// terminate the Node.js process with a non-zero exit code.
|
||||
process.on('unhandledRejection', err => {
|
||||
throw err;
|
||||
});
|
||||
|
||||
// Ensure environment variables are read.
|
||||
require('../config/env');
|
||||
|
||||
|
||||
const jest = require('jest');
|
||||
const execSync = require('child_process').execSync;
|
||||
let argv = process.argv.slice(2);
|
||||
|
||||
function isInGitRepository() {
|
||||
try {
|
||||
execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' });
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function isInMercurialRepository() {
|
||||
try {
|
||||
execSync('hg --cwd . root', { stdio: 'ignore' });
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Watch unless on CI, in coverage mode, or explicitly running all tests
|
||||
if (
|
||||
!process.env.CI &&
|
||||
argv.indexOf('--coverage') === -1 &&
|
||||
argv.indexOf('--watchAll') === -1
|
||||
) {
|
||||
// https://github.com/facebook/create-react-app/issues/5210
|
||||
const hasSourceControl = isInGitRepository() || isInMercurialRepository();
|
||||
argv.push(hasSourceControl ? '--watch' : '--watchAll');
|
||||
}
|
||||
|
||||
|
||||
jest.run(argv);
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import CssBaseline from '@material-ui/core/CssBaseline';
|
||||
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
|
||||
import Navbar from "./component/Navbar.js"
|
||||
import FileManager from "./component/FileManager/FileManager.js"
|
||||
import AlertBar from "./component/Snackbar"
|
||||
|
||||
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles';
|
||||
|
||||
const theme = createMuiTheme(window.colorTheme);
|
||||
const styles = theme => ({
|
||||
|
||||
root: {
|
||||
display: 'flex',
|
||||
},
|
||||
content: {
|
||||
flexGrow: 1,
|
||||
padding: theme.spacing.unit * 0,
|
||||
minWidth: 0,
|
||||
},
|
||||
toolbar: theme.mixins.toolbar,
|
||||
});
|
||||
|
||||
class App extends Component {
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
return (
|
||||
<React.Fragment>
|
||||
<MuiThemeProvider theme={theme}>
|
||||
<div className={classes.root} id="container">
|
||||
<CssBaseline />
|
||||
<AlertBar/>
|
||||
<Navbar />
|
||||
<main className={classes.content}>
|
||||
<div className={classes.toolbar} />
|
||||
<FileManager/>
|
||||
</main>
|
||||
</div></MuiThemeProvider>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
App.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default withStyles(styles)(App);
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import App from './App';
|
||||
|
||||
it('renders without crashing', () => {
|
||||
const div = document.createElement('div');
|
||||
ReactDOM.render(<App />, div);
|
||||
ReactDOM.unmountComponentAtNode(div);
|
||||
});
|
||||
|
|
@ -0,0 +1,193 @@
|
|||
export const navitateTo = path => {
|
||||
return {
|
||||
type: 'NAVIGATOR_TO',
|
||||
path:path,
|
||||
}
|
||||
}
|
||||
|
||||
export const navitateUp = () => {
|
||||
return {
|
||||
type: 'NAVIGATOR_UP',
|
||||
}
|
||||
}
|
||||
|
||||
export const drawerToggleAction = open => {
|
||||
return {
|
||||
type: 'DRAWER_TOGGLE',
|
||||
open:open,
|
||||
}
|
||||
}
|
||||
|
||||
export const changeViewMethod = method => {
|
||||
return {
|
||||
type: 'CHANGE_VIEW_METHOD',
|
||||
method:method,
|
||||
}
|
||||
}
|
||||
|
||||
export const changeSortMethod = method => {
|
||||
return {
|
||||
type: 'CHANGE_SORT_METHOD',
|
||||
method:method,
|
||||
}
|
||||
}
|
||||
|
||||
export const updateFileList = list => {
|
||||
return {
|
||||
type: 'UPDATE_FILE_LIST',
|
||||
list:list,
|
||||
}
|
||||
}
|
||||
|
||||
export const changeContextMenu = (type,open) => {
|
||||
return {
|
||||
type: 'CHANGE_CONTEXT_MENU',
|
||||
menuType:type,
|
||||
open:open,
|
||||
}
|
||||
}
|
||||
|
||||
export const addSelectedTarget = targets => {
|
||||
return {
|
||||
type: 'ADD_SELECTED_TARGET',
|
||||
targets:targets,
|
||||
}
|
||||
}
|
||||
|
||||
export const setSelectedTarget = targets => {
|
||||
return {
|
||||
type: 'SET_SELECTED_TARGET',
|
||||
targets:targets,
|
||||
}
|
||||
}
|
||||
|
||||
export const removeSelectedTarget = id => {
|
||||
return {
|
||||
type: 'RMOVE_SELECTED_TARGET',
|
||||
id:id,
|
||||
}
|
||||
}
|
||||
|
||||
export const setNavigatorLoadingStatus = status => {
|
||||
return {
|
||||
type: 'SET_NAVIGATOR_LOADING_STATUE',
|
||||
status:status,
|
||||
}
|
||||
}
|
||||
|
||||
export const setNavigatorError = (status,msg) => {
|
||||
return {
|
||||
type: 'SET_NAVIGATOR_ERROR',
|
||||
status:status,
|
||||
msg:msg,
|
||||
}
|
||||
}
|
||||
|
||||
export const openCreateFolderDialog = () => {
|
||||
return {
|
||||
type: 'OPEN_CREATE_FOLDER_DIALOG',
|
||||
}
|
||||
}
|
||||
|
||||
export const openRenameDialog = () => {
|
||||
return {
|
||||
type: 'OPEN_RENAME_DIALOG',
|
||||
}
|
||||
}
|
||||
|
||||
export const openMoveDialog = () => {
|
||||
return {
|
||||
type: 'OPEN_MOVE_DIALOG',
|
||||
}
|
||||
}
|
||||
|
||||
export const openRemoveDialog = () => {
|
||||
return {
|
||||
type: 'OPEN_REMOVE_DIALOG',
|
||||
}
|
||||
}
|
||||
|
||||
export const openShareDialog = () => {
|
||||
return {
|
||||
type: 'OPEN_SHARE_DIALOG',
|
||||
}
|
||||
}
|
||||
|
||||
export const openMusicDialog = () => {
|
||||
return {
|
||||
type: 'OPEN_MUSIC_DIALOG',
|
||||
}
|
||||
}
|
||||
|
||||
export const openRemoteDownloadDialog = ()=>{
|
||||
return {
|
||||
type:'OPEN_REMOTE_DOWNLOAD_DIALOG',
|
||||
}
|
||||
}
|
||||
|
||||
export const openTorrentDownloadDialog = ()=>{
|
||||
return {
|
||||
type:'OPEN_TORRENT_DOWNLOAD_DIALOG',
|
||||
}
|
||||
}
|
||||
|
||||
export const openGetSourceDialog = ()=>{
|
||||
return {
|
||||
type:'OPEN_GET_SOURCE_DIALOG',
|
||||
}
|
||||
}
|
||||
|
||||
export const closeAllModals = () => {
|
||||
return {
|
||||
type: 'CLOSE_ALL_MODALS',
|
||||
}
|
||||
}
|
||||
|
||||
export const toggleSnackbar = (vertical,horizontal,msg,color) => {
|
||||
return {
|
||||
type: 'TOGGLE_SNACKBAR',
|
||||
vertical:vertical,
|
||||
horizontal:horizontal,
|
||||
msg:msg,
|
||||
color:color,
|
||||
}
|
||||
}
|
||||
|
||||
export const setModalsLoading = (status) => {
|
||||
return {
|
||||
type: 'SET_MODALS_LOADING',
|
||||
status:status,
|
||||
}
|
||||
}
|
||||
|
||||
export const refreshFileList = () => {
|
||||
return {
|
||||
type: 'REFRESH_FILE_LIST',
|
||||
}
|
||||
}
|
||||
|
||||
export const searchMyFile = (keywords) => {
|
||||
return {
|
||||
type: 'SEARCH_MY_FILE',
|
||||
keywords: keywords,
|
||||
}
|
||||
}
|
||||
|
||||
export const showImgPreivew = (first) => {
|
||||
return {
|
||||
type: 'SHOW_IMG_PREIVEW',
|
||||
first: first,
|
||||
}
|
||||
}
|
||||
|
||||
export const refreshStorage = () => {
|
||||
return {
|
||||
type: 'REFRESH_STORAGE',
|
||||
}
|
||||
}
|
||||
|
||||
export const saveFile = () => {
|
||||
return {
|
||||
type: 'SAVE_FILE',
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,355 @@
|
|||
import React, { Component } from 'react'
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import { connect } from 'react-redux'
|
||||
import Card from '@material-ui/core/Card';
|
||||
import LinearProgress from '@material-ui/core/LinearProgress';
|
||||
import ImageIcon from '@material-ui/icons/PhotoSizeSelectActual'
|
||||
import VideoIcon from '@material-ui/icons/Videocam'
|
||||
import AudioIcon from '@material-ui/icons/Audiotrack'
|
||||
import PdfIcon from "@material-ui/icons/PictureAsPdf"
|
||||
import RefreshIcon from "@material-ui/icons/Refresh"
|
||||
import DeleteIcon from "@material-ui/icons/Delete"
|
||||
import FileShowIcon from "@material-ui/icons/InsertDriveFile"
|
||||
import {FileWordBox,FilePowerpointBox,FileExcelBox,ScriptText,MagnetOn,ZipBox,WindowRestore,Android} from 'mdi-material-ui'
|
||||
import CardContent from '@material-ui/core/CardContent';
|
||||
import { toggleSnackbar,}from "../actions/index"
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import axios from 'axios'
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import {sizeToString} from '../untils/index'
|
||||
import {mediaType} from "../config"
|
||||
|
||||
const styles = theme => ({
|
||||
card: {
|
||||
marginTop:"20px",
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
},
|
||||
actions: {
|
||||
display: 'flex',
|
||||
},
|
||||
title:{
|
||||
marginTop:"20px",
|
||||
},
|
||||
layout: {
|
||||
width: 'auto',
|
||||
marginTop:'30px',
|
||||
marginLeft: theme.spacing.unit * 3,
|
||||
marginRight: theme.spacing.unit * 3,
|
||||
[theme.breakpoints.up(1100 + theme.spacing.unit * 3 * 2)]: {
|
||||
width: 700,
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
},
|
||||
},
|
||||
shareTitle:{
|
||||
maxWidth:"200px",
|
||||
},
|
||||
avatarFile:{
|
||||
backgroundColor: theme.palette.primary.light,
|
||||
},
|
||||
avatarFolder:{
|
||||
backgroundColor: theme.palette.secondary.light,
|
||||
},
|
||||
gird:{
|
||||
marginTop:"30px",
|
||||
},
|
||||
iconContainer:{
|
||||
width:"90px",
|
||||
height:"90px",
|
||||
padding: "29px",
|
||||
marginTop: "6px",
|
||||
paddingLeft: "35px",
|
||||
[theme.breakpoints.down("md")]: {
|
||||
display:"none"
|
||||
}
|
||||
},
|
||||
content:{
|
||||
width:"100%",
|
||||
minWidth: 0,
|
||||
},
|
||||
contentSide:{
|
||||
minWidth: 0,
|
||||
paddingTop: "24px",
|
||||
paddingRight: "28px",
|
||||
[theme.breakpoints.down("md")]: {
|
||||
display:"none"
|
||||
}
|
||||
},
|
||||
iconImgBig:{
|
||||
color:"#d32f2f",
|
||||
fontSize: "30px",
|
||||
},
|
||||
iconVideoBig:{
|
||||
color:"#d50000",
|
||||
fontSize: "30px",
|
||||
},
|
||||
iconAudioBig:{
|
||||
color:"#651fff",
|
||||
fontSize: "30px",
|
||||
},
|
||||
iconPdfBig:{
|
||||
color:"#f44336",
|
||||
fontSize: "30px",
|
||||
},
|
||||
iconWordBig:{
|
||||
color:"#538ce5",
|
||||
fontSize: "30px",
|
||||
},
|
||||
iconPptBig:{
|
||||
color:"rgb(239, 99, 63)",
|
||||
fontSize: "30px",
|
||||
},
|
||||
iconExcelBig:{
|
||||
color:"#4caf50",
|
||||
fontSize: "30px",
|
||||
},
|
||||
iconTextBig:{
|
||||
color:"#607d8b",
|
||||
fontSize: "30px",
|
||||
},
|
||||
iconFileBig:{
|
||||
color:"#424242",
|
||||
fontSize: "30px",
|
||||
},
|
||||
iconTorrentBig:{
|
||||
color:"#5c6bc0",
|
||||
fontSize: "30px",
|
||||
},
|
||||
iconZipBig:{
|
||||
color:"#f9a825",
|
||||
fontSize: "30px",
|
||||
},
|
||||
iconAndroidBig:{
|
||||
color:"#8bc34a",
|
||||
fontSize: "30px",
|
||||
},
|
||||
iconExeBig:{
|
||||
color:"#1a237e",
|
||||
fontSize: "30px",
|
||||
},
|
||||
hide:{
|
||||
display:"none",
|
||||
},
|
||||
loadingAnimation:{
|
||||
borderRadius: "6px 6px 0 0",
|
||||
},
|
||||
shareFix:{
|
||||
marginLeft: "20px",
|
||||
},
|
||||
loadMore:{
|
||||
textAlign:"center",
|
||||
marginTop:"20px",
|
||||
marginBottom:"20px",
|
||||
}
|
||||
})
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
toggleSnackbar:(vertical,horizontal,msg,color)=>{
|
||||
dispatch(toggleSnackbar(vertical,horizontal,msg,color))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const getIcon = (classes,name)=>{
|
||||
let iconBig;
|
||||
let fileType =name.split(".").pop().toLowerCase();
|
||||
if (mediaType["image"].indexOf(fileType)!==-1){
|
||||
iconBig = (<ImageIcon className={classes.iconImgBig}/>);
|
||||
}else if(mediaType["video"].indexOf(fileType)!==-1){
|
||||
iconBig = (<VideoIcon className={classes.iconVideoBig}/>);
|
||||
}else if(mediaType["audio"].indexOf(fileType)!==-1){
|
||||
iconBig = (<AudioIcon className={classes.iconAudioBig}/>);
|
||||
}else if(mediaType["pdf"].indexOf(fileType)!==-1){
|
||||
iconBig = (<PdfIcon className={classes.iconPdfBig}/>);
|
||||
}else if(mediaType["word"].indexOf(fileType)!==-1){
|
||||
iconBig = (<FileWordBox className={classes.iconWordBig}/>);
|
||||
}else if(mediaType["ppt"].indexOf(fileType)!==-1){
|
||||
iconBig = (<FilePowerpointBox className={classes.iconPptBig}/>);
|
||||
}else if(mediaType["excel"].indexOf(fileType)!==-1){
|
||||
iconBig = (<FileExcelBox className={classes.iconExcelBig}/>);
|
||||
}else if(mediaType["text"].indexOf(fileType)!==-1){
|
||||
iconBig = (<ScriptText className={classes.iconTextBig}/>);
|
||||
}else if(mediaType["torrent"].indexOf(fileType)!==-1){
|
||||
iconBig = (<MagnetOn className={classes.iconTorrentBig}/>);
|
||||
}else if(mediaType["zip"].indexOf(fileType)!==-1){
|
||||
iconBig = (<ZipBox className={classes.iconZipBig}/>);
|
||||
}else if(mediaType["excute"].indexOf(fileType)!==-1){
|
||||
iconBig = (<WindowRestore className={classes.iconExeBig}/>);
|
||||
}else if(mediaType["android"].indexOf(fileType)!==-1){
|
||||
iconBig = (<Android className={classes.iconAndroidBig}/>);
|
||||
}else{
|
||||
iconBig = (<FileShowIcon className={classes.iconTextBig}/>);
|
||||
}
|
||||
return iconBig;
|
||||
}
|
||||
|
||||
class DownloadCompoment extends Component {
|
||||
|
||||
page=0;
|
||||
|
||||
state={
|
||||
downloading:[],
|
||||
loading:false,
|
||||
finishedList:[],
|
||||
continue:true,
|
||||
}
|
||||
|
||||
componentDidMount = ()=>{
|
||||
this.loadDownloading();
|
||||
}
|
||||
|
||||
loadDownloading = ()=>{
|
||||
this.setState({
|
||||
loading:true,
|
||||
});
|
||||
axios.get('/RemoteDownload/FlushUser').then( (response)=> {
|
||||
axios.post('/RemoteDownload/ListDownloading').then((response)=> {
|
||||
this.setState({
|
||||
downloading:response.data,
|
||||
loading:false,
|
||||
});
|
||||
|
||||
})
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.props.toggleSnackbar("top","right","加载失败","error");
|
||||
this.setState({
|
||||
loading:false,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
loadMore = ()=>{
|
||||
this.setState({
|
||||
loading:true,
|
||||
});
|
||||
axios.get('/RemoteDownload/ListFinished?page='+(++this.page)).then( (response)=> {
|
||||
this.setState({
|
||||
finishedList:response.data,
|
||||
loading:false,
|
||||
continue:response.data.length<10?false:true,
|
||||
});
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.props.toggleSnackbar("top","right","加载失败","error");
|
||||
this.setState({
|
||||
loading:false,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
cancelDownload = id=>{
|
||||
axios.post('/RemoteDownload/Cancel',{
|
||||
id:id,
|
||||
}).then( (response)=> {
|
||||
if(response.data.error!==0){
|
||||
this.props.toggleSnackbar("top","right",response.message,"error");
|
||||
}else{
|
||||
this.setState({
|
||||
downloading:this.state.downloading.filter(value=>{
|
||||
return value.id!==id;
|
||||
})
|
||||
});
|
||||
this.props.toggleSnackbar("top","right","取消成功","success");
|
||||
}
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.props.toggleSnackbar("top","right",error.message,"error");
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
|
||||
|
||||
return (
|
||||
<div className={classes.layout}>
|
||||
<Typography color="textSecondary" variant="h4" className={classes.title}>进行中
|
||||
<IconButton disabled={this.state.loading} onClick={this.loadDownloading}><RefreshIcon/></IconButton>
|
||||
</Typography>
|
||||
{this.state.downloading.map(value=>{
|
||||
value.percent = !value.hasOwnProperty("completedLength")?0:(value.completedLength/value.totalLength)
|
||||
return (
|
||||
<Card className={classes.card} key={value.id}>
|
||||
<div className={classes.iconContainer}>
|
||||
{getIcon(classes,value.fileName)}
|
||||
</div>
|
||||
<CardContent className={classes.content}>
|
||||
<Typography color="primary" variant="h6" noWrap>
|
||||
{value.fileName}
|
||||
</Typography>
|
||||
<LinearProgress color="secondary" variant="determinate" value={value.percent} />
|
||||
<Typography variant="subtitle1" color="textSecondary" noWrap >
|
||||
{value.hasOwnProperty("completedLength")&&
|
||||
<span>{value.percent.toFixed(2)}% - {value.completedLength==="0"?"0Bytes":sizeToString(value.completedLength)}/{value.totalLength==="0"?"0Bytes":sizeToString(value.totalLength)} - {value.downloadSpeed==="0"?"0B/s":sizeToString(value.downloadSpeed)+"/s"}</span>
|
||||
}
|
||||
{!value.hasOwnProperty("completedLength")&&
|
||||
<span> - </span>
|
||||
}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
<CardContent className={classes.contentSide} onClick={()=>this.cancelDownload(value.id)}>
|
||||
<IconButton><DeleteIcon/></IconButton>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
})}
|
||||
<Typography color="textSecondary" variant="h4" className={classes.title}>已完成</Typography>
|
||||
<div className={classes.loadMore}>
|
||||
{this.state.finishedList.map(value=>{
|
||||
|
||||
return (
|
||||
<Card className={classes.card} key={value.id}>
|
||||
{(JSON.stringify(value.fileName) !== '[]')&&
|
||||
<div className={classes.iconContainer}>
|
||||
{getIcon(classes,value.fileName)}
|
||||
</div>}
|
||||
|
||||
<CardContent className={classes.content}>
|
||||
<Typography color="primary" variant="h6" style={{ textAlign: "left"}} noWrap>
|
||||
{value.fileName}
|
||||
</Typography>
|
||||
<Typography variant="subtitle1" color="textSecondary" noWrap style={{ textAlign: "left"}}>
|
||||
{(()=>{switch (value.status) {
|
||||
case "canceled":
|
||||
return (<div>已取消</div>);
|
||||
case "error":
|
||||
return (<div>错误:{value.msg}</div>);
|
||||
case "success":
|
||||
return (<div>成功</div>);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
})()}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
})}
|
||||
<Button size="large"
|
||||
className={classes.margin}
|
||||
disabled={!this.state.continue}
|
||||
onClick={this.loadMore}
|
||||
>
|
||||
加载更多
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const Download = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)( withStyles(styles)(DownloadCompoment))
|
||||
|
||||
export default Download
|
||||
|
|
@ -0,0 +1,341 @@
|
|||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux'
|
||||
import {
|
||||
changeContextMenu,
|
||||
setNavigatorLoadingStatus,
|
||||
navitateTo,
|
||||
openCreateFolderDialog,
|
||||
openRenameDialog,
|
||||
openMoveDialog,
|
||||
openRemoveDialog,
|
||||
openShareDialog,
|
||||
showImgPreivew,
|
||||
openMusicDialog,
|
||||
toggleSnackbar,
|
||||
openRemoteDownloadDialog,
|
||||
openTorrentDownloadDialog,
|
||||
openGetSourceDialog,
|
||||
} from "../../actions/index"
|
||||
import {isPreviewable,isTorrent} from "../../config"
|
||||
import {allowSharePreview} from "../../untils/index"
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import Popover from '@material-ui/core/Popover';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import MenuList from '@material-ui/core/MenuList';
|
||||
import MenuItem from '@material-ui/core/MenuItem';
|
||||
import Divider from '@material-ui/core/Divider';
|
||||
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
||||
import UploadIcon from '@material-ui/icons/CloudUpload'
|
||||
import DownloadIcon from '@material-ui/icons/CloudDownload'
|
||||
import NewFolderIcon from '@material-ui/icons/CreateNewFolder'
|
||||
import OpenFolderIcon from '@material-ui/icons/FolderOpen'
|
||||
import ShareIcon from '@material-ui/icons/Share'
|
||||
import RenameIcon from '@material-ui/icons/BorderColor'
|
||||
import MoveIcon from '@material-ui/icons/Input'
|
||||
import LinkIcon from '@material-ui/icons/InsertLink'
|
||||
import DeleteIcon from '@material-ui/icons/Delete'
|
||||
import OpenIcon from '@material-ui/icons/OpenInNew'
|
||||
import {MagnetOn} from 'mdi-material-ui'
|
||||
|
||||
const styles = theme => ({
|
||||
propover:{
|
||||
minWidth:"200px!important",
|
||||
}
|
||||
})
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
menuType:state.viewUpdate.contextType,
|
||||
menuOpen:state.viewUpdate.contextOpen,
|
||||
isMultiple:state.explorer.selectProps.isMultiple,
|
||||
withFolder:state.explorer.selectProps.withFolder,
|
||||
withFile:state.explorer.selectProps.withFile,
|
||||
path:state.navigator.path,
|
||||
selected:state.explorer.selected,
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
changeContextMenu: (type,open) => {
|
||||
dispatch(changeContextMenu(type,open))
|
||||
},
|
||||
setNavigatorLoadingStatus: status => {
|
||||
dispatch(setNavigatorLoadingStatus(status))
|
||||
},
|
||||
navitateTo:path => {
|
||||
dispatch(navitateTo(path))
|
||||
},
|
||||
openCreateFolderDialog:()=>{
|
||||
dispatch(openCreateFolderDialog())
|
||||
},
|
||||
openRenameDialog:()=>{
|
||||
dispatch(openRenameDialog())
|
||||
},
|
||||
openMoveDialog:()=>{
|
||||
dispatch(openMoveDialog())
|
||||
},
|
||||
openRemoveDialog:()=>{
|
||||
dispatch(openRemoveDialog())
|
||||
},
|
||||
openShareDialog:()=>{
|
||||
dispatch(openShareDialog())
|
||||
},
|
||||
showImgPreivew:(first)=>{
|
||||
dispatch(showImgPreivew(first))
|
||||
},
|
||||
openMusicDialog:()=>{
|
||||
dispatch(openMusicDialog())
|
||||
},
|
||||
toggleSnackbar:(vertical,horizontal,msg,color)=>{
|
||||
dispatch(toggleSnackbar(vertical,horizontal,msg,color))
|
||||
},
|
||||
openRemoteDownloadDialog:()=>{
|
||||
dispatch(openRemoteDownloadDialog())
|
||||
},
|
||||
openTorrentDownloadDialog:()=>{
|
||||
dispatch(openTorrentDownloadDialog())
|
||||
},
|
||||
openGetSourceDialog:()=>{
|
||||
dispatch(openGetSourceDialog())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ContextMenuCompoment extends Component {
|
||||
|
||||
X=0;
|
||||
Y=0;
|
||||
|
||||
state={
|
||||
}
|
||||
|
||||
componentDidMount = ()=>{
|
||||
window.document.addEventListener("mousemove",this.setPoint);
|
||||
}
|
||||
|
||||
setPoint = e=>{
|
||||
this.Y=e.clientY;
|
||||
this.X=e.clientX;
|
||||
};
|
||||
|
||||
|
||||
openDownload = ()=>{
|
||||
if(!allowSharePreview()){
|
||||
this.props.toggleSnackbar("top","right","未登录用户无法预览","warning");
|
||||
this.props.changeContextMenu("file",false);
|
||||
return;
|
||||
}
|
||||
this.props.changeContextMenu("file",false);
|
||||
let downloadPath = this.props.selected[0].path === "/" ? this.props.selected[0].path+this.props.selected[0].name:this.props.selected[0].path+"/"+this.props.selected[0].name;
|
||||
window.open(window.apiURL.download+"?action=download&path="+encodeURIComponent(downloadPath));
|
||||
|
||||
}
|
||||
|
||||
enterFolder = () => {
|
||||
this.props.navitateTo(this.props.path==="/"?this.props.path+this.props.selected[0].name:this.props.path+"/"+this.props.selected[0].name);
|
||||
}
|
||||
|
||||
clickUpload = () => {
|
||||
this.props.changeContextMenu("empty",false);
|
||||
let uploadButton = document.getElementsByClassName("uploadForm")[0];
|
||||
if (document.body.contains(uploadButton)){
|
||||
uploadButton.click();
|
||||
}else{
|
||||
this.props.toggleSnackbar("top","right","上传组件还未加载完成","warning");
|
||||
}
|
||||
}
|
||||
|
||||
openPreview = ()=>{
|
||||
if(!allowSharePreview()){
|
||||
this.props.toggleSnackbar("top","right","未登录用户无法预览","warning");
|
||||
this.props.changeContextMenu("file",false);
|
||||
return;
|
||||
}
|
||||
this.props.changeContextMenu("file",false);
|
||||
let previewPath = this.props.selected[0].path === "/" ? this.props.selected[0].path+this.props.selected[0].name:this.props.selected[0].path+"/"+this.props.selected[0].name;
|
||||
switch(isPreviewable(this.props.selected[0].name)){
|
||||
case 'img':
|
||||
this.props.showImgPreivew(this.props.selected[0]);
|
||||
return;
|
||||
case 'msDoc':
|
||||
window.open(window.apiURL.docPreiview+"/?path="+encodeURIComponent(previewPath));
|
||||
return;
|
||||
case 'audio':
|
||||
this.props.openMusicDialog();
|
||||
return;
|
||||
case 'open':
|
||||
window.open(window.apiURL.preview+"/?action=preview&path="+encodeURIComponent(previewPath));
|
||||
return;
|
||||
case 'video':
|
||||
if(window.isSharePage){
|
||||
window.location.href=("/Viewer/Video?share=true&shareKey="+window.shareInfo.shareId+"&path="+encodeURIComponent(previewPath));
|
||||
return;
|
||||
}
|
||||
window.location.href=("/Viewer/Video?&path="+encodeURIComponent(previewPath));
|
||||
return;
|
||||
case 'edit':
|
||||
if(window.isSharePage){
|
||||
window.location.href=("/Viewer/Markdown?share=true&shareKey="+window.shareInfo.shareId+"&path="+encodeURIComponent(previewPath));
|
||||
return;
|
||||
}
|
||||
window.location.href=("/Viewer/Markdown?path="+encodeURIComponent(previewPath));
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
const { classes} = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Popover
|
||||
id="simple-popper"
|
||||
open={this.props.menuOpen}
|
||||
anchorReference="anchorPosition"
|
||||
anchorPosition={{ top: this.Y, left: this.X }}
|
||||
onClose={()=>this.props.changeContextMenu(this.props.menuType,false)}
|
||||
anchorOrigin={{
|
||||
vertical: 'top',
|
||||
horizontal: 'left',
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: 'top',
|
||||
horizontal: 'left',
|
||||
}}
|
||||
>
|
||||
{this.props.menuType==="empty"&&
|
||||
<MenuList>
|
||||
<MenuItem onClick={this.clickUpload}>
|
||||
<ListItemIcon>
|
||||
<UploadIcon/>
|
||||
</ListItemIcon>
|
||||
<Typography variant="inherit">上传文件</Typography>
|
||||
</MenuItem>
|
||||
{window.uploadConfig.allowRemoteDownload==="1"&&
|
||||
<MenuItem onClick={()=>this.props.openRemoteDownloadDialog()}>
|
||||
<ListItemIcon>
|
||||
<DownloadIcon/>
|
||||
</ListItemIcon>
|
||||
<Typography variant="inherit">离线下载</Typography>
|
||||
</MenuItem>
|
||||
}
|
||||
|
||||
<Divider/>
|
||||
<MenuItem onClick = {()=>this.props.openCreateFolderDialog()}>
|
||||
<ListItemIcon>
|
||||
<NewFolderIcon/>
|
||||
</ListItemIcon>
|
||||
<Typography variant="inherit">创建文件夹</Typography>
|
||||
</MenuItem>
|
||||
|
||||
</MenuList>
|
||||
}
|
||||
{this.props.menuType!=="empty"&&
|
||||
<MenuList>
|
||||
{(!this.props.isMultiple && this.props.withFolder)&&
|
||||
<MenuItem onClick={this.enterFolder}>
|
||||
<ListItemIcon>
|
||||
<OpenFolderIcon/>
|
||||
</ListItemIcon>
|
||||
<Typography variant="inherit">进入</Typography>
|
||||
</MenuItem>
|
||||
}
|
||||
{(!this.props.isMultiple&&this.props.withFile&&isPreviewable(this.props.selected[0].name))&&
|
||||
<div>
|
||||
<MenuItem onClick={()=>this.openPreview()}>
|
||||
<ListItemIcon>
|
||||
<OpenIcon/>
|
||||
</ListItemIcon>
|
||||
<Typography variant="inherit">打开</Typography>
|
||||
</MenuItem>
|
||||
<Divider/>
|
||||
</div>
|
||||
}
|
||||
|
||||
{(!this.props.isMultiple&&this.props.withFile)&&
|
||||
<MenuItem onClick={()=>this.openDownload()}>
|
||||
<ListItemIcon>
|
||||
<DownloadIcon/>
|
||||
</ListItemIcon>
|
||||
<Typography variant="inherit">下载</Typography>
|
||||
</MenuItem>
|
||||
}
|
||||
|
||||
{(!this.props.isMultiple&&this.props.withFile&&(window.uploadConfig.allowSource==="1"))&&
|
||||
<MenuItem onClick={()=>this.props.openGetSourceDialog()}>
|
||||
<ListItemIcon>
|
||||
<LinkIcon/>
|
||||
</ListItemIcon>
|
||||
<Typography variant="inherit">获取外链</Typography>
|
||||
</MenuItem>
|
||||
}
|
||||
|
||||
{(!this.props.isMultiple&&window.isHomePage&&(window.uploadConfig.allowTorrentDownload==="1")&&this.props.withFile&&isTorrent(this.props.selected[0].name))&&
|
||||
<MenuItem onClick={()=>this.props.openTorrentDownloadDialog()}>
|
||||
<ListItemIcon>
|
||||
<MagnetOn/>
|
||||
</ListItemIcon>
|
||||
<Typography variant="inherit">创建离线下载任务</Typography>
|
||||
</MenuItem>
|
||||
}
|
||||
|
||||
{(!this.props.isMultiple &&window.isHomePage)&&
|
||||
<MenuItem onClick={()=>this.props.openShareDialog()}>
|
||||
<ListItemIcon>
|
||||
<ShareIcon/>
|
||||
</ListItemIcon>
|
||||
<Typography variant="inherit">分享</Typography>
|
||||
</MenuItem>
|
||||
}
|
||||
|
||||
{(!this.props.isMultiple&&window.isHomePage)&&
|
||||
<MenuItem onClick={()=>this.props.openRenameDialog() }>
|
||||
<ListItemIcon>
|
||||
<RenameIcon/>
|
||||
</ListItemIcon>
|
||||
<Typography variant="inherit">重命名</Typography>
|
||||
</MenuItem>
|
||||
}
|
||||
{window.isHomePage&&<div>
|
||||
<MenuItem onClick={()=>this.props.openMoveDialog() }>
|
||||
<ListItemIcon>
|
||||
<MoveIcon/>
|
||||
</ListItemIcon>
|
||||
<Typography variant="inherit">移动</Typography>
|
||||
</MenuItem>
|
||||
<Divider/>
|
||||
<MenuItem className={classes.propover} onClick={()=>this.props.openRemoveDialog()}>
|
||||
<ListItemIcon>
|
||||
<DeleteIcon/>
|
||||
</ListItemIcon>
|
||||
<Typography variant="inherit">删除</Typography>
|
||||
</MenuItem>
|
||||
</div>}
|
||||
|
||||
|
||||
|
||||
</MenuList>
|
||||
}
|
||||
</Popover>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ContextMenuCompoment.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
menuType:PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
|
||||
const ContextMenu = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)( withStyles(styles)(ContextMenuCompoment))
|
||||
|
||||
export default ContextMenu
|
||||
|
|
@ -0,0 +1,271 @@
|
|||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux'
|
||||
|
||||
import {navitateTo,changeContextMenu,navitateUp} from "../../actions/index"
|
||||
import ObjectIcon from "./ObjectIcon"
|
||||
import ContextMenu from "./ContextMenu"
|
||||
import Table from '@material-ui/core/Table';
|
||||
import TableBody from '@material-ui/core/TableBody';
|
||||
import TableCell from '@material-ui/core/TableCell';
|
||||
import TableHead from '@material-ui/core/TableHead';
|
||||
import TableRow from '@material-ui/core/TableRow';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import CircularProgress from '@material-ui/core/CircularProgress';
|
||||
import Paper from '@material-ui/core/Paper'
|
||||
import EmptyIcon from "@material-ui/icons/Unarchive"
|
||||
import SadIcon from "@material-ui/icons/SentimentVeryDissatisfied"
|
||||
import classNames from 'classnames';
|
||||
import ImgPreivew from "./ImgPreview"
|
||||
import Button from '@material-ui/core/Button';
|
||||
import UpIcon from '@material-ui/icons/ArrowUpward'
|
||||
|
||||
const styles = theme => ({
|
||||
paper: {
|
||||
padding: theme.spacing.unit * 2,
|
||||
textAlign: 'center',
|
||||
color: theme.palette.text.secondary,
|
||||
margin:"10px",
|
||||
|
||||
},
|
||||
root: {
|
||||
flexGrow: 1,
|
||||
padding:"10px",
|
||||
overflowY: "auto",
|
||||
height: "calc(100vh - 112px)",
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
overflowY: "auto",
|
||||
height: "calc(100vh - 112px)",
|
||||
},
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
height: "100%",
|
||||
},
|
||||
},
|
||||
rootTable:{
|
||||
padding:"0px",
|
||||
backgroundColor:theme.palette.background.paper.white,
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
overflowY: "auto",
|
||||
height: "calc(100vh - 112px)",
|
||||
},
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
height: "100%",
|
||||
},
|
||||
},
|
||||
typeHeader:{
|
||||
margin: "10px 25px",
|
||||
color: "#6b6b6b",
|
||||
fontWeight: "500",
|
||||
},
|
||||
loading:{
|
||||
justifyContent: "center",
|
||||
display: "flex",
|
||||
marginTop:"40px",
|
||||
},
|
||||
errorBox:{
|
||||
padding: theme.spacing.unit * 4,
|
||||
},
|
||||
errorMsg:{
|
||||
marginTop:"10px",
|
||||
},
|
||||
emptyContainer:{
|
||||
bottom: "0",
|
||||
height: "300px",
|
||||
margin: "50px auto",
|
||||
width: "300px",
|
||||
color: theme.palette.explorer.emptyIcon,
|
||||
textAlign: "center",
|
||||
paddingTop: "20px",
|
||||
},
|
||||
emptyIcon:{
|
||||
fontSize: "160px",
|
||||
},
|
||||
emptyInfoBig:{
|
||||
fontSize: "25px",
|
||||
color:theme.palette.text.disabled,
|
||||
},
|
||||
emptyInfoSmall:{
|
||||
color:theme.palette.text.hint,
|
||||
},
|
||||
hideAuto:{
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
display:"none",
|
||||
}
|
||||
},
|
||||
flexFix:{
|
||||
minWidth: 0,
|
||||
},
|
||||
upButton:{
|
||||
marginLeft: "20px",
|
||||
marginTop: "10px",
|
||||
marginBottom: "10px",
|
||||
}
|
||||
})
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
path: state.navigator.path,
|
||||
drawerDesktopOpen:state.viewUpdate.open,
|
||||
viewMethod:state.viewUpdate.explorerViewMethod,
|
||||
sortMethod:state.viewUpdate.sortMethod,
|
||||
fileList:state.explorer.fileList,
|
||||
dirList:state.explorer.dirList,
|
||||
loading:state.viewUpdate.navigatorLoading,
|
||||
navigatorError:state.viewUpdate.navigatorError,
|
||||
navigatorErrorMsg:state.viewUpdate.navigatorErrorMsg,
|
||||
keywords:state.explorer.keywords,
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
navigateToPath: path => {
|
||||
dispatch(navitateTo(path))
|
||||
},
|
||||
|
||||
changeContextMenu: (type,open) => {
|
||||
dispatch(changeContextMenu(type,open))
|
||||
},
|
||||
navitateUp:()=>{
|
||||
dispatch(navitateUp())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ExplorerCompoment extends Component {
|
||||
|
||||
contextMenu = (e) => {
|
||||
e.preventDefault();
|
||||
if(this.props.keywords===null&&!window.isSharePage){
|
||||
if(!this.props.loading){
|
||||
this.props.changeContextMenu("empty",true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
const { classes} = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
onContextMenu = {this.contextMenu}
|
||||
className={classNames({
|
||||
[classes.root]: this.props.viewMethod!=="list",
|
||||
[classes.rootTable]: this.props.viewMethod==="list",
|
||||
}, classes.button)}
|
||||
>
|
||||
<ContextMenu/>
|
||||
<ImgPreivew/>
|
||||
{this.props.navigatorError&&
|
||||
<Paper elevation={1} className={classes.errorBox}>
|
||||
<Typography variant="h5" component="h3">
|
||||
:( 请求时出现错误
|
||||
</Typography>
|
||||
<Typography color={"textSecondary"} className={classes.errorMsg}>{this.props.navigatorErrorMsg.message}</Typography>
|
||||
</Paper>
|
||||
}
|
||||
|
||||
{(this.props.loading && !this.props.navigatorError) &&
|
||||
<div className={classes.loading}>
|
||||
<CircularProgress />
|
||||
</div>
|
||||
}
|
||||
|
||||
{(window.isMobile&&this.props.path!=="/"&&!this.props.loading)&&
|
||||
<Button variant="outlined" className={classes.upButton} onClick={()=>this.props.navitateUp()}>
|
||||
<UpIcon/>回到上级目录
|
||||
</Button>
|
||||
}
|
||||
|
||||
{(this.props.keywords===null&&window.isHomePage&&this.props.dirList.length===0&&this.props.fileList.length===0&&!this.props.loading&&!this.props.navigatorError)&&
|
||||
<div className={classes.emptyContainer}>
|
||||
<EmptyIcon className={classes.emptyIcon}/>
|
||||
<div className={classes.emptyInfoBig}>拖拽文件至此</div>
|
||||
<div className={classes.emptyInfoSmall}>或点击左侧“上传文件”按钮添加文件</div>
|
||||
|
||||
</div>
|
||||
}
|
||||
{((this.props.keywords!==null&&this.props.dirList.length===0&&this.props.fileList.length===0&&!this.props.loading&&!this.props.navigatorError)||(this.props.dirList.length===0&&this.props.fileList.length===0&&!this.props.loading&&!this.props.navigatorError&&window.isSharePage))&&
|
||||
<div className={classes.emptyContainer}>
|
||||
<SadIcon className={classes.emptyIcon}/>
|
||||
<div className={classes.emptyInfoBig}>什么都没有找到</div>
|
||||
|
||||
</div>
|
||||
}
|
||||
{(this.props.viewMethod!=="list" &&(this.props.dirList.length!==0||this.props.fileList.length!==0)&&!this.props.loading)&&
|
||||
<div className={classes.flexFix}>
|
||||
|
||||
{(this.props.dirList.length!==0 && !this.props.loading)&&
|
||||
<div>
|
||||
<Typography className={classes.typeHeader}>文件夹</Typography>
|
||||
<Grid container spacing={0}
|
||||
alignItems="flex-start"
|
||||
>
|
||||
{this.props.dirList.map((value,index)=>(
|
||||
<Grid item xs={6} md={3} sm={4} lg={2}>
|
||||
<ObjectIcon file={value}/>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</div>
|
||||
}
|
||||
{(this.props.fileList.length!==0 && !this.props.loading)&&
|
||||
<div>
|
||||
<Typography className={classes.typeHeader}>文件</Typography>
|
||||
<Grid container spacing={0}
|
||||
alignItems="flex-start"
|
||||
>
|
||||
{this.props.fileList.map((value,index)=>(
|
||||
<Grid item xs={6} md={3} sm={4} lg={2}>
|
||||
<ObjectIcon file={value}/>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
{(this.props.viewMethod==="list" &&(this.props.dirList.length!==0 || this.props.fileList.length!==0)&&!this.props.loading)&&
|
||||
<Table className={classes.table}>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>名称</TableCell>
|
||||
<TableCell className={classes.hideAuto}>大小</TableCell>
|
||||
<TableCell className={classes.hideAuto}>日期</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{this.props.dirList.map((value,index)=>(
|
||||
<ObjectIcon file={value}/>
|
||||
))}
|
||||
{this.props.fileList.map((value,index)=>(
|
||||
<ObjectIcon file={value}/>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
}
|
||||
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ExplorerCompoment.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
path:PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
|
||||
const Explorer = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)( withStyles(styles)(ExplorerCompoment))
|
||||
|
||||
export default Explorer
|
||||
|
|
@ -0,0 +1,345 @@
|
|||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux'
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
|
||||
import ButtonBase from '@material-ui/core/ButtonBase';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import classNames from 'classnames';
|
||||
import {allowSharePreview} from "../../untils/index"
|
||||
import ImageIcon from '@material-ui/icons/PhotoSizeSelectActual'
|
||||
import VideoIcon from '@material-ui/icons/Videocam'
|
||||
import AudioIcon from '@material-ui/icons/Audiotrack'
|
||||
import PdfIcon from "@material-ui/icons/PictureAsPdf"
|
||||
import Divider from "@material-ui/core/Divider"
|
||||
import FileShowIcon from "@material-ui/icons/InsertDriveFile"
|
||||
import Tooltip from '@material-ui/core/Tooltip';
|
||||
import {FileWordBox,FilePowerpointBox,FileExcelBox,ScriptText,MagnetOn,ZipBox,WindowRestore,Android} from 'mdi-material-ui'
|
||||
import { LazyLoadImage } from 'react-lazy-load-image-component';
|
||||
import ContentLoader from 'react-content-loader'
|
||||
import {mediaType} from "../../config"
|
||||
|
||||
const styles = theme => ({
|
||||
container: {
|
||||
padding: "7px",
|
||||
},
|
||||
|
||||
selected: {
|
||||
"&:hover": {
|
||||
border: "1px solid #d0d0d0",
|
||||
},
|
||||
backgroundColor: theme.palette.explorer.bgSelected,
|
||||
|
||||
},
|
||||
|
||||
notSelected: {
|
||||
"&:hover": {
|
||||
backgroundColor: "#f9f9f9",
|
||||
border: "1px solid #d0d0d0",
|
||||
},
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
},
|
||||
|
||||
button: {
|
||||
border: "1px solid #dadce0",
|
||||
width: "100%",
|
||||
borderRadius: "6px",
|
||||
boxSizing: "border-box",
|
||||
transition: "background-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,box-shadow 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,border 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms",
|
||||
alignItems: "initial",
|
||||
display: "initial",
|
||||
},
|
||||
folderNameSelected: {
|
||||
color: theme.palette.primary.dark,
|
||||
fontWeight: "500",
|
||||
},
|
||||
folderNameNotSelected: {
|
||||
color: theme.palette.explorer.filename,
|
||||
},
|
||||
folderName: {
|
||||
marginTop: "15px",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: "nowrap",
|
||||
overflow: "hidden",
|
||||
marginRight: "20px",
|
||||
},
|
||||
preview:{
|
||||
overflow: "hidden",
|
||||
height:"150px",
|
||||
width:"100%",
|
||||
borderRadius: "6px 6px 0 0",
|
||||
},
|
||||
previewIcon:{
|
||||
overflow: "hidden",
|
||||
height:"149px",
|
||||
width:"100%",
|
||||
borderRadius: "6px 6px 0 0",
|
||||
backgroundColor:theme.palette.background.paper,
|
||||
paddingTop:"50px",
|
||||
},
|
||||
picPreview:{
|
||||
"height": "auto",
|
||||
"width": "100%",
|
||||
},
|
||||
fileInfo:{
|
||||
height:"50px",
|
||||
display: "flex",
|
||||
},
|
||||
icon: {
|
||||
margin: "10px 10px 10px 16px",
|
||||
height: "30px",
|
||||
minWidth: "30px",
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
borderRadius: "90%",
|
||||
paddingTop: "2px",
|
||||
color: theme.palette.explorer.icon,
|
||||
},
|
||||
iconImg : {
|
||||
color:"#d32f2f",
|
||||
},
|
||||
iconImgBig:{
|
||||
color:"#d32f2f",
|
||||
fontSize: "50px",
|
||||
},
|
||||
iconVideo : {
|
||||
color:"#d50000",
|
||||
},
|
||||
iconVideoBig:{
|
||||
color:"#d50000",
|
||||
fontSize: "50px",
|
||||
},
|
||||
iconAudio : {
|
||||
color:"#651fff",
|
||||
},
|
||||
iconAudioBig:{
|
||||
color:"#651fff",
|
||||
fontSize: "50px",
|
||||
},
|
||||
iconPdf : {
|
||||
color:"#f44336",
|
||||
},
|
||||
iconPdfBig:{
|
||||
color:"#f44336",
|
||||
fontSize: "50px",
|
||||
},
|
||||
iconWord : {
|
||||
color:"#538ce5",
|
||||
},
|
||||
iconWordBig:{
|
||||
color:"#538ce5",
|
||||
fontSize: "50px",
|
||||
},
|
||||
iconPpt : {
|
||||
color:"rgb(239, 99, 63)",
|
||||
},
|
||||
iconPptBig:{
|
||||
color:"rgb(239, 99, 63)",
|
||||
fontSize: "50px",
|
||||
},
|
||||
iconExcel : {
|
||||
color:"#4caf50",
|
||||
},
|
||||
iconExcelBig:{
|
||||
color:"#4caf50",
|
||||
fontSize: "50px",
|
||||
},
|
||||
iconText : {
|
||||
color:"#607d8b",
|
||||
},
|
||||
iconTextBig:{
|
||||
color:"#607d8b",
|
||||
fontSize: "50px",
|
||||
},
|
||||
iconFile : {
|
||||
color:"#424242",
|
||||
},
|
||||
iconFileBig:{
|
||||
color:"#424242",
|
||||
fontSize: "50px",
|
||||
},
|
||||
iconTorrent : {
|
||||
color:"#5c6bc0",
|
||||
},
|
||||
iconTorrentBig:{
|
||||
color:"#5c6bc0",
|
||||
fontSize: "50px",
|
||||
},
|
||||
iconZip : {
|
||||
color:"#f9a825",
|
||||
},
|
||||
iconZipBig:{
|
||||
color:"#f9a825",
|
||||
fontSize: "50px",
|
||||
},
|
||||
iconAndroid : {
|
||||
color:"#8bc34a",
|
||||
},
|
||||
iconAndroidBig:{
|
||||
color:"#8bc34a",
|
||||
fontSize: "50px",
|
||||
},
|
||||
iconExe : {
|
||||
color:"#1a237e",
|
||||
},
|
||||
iconExeBig:{
|
||||
color:"#1a237e",
|
||||
fontSize: "50px",
|
||||
},
|
||||
hide:{
|
||||
display:"none",
|
||||
},
|
||||
loadingAnimation:{
|
||||
borderRadius: "6px 6px 0 0",
|
||||
},
|
||||
shareFix:{
|
||||
marginLeft: "20px",
|
||||
}
|
||||
})
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
path: state.navigator.path,
|
||||
selected: state.explorer.selected,
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class FileIconCompoment extends Component {
|
||||
|
||||
static defaultProps = {
|
||||
share: false,
|
||||
}
|
||||
|
||||
state={
|
||||
loading:false,
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
const { classes } = this.props;
|
||||
|
||||
const isSelected = (this.props.selected.findIndex((value) => {
|
||||
return value === this.props.file;
|
||||
})) !== -1;
|
||||
|
||||
let icon,iconBig;
|
||||
let fileType =this.props.file.name.split(".").pop().toLowerCase();
|
||||
if (mediaType["image"].indexOf(fileType)!==-1){
|
||||
icon = (<ImageIcon className={classes.iconImg}/>);
|
||||
iconBig = (<ImageIcon className={classes.iconImgBig}/>);
|
||||
}else if(mediaType["video"].indexOf(fileType)!==-1){
|
||||
icon = (<VideoIcon className={classes.iconVideo}/>);
|
||||
iconBig = (<VideoIcon className={classes.iconVideoBig}/>);
|
||||
}else if(mediaType["audio"].indexOf(fileType)!==-1){
|
||||
icon = (<AudioIcon className={classes.iconAudio}/>);
|
||||
iconBig = (<AudioIcon className={classes.iconAudioBig}/>);
|
||||
}else if(mediaType["pdf"].indexOf(fileType)!==-1){
|
||||
icon = (<PdfIcon className={classes.iconPdf}/>);
|
||||
iconBig = (<PdfIcon className={classes.iconPdfBig}/>);
|
||||
}else if(mediaType["word"].indexOf(fileType)!==-1){
|
||||
icon = (<FileWordBox className={classes.iconWord}/>);
|
||||
iconBig = (<FileWordBox className={classes.iconWordBig}/>);
|
||||
}else if(mediaType["ppt"].indexOf(fileType)!==-1){
|
||||
icon = (<FilePowerpointBox className={classes.iconPpt}/>);
|
||||
iconBig = (<FilePowerpointBox className={classes.iconPptBig}/>);
|
||||
}else if(mediaType["excel"].indexOf(fileType)!==-1){
|
||||
icon = (<FileExcelBox className={classes.iconExcel}/>);
|
||||
iconBig = (<FileExcelBox className={classes.iconExcelBig}/>);
|
||||
}else if(mediaType["text"].indexOf(fileType)!==-1){
|
||||
icon = (<ScriptText className={classes.iconText}/>);
|
||||
iconBig = (<ScriptText className={classes.iconTextBig}/>);
|
||||
}else if(mediaType["torrent"].indexOf(fileType)!==-1){
|
||||
icon = (<MagnetOn className={classes.iconTorrent}/>);
|
||||
iconBig = (<MagnetOn className={classes.iconTorrentBig}/>);
|
||||
}else if(mediaType["zip"].indexOf(fileType)!==-1){
|
||||
icon = (<ZipBox className={classes.iconZip}/>);
|
||||
iconBig = (<ZipBox className={classes.iconZipBig}/>);
|
||||
}else if(mediaType["excute"].indexOf(fileType)!==-1){
|
||||
icon = (<WindowRestore className={classes.iconExe}/>);
|
||||
iconBig = (<WindowRestore className={classes.iconExeBig}/>);
|
||||
}else if(mediaType["android"].indexOf(fileType)!==-1){
|
||||
icon = (<Android className={classes.iconAndroid}/>);
|
||||
iconBig = (<Android className={classes.iconAndroidBig}/>);
|
||||
}else{
|
||||
icon = (<FileShowIcon className={classes.iconText}/>);
|
||||
iconBig = (<FileShowIcon className={classes.iconTextBig}/>);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classes.container}>
|
||||
<ButtonBase
|
||||
focusRipple
|
||||
className={classNames({
|
||||
[classes.selected]: isSelected,
|
||||
[classes.notSelected]: !isSelected,
|
||||
}, classes.button)}
|
||||
>
|
||||
{(this.props.file.pic!==""&& this.props.file.pic!==" "&&allowSharePreview())&&
|
||||
<div className={classes.preview}>
|
||||
<LazyLoadImage
|
||||
className = {classNames({
|
||||
[classes.hide]:this.state.loading,
|
||||
[classes.picPreview]:!this.state.loading,
|
||||
})}
|
||||
src={window.apiURL.imgThumb+"?isImg=true&path="+encodeURIComponent(this.props.file.path==="/"?this.props.file.path+this.props.file.name:this.props.file.path+"/"+this.props.file.name)}
|
||||
afterLoad = {()=>this.setState({loading:false})}
|
||||
beforeLoad = {()=>this.setState({loading:true})}
|
||||
/>
|
||||
<ContentLoader
|
||||
height={150}
|
||||
width={170}
|
||||
className = {classNames({
|
||||
[classes.hide]:!this.state.loading,
|
||||
},classes.loadingAnimation)}
|
||||
>
|
||||
<rect x="0" y="0" width="100%" height="150" />
|
||||
</ContentLoader>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
}
|
||||
{(this.props.file.pic===""|| this.props.file.pic===" "||!allowSharePreview())&&
|
||||
<div className={classes.previewIcon}>
|
||||
{iconBig}
|
||||
</div>
|
||||
|
||||
}
|
||||
{(this.props.file.pic===""|| this.props.file.pic===" "||!allowSharePreview())&& <Divider/> }
|
||||
<div className={classes.fileInfo}>
|
||||
{!this.props.share&&<div className={classNames(classes.icon, {
|
||||
[classes.iconSelected]: isSelected,
|
||||
[classes.iconNotSelected]: !isSelected,
|
||||
})}>{icon}</div>}
|
||||
<Tooltip title={this.props.file.name} aria-label={this.props.file.name}>
|
||||
<Typography className={classNames(classes.folderName, {
|
||||
[classes.folderNameSelected]: isSelected,
|
||||
[classes.folderNameNotSelected]: !isSelected,
|
||||
[classes.shareFix]:this.props.share,
|
||||
})}>{this.props.file.name}</Typography>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</ButtonBase>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
FileIconCompoment.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
file: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
|
||||
const FileIcon = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(withStyles(styles)(FileIconCompoment))
|
||||
|
||||
export default FileIcon
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
import React, { Component } from 'react'
|
||||
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
|
||||
import Navigator from "./Navigator"
|
||||
import Explorer from "./Explorer"
|
||||
import Modals from "./Modals"
|
||||
|
||||
const styles = theme => ({
|
||||
|
||||
})
|
||||
|
||||
class FileManager extends Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<Modals/>
|
||||
<Navigator/>
|
||||
<Explorer/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
FileManager.propTypes = {
|
||||
};
|
||||
|
||||
export default withStyles(styles)(FileManager);
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux'
|
||||
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
|
||||
import ButtonBase from '@material-ui/core/ButtonBase';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import FolderIcon from '@material-ui/icons/Folder'
|
||||
import classNames from 'classnames';
|
||||
import Tooltip from '@material-ui/core/Tooltip';
|
||||
|
||||
const styles = theme => ({
|
||||
container: {
|
||||
padding: "7px",
|
||||
},
|
||||
|
||||
selected: {
|
||||
"&:hover": {
|
||||
border: "1px solid #d0d0d0",
|
||||
},
|
||||
backgroundColor: theme.palette.explorer.bgSelected,
|
||||
|
||||
},
|
||||
|
||||
notSelected: {
|
||||
"&:hover": {
|
||||
backgroundColor: "#f9f9f9",
|
||||
border: "1px solid #d0d0d0",
|
||||
},
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
},
|
||||
|
||||
button: {
|
||||
height: "50px",
|
||||
border: "1px solid #dadce0",
|
||||
width: "100%",
|
||||
borderRadius: "6px",
|
||||
boxSizing: "border-box",
|
||||
transition: "background-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,box-shadow 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,border 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms",
|
||||
display: "flex",
|
||||
justifyContent: "left",
|
||||
alignItems: "initial",
|
||||
},
|
||||
icon: {
|
||||
margin: "10px 10px 10px 16px",
|
||||
height: "30px",
|
||||
minWidth: "30px",
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
borderRadius: "90%",
|
||||
paddingTop: "2px",
|
||||
color: theme.palette.explorer.icon,
|
||||
},
|
||||
folderNameSelected: {
|
||||
color: theme.palette.primary.dark,
|
||||
fontWeight: "500",
|
||||
},
|
||||
folderNameNotSelected: {
|
||||
color: theme.palette.explorer.filename,
|
||||
},
|
||||
folderName: {
|
||||
marginTop: "15px",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: "nowrap",
|
||||
overflow: "hidden",
|
||||
marginRight: "20px",
|
||||
}
|
||||
})
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
selected: state.explorer.selected,
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class FolderCompoment extends Component {
|
||||
|
||||
state = {
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
|
||||
const { classes } = this.props;
|
||||
|
||||
const isSelected = (this.props.selected.findIndex((value) => {
|
||||
return value === this.props.folder;
|
||||
})) !== -1;
|
||||
|
||||
return (
|
||||
<ButtonBase
|
||||
focusRipple
|
||||
className={classNames({
|
||||
[classes.selected]: isSelected,
|
||||
[classes.notSelected]: !isSelected,
|
||||
}, classes.button)}
|
||||
>
|
||||
<div className={classNames(classes.icon, {
|
||||
[classes.iconSelected]: isSelected,
|
||||
[classes.iconNotSelected]: !isSelected,
|
||||
})}><FolderIcon /></div>
|
||||
<Tooltip title={this.props.folder.name} aria-label={this.props.folder.name}>
|
||||
<Typography className={classNames(classes.folderName, {
|
||||
[classes.folderNameSelected]: isSelected,
|
||||
[classes.folderNameNotSelected]: !isSelected,
|
||||
})}>{this.props.folder.name}</Typography>
|
||||
</Tooltip>
|
||||
</ButtonBase>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
FolderCompoment.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
folder: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
|
||||
const Folder = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(withStyles(styles)(FolderCompoment))
|
||||
|
||||
export default Folder
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux'
|
||||
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import {
|
||||
showImgPreivew,
|
||||
}from "../../actions/index"
|
||||
import {imgPreviewSuffix} from "../../config"
|
||||
import PhotoSwipe from'react-photoswipe';
|
||||
import('react-photoswipe/lib/photoswipe.css')
|
||||
|
||||
const styles = theme => ({
|
||||
})
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
first:state.explorer.imgPreview.first,
|
||||
other:state.explorer.imgPreview.other,
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
showImgPreivew:(first)=>{
|
||||
dispatch(showImgPreivew(first))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ImgPreviewCompoment extends Component {
|
||||
|
||||
state = {
|
||||
first:[],
|
||||
items:[],
|
||||
open:false,
|
||||
loaded:false,
|
||||
}
|
||||
|
||||
options={
|
||||
history: false,
|
||||
focus: false,
|
||||
showAnimationDuration: 5,
|
||||
hideAnimationDuration: 0,
|
||||
bgOpacity: 0.8,
|
||||
closeOnScroll: 0,
|
||||
};
|
||||
|
||||
componentWillReceiveProps = (nextProps)=>{
|
||||
let items = [];
|
||||
if(nextProps.first!==null){
|
||||
if(!this.state.loaded){
|
||||
this.setState({
|
||||
loaded:true,
|
||||
})
|
||||
}
|
||||
var firstOne;
|
||||
// eslint-disable-next-line
|
||||
nextProps.other.map((value)=>{
|
||||
let fileType =value.name.split(".").pop().toLowerCase();
|
||||
|
||||
if(imgPreviewSuffix.indexOf(fileType)!==-1){
|
||||
let newImg = {
|
||||
h:0,
|
||||
w:0,
|
||||
title:value.name,
|
||||
src:window.apiURL.preview+"?action=preview&path="+encodeURIComponent(value.path==="/"?value.path+value.name:value.path+"/"+value.name),
|
||||
};
|
||||
if((value.path===nextProps.first.path)&&(value.name===nextProps.first.name)){
|
||||
firstOne = newImg;
|
||||
}else{
|
||||
items.push(newImg);
|
||||
}
|
||||
|
||||
};
|
||||
});
|
||||
items.unshift(firstOne);
|
||||
this.setState({
|
||||
items:items,
|
||||
open:true,
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
handleClose=()=>{
|
||||
this.props.showImgPreivew(null);
|
||||
this.setState({
|
||||
loaded:true,
|
||||
open:false,
|
||||
});
|
||||
}
|
||||
|
||||
setSize = (ps,index,item)=>{
|
||||
if (item.h < 1 || item.w < 1) {
|
||||
let img = new Image()
|
||||
img.onload = () => {
|
||||
item.w = img.width
|
||||
item.h = img.height
|
||||
ps.invalidateCurrItems()
|
||||
ps.updateSize(true)
|
||||
}
|
||||
img.src = item.src
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
if(this.state.loaded){
|
||||
return (
|
||||
<div>
|
||||
<PhotoSwipe isOpen={this.state.open} items={this.state.items} options={this.options} onClose={this.handleClose} imageLoadComplete={this.setSize}/>
|
||||
</div>
|
||||
);
|
||||
}else{
|
||||
return (<div></div>);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
ImgPreviewCompoment.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
|
||||
const ImgPreivew = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(withStyles(styles)(ImgPreviewCompoment))
|
||||
|
||||
export default ImgPreivew
|
||||
|
|
@ -0,0 +1,720 @@
|
|||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux'
|
||||
import {
|
||||
closeAllModals,
|
||||
toggleSnackbar,
|
||||
setModalsLoading,
|
||||
refreshFileList,
|
||||
refreshStorage,
|
||||
} from "../../actions/index"
|
||||
import PathSelector from "./PathSelector"
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import Dialog from '@material-ui/core/Dialog';
|
||||
import DialogActions from '@material-ui/core/DialogActions';
|
||||
import DialogContent from '@material-ui/core/DialogContent';
|
||||
import DialogTitle from '@material-ui/core/DialogTitle';
|
||||
import DialogContentText from '@material-ui/core/DialogContentText';
|
||||
import CircularProgress from '@material-ui/core/CircularProgress';
|
||||
import Checkbox from '@material-ui/core/Checkbox';
|
||||
import axios from 'axios'
|
||||
import FormControl from '@material-ui/core/FormControl';
|
||||
import FormControlLabel from '@material-ui/core/FormControlLabel';
|
||||
|
||||
const styles = theme => ({
|
||||
wrapper: {
|
||||
margin: theme.spacing.unit,
|
||||
position: 'relative',
|
||||
},
|
||||
buttonProgress: {
|
||||
color: theme.palette.secondary.light ,
|
||||
position: 'absolute',
|
||||
top: '50%',
|
||||
left: '50%',
|
||||
marginTop: -12,
|
||||
marginLeft: -12,
|
||||
},
|
||||
contentFix:{
|
||||
padding: "10px 24px 0px 24px",
|
||||
},
|
||||
shareUrl:{
|
||||
minWidth:"400px",
|
||||
},
|
||||
widthAnimation:{
|
||||
|
||||
},
|
||||
})
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
path:state.navigator.path,
|
||||
selected:state.explorer.selected,
|
||||
modalsStatus:state.viewUpdate.modals,
|
||||
modalsLoading:state.viewUpdate.modalsLoading,
|
||||
dirList:state.explorer.dirList,
|
||||
fileList:state.explorer.fileList,
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
closeAllModals:()=>{
|
||||
dispatch(closeAllModals());
|
||||
},
|
||||
toggleSnackbar:(vertical,horizontal,msg,color)=>{
|
||||
dispatch(toggleSnackbar(vertical,horizontal,msg,color))
|
||||
},
|
||||
setModalsLoading:(status)=>{
|
||||
dispatch(setModalsLoading(status))
|
||||
},
|
||||
refreshFileList:()=>{
|
||||
dispatch(refreshFileList())
|
||||
},
|
||||
refreshStorage:()=>{
|
||||
dispatch(refreshStorage())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ModalsCompoment extends Component {
|
||||
|
||||
|
||||
state={
|
||||
newFolderName: "",
|
||||
newName:"",
|
||||
selectedPath:"",
|
||||
selectedPathName:"",
|
||||
secretShare:false,
|
||||
sharePwd:"",
|
||||
shareUrl:"",
|
||||
downloadURL:"",
|
||||
remoteDownloadPathSelect:false,
|
||||
source:"",
|
||||
}
|
||||
|
||||
handleInputChange = (e)=>{
|
||||
this.setState({
|
||||
[e.target.id]:e.target.value,
|
||||
});
|
||||
}
|
||||
|
||||
newNameSuffix = "";
|
||||
|
||||
componentWillReceiveProps = (nextProps)=>{
|
||||
if(this.props.modalsStatus.rename!==nextProps.modalsStatus.rename){
|
||||
let name = nextProps.selected[0].name.split(".");
|
||||
if(name.length>1){
|
||||
this.newNameSuffix = name.pop();
|
||||
}
|
||||
this.setState({
|
||||
newName:name.join("."),
|
||||
});
|
||||
return;
|
||||
}
|
||||
if((this.props.modalsStatus.getSource!==nextProps.modalsStatus.getSource)&&nextProps.modalsStatus.getSource===true){
|
||||
axios.post('/File/gerSource', {
|
||||
action: 'source',
|
||||
path:(this.props.selected[0].path === "/"?"":this.props.path)+"/"+this.props.selected[0].name,
|
||||
})
|
||||
.then( (response)=> {
|
||||
this.setState({
|
||||
source:response.data.url,
|
||||
})
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.props.toggleSnackbar("top","right",error.message ,"error");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
submitShare = e => {
|
||||
e.preventDefault();
|
||||
this.props.setModalsLoading(true);
|
||||
axios.post('/File/Share', {
|
||||
action: 'share',
|
||||
item: this.props.selected[0].path === "/" ? this.props.selected[0].path+this.props.selected[0].name:this.props.selected[0].path+"/"+this.props.selected[0].name,
|
||||
shareType:this.state.secretShare?"private":"public",
|
||||
pwd:this.state.sharePwd
|
||||
})
|
||||
.then( (response)=> {
|
||||
if(response.data.result!==""){
|
||||
this.setState({
|
||||
shareUrl:response.data.result,
|
||||
});
|
||||
}else{
|
||||
this.props.toggleSnackbar("top","right",response.data.result.error,"warning");
|
||||
}
|
||||
this.props.setModalsLoading(false);
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.props.toggleSnackbar("top","right",error.message ,"error");
|
||||
this.props.setModalsLoading(false);
|
||||
});
|
||||
}
|
||||
|
||||
submitRemove = e =>{
|
||||
e.preventDefault();
|
||||
this.props.setModalsLoading(true);
|
||||
let dirs=[],items = [];
|
||||
// eslint-disable-next-line
|
||||
this.props.selected.map((value)=>{
|
||||
if(value.type==="dir"){
|
||||
dirs.push(value.path === "/" ? value.path+value.name:value.path+"/"+value.name);
|
||||
}else{
|
||||
items.push(value.path === "/" ? value.path+value.name:value.path+"/"+value.name);
|
||||
}
|
||||
});
|
||||
axios.post('/File/Delete', {
|
||||
action: 'delete',
|
||||
items: items,
|
||||
dirs:dirs,
|
||||
newPath:this.state.selectedPath === "//"?"/":this.state.selectedPath,
|
||||
})
|
||||
.then( (response)=> {
|
||||
if(response.data.result.success){
|
||||
this.onClose();
|
||||
this.props.refreshFileList();
|
||||
}else{
|
||||
this.props.toggleSnackbar("top","right",response.data.result.error,"warning");
|
||||
}
|
||||
this.props.setModalsLoading(false);
|
||||
this.props.refreshStorage();
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.props.toggleSnackbar("top","right",error.message ,"error");
|
||||
this.props.setModalsLoading(false);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
submitMove = e =>{
|
||||
e.preventDefault();
|
||||
this.props.setModalsLoading(true);
|
||||
let dirs=[],items = [];
|
||||
// eslint-disable-next-line
|
||||
this.props.selected.map((value)=>{
|
||||
if(value.type==="dir"){
|
||||
dirs.push(value.path === "/" ? value.path+value.name:value.path+"/"+value.name);
|
||||
}else{
|
||||
items.push(value.path === "/" ? value.path+value.name:value.path+"/"+value.name);
|
||||
}
|
||||
});
|
||||
axios.post('/File/Move', {
|
||||
action: 'move',
|
||||
items: items,
|
||||
dirs:dirs,
|
||||
newPath:this.state.selectedPath === "//"?"/":this.state.selectedPath,
|
||||
})
|
||||
.then( (response)=> {
|
||||
if(response.data.result.success){
|
||||
this.onClose();
|
||||
this.props.refreshFileList();
|
||||
}else{
|
||||
this.props.toggleSnackbar("top","right",response.data.result.error,"warning");
|
||||
}
|
||||
this.props.setModalsLoading(false);
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.props.toggleSnackbar("top","right",error.message ,"error");
|
||||
this.props.setModalsLoading(false);
|
||||
});
|
||||
}
|
||||
|
||||
submitRename = e =>{
|
||||
e.preventDefault();
|
||||
this.props.setModalsLoading(true);
|
||||
let newName = this.state.newName+(this.newNameSuffix===""?"":"."+this.newNameSuffix);
|
||||
if(this.props.dirList.findIndex((value,index)=>{
|
||||
return value.name === newName;
|
||||
})!==-1 || this.props.fileList.findIndex((value,index)=>{
|
||||
return value.name === newName;
|
||||
})!==-1){
|
||||
this.props.toggleSnackbar("top","right","新名称与已有文件重复","warning");
|
||||
this.props.setModalsLoading(false);
|
||||
}else{
|
||||
axios.post('/File/Rename', {
|
||||
action: 'rename',
|
||||
item: (this.props.selected[0].path === "/"?"":this.props.path)+"/"+this.props.selected[0].name,
|
||||
newItemPath:(this.props.selected[0].path === "/"?"":this.props.path)+"/"+newName,
|
||||
})
|
||||
.then( (response)=> {
|
||||
if(response.data.result.success){
|
||||
this.onClose();
|
||||
this.props.refreshFileList();
|
||||
}else{
|
||||
this.props.toggleSnackbar("top","right",response.data.result.error,"warning");
|
||||
}
|
||||
this.props.setModalsLoading(false);
|
||||
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.props.toggleSnackbar("top","right",error.message ,"error");
|
||||
this.props.setModalsLoading(false);
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
submitCreateNewFolder = e =>{
|
||||
e.preventDefault();
|
||||
this.props.setModalsLoading(true);
|
||||
if(this.props.dirList.findIndex((value,index)=>{
|
||||
return value.name === this.state.newFolderName;
|
||||
})!==-1){
|
||||
this.props.toggleSnackbar("top","right","文件夹名称重复","warning");
|
||||
this.props.setModalsLoading(false);
|
||||
}else{
|
||||
axios.post('/File/createFolder', {
|
||||
action: '"createFolder"',
|
||||
newPath: (this.props.path === "/"?"":this.props.path)+"/"+this.state.newFolderName,
|
||||
})
|
||||
.then( (response)=> {
|
||||
if(response.data.result.success){
|
||||
this.onClose();
|
||||
this.props.refreshFileList();
|
||||
}else{
|
||||
this.props.toggleSnackbar("top","right",response.data.result.error,"warning");
|
||||
}
|
||||
this.props.setModalsLoading(false);
|
||||
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.props.setModalsLoading(false);
|
||||
|
||||
this.props.toggleSnackbar("top","right",error.message ,"error");
|
||||
});
|
||||
}
|
||||
//this.props.toggleSnackbar();
|
||||
}
|
||||
|
||||
submitTorrentDownload = e =>{
|
||||
e.preventDefault();
|
||||
this.props.setModalsLoading(true);
|
||||
axios.post('/RemoteDownload/AddTorrent', {
|
||||
action: "torrentDownload",
|
||||
id: this.props.selected[0].id,
|
||||
savePath: this.state.selectedPath,
|
||||
})
|
||||
.then( (response)=> {
|
||||
if(response.data.result.success){
|
||||
this.props.toggleSnackbar("top","right","任务已创建","success");
|
||||
this.onClose();
|
||||
}else{
|
||||
this.props.toggleSnackbar("top","right",response.data.result.error,"warning");
|
||||
}
|
||||
this.props.setModalsLoading(false);
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.props.toggleSnackbar("top","right",error.message ,"error");
|
||||
this.props.setModalsLoading(false);
|
||||
});
|
||||
}
|
||||
|
||||
submitDownload = e=>{
|
||||
e.preventDefault();
|
||||
this.props.setModalsLoading(true);
|
||||
axios.post('/RemoteDownload/addUrl', {
|
||||
action: 'remoteDownload',
|
||||
url: this.state.downloadURL,
|
||||
path: this.state.selectedPath,
|
||||
})
|
||||
.then( (response)=> {
|
||||
if(response.data.result.success){
|
||||
this.props.toggleSnackbar("top","right","任务已创建","success");
|
||||
this.onClose();
|
||||
}else{
|
||||
this.props.toggleSnackbar("top","right",response.data.result.error,"warning");
|
||||
}
|
||||
this.props.setModalsLoading(false);
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.props.toggleSnackbar("top","right",error.message ,"error");
|
||||
this.props.setModalsLoading(false);
|
||||
});
|
||||
}
|
||||
|
||||
setMoveTarget = (folder) =>{
|
||||
let path = folder.path === "/" ?folder.path+folder.name:folder.path+"/"+folder.name;
|
||||
this.setState({
|
||||
selectedPath:path,
|
||||
selectedPathName:folder.name,
|
||||
});
|
||||
}
|
||||
|
||||
remoteDownloadNext = ()=>{
|
||||
this.props.closeAllModals();
|
||||
this.setState({
|
||||
remoteDownloadPathSelect:true,
|
||||
});
|
||||
}
|
||||
|
||||
onClose = ()=>{
|
||||
this.setState({
|
||||
newFolderName: "",
|
||||
newName:"",
|
||||
selectedPath:"",
|
||||
selectedPathName:"",
|
||||
secretShare:false,
|
||||
sharePwd:"",
|
||||
downloadURL:"",
|
||||
shareUrl:"",
|
||||
remoteDownloadPathSelect:false,
|
||||
source:"",
|
||||
});
|
||||
this.newNameSuffix = "";
|
||||
this.props.closeAllModals();
|
||||
}
|
||||
|
||||
handleChange = name => event => {
|
||||
this.setState({ [name]: event.target.checked });
|
||||
};
|
||||
|
||||
render() {
|
||||
|
||||
const { classes} = this.props;
|
||||
|
||||
const previewApi = window.apiURL.preview;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Dialog
|
||||
open={this.props.modalsStatus.getSource}
|
||||
onClose={this.onClose}
|
||||
aria-labelledby="form-dialog-title"
|
||||
>
|
||||
<DialogTitle id="form-dialog-title">获取文件外链</DialogTitle>
|
||||
|
||||
<DialogContent>
|
||||
<form onSubmit={this.submitCreateNewFolder}>
|
||||
<TextField
|
||||
autoFocus
|
||||
margin="dense"
|
||||
id="newFolderName"
|
||||
label="外链地址"
|
||||
type="text"
|
||||
value={this.state.source}
|
||||
fullWidth
|
||||
/>
|
||||
</form>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={this.onClose}>
|
||||
关闭
|
||||
</Button>
|
||||
</DialogActions>
|
||||
|
||||
</Dialog>
|
||||
<Dialog
|
||||
open={this.props.modalsStatus.createNewFolder}
|
||||
onClose={this.onClose}
|
||||
aria-labelledby="form-dialog-title"
|
||||
>
|
||||
<DialogTitle id="form-dialog-title">新建文件夹</DialogTitle>
|
||||
|
||||
<DialogContent>
|
||||
<form onSubmit={this.submitCreateNewFolder}>
|
||||
<TextField
|
||||
autoFocus
|
||||
margin="dense"
|
||||
id="newFolderName"
|
||||
label="文件夹名称"
|
||||
type="text"
|
||||
value={this.state.newFolderName}
|
||||
onChange={(e)=>this.handleInputChange(e)}
|
||||
fullWidth
|
||||
/>
|
||||
</form>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={this.onClose}>
|
||||
取消
|
||||
</Button>
|
||||
<div className={classes.wrapper}>
|
||||
<Button onClick={this.submitCreateNewFolder} color="primary" disabled={this.state.newFolderName==="" || this.props.modalsLoading }>
|
||||
创建
|
||||
{this.props.modalsLoading && <CircularProgress size={24} className={classes.buttonProgress} />}
|
||||
</Button>
|
||||
</div>
|
||||
</DialogActions>
|
||||
|
||||
</Dialog>
|
||||
<Dialog
|
||||
open={this.props.modalsStatus.rename}
|
||||
onClose={this.onClose}
|
||||
aria-labelledby="form-dialog-title"
|
||||
maxWidth="sm"
|
||||
fullWidth={true}
|
||||
>
|
||||
<DialogTitle id="form-dialog-title">重命名</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText>
|
||||
输入 <strong>{this.props.selected.length===1?this.props.selected[0].name:""}</strong> 的新名称:
|
||||
</DialogContentText>
|
||||
<form onSubmit={this.submitRename}>
|
||||
<TextField
|
||||
autoFocus
|
||||
margin="dense"
|
||||
id="newName"
|
||||
label="新名称"
|
||||
type="text"
|
||||
value={this.state.newName}
|
||||
onChange={(e)=>this.handleInputChange(e)}
|
||||
fullWidth
|
||||
|
||||
/>
|
||||
</form>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={this.onClose}>
|
||||
取消
|
||||
</Button>
|
||||
<div className={classes.wrapper}>
|
||||
<Button onClick={this.submitRename} color="primary" disabled={this.state.newName==="" || this.props.modalsLoading }>
|
||||
确定
|
||||
{this.props.modalsLoading && <CircularProgress size={24} className={classes.buttonProgress} />}
|
||||
</Button>
|
||||
</div>
|
||||
</DialogActions>
|
||||
|
||||
</Dialog>
|
||||
<Dialog
|
||||
open={this.props.modalsStatus.move}
|
||||
onClose={this.onClose}
|
||||
aria-labelledby="form-dialog-title"
|
||||
>
|
||||
<DialogTitle id="form-dialog-title">移动至</DialogTitle>
|
||||
<PathSelector presentPath={this.props.path} selected={this.props.selected} onSelect ={ this.setMoveTarget}/>
|
||||
|
||||
{this.state.selectedPath!==""&&<DialogContent className={classes.contentFix}>
|
||||
<DialogContentText >
|
||||
移动至 <strong>{this.state.selectedPathName}</strong>
|
||||
</DialogContentText>
|
||||
</DialogContent>}
|
||||
<DialogActions>
|
||||
<Button onClick={this.onClose}>
|
||||
取消
|
||||
</Button>
|
||||
<div className={classes.wrapper}>
|
||||
<Button onClick={this.submitMove} color="primary" disabled={this.state.selectedPath==="" || this.props.modalsLoading }>
|
||||
确定
|
||||
{this.props.modalsLoading && <CircularProgress size={24} className={classes.buttonProgress} />}
|
||||
</Button>
|
||||
</div>
|
||||
</DialogActions>
|
||||
|
||||
</Dialog>
|
||||
<Dialog
|
||||
open={this.props.modalsStatus.remove}
|
||||
onClose={this.onClose}
|
||||
aria-labelledby="form-dialog-title"
|
||||
>
|
||||
<DialogTitle id="form-dialog-title">删除对象</DialogTitle>
|
||||
|
||||
<DialogContent>
|
||||
<DialogContentText>
|
||||
确定要删除{(this.props.selected.length === 1)&&
|
||||
<strong> {this.props.selected[0].name} </strong>
|
||||
}{(this.props.selected.length > 1)&&
|
||||
<span>这{this.props.selected.length}个对象</span>
|
||||
}吗?
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={this.onClose}>
|
||||
取消
|
||||
</Button>
|
||||
<div className={classes.wrapper}>
|
||||
<Button onClick={this.submitRemove} color="primary" disabled={this.props.modalsLoading }>
|
||||
确定
|
||||
{this.props.modalsLoading && <CircularProgress size={24} className={classes.buttonProgress} />}
|
||||
</Button>
|
||||
</div>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
<Dialog
|
||||
open={this.props.modalsStatus.share}
|
||||
onClose={this.onClose}
|
||||
aria-labelledby="form-dialog-title"
|
||||
className={classes.widthAnimation}
|
||||
>
|
||||
<DialogTitle id="form-dialog-title">创建分享链接</DialogTitle>
|
||||
|
||||
<DialogContent>
|
||||
<DialogContentText>
|
||||
获取用于共享的链接
|
||||
</DialogContentText>
|
||||
{this.state.shareUrl===""&&
|
||||
<form
|
||||
onSubmit = {this.submitShare}
|
||||
>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={this.state.secretShare}
|
||||
onChange={this.handleChange('secretShare')}
|
||||
name="secretShare"
|
||||
value="false"
|
||||
/>}
|
||||
label="使用密码保护链接"/>
|
||||
{this.state.secretShare&&
|
||||
<FormControl margin="nonw" fullWidth>
|
||||
<TextField
|
||||
id="sharePwd"
|
||||
onChange={this.handleInputChange}
|
||||
label="分享密码"
|
||||
type="password"
|
||||
margin="none"
|
||||
autoFocus
|
||||
value={this.state.sharePwd}
|
||||
required
|
||||
/></FormControl>}
|
||||
</form>
|
||||
}
|
||||
{this.state.shareUrl!==""&&
|
||||
<TextField
|
||||
id="shareUrl"
|
||||
label="分享链接"
|
||||
autoFocus
|
||||
fullWidth
|
||||
className={classes.shareUrl}
|
||||
value={this.state.shareUrl}
|
||||
/>
|
||||
|
||||
}
|
||||
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={this.onClose}>
|
||||
{this.state.shareUrl===""?"取消":"关闭"}
|
||||
</Button>
|
||||
{this.state.shareUrl===""&&<div className={classes.wrapper}>
|
||||
<Button onClick={this.submitShare} color="primary" disabled={this.props.modalsLoading||(this.state.secretShare&&this.state.sharePwd==="") }>
|
||||
确定
|
||||
{this.props.modalsLoading && <CircularProgress size={24} className={classes.buttonProgress} />}
|
||||
</Button>
|
||||
</div>}
|
||||
</DialogActions>
|
||||
|
||||
</Dialog>
|
||||
<Dialog
|
||||
open={this.props.modalsStatus.music}
|
||||
onClose={this.onClose}
|
||||
aria-labelledby="form-dialog-title"
|
||||
>
|
||||
<DialogTitle id="form-dialog-title">音频播放</DialogTitle>
|
||||
|
||||
<DialogContent>
|
||||
<DialogContentText>
|
||||
{(this.props.selected.length!==0)&&
|
||||
<audio controls src={previewApi+"?action=preview&path="+(this.props.selected[0].path === "/" ? this.props.selected[0].path+this.props.selected[0].name:this.props.selected[0].path+"/"+this.props.selected[0].name)}></audio>
|
||||
}
|
||||
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={this.onClose}>
|
||||
关闭
|
||||
</Button>
|
||||
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
<Dialog
|
||||
open={this.props.modalsStatus.remoteDownload}
|
||||
onClose={this.onClose}
|
||||
aria-labelledby="form-dialog-title"
|
||||
fullWidth
|
||||
>
|
||||
<DialogTitle id="form-dialog-title">新建离线下载任务</DialogTitle>
|
||||
|
||||
<DialogContent>
|
||||
<DialogContentText>
|
||||
<TextField
|
||||
label="文件地址"
|
||||
autoFocus
|
||||
fullWidth
|
||||
id="downloadURL"
|
||||
onChange={this.handleInputChange}
|
||||
placeholder="输入文件下载地址,支持 HTTP(s)/FTP/磁力链"
|
||||
></TextField>
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={this.onClose}>
|
||||
关闭
|
||||
</Button>
|
||||
<Button onClick={this.remoteDownloadNext} color="primary" disabled={this.props.modalsLoading||(this.state.downloadURL==="") }>
|
||||
下一步
|
||||
</Button>
|
||||
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
<Dialog
|
||||
open={this.state.remoteDownloadPathSelect}
|
||||
onClose={this.onClose}
|
||||
aria-labelledby="form-dialog-title"
|
||||
>
|
||||
<DialogTitle id="form-dialog-title">选择存储位置</DialogTitle>
|
||||
<PathSelector presentPath={this.props.path} selected={this.props.selected} onSelect ={ this.setMoveTarget}/>
|
||||
|
||||
{this.state.selectedPath!==""&&<DialogContent className={classes.contentFix}>
|
||||
<DialogContentText >
|
||||
下载至 <strong>{this.state.selectedPathName}</strong>
|
||||
</DialogContentText>
|
||||
</DialogContent>}
|
||||
<DialogActions>
|
||||
<Button onClick={this.onClose}>
|
||||
取消
|
||||
</Button>
|
||||
<div className={classes.wrapper}>
|
||||
<Button onClick={this.submitDownload} color="primary" disabled={this.state.selectedPath==="" || this.props.modalsLoading }>
|
||||
创建任务
|
||||
{this.props.modalsLoading && <CircularProgress size={24} className={classes.buttonProgress} />}
|
||||
</Button>
|
||||
</div>
|
||||
</DialogActions>
|
||||
|
||||
</Dialog>
|
||||
<Dialog
|
||||
open={this.props.modalsStatus.torrentDownload}
|
||||
onClose={this.onClose}
|
||||
aria-labelledby="form-dialog-title"
|
||||
>
|
||||
<DialogTitle id="form-dialog-title">选择存储位置</DialogTitle>
|
||||
<PathSelector presentPath={this.props.path} selected={this.props.selected} onSelect ={ this.setMoveTarget}/>
|
||||
|
||||
{this.state.selectedPath!==""&&<DialogContent className={classes.contentFix}>
|
||||
<DialogContentText >
|
||||
下载至 <strong>{this.state.selectedPathName}</strong>
|
||||
</DialogContentText>
|
||||
</DialogContent>}
|
||||
<DialogActions>
|
||||
<Button onClick={this.onClose}>
|
||||
取消
|
||||
</Button>
|
||||
<div className={classes.wrapper}>
|
||||
<Button onClick={this.submitTorrentDownload} color="primary" disabled={this.state.selectedPath==="" || this.props.modalsLoading }>
|
||||
创建任务
|
||||
{this.props.modalsLoading && <CircularProgress size={24} className={classes.buttonProgress} />}
|
||||
</Button>
|
||||
</div>
|
||||
</DialogActions>
|
||||
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ModalsCompoment.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
|
||||
const Modals = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)( withStyles(styles)(ModalsCompoment))
|
||||
|
||||
export default Modals
|
||||
|
|
@ -0,0 +1,464 @@
|
|||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux'
|
||||
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import Divider from '@material-ui/core/Divider';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import RightIcon from '@material-ui/icons/KeyboardArrowRight'
|
||||
import MoreIcon from '@material-ui/icons/MoreHoriz'
|
||||
import ViewListIcon from '@material-ui/icons/ViewList'
|
||||
import ViewModuleIcon from '@material-ui/icons/ViewModule'
|
||||
import ViewSmallIcon from '@material-ui/icons/ViewComfy'
|
||||
import TextTotateVerticalIcon from '@material-ui/icons/TextRotateVertical'
|
||||
import FolderIcon from '@material-ui/icons/Folder'
|
||||
import ExpandMore from '@material-ui/icons/ExpandMore';
|
||||
import Menu from '@material-ui/core/Menu';
|
||||
import MenuItem from '@material-ui/core/MenuItem';
|
||||
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
||||
import ListItemText from '@material-ui/core/ListItemText';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import ShareIcon from '@material-ui/icons/Share'
|
||||
import NewFolderIcon from '@material-ui/icons/CreateNewFolder'
|
||||
import RefreshIcon from '@material-ui/icons/Refresh'
|
||||
import {
|
||||
navitateTo,
|
||||
navitateUp,
|
||||
changeViewMethod,
|
||||
changeSortMethod,
|
||||
setNavigatorError,
|
||||
updateFileList,
|
||||
setNavigatorLoadingStatus,
|
||||
refreshFileList,
|
||||
setSelectedTarget,
|
||||
openCreateFolderDialog,
|
||||
openShareDialog,
|
||||
} from "../../actions/index"
|
||||
import axios from 'axios'
|
||||
import {setCookie,setGetParameter} from "../../untils/index"
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
path: state.navigator.path,
|
||||
refresh: state.navigator.refresh,
|
||||
drawerDesktopOpen:state.viewUpdate.open,
|
||||
viewMethod:state.viewUpdate.explorerViewMethod,
|
||||
keywords:state.explorer.keywords,
|
||||
sortMethod:state.viewUpdate.sortMethod,
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
navigateToPath: path => {
|
||||
dispatch(navitateTo(path))
|
||||
},
|
||||
navitateUp:()=>{
|
||||
dispatch(navitateUp())
|
||||
},
|
||||
changeView:method=>{
|
||||
dispatch(changeViewMethod(method))
|
||||
},
|
||||
changeSort:method=>{
|
||||
dispatch(changeSortMethod(method))
|
||||
},
|
||||
setNavigatorError:(status,msg)=>{
|
||||
dispatch(setNavigatorError(status,msg))
|
||||
},
|
||||
updateFileList:list=>{
|
||||
dispatch(updateFileList(list))
|
||||
},
|
||||
setNavigatorLoadingStatus:status=>{
|
||||
dispatch(setNavigatorLoadingStatus(status))
|
||||
},
|
||||
refreshFileList:()=>{
|
||||
dispatch(refreshFileList())
|
||||
},
|
||||
setSelectedTarget:(target)=>{
|
||||
dispatch(setSelectedTarget(target))
|
||||
},
|
||||
openCreateFolderDialog:()=>{
|
||||
dispatch(openCreateFolderDialog())
|
||||
},
|
||||
openShareDialog:()=>{
|
||||
dispatch(openShareDialog())
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const delay = (ms) => new Promise(
|
||||
(resolve) => setTimeout(resolve, ms)
|
||||
);
|
||||
|
||||
const sortOptions = [
|
||||
"文件名称正序",
|
||||
"文件名称倒序",
|
||||
"上传时间正序",
|
||||
"上传时间到序",
|
||||
"文件大小正序",
|
||||
"文件大小倒序",
|
||||
];
|
||||
|
||||
const styles = theme => ({
|
||||
container:{
|
||||
[theme.breakpoints.down('xs')]: {
|
||||
display:"none",
|
||||
},
|
||||
height:"48px",
|
||||
overflow:"hidden",
|
||||
backgroundColor:"#fff",
|
||||
},
|
||||
navigatorContainer:{
|
||||
"display": "flex",
|
||||
"justifyContent": "space-between",
|
||||
},
|
||||
nav:{
|
||||
height:"47px",
|
||||
padding:"5px 15px",
|
||||
display:"flex",
|
||||
},
|
||||
optionContainer:{
|
||||
paddingTop: "6px",
|
||||
marginRight:"10px",
|
||||
},
|
||||
rightIcon:{
|
||||
marginTop: "6px",
|
||||
verticalAlign: "top",
|
||||
color:"#868686",
|
||||
},
|
||||
expandMore:{
|
||||
color:"#8d8d8d",
|
||||
},
|
||||
sideButton:{
|
||||
padding:"8px",
|
||||
marginRight:"5px",
|
||||
}
|
||||
})
|
||||
|
||||
class NavigatorCompoment extends Component {
|
||||
|
||||
keywords = null;
|
||||
|
||||
state = {
|
||||
hidden:false,
|
||||
hiddenFolders:[],
|
||||
folders:[],
|
||||
anchorEl: null,
|
||||
hiddenMode:false,
|
||||
anchorHidden:null,
|
||||
anchorSort:null,
|
||||
selectedIndex:0,
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.element = React.createRef();
|
||||
}
|
||||
|
||||
componentDidMount = ()=>{
|
||||
this.renderPath();
|
||||
window.onpopstate = (event)=>{
|
||||
var url = new URL(window.location.href);
|
||||
var c = url.searchParams.get("path");
|
||||
if(c!==null&&c!==this.props.path){
|
||||
this.props.navigateToPath(c);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
renderPath = (path=null)=>{
|
||||
this.setState({
|
||||
folders:path!==null?path.substr(1).split("/"):this.props.path.substr(1).split("/"),
|
||||
});
|
||||
var newPath = path!==null?path:this.props.path;
|
||||
var apiURL = this.keywords===null?window.apiURL.listFile:'/File/SearchFile';
|
||||
newPath = this.keywords===null?newPath:this.keywords;
|
||||
axios.post(apiURL, {
|
||||
action: 'list',
|
||||
path: newPath
|
||||
})
|
||||
.then( (response)=> {
|
||||
this.props.updateFileList(response.data.result);
|
||||
this.props.setNavigatorLoadingStatus(false);
|
||||
let pathTemp = (null?path.substr(1).split("/"):this.props.path.substr(1).split("/")).join(",");
|
||||
setCookie("path_tmp",encodeURIComponent(pathTemp),1);
|
||||
if(this.keywords===null){
|
||||
setGetParameter("path",encodeURIComponent(newPath));
|
||||
}
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.props.setNavigatorError(true,error);
|
||||
});
|
||||
this.checkOverFlow();
|
||||
}
|
||||
|
||||
redresh = (path) => {
|
||||
this.props.setNavigatorLoadingStatus(true);
|
||||
this.props.setNavigatorError(false,"error");
|
||||
this.renderPath(path);
|
||||
}
|
||||
|
||||
componentWillReceiveProps = (nextProps)=>{
|
||||
if(this.props.keywords!==nextProps.keywords){
|
||||
this.keywords=nextProps.keywords
|
||||
}
|
||||
if(this.props.path !== nextProps.path){
|
||||
this.renderPath(nextProps.path);
|
||||
}
|
||||
if(this.props.refresh !== nextProps.refresh){
|
||||
this.redresh(nextProps.path);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
componentDidUpdate = (prevProps,prevStates)=>{
|
||||
if(this.state.folders !== prevStates.folders){
|
||||
this.checkOverFlow();
|
||||
}
|
||||
if(this.props.drawerDesktopOpen !== prevProps.drawerDesktopOpen){
|
||||
delay(500).then(() => this.checkOverFlow());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
checkOverFlow = ()=>{
|
||||
const hasOverflowingChildren = this.element.current.offsetHeight < this.element.current.scrollHeight ||
|
||||
this.element.current.offsetWidth < this.element.current.scrollWidth;
|
||||
if(hasOverflowingChildren && !this.state.hiddenMode){
|
||||
this.setState({hiddenMode:true});
|
||||
}
|
||||
if(!hasOverflowingChildren && this.state.hiddenMode){
|
||||
this.setState({hiddenMode:false});
|
||||
}
|
||||
}
|
||||
|
||||
navigateTo=(event,id)=> {
|
||||
if (id === this.state.folders.length-1){
|
||||
//最后一个路径
|
||||
this.setState({ anchorEl: event.currentTarget });
|
||||
return;
|
||||
}else if(id===-1 && this.state.folders.length === 1 && this.state.folders[0] === ""){
|
||||
this.props.refreshFileList();
|
||||
this.handleClose();
|
||||
return;
|
||||
}else if (id === -1){
|
||||
this.props.navigateToPath("/");
|
||||
this.handleClose();
|
||||
return;
|
||||
}else{
|
||||
this.props.navigateToPath("/"+this.state.folders.slice(0,id+1).join("/"));
|
||||
this.handleClose();
|
||||
}
|
||||
}
|
||||
|
||||
handleClose = () => {
|
||||
this.setState({ anchorEl: null ,anchorHidden:null,anchorSort:null});
|
||||
};
|
||||
|
||||
showHiddenPath = (e) => {
|
||||
this.setState({ anchorHidden: e.currentTarget });
|
||||
}
|
||||
|
||||
showSortOptions = (e) => {
|
||||
this.setState({ anchorSort: e.currentTarget });
|
||||
}
|
||||
|
||||
performAction = e => {
|
||||
this.handleClose();
|
||||
if(e==="refresh"){
|
||||
this.redresh();
|
||||
return;
|
||||
}
|
||||
let presentPath = this.props.path.split("/");
|
||||
let newTarget = [{
|
||||
type:"dir",
|
||||
name:presentPath.pop(),
|
||||
path:presentPath.length===1?"/":presentPath.join("/"),
|
||||
}];
|
||||
//this.props.navitateUp();
|
||||
switch (e) {
|
||||
case "share":
|
||||
this.props.setSelectedTarget(newTarget);
|
||||
this.props.openShareDialog();
|
||||
break;
|
||||
case "newfolder":
|
||||
this.props.openCreateFolderDialog();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
toggleViewMethod = () => {
|
||||
this.props.changeView(this.props.viewMethod==="icon"?"list":(this.props.viewMethod==="list"?"smallIcon":"icon"));
|
||||
}
|
||||
|
||||
handleMenuItemClick = (e,index) => {
|
||||
this.setState({ selectedIndex: index, anchorEl: null });
|
||||
let optionsTable = {
|
||||
0:"namePos",
|
||||
1:"nameRev",
|
||||
2:"timePos",
|
||||
3:"timeRev",
|
||||
4:"sizePos",
|
||||
5:"sizeRes",
|
||||
};
|
||||
this.props.changeSort(optionsTable[index]);
|
||||
this.handleClose();
|
||||
this.props.refreshFileList();
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
|
||||
const { classes} = this.props;
|
||||
|
||||
let presentFolderMenu = (<Menu
|
||||
id="presentFolderMenu"
|
||||
anchorEl={this.state.anchorEl}
|
||||
open={Boolean(this.state.anchorEl)}
|
||||
onClose={this.handleClose}
|
||||
disableAutoFocusItem={true}
|
||||
>
|
||||
<MenuItem onClick={()=>this.performAction("refresh")}>
|
||||
<ListItemIcon><RefreshIcon/></ListItemIcon>
|
||||
刷新
|
||||
</MenuItem>
|
||||
{(this.props.keywords===null&&window.isHomePage)&&
|
||||
<div>
|
||||
<Divider/>
|
||||
<MenuItem onClick={()=>this.performAction("share")}>
|
||||
<ListItemIcon><ShareIcon/></ListItemIcon>
|
||||
分享
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem onClick={()=>this.performAction("newfolder")}>
|
||||
<ListItemIcon><NewFolderIcon/></ListItemIcon>
|
||||
创建文件夹
|
||||
</MenuItem>
|
||||
|
||||
</div>
|
||||
}
|
||||
|
||||
</Menu>);
|
||||
|
||||
return (
|
||||
<div className={classes.container}>
|
||||
<div className={classes.navigatorContainer}>
|
||||
<div className={classes.nav} ref={this.element}>
|
||||
<span>
|
||||
<Button component="span" onClick={(e)=>this.navigateTo(e,-1)}>
|
||||
/
|
||||
</Button>
|
||||
<RightIcon className={classes.rightIcon}/>
|
||||
</span>
|
||||
{this.state.hiddenMode &&
|
||||
<span>
|
||||
<Button title="显示路径" component="span" onClick={this.showHiddenPath}>
|
||||
<MoreIcon/>
|
||||
</Button>
|
||||
<Menu
|
||||
id="hiddenPathMenu"
|
||||
anchorEl={this.state.anchorHidden}
|
||||
open={Boolean(this.state.anchorHidden)}
|
||||
onClose={this.handleClose}
|
||||
disableAutoFocusItem={true}
|
||||
>
|
||||
{this.state.folders.slice(0,-1).map((folder,id)=>(
|
||||
<MenuItem onClick={(e)=>this.navigateTo(e,id)}>
|
||||
<ListItemIcon>
|
||||
<FolderIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText inset primary={folder} />
|
||||
</MenuItem>
|
||||
))}
|
||||
</Menu>
|
||||
<RightIcon className={classes.rightIcon}/>
|
||||
<Button component="span" onClick={(e)=>this.navigateTo(e,this.state.folders.length-1)}>
|
||||
{this.state.folders.slice(-1)}
|
||||
<ExpandMore className={classes.expandMore}/>
|
||||
</Button>
|
||||
{presentFolderMenu}
|
||||
</span>
|
||||
}
|
||||
{!this.state.hiddenMode && this.state.folders.map((folder,id,folders)=>(
|
||||
<span key={id}>
|
||||
{folder !=="" &&
|
||||
<span>
|
||||
<Button component="span" onClick={(e)=>this.navigateTo(e,id)}>
|
||||
{folder === ""?"":folder}
|
||||
{(id === folders.length-1) &&
|
||||
<ExpandMore className={classes.expandMore}/>
|
||||
}
|
||||
</Button>
|
||||
{(id === folders.length-1) &&
|
||||
presentFolderMenu
|
||||
}
|
||||
{(id !== folders.length-1) && <RightIcon className={classes.rightIcon}/>}
|
||||
</span>
|
||||
}
|
||||
|
||||
</span>
|
||||
))}
|
||||
|
||||
</div>
|
||||
<div className={classes.optionContainer}>
|
||||
{(this.props.viewMethod === "icon")&&
|
||||
<IconButton title="列表展示" className={classes.sideButton} onClick={this.toggleViewMethod}>
|
||||
<ViewListIcon fontSize="small" />
|
||||
</IconButton>
|
||||
}
|
||||
{(this.props.viewMethod === "list")&&
|
||||
<IconButton title="小图标展示" className={classes.sideButton} onClick={this.toggleViewMethod}>
|
||||
<ViewSmallIcon fontSize="small" />
|
||||
</IconButton>
|
||||
}
|
||||
|
||||
{(this.props.viewMethod === "smallIcon")&&
|
||||
<IconButton title="大图标展示" className={classes.sideButton} onClick={this.toggleViewMethod}>
|
||||
<ViewModuleIcon fontSize="small" />
|
||||
</IconButton>
|
||||
}
|
||||
|
||||
<IconButton title="排序方式" className={classes.sideButton} onClick={this.showSortOptions}>
|
||||
<TextTotateVerticalIcon fontSize="small" />
|
||||
</IconButton>
|
||||
<Menu
|
||||
id="sort-menu"
|
||||
anchorEl={this.state.anchorSort}
|
||||
open={Boolean(this.state.anchorSort)}
|
||||
onClose={this.handleClose}
|
||||
>
|
||||
{sortOptions.map((option, index) => (
|
||||
<MenuItem
|
||||
key={option}
|
||||
selected={index === this.state.selectedIndex}
|
||||
onClick={event => this.handleMenuItemClick(event, index)}
|
||||
>
|
||||
{option}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Menu>
|
||||
</div>
|
||||
</div>
|
||||
<Divider/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
NavigatorCompoment.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
path:PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
|
||||
const Navigator = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)( withStyles(styles)(NavigatorCompoment))
|
||||
|
||||
export default Navigator
|
||||
|
|
@ -0,0 +1,215 @@
|
|||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux'
|
||||
import {
|
||||
changeContextMenu,
|
||||
setSelectedTarget,
|
||||
addSelectedTarget,
|
||||
removeSelectedTarget,
|
||||
setNavigatorLoadingStatus,
|
||||
navitateTo,
|
||||
showImgPreivew,
|
||||
openMusicDialog,
|
||||
toggleSnackbar
|
||||
} from "../../actions/index"
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import Folder from "./Folder"
|
||||
import FileIcon from "./FileIcon"
|
||||
import SmallIcon from "./SmallIcon"
|
||||
import TableItem from "./TableRow"
|
||||
import classNames from 'classnames';
|
||||
import {isPreviewable} from "../../config"
|
||||
import {allowSharePreview} from "../../untils/index"
|
||||
const styles = theme => ({
|
||||
container: {
|
||||
padding: "7px",
|
||||
},
|
||||
fixFlex:{
|
||||
minWidth:0,
|
||||
}
|
||||
})
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
path: state.navigator.path,
|
||||
selected: state.explorer.selected,
|
||||
viewMethod:state.viewUpdate.explorerViewMethod,
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
ContextMenu: (type, open) => {
|
||||
dispatch(changeContextMenu(type, open))
|
||||
},
|
||||
setSelectedTarget: targets => {
|
||||
dispatch(setSelectedTarget(targets))
|
||||
},
|
||||
addSelectedTarget: targets => {
|
||||
dispatch(addSelectedTarget(targets))
|
||||
},
|
||||
removeSelectedTarget: id => {
|
||||
dispatch(removeSelectedTarget(id));
|
||||
},
|
||||
setNavigatorLoadingStatus: status => {
|
||||
dispatch(setNavigatorLoadingStatus(status));
|
||||
},
|
||||
navitateTo:path => {
|
||||
dispatch(navitateTo(path))
|
||||
},
|
||||
showImgPreivew:(first)=>{
|
||||
dispatch(showImgPreivew(first))
|
||||
},
|
||||
openMusicDialog:()=>{
|
||||
dispatch(openMusicDialog())
|
||||
},
|
||||
toggleSnackbar:(vertical,horizontal,msg,color)=>{
|
||||
dispatch(toggleSnackbar(vertical,horizontal,msg,color))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
class ObjectCompoment extends Component {
|
||||
|
||||
state = {
|
||||
}
|
||||
|
||||
contextMenu = (e) => {
|
||||
e.preventDefault();
|
||||
if ((this.props.selected.findIndex((value) => {
|
||||
return value === this.props.file;
|
||||
})) === -1) {
|
||||
this.props.setSelectedTarget([this.props.file]);
|
||||
}
|
||||
this.props.ContextMenu("file", true);
|
||||
}
|
||||
|
||||
selectFile = (e) => {
|
||||
let presentIndex = this.props.selected.findIndex((value) => {
|
||||
return value === this.props.file;
|
||||
});
|
||||
if (presentIndex !== -1 && e.ctrlKey) {
|
||||
this.props.removeSelectedTarget(presentIndex);
|
||||
} else {
|
||||
if (e.ctrlKey) {
|
||||
this.props.addSelectedTarget(this.props.file);
|
||||
} else {
|
||||
this.props.setSelectedTarget([this.props.file]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleClick=(e)=> {
|
||||
if(window.isMobile){
|
||||
this.selectFile(e);
|
||||
if(this.props.file.type==="dir"){
|
||||
this.enterFolder();
|
||||
return;
|
||||
}
|
||||
}else{
|
||||
this.selectFile(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
handleDoubleClick() {
|
||||
if(this.props.file.type==="dir"){
|
||||
this.enterFolder();
|
||||
return;
|
||||
}
|
||||
if(!allowSharePreview()){
|
||||
this.props.toggleSnackbar("top","right","未登录用户无法预览","warning");
|
||||
return;
|
||||
}
|
||||
let previewPath = this.props.selected[0].path === "/" ? this.props.selected[0].path+this.props.selected[0].name:this.props.selected[0].path+"/"+this.props.selected[0].name;
|
||||
switch(isPreviewable(this.props.selected[0].name)){
|
||||
case 'img':
|
||||
this.props.showImgPreivew(this.props.selected[0]);
|
||||
return;
|
||||
case 'msDoc':
|
||||
window.open(window.apiURL.docPreiview+"/?path="+encodeURIComponent(previewPath));
|
||||
return;
|
||||
case 'audio':
|
||||
this.props.openMusicDialog();
|
||||
return;
|
||||
case 'open':
|
||||
window.open(window.apiURL.preview+"/?action=preview&path="+encodeURIComponent(previewPath));
|
||||
return;
|
||||
case 'video':
|
||||
if(window.isSharePage){
|
||||
window.location.href=("/Viewer/Video?share=true&shareKey="+window.shareInfo.shareId+"&path="+encodeURIComponent(previewPath));
|
||||
return;
|
||||
}
|
||||
window.location.href=("/Viewer/Video?path="+encodeURIComponent(previewPath));
|
||||
return;
|
||||
case 'edit':
|
||||
if(window.isSharePage){
|
||||
window.location.href=("/Viewer/Markdown?share=true&shareKey="+window.shareInfo.shareId+"&path="+encodeURIComponent(previewPath));
|
||||
return;
|
||||
}
|
||||
window.location.href=("/Viewer/Markdown?path="+encodeURIComponent(previewPath));
|
||||
return;
|
||||
default:
|
||||
window.open(window.apiURL.download+"?action=download&path="+encodeURIComponent(previewPath));
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
enterFolder = ()=>{
|
||||
this.props.navitateTo(this.props.path==="/"?this.props.path+this.props.file.name:this.props.path+"/"+this.props.file.name );
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
const { classes } = this.props;
|
||||
|
||||
if(this.props.viewMethod === "list"){
|
||||
return (
|
||||
<TableItem
|
||||
contextMenu={this.contextMenu}
|
||||
handleClick={this.handleClick}
|
||||
handleDoubleClick = {this.handleDoubleClick.bind(this)}
|
||||
file={this.props.file}/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames({
|
||||
[classes.container]: this.props.viewMethod!=="list",
|
||||
})}
|
||||
>
|
||||
<div
|
||||
className={classes.fixFlex}
|
||||
onContextMenu={this.contextMenu}
|
||||
onClick={this.handleClick}
|
||||
onDoubleClick = {this.handleDoubleClick.bind(this)}
|
||||
>
|
||||
{(this.props.file.type==="dir" &&this.props.viewMethod !== "list") &&
|
||||
<Folder folder={this.props.file}/>
|
||||
}
|
||||
{((this.props.file.type==="file") && this.props.viewMethod === "icon") &&
|
||||
<FileIcon file={this.props.file}/>
|
||||
}
|
||||
{((this.props.file.type==="file") && this.props.viewMethod === "smallIcon") &&
|
||||
<SmallIcon file={this.props.file}/>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ObjectCompoment.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
file: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
|
||||
const ObjectIcon = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(withStyles(styles)(ObjectCompoment))
|
||||
|
||||
export default ObjectIcon
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types';
|
||||
import MenuList from '@material-ui/core/MenuList';
|
||||
import MenuItem from '@material-ui/core/MenuItem';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
||||
import ListItemText from '@material-ui/core/ListItemText';
|
||||
import FolderIcon from '@material-ui/icons/Folder'
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction';
|
||||
import RightIcon from "@material-ui/icons/KeyboardArrowRight"
|
||||
import UpIcon from "@material-ui/icons/ArrowUpward"
|
||||
import { connect } from 'react-redux'
|
||||
import classNames from 'classnames';
|
||||
import {
|
||||
toggleSnackbar,
|
||||
} from "../../actions/index"
|
||||
import axios from 'axios'
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
toggleSnackbar:(vertical,horizontal,msg,color)=>{
|
||||
dispatch(toggleSnackbar(vertical,horizontal,msg,color))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const styles = theme => ({
|
||||
iconWhite:{
|
||||
color: theme.palette.common.white,
|
||||
},
|
||||
selected: {
|
||||
backgroundColor: theme.palette.primary.main+"!important",
|
||||
'& $primary, & $icon': {
|
||||
color: theme.palette.common.white,
|
||||
},
|
||||
},
|
||||
primary: {},
|
||||
icon: {},
|
||||
buttonIcon:{},
|
||||
selector:{
|
||||
minWidth: "300px",
|
||||
},
|
||||
container:{
|
||||
maxHeight: "330px",
|
||||
overflowY:" auto",
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
class PathSelectorCompoment extends Component {
|
||||
|
||||
state={
|
||||
presentPath:"/",
|
||||
dirList:[],
|
||||
selectedTarget:null,
|
||||
}
|
||||
|
||||
componentDidMount= ()=>{
|
||||
let toBeLoad = this.props.presentPath;
|
||||
this.enterFolder(toBeLoad);
|
||||
}
|
||||
|
||||
back = ()=>{
|
||||
let paths = this.state.presentPath.split("/");
|
||||
paths.pop();
|
||||
let toBeLoad = paths.join("/");
|
||||
this.enterFolder(toBeLoad===""?"/":toBeLoad);
|
||||
}
|
||||
|
||||
enterFolder = (toBeLoad)=>{
|
||||
axios.post('/File/ListFile', {
|
||||
action: 'list',
|
||||
path: toBeLoad,
|
||||
})
|
||||
.then( (response)=> {
|
||||
var dirList = response.data.result.filter( (x)=> {
|
||||
return (x.type === "dir" && (this.props.selected.findIndex((value)=>{
|
||||
return (value.name === x.name )&&(value.path === x.path);
|
||||
}))===-1);
|
||||
});
|
||||
if(toBeLoad ==="/"){
|
||||
dirList.unshift({name:"/",path:""})
|
||||
}
|
||||
this.setState({
|
||||
presentPath:toBeLoad,
|
||||
dirList:dirList,
|
||||
selectedTarget:null,
|
||||
})
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.props.toggleSnackbar("top","right",error.message,"warning");
|
||||
});
|
||||
}
|
||||
|
||||
handleSelect = (index) =>{
|
||||
this.setState({selectedTarget:index});
|
||||
this.props.onSelect(this.state.dirList[index]);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
const { classes} = this.props;
|
||||
|
||||
return (
|
||||
<div className={classes.container}>
|
||||
<MenuList className={classes.selector}>
|
||||
{this.state.presentPath!=="/"&&
|
||||
<MenuItem onClick={this.back}>
|
||||
<ListItemIcon >
|
||||
<UpIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="返回上一层" />
|
||||
</MenuItem>
|
||||
}
|
||||
{this.state.dirList.map((value,index)=>(
|
||||
<MenuItem classes={{
|
||||
selected:classes.selected
|
||||
}} key={index} selected={this.state.selectedTarget === index} onClick={()=>this.handleSelect(index)}>
|
||||
<ListItemIcon className={classes.icon}>
|
||||
<FolderIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText classes={{ primary: classes.primary }} primary={value.name} />
|
||||
<ListItemSecondaryAction className={classes.buttonIcon}>
|
||||
<IconButton className={classNames({
|
||||
[classes.iconWhite]:this.state.selectedTarget === index,
|
||||
})} onClick={()=>this.enterFolder(value.path === "/"?value.path+value.name:value.path+"/"+value.name)}>
|
||||
<RightIcon />
|
||||
</IconButton>
|
||||
</ListItemSecondaryAction>
|
||||
</MenuItem>
|
||||
))}
|
||||
|
||||
</MenuList>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
PathSelectorCompoment.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
presentPath:PropTypes.string.isRequired,
|
||||
selected:PropTypes.array.isRequired,
|
||||
};
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
|
||||
)(withStyles(styles)(PathSelectorCompoment))
|
||||
|
|
@ -0,0 +1,257 @@
|
|||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux'
|
||||
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
|
||||
import ButtonBase from '@material-ui/core/ButtonBase';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import classNames from 'classnames';
|
||||
import Tooltip from '@material-ui/core/Tooltip';
|
||||
import ImageIcon from '@material-ui/icons/PhotoSizeSelectActual'
|
||||
import VideoIcon from '@material-ui/icons/Videocam'
|
||||
import AudioIcon from '@material-ui/icons/Audiotrack'
|
||||
import PdfIcon from "@material-ui/icons/PictureAsPdf"
|
||||
import {FileWordBox,FilePowerpointBox,FileExcelBox,ScriptText,MagnetOn,ZipBox,WindowRestore,Android} from 'mdi-material-ui'
|
||||
import FileShowIcon from "@material-ui/icons/InsertDriveFile"
|
||||
import {mediaType} from "../../config"
|
||||
|
||||
const styles = theme => ({
|
||||
container: {
|
||||
padding: "7px",
|
||||
},
|
||||
|
||||
selected: {
|
||||
"&:hover": {
|
||||
border: "1px solid #d0d0d0",
|
||||
},
|
||||
backgroundColor: theme.palette.explorer.bgSelected,
|
||||
|
||||
},
|
||||
|
||||
notSelected: {
|
||||
"&:hover": {
|
||||
backgroundColor: "#f9f9f9",
|
||||
border: "1px solid #d0d0d0",
|
||||
},
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
},
|
||||
|
||||
button: {
|
||||
height: "50px",
|
||||
border: "1px solid #dadce0",
|
||||
width: "100%",
|
||||
borderRadius: "6px",
|
||||
boxSizing: "border-box",
|
||||
transition: "background-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,box-shadow 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,border 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms",
|
||||
display: "flex",
|
||||
justifyContent: "left",
|
||||
alignItems: "initial",
|
||||
},
|
||||
icon: {
|
||||
margin: "10px 10px 10px 16px",
|
||||
height: "30px",
|
||||
minWidth: "30px",
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
borderRadius: "90%",
|
||||
paddingTop: "2px",
|
||||
color: theme.palette.explorer.icon,
|
||||
},
|
||||
folderNameSelected: {
|
||||
color: theme.palette.primary.dark,
|
||||
fontWeight: "500",
|
||||
},
|
||||
folderNameNotSelected: {
|
||||
color: theme.palette.explorer.filename,
|
||||
},
|
||||
folderName: {
|
||||
marginTop: "15px",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: "nowrap",
|
||||
overflow: "hidden",
|
||||
marginRight: "20px",
|
||||
},
|
||||
iconImg : {
|
||||
color:"#d32f2f",
|
||||
},
|
||||
iconImgBig:{
|
||||
color:"#d32f2f",
|
||||
fontSize: "50px",
|
||||
},
|
||||
iconVideo : {
|
||||
color:"#d50000",
|
||||
},
|
||||
iconVideoBig:{
|
||||
color:"#d50000",
|
||||
fontSize: "50px",
|
||||
},
|
||||
iconAudio : {
|
||||
color:"#651fff",
|
||||
},
|
||||
iconAudioBig:{
|
||||
color:"#651fff",
|
||||
fontSize: "50px",
|
||||
},
|
||||
iconPdf : {
|
||||
color:"#f44336",
|
||||
},
|
||||
iconPdfBig:{
|
||||
color:"#f44336",
|
||||
fontSize: "50px",
|
||||
},
|
||||
iconWord : {
|
||||
color:"#538ce5",
|
||||
},
|
||||
iconWordBig:{
|
||||
color:"#538ce5",
|
||||
fontSize: "50px",
|
||||
},
|
||||
iconPpt : {
|
||||
color:"rgb(239, 99, 63)",
|
||||
},
|
||||
iconPptBig:{
|
||||
color:"rgb(239, 99, 63)",
|
||||
fontSize: "50px",
|
||||
},
|
||||
iconExcel : {
|
||||
color:"#4caf50",
|
||||
},
|
||||
iconExcelBig:{
|
||||
color:"#4caf50",
|
||||
fontSize: "50px",
|
||||
},
|
||||
iconText : {
|
||||
color:"#607d8b",
|
||||
},
|
||||
iconTextBig:{
|
||||
color:"#607d8b",
|
||||
fontSize: "50px",
|
||||
},
|
||||
iconFile : {
|
||||
color:"#424242",
|
||||
},
|
||||
iconFileBig:{
|
||||
color:"#424242",
|
||||
fontSize: "50px",
|
||||
},
|
||||
iconTorrent : {
|
||||
color:"#5c6bc0",
|
||||
},
|
||||
iconTorrentBig:{
|
||||
color:"#5c6bc0",
|
||||
fontSize: "50px",
|
||||
},
|
||||
iconZip : {
|
||||
color:"#f9a825",
|
||||
},
|
||||
iconZipBig:{
|
||||
color:"#f9a825",
|
||||
fontSize: "50px",
|
||||
},
|
||||
iconAndroid : {
|
||||
color:"#8bc34a",
|
||||
},
|
||||
iconAndroidBig:{
|
||||
color:"#8bc34a",
|
||||
fontSize: "50px",
|
||||
},
|
||||
iconExe : {
|
||||
color:"#1a237e",
|
||||
},
|
||||
iconExeBig:{
|
||||
color:"#1a237e",
|
||||
fontSize: "50px",
|
||||
},
|
||||
})
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
selected: state.explorer.selected,
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
}
|
||||
}
|
||||
|
||||
class SmallIconCompoment extends Component {
|
||||
|
||||
state = {
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
|
||||
const { classes } = this.props;
|
||||
|
||||
let icon;
|
||||
let fileType =this.props.file.name.split(".").pop().toLowerCase();
|
||||
if (mediaType["image"].indexOf(fileType)!==-1){
|
||||
icon = (<ImageIcon className={classes.iconImg}/>);
|
||||
}else if(mediaType["video"].indexOf(fileType)!==-1){
|
||||
icon = (<VideoIcon className={classes.iconVideo}/>);
|
||||
}else if(mediaType["audio"].indexOf(fileType)!==-1){
|
||||
icon = (<AudioIcon className={classes.iconAudio}/>);
|
||||
}else if(mediaType["pdf"].indexOf(fileType)!==-1){
|
||||
icon = (<PdfIcon className={classes.iconPdf}/>);
|
||||
}else if(mediaType["word"].indexOf(fileType)!==-1){
|
||||
icon = (<FileWordBox className={classes.iconWord}/>);
|
||||
}else if(mediaType["ppt"].indexOf(fileType)!==-1){
|
||||
icon = (<FilePowerpointBox className={classes.iconPpt}/>);
|
||||
}else if(mediaType["excel"].indexOf(fileType)!==-1){
|
||||
icon = (<FileExcelBox className={classes.iconExcel}/>);
|
||||
}else if(mediaType["text"].indexOf(fileType)!==-1){
|
||||
icon = (<ScriptText className={classes.iconText}/>);
|
||||
}else if(mediaType["torrent"].indexOf(fileType)!==-1){
|
||||
icon = (<MagnetOn className={classes.iconTorrent}/>);
|
||||
}else if(mediaType["zip"].indexOf(fileType)!==-1){
|
||||
icon = (<ZipBox className={classes.iconZip}/>);
|
||||
}else if(mediaType["excute"].indexOf(fileType)!==-1){
|
||||
icon = (<WindowRestore className={classes.iconExe}/>);
|
||||
}else if(mediaType["android"].indexOf(fileType)!==-1){
|
||||
icon = (<Android className={classes.iconAndroid}/>);
|
||||
}else{
|
||||
icon = (<FileShowIcon className={classes.iconText}/>);
|
||||
}
|
||||
|
||||
|
||||
const isSelected = (this.props.selected.findIndex((value) => {
|
||||
return value === this.props.file;
|
||||
})) !== -1;
|
||||
|
||||
return (
|
||||
<ButtonBase
|
||||
focusRipple
|
||||
className={classNames({
|
||||
[classes.selected]: isSelected,
|
||||
[classes.notSelected]: !isSelected,
|
||||
}, classes.button)}
|
||||
>
|
||||
<div className={classNames(classes.icon, {
|
||||
[classes.iconSelected]: isSelected,
|
||||
[classes.iconNotSelected]: !isSelected,
|
||||
})}>{icon}</div>
|
||||
<Tooltip title={this.props.file.name} aria-label={this.props.file.name}>
|
||||
<Typography className={classNames(classes.folderName, {
|
||||
[classes.folderNameSelected]: isSelected,
|
||||
[classes.folderNameNotSelected]: !isSelected,
|
||||
})}>{this.props.file.name}</Typography>
|
||||
</Tooltip>
|
||||
</ButtonBase>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SmallIconCompoment.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
file: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
|
||||
const SmallIcon = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(withStyles(styles)(SmallIconCompoment))
|
||||
|
||||
export default SmallIcon
|
||||
|
|
@ -0,0 +1,232 @@
|
|||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux'
|
||||
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
|
||||
import TableCell from '@material-ui/core/TableCell';
|
||||
import TableRow from '@material-ui/core/TableRow';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import FolderIcon from '@material-ui/icons/Folder'
|
||||
import classNames from 'classnames';
|
||||
import ImageIcon from '@material-ui/icons/PhotoSizeSelectActual'
|
||||
import VideoIcon from '@material-ui/icons/Videocam'
|
||||
import AudioIcon from '@material-ui/icons/Audiotrack'
|
||||
import PdfIcon from "@material-ui/icons/PictureAsPdf"
|
||||
import {FileWordBox,FilePowerpointBox,FileExcelBox,ScriptText,MagnetOn,ZipBox,WindowRestore,Android} from 'mdi-material-ui'
|
||||
import FileShowIcon from "@material-ui/icons/InsertDriveFile"
|
||||
import {sizeToString} from "../../untils/index"
|
||||
import {mediaType} from "../../config"
|
||||
|
||||
const styles = theme => ({
|
||||
selected: {
|
||||
"&:hover": {
|
||||
},
|
||||
backgroundColor: theme.palette.explorer.bgSelected,
|
||||
|
||||
},
|
||||
|
||||
notSelected: {
|
||||
"&:hover": {
|
||||
backgroundColor: "#ececec",
|
||||
},
|
||||
},
|
||||
icon:{
|
||||
verticalAlign: "middle",
|
||||
marginRight: "20px",
|
||||
color: theme.palette.explorer.icon,
|
||||
},
|
||||
iconImg : {
|
||||
verticalAlign: "middle",
|
||||
color:"#d32f2f",
|
||||
marginRight: "20px",
|
||||
},
|
||||
iconVideo : {
|
||||
verticalAlign: "middle",
|
||||
color:"#d50000",
|
||||
marginRight: "20px",
|
||||
},
|
||||
iconAudio : {
|
||||
color:"#651fff",
|
||||
marginRight: "20px",
|
||||
verticalAlign: "middle",
|
||||
},
|
||||
iconPdf : {
|
||||
verticalAlign: "middle",
|
||||
color:"#f44336",
|
||||
marginRight: "20px",
|
||||
},
|
||||
iconWord : {
|
||||
verticalAlign: "middle",
|
||||
color:"#538ce5",
|
||||
marginRight: "20px",
|
||||
},
|
||||
iconPpt : {
|
||||
verticalAlign: "middle",
|
||||
color:"rgb(239, 99, 63)",
|
||||
marginRight: "20px",
|
||||
},
|
||||
iconExcel : {
|
||||
verticalAlign: "middle",
|
||||
color:"#4caf50",
|
||||
marginRight: "20px",
|
||||
},
|
||||
iconText : {
|
||||
verticalAlign: "middle",
|
||||
color:"#607d8b",
|
||||
marginRight: "20px",
|
||||
},
|
||||
iconFile : {
|
||||
verticalAlign: "middle",
|
||||
color:"#424242",
|
||||
marginRight: "20px",
|
||||
},
|
||||
iconTorrent : {
|
||||
color:"#5c6bc0",
|
||||
marginRight: "20px",
|
||||
verticalAlign: "middle",
|
||||
},
|
||||
iconZip : {
|
||||
color:"#f9a825",
|
||||
marginRight: "20px",
|
||||
verticalAlign: "middle",
|
||||
},
|
||||
iconAndroid : {
|
||||
color:"#8bc34a",
|
||||
marginRight: "20px",
|
||||
verticalAlign: "middle",
|
||||
},
|
||||
iconExe : {
|
||||
color:"#1a237e",
|
||||
marginRight: "20px",
|
||||
verticalAlign: "middle",
|
||||
},
|
||||
folderNameSelected: {
|
||||
color: theme.palette.primary.dark,
|
||||
fontWeight: "500",
|
||||
userSelect: "none",
|
||||
},
|
||||
folderNameNotSelected: {
|
||||
color: theme.palette.explorer.filename,
|
||||
userSelect: "none",
|
||||
},
|
||||
folderName:{
|
||||
marginRight:"20px",
|
||||
},
|
||||
hideAuto:{
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
display:"none",
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
selected: state.explorer.selected,
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class TableRowCompoment extends Component {
|
||||
|
||||
state = {
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
|
||||
const { classes } = this.props;
|
||||
|
||||
let icon;
|
||||
let fileType =this.props.file.name.split(".").pop().toLowerCase();
|
||||
if(this.props.file.type==="dir"){
|
||||
icon = (<FolderIcon className={classes.icon}/>);
|
||||
}else{
|
||||
if (mediaType["image"].indexOf(fileType)!==-1){
|
||||
icon = (<ImageIcon className={classes.iconImg}/>);
|
||||
}else if(mediaType["video"].indexOf(fileType)!==-1){
|
||||
icon = (<VideoIcon className={classes.iconVideo}/>);
|
||||
}else if(mediaType["audio"].indexOf(fileType)!==-1){
|
||||
icon = (<AudioIcon className={classes.iconAudio}/>);
|
||||
}else if(mediaType["pdf"].indexOf(fileType)!==-1){
|
||||
icon = (<PdfIcon className={classes.iconPdf}/>);
|
||||
}else if(mediaType["word"].indexOf(fileType)!==-1){
|
||||
icon = (<FileWordBox className={classes.iconWord}/>);
|
||||
}else if(mediaType["ppt"].indexOf(fileType)!==-1){
|
||||
icon = (<FilePowerpointBox className={classes.iconPpt}/>);
|
||||
}else if(mediaType["excel"].indexOf(fileType)!==-1){
|
||||
icon = (<FileExcelBox className={classes.iconExcel}/>);
|
||||
}else if(mediaType["text"].indexOf(fileType)!==-1){
|
||||
icon = (<ScriptText className={classes.iconText}/>);
|
||||
}else if(mediaType["torrent"].indexOf(fileType)!==-1){
|
||||
icon = (<MagnetOn className={classes.iconTorrent}/>);
|
||||
}else if(mediaType["zip"].indexOf(fileType)!==-1){
|
||||
icon = (<ZipBox className={classes.iconZip}/>);
|
||||
}else if(mediaType["excute"].indexOf(fileType)!==-1){
|
||||
icon = (<WindowRestore className={classes.iconExe}/>);
|
||||
}else if(mediaType["android"].indexOf(fileType)!==-1){
|
||||
icon = (<Android className={classes.iconAndroid}/>);
|
||||
}else{
|
||||
icon = (<FileShowIcon className={classes.iconText}/>);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
const isSelected = (this.props.selected.findIndex((value) => {
|
||||
return value === this.props.file;
|
||||
})) !== -1;
|
||||
|
||||
return (
|
||||
<TableRow
|
||||
onContextMenu={this.props.contextMenu}
|
||||
onClick={this.props.handleClick}
|
||||
onDoubleClick = {this.props.handleDoubleClick.bind(this)}
|
||||
className={classNames({
|
||||
[classes.selected]: isSelected,
|
||||
[classes.notSelected]: !isSelected,
|
||||
}, classes.button)}
|
||||
>
|
||||
<TableCell component="th" scope="row">
|
||||
|
||||
<Typography className={classNames(classes.folderName, {
|
||||
[classes.folderNameSelected]: isSelected,
|
||||
[classes.folderNameNotSelected]: !isSelected,
|
||||
})}>{icon}{this.props.file.name}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<TableCell className={classes.hideAuto}>
|
||||
<Typography className={classNames(classes.folderName, {
|
||||
[classes.folderNameSelected]: isSelected,
|
||||
[classes.folderNameNotSelected]: !isSelected,
|
||||
})}> {this.props.file.type!=="dir"&&sizeToString(this.props.file.size)}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<TableCell className={classes.hideAuto}><Typography className={classNames(classes.folderName, {
|
||||
[classes.folderNameSelected]: isSelected,
|
||||
[classes.folderNameNotSelected]: !isSelected,
|
||||
})}> {this.props.file.date}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TableRowCompoment.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
file: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
|
||||
const TableItem = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(withStyles(styles)(TableRowCompoment))
|
||||
|
||||
export default TableItem
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
import React, { Component } from 'react'
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import { connect } from 'react-redux'
|
||||
import Button from '@material-ui/core/Button';
|
||||
import Card from '@material-ui/core/Card';
|
||||
import Divider from '@material-ui/core/Divider';
|
||||
import CardHeader from '@material-ui/core/CardHeader';
|
||||
import CardContent from '@material-ui/core/CardContent';
|
||||
import CardActions from '@material-ui/core/CardActions';
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import Avatar from '@material-ui/core/Avatar';
|
||||
import { toggleSnackbar,}from "../actions/index"
|
||||
import axios from 'axios'
|
||||
const styles = theme => ({
|
||||
card: {
|
||||
maxWidth: 400,
|
||||
margin: "0 auto",
|
||||
},
|
||||
actions: {
|
||||
display: 'flex',
|
||||
},
|
||||
layout: {
|
||||
width: 'auto',
|
||||
marginTop:'110px',
|
||||
marginLeft: theme.spacing.unit * 3,
|
||||
marginRight: theme.spacing.unit * 3,
|
||||
[theme.breakpoints.up(1100 + theme.spacing.unit * 3 * 2)]: {
|
||||
width: 1100,
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
},
|
||||
},
|
||||
continue:{
|
||||
marginLeft:"auto",
|
||||
marginRight: "10px",
|
||||
marginRottom: "10px",
|
||||
}
|
||||
})
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
toggleSnackbar:(vertical,horizontal,msg,color)=>{
|
||||
dispatch(toggleSnackbar(vertical,horizontal,msg,color))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
class LockedFileCompoment extends Component {
|
||||
|
||||
state = {
|
||||
pwd:"",
|
||||
loading:false,
|
||||
};
|
||||
|
||||
handleChange = name => event => {
|
||||
this.setState({ [name]: event.target.value });
|
||||
};
|
||||
|
||||
submit = e=>{
|
||||
e.preventDefault();
|
||||
if(this.state.pwd===""){
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
loading:true,
|
||||
});
|
||||
axios.post("/Share/chekPwd",{
|
||||
key: window.shareInfo.shareId,
|
||||
password: this.state.pwd
|
||||
})
|
||||
.then( (response)=> {
|
||||
if(response.data.error!==0){
|
||||
this.setState({
|
||||
loading:false,
|
||||
});
|
||||
this.props.toggleSnackbar("top","right",response.data.msg ,"warning");
|
||||
}else{
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.setState({
|
||||
loading:false,
|
||||
});
|
||||
this.props.toggleSnackbar("top","right",error.message ,"error");
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
|
||||
|
||||
return (
|
||||
<div className={classes.layout}>
|
||||
<Card className={classes.card}>
|
||||
<CardHeader
|
||||
avatar={
|
||||
<Avatar aria-label="Recipe" src={"/Member/Avatar/1/"+window.shareInfo.ownerUid}>
|
||||
</Avatar>
|
||||
}
|
||||
title={window.shareInfo.ownerNick+" 的加密分享"}
|
||||
subheader={window.shareInfo.shareDate}
|
||||
/>
|
||||
<Divider/>
|
||||
<CardContent>
|
||||
<form onSubmit={this.submit}>
|
||||
<TextField
|
||||
id="pwd"
|
||||
label="输入分享密码"
|
||||
value={this.state.pwd}
|
||||
onChange={this.handleChange('pwd')}
|
||||
margin="normal"
|
||||
type="password"
|
||||
autoFocus
|
||||
fullWidth
|
||||
color="secondary"
|
||||
/>
|
||||
</form>
|
||||
</CardContent>
|
||||
<CardActions className={classes.actions} disableActionSpacing>
|
||||
<Button onClick={this.submit} color="secondary" className={classes.continue} variant="contained" disabled={this.state.pwd==="" || this.state.loading}>继续</Button>
|
||||
</CardActions>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const LockedFile = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)( withStyles(styles)(LockedFileCompoment))
|
||||
|
||||
export default LockedFile
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
import React, { Component } from 'react'
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import { connect } from 'react-redux'
|
||||
import Button from '@material-ui/core/Button';
|
||||
import EmailIcon from '@material-ui/icons/EmailOutlined';
|
||||
import Paper from '@material-ui/core/Paper';
|
||||
import Avatar from '@material-ui/core/Avatar';
|
||||
import { toggleSnackbar, } from "../../actions/index"
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
|
||||
const styles = theme => ({
|
||||
layout: {
|
||||
width: 'auto',
|
||||
marginTop: '110px',
|
||||
marginLeft: theme.spacing.unit * 3,
|
||||
marginRight: theme.spacing.unit * 3,
|
||||
[theme.breakpoints.up(1100 + theme.spacing.unit * 3 * 2)]: {
|
||||
width: 400,
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
},
|
||||
},
|
||||
paper: {
|
||||
marginTop: theme.spacing.unit * 8,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
padding: `${theme.spacing.unit * 2}px ${theme.spacing.unit * 3}px ${theme.spacing.unit * 3}px`,
|
||||
},
|
||||
avatar: {
|
||||
margin: theme.spacing.unit,
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
},
|
||||
avatarSuccess:{
|
||||
margin: theme.spacing.unit,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
},
|
||||
form: {
|
||||
width: '100%', // Fix IE 11 issue.
|
||||
marginTop: theme.spacing.unit,
|
||||
},
|
||||
submit: {
|
||||
marginTop: theme.spacing.unit * 3,
|
||||
},
|
||||
link: {
|
||||
marginTop: "10px",
|
||||
display:"flex",
|
||||
width: "100%",
|
||||
justifyContent: "space-between",
|
||||
},
|
||||
captchaContainer:{
|
||||
display:"flex",
|
||||
marginTop: "10px",
|
||||
}
|
||||
})
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
toggleSnackbar: (vertical, horizontal, msg, color) => {
|
||||
dispatch(toggleSnackbar(vertical, horizontal, msg, color))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
class EmailActivicationCompoment extends Component {
|
||||
|
||||
state={
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
|
||||
|
||||
return (
|
||||
<div className={classes.layout}>
|
||||
<Paper className={classes.paper}>
|
||||
<Avatar className={classes.avatar}>
|
||||
<EmailIcon />
|
||||
</Avatar>
|
||||
<Typography component="h1" variant="h5">
|
||||
激活成功
|
||||
</Typography>
|
||||
<Typography style={{marginTop:"20px"}}>您的账号已被成功激活。</Typography>
|
||||
<Button
|
||||
type="submit"
|
||||
fullWidth
|
||||
variant="contained"
|
||||
color="primary"
|
||||
className={classes.submit}
|
||||
onClick={()=>window.location.href="/Login"}
|
||||
>
|
||||
返回登录
|
||||
</Button>
|
||||
|
||||
</Paper>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const EmailActivication = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(withStyles(styles)(EmailActivicationCompoment))
|
||||
|
||||
export default EmailActivication
|
||||
|
|
@ -0,0 +1,216 @@
|
|||
import React, { Component } from 'react'
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import { connect } from 'react-redux'
|
||||
import Button from '@material-ui/core/Button';
|
||||
import FormControl from '@material-ui/core/FormControl';
|
||||
import Divider from '@material-ui/core/Divider';
|
||||
import Link from '@material-ui/core/Link';
|
||||
import Input from '@material-ui/core/Input';
|
||||
import InputLabel from '@material-ui/core/InputLabel';
|
||||
import LockOutlinedIcon from '@material-ui/icons/LockOutlined';
|
||||
import Paper from '@material-ui/core/Paper';
|
||||
import Avatar from '@material-ui/core/Avatar';
|
||||
import { toggleSnackbar, } from "../../actions/index"
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import axios from 'axios'
|
||||
const styles = theme => ({
|
||||
layout: {
|
||||
width: 'auto',
|
||||
marginTop: '110px',
|
||||
marginLeft: theme.spacing.unit * 3,
|
||||
marginRight: theme.spacing.unit * 3,
|
||||
[theme.breakpoints.up(1100 + theme.spacing.unit * 3 * 2)]: {
|
||||
width: 400,
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
},
|
||||
},
|
||||
paper: {
|
||||
marginTop: theme.spacing.unit * 8,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
padding: `${theme.spacing.unit * 2}px ${theme.spacing.unit * 3}px ${theme.spacing.unit * 3}px`,
|
||||
},
|
||||
avatar: {
|
||||
margin: theme.spacing.unit,
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
},
|
||||
form: {
|
||||
width: '100%', // Fix IE 11 issue.
|
||||
marginTop: theme.spacing.unit,
|
||||
},
|
||||
submit: {
|
||||
marginTop: theme.spacing.unit * 3,
|
||||
},
|
||||
link: {
|
||||
marginTop: "10px",
|
||||
display:"flex",
|
||||
width: "100%",
|
||||
justifyContent: "space-between",
|
||||
},
|
||||
captchaContainer:{
|
||||
display:"flex",
|
||||
marginTop: "10px",
|
||||
}
|
||||
})
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
toggleSnackbar: (vertical, horizontal, msg, color) => {
|
||||
dispatch(toggleSnackbar(vertical, horizontal, msg, color))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
class LoginFormCompoment extends Component {
|
||||
|
||||
state={
|
||||
email:"",
|
||||
pwd:"",
|
||||
captcha:"",
|
||||
loading:false,
|
||||
captchaUrl:"/captcha?initial",
|
||||
}
|
||||
|
||||
refreshCaptcha = ()=>{
|
||||
this.setState({
|
||||
captchaUrl:"/captcha?"+Math.random(),
|
||||
});
|
||||
}
|
||||
|
||||
login = e=>{
|
||||
e.preventDefault();
|
||||
this.setState({
|
||||
loading:true,
|
||||
});
|
||||
axios.post('/Member/Login',{
|
||||
userMail:this.state.email,
|
||||
userPass:this.state.pwd,
|
||||
captchaCode:this.state.captcha,
|
||||
}).then( (response)=> {
|
||||
if(response.data.code!=="200"){
|
||||
this.setState({
|
||||
loading:false,
|
||||
});
|
||||
if(response.data.message==="tsp"){
|
||||
window.location.href="/Member/TwoStep";
|
||||
}else{
|
||||
this.props.toggleSnackbar("top","right",response.data.message,"warning");
|
||||
this.refreshCaptcha();
|
||||
}
|
||||
}else{
|
||||
this.setState({
|
||||
loading:false,
|
||||
});
|
||||
window.location.href="/Home";
|
||||
this.props.toggleSnackbar("top","right","登录成功","success");
|
||||
}
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.setState({
|
||||
loading:false,
|
||||
});
|
||||
this.props.toggleSnackbar("top","right",error.message,"error");
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
handleChange = name => event => {
|
||||
this.setState({ [name]: event.target.value });
|
||||
};
|
||||
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
|
||||
|
||||
return (
|
||||
<div className={classes.layout}>
|
||||
<Paper className={classes.paper}>
|
||||
<Avatar className={classes.avatar}>
|
||||
<LockOutlinedIcon />
|
||||
</Avatar>
|
||||
<Typography component="h1" variant="h5">
|
||||
登录{window.siteInfo.mainTitle}
|
||||
</Typography>
|
||||
<form className={classes.form} onSubmit={this.login}>
|
||||
<FormControl margin="normal" required fullWidth>
|
||||
<InputLabel htmlFor="email">电子邮箱</InputLabel>
|
||||
<Input
|
||||
id="email"
|
||||
type="email"
|
||||
name="email"
|
||||
onChange={this.handleChange("email")}
|
||||
autoComplete
|
||||
value={this.state.email}
|
||||
autoFocus />
|
||||
</FormControl>
|
||||
<FormControl margin="normal" required fullWidth>
|
||||
<InputLabel htmlFor="password">密码</InputLabel>
|
||||
<Input
|
||||
name="password"
|
||||
onChange={this.handleChange("pwd")}
|
||||
type="password"
|
||||
id="password"
|
||||
value={this.state.pwd}
|
||||
autoComplete />
|
||||
</FormControl>
|
||||
{window.captcha==="1"&&
|
||||
<div className={classes.captchaContainer}>
|
||||
<FormControl margin="normal" required fullWidth>
|
||||
<InputLabel htmlFor="captcha">验证码</InputLabel>
|
||||
<Input
|
||||
name="captcha"
|
||||
onChange={this.handleChange("captcha")}
|
||||
type="text"
|
||||
id="captcha"
|
||||
value={this.state.captcha}
|
||||
autoComplete />
|
||||
|
||||
</FormControl> <div>
|
||||
<img src={this.state.captchaUrl} alt="captcha" onClick={this.refreshCaptcha}></img>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<Button
|
||||
type="submit"
|
||||
fullWidth
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={this.state.loading}
|
||||
className={classes.submit}
|
||||
>
|
||||
登录
|
||||
</Button> </form> <Divider/>
|
||||
<div className={classes.link}>
|
||||
<div>
|
||||
<Link href={"/Member/FindPwd"}>
|
||||
忘记密码
|
||||
</Link>
|
||||
</div>
|
||||
<div>
|
||||
<Link href={"/SignUp"}>
|
||||
注册账号
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</Paper>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const LoginForm = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(withStyles(styles)(LoginFormCompoment))
|
||||
|
||||
export default LoginForm
|
||||
|
|
@ -0,0 +1,258 @@
|
|||
import React, { Component } from 'react'
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import { connect } from 'react-redux'
|
||||
import Button from '@material-ui/core/Button';
|
||||
import FormControl from '@material-ui/core/FormControl';
|
||||
import Divider from '@material-ui/core/Divider';
|
||||
import Link from '@material-ui/core/Link';
|
||||
import Input from '@material-ui/core/Input';
|
||||
import InputLabel from '@material-ui/core/InputLabel';
|
||||
import RegIcon from '@material-ui/icons/AssignmentIndOutlined';
|
||||
import EmailIcon from '@material-ui/icons/EmailOutlined';
|
||||
import Paper from '@material-ui/core/Paper';
|
||||
import Avatar from '@material-ui/core/Avatar';
|
||||
import { toggleSnackbar, } from "../../actions/index"
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import axios from 'axios'
|
||||
|
||||
const styles = theme => ({
|
||||
layout: {
|
||||
width: 'auto',
|
||||
marginTop: '110px',
|
||||
marginLeft: theme.spacing.unit * 3,
|
||||
marginRight: theme.spacing.unit * 3,
|
||||
[theme.breakpoints.up(1100 + theme.spacing.unit * 3 * 2)]: {
|
||||
width: 400,
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
},
|
||||
},
|
||||
paper: {
|
||||
marginTop: theme.spacing.unit * 8,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
padding: `${theme.spacing.unit * 2}px ${theme.spacing.unit * 3}px ${theme.spacing.unit * 3}px`,
|
||||
},
|
||||
avatar: {
|
||||
margin: theme.spacing.unit,
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
},
|
||||
avatarSuccess:{
|
||||
margin: theme.spacing.unit,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
},
|
||||
form: {
|
||||
width: '100%', // Fix IE 11 issue.
|
||||
marginTop: theme.spacing.unit,
|
||||
},
|
||||
submit: {
|
||||
marginTop: theme.spacing.unit * 3,
|
||||
},
|
||||
link: {
|
||||
marginTop: "10px",
|
||||
display:"flex",
|
||||
width: "100%",
|
||||
justifyContent: "space-between",
|
||||
},
|
||||
captchaContainer:{
|
||||
display:"flex",
|
||||
marginTop: "10px",
|
||||
}
|
||||
})
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
toggleSnackbar: (vertical, horizontal, msg, color) => {
|
||||
dispatch(toggleSnackbar(vertical, horizontal, msg, color))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const sleep= (time)=> {
|
||||
return new Promise((resolve) => setTimeout(resolve, time));
|
||||
}
|
||||
|
||||
class RegisterFormCompoment extends Component {
|
||||
|
||||
state={
|
||||
email:"",
|
||||
pwd:"",
|
||||
pwdRepeat:"",
|
||||
captcha:"",
|
||||
loading:false,
|
||||
captchaUrl:"/captcha?initial",
|
||||
showStatue:"loginForm",
|
||||
}
|
||||
|
||||
refreshCaptcha = ()=>{
|
||||
this.setState({
|
||||
captchaUrl:"/captcha?"+Math.random(),
|
||||
});
|
||||
}
|
||||
|
||||
register = e=>{
|
||||
e.preventDefault();
|
||||
if(this.state.pwdRepeat !== this.state.pwd){
|
||||
this.props.toggleSnackbar("top","right","两次密码输入不一致","warning");
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
loading:true,
|
||||
});
|
||||
axios.post('/Member/Register',{
|
||||
"username-reg":this.state.email,
|
||||
"password-reg":this.state.pwd,
|
||||
captchaCode:this.state.captcha,
|
||||
}).then( (response)=> {
|
||||
if(response.data.code!=="200"){
|
||||
this.setState({
|
||||
loading:false,
|
||||
});
|
||||
this.props.toggleSnackbar("top","right",response.data.message,"warning");
|
||||
this.refreshCaptcha();
|
||||
}else{
|
||||
if(response.data.message==="ec"){
|
||||
this.setState({
|
||||
showStatue:"email",
|
||||
});
|
||||
}else{
|
||||
this.props.toggleSnackbar("top","right","注册成功","success");
|
||||
sleep(1000).then(() => {
|
||||
window.location.href="/Home";
|
||||
this.setState({
|
||||
loading:false,
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.setState({
|
||||
loading:false,
|
||||
});
|
||||
this.props.toggleSnackbar("top","right",error.message,"error");
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
handleChange = name => event => {
|
||||
this.setState({ [name]: event.target.value });
|
||||
};
|
||||
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
|
||||
|
||||
return (
|
||||
<div className={classes.layout}>
|
||||
{this.state.showStatue==="loginForm"&&<Paper className={classes.paper}>
|
||||
<Avatar className={classes.avatar}>
|
||||
<RegIcon />
|
||||
</Avatar>
|
||||
<Typography component="h1" variant="h5">
|
||||
注册{window.siteInfo.mainTitle}
|
||||
</Typography>
|
||||
<form className={classes.form} onSubmit={this.register}>
|
||||
<FormControl margin="normal" required fullWidth>
|
||||
<InputLabel htmlFor="email">电子邮箱</InputLabel>
|
||||
<Input
|
||||
id="email"
|
||||
type="email"
|
||||
name="email"
|
||||
onChange={this.handleChange("email")}
|
||||
autoComplete
|
||||
value={this.state.email}
|
||||
autoFocus />
|
||||
</FormControl>
|
||||
<FormControl margin="normal" required fullWidth>
|
||||
<InputLabel htmlFor="password">密码</InputLabel>
|
||||
<Input
|
||||
name="password"
|
||||
onChange={this.handleChange("pwd")}
|
||||
type="password"
|
||||
id="password"
|
||||
value={this.state.pwd}
|
||||
autoComplete />
|
||||
</FormControl>
|
||||
<FormControl margin="normal" required fullWidth>
|
||||
<InputLabel htmlFor="password">密码</InputLabel>
|
||||
<Input
|
||||
name="pwdRepeat"
|
||||
onChange={this.handleChange("pwdRepeat")}
|
||||
type="password"
|
||||
id="pwdRepeat"
|
||||
value={this.state.pwdRepeat}
|
||||
autoComplete />
|
||||
</FormControl>
|
||||
{window.regCaptcha==="1"&&
|
||||
<div className={classes.captchaContainer}>
|
||||
<FormControl margin="normal" required fullWidth>
|
||||
<InputLabel htmlFor="captcha">验证码</InputLabel>
|
||||
<Input
|
||||
name="captcha"
|
||||
onChange={this.handleChange("captcha")}
|
||||
type="text"
|
||||
id="captcha"
|
||||
value={this.state.captcha}
|
||||
autoComplete />
|
||||
|
||||
</FormControl> <div>
|
||||
<img alt="captcha" src={this.state.captchaUrl} onClick={this.refreshCaptcha}></img>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<Button
|
||||
type="submit"
|
||||
fullWidth
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={this.state.loading}
|
||||
className={classes.submit}
|
||||
>
|
||||
注册账号
|
||||
</Button> </form> <Divider/>
|
||||
<div className={classes.link}>
|
||||
<div>
|
||||
<Link href={"/Login"}>
|
||||
返回登录
|
||||
</Link>
|
||||
</div>
|
||||
<div>
|
||||
<Link href={"/Member/FindPwd"}>
|
||||
忘记密码
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</Paper>}
|
||||
|
||||
{this.state.showStatue==="email"&&<Paper className={classes.paper}>
|
||||
<Avatar className={classes.avatarSuccess}>
|
||||
<EmailIcon />
|
||||
</Avatar>
|
||||
<Typography component="h1" variant="h5">
|
||||
邮件激活
|
||||
</Typography>
|
||||
<Typography style={{marginTop:"10px"}}>一封激活邮件已经发送至您的邮箱,请访问邮件中的链接以继续完成注册。</Typography>
|
||||
|
||||
</Paper>}
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const RegisterForm = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(withStyles(styles)(RegisterFormCompoment))
|
||||
|
||||
export default RegisterForm
|
||||
|
|
@ -0,0 +1,200 @@
|
|||
import React, { Component } from 'react'
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import { connect } from 'react-redux'
|
||||
import Button from '@material-ui/core/Button';
|
||||
import FormControl from '@material-ui/core/FormControl';
|
||||
import Divider from '@material-ui/core/Divider';
|
||||
import Link from '@material-ui/core/Link';
|
||||
import Input from '@material-ui/core/Input';
|
||||
import InputLabel from '@material-ui/core/InputLabel';
|
||||
import KeyIcon from '@material-ui/icons/VpnKeyOutlined';
|
||||
import Paper from '@material-ui/core/Paper';
|
||||
import Avatar from '@material-ui/core/Avatar';
|
||||
import { toggleSnackbar, } from "../../actions/index"
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import axios from 'axios'
|
||||
const styles = theme => ({
|
||||
layout: {
|
||||
width: 'auto',
|
||||
marginTop: '110px',
|
||||
marginLeft: theme.spacing.unit * 3,
|
||||
marginRight: theme.spacing.unit * 3,
|
||||
[theme.breakpoints.up(1100 + theme.spacing.unit * 3 * 2)]: {
|
||||
width: 400,
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
},
|
||||
},
|
||||
paper: {
|
||||
marginTop: theme.spacing.unit * 8,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
padding: `${theme.spacing.unit * 2}px ${theme.spacing.unit * 3}px ${theme.spacing.unit * 3}px`,
|
||||
},
|
||||
avatar: {
|
||||
margin: theme.spacing.unit,
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
},
|
||||
form: {
|
||||
width: '100%', // Fix IE 11 issue.
|
||||
marginTop: theme.spacing.unit,
|
||||
},
|
||||
submit: {
|
||||
marginTop: theme.spacing.unit * 3,
|
||||
},
|
||||
link: {
|
||||
marginTop: "10px",
|
||||
display:"flex",
|
||||
width: "100%",
|
||||
justifyContent: "space-between",
|
||||
},
|
||||
captchaContainer:{
|
||||
display:"flex",
|
||||
marginTop: "10px",
|
||||
}
|
||||
})
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
toggleSnackbar: (vertical, horizontal, msg, color) => {
|
||||
dispatch(toggleSnackbar(vertical, horizontal, msg, color))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
class ResetPwdCompoment extends Component {
|
||||
|
||||
state={
|
||||
email:"",
|
||||
captcha:"",
|
||||
loading:false,
|
||||
captchaUrl:"/captcha?initial",
|
||||
}
|
||||
|
||||
refreshCaptcha = ()=>{
|
||||
this.setState({
|
||||
captchaUrl:"/captcha?"+Math.random(),
|
||||
});
|
||||
}
|
||||
|
||||
login = e=>{
|
||||
e.preventDefault();
|
||||
this.setState({
|
||||
loading:true,
|
||||
});
|
||||
axios.post('/Member/ForgetPwd',{
|
||||
regEmail:this.state.email,
|
||||
captchaCode:this.state.captcha,
|
||||
}).then( (response)=> {
|
||||
if(response.data.code!=="200"){
|
||||
this.setState({
|
||||
loading:false,
|
||||
});
|
||||
this.props.toggleSnackbar("top","right",response.data.message,"warning");
|
||||
this.refreshCaptcha();
|
||||
}else{
|
||||
this.setState({
|
||||
loading:false,
|
||||
email:"",
|
||||
});
|
||||
this.props.toggleSnackbar("top","right","密码重置邮件已发送,请注意查收","success");
|
||||
}
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.setState({
|
||||
loading:false,
|
||||
});
|
||||
this.props.toggleSnackbar("top","right",error.message,"error");
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
handleChange = name => event => {
|
||||
this.setState({ [name]: event.target.value });
|
||||
};
|
||||
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
|
||||
|
||||
return (
|
||||
<div className={classes.layout}>
|
||||
<Paper className={classes.paper}>
|
||||
<Avatar className={classes.avatar}>
|
||||
<KeyIcon />
|
||||
</Avatar>
|
||||
<Typography component="h1" variant="h5">
|
||||
找回密码
|
||||
</Typography>
|
||||
<form className={classes.form} onSubmit={this.login}>
|
||||
<FormControl margin="normal" required fullWidth>
|
||||
<InputLabel htmlFor="email">注册邮箱</InputLabel>
|
||||
<Input
|
||||
id="email"
|
||||
type="email"
|
||||
name="email"
|
||||
onChange={this.handleChange("email")}
|
||||
autoComplete
|
||||
value={this.state.email}
|
||||
autoFocus />
|
||||
</FormControl>
|
||||
{window.findPwdCaptcha==="1"&&
|
||||
<div className={classes.captchaContainer}>
|
||||
<FormControl margin="normal" required fullWidth>
|
||||
<InputLabel htmlFor="captcha">验证码</InputLabel>
|
||||
<Input
|
||||
name="captcha"
|
||||
onChange={this.handleChange("captcha")}
|
||||
type="text"
|
||||
id="captcha"
|
||||
value={this.state.captcha}
|
||||
autoComplete />
|
||||
|
||||
</FormControl> <div>
|
||||
<img alt="captcha" src={this.state.captchaUrl} onClick={this.refreshCaptcha}></img>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<Button
|
||||
type="submit"
|
||||
fullWidth
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={this.state.loading}
|
||||
className={classes.submit}
|
||||
>
|
||||
发送密码重置邮件
|
||||
</Button> </form> <Divider/>
|
||||
<div className={classes.link}>
|
||||
<div>
|
||||
<Link href={"/Login"}>
|
||||
返回登录
|
||||
</Link>
|
||||
</div>
|
||||
<div>
|
||||
<Link href={"/SignUp"}>
|
||||
注册账号
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</Paper>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const ResetPwd = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(withStyles(styles)(ResetPwdCompoment))
|
||||
|
||||
export default ResetPwd
|
||||
|
|
@ -0,0 +1,191 @@
|
|||
import React, { Component } from 'react'
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import { connect } from 'react-redux'
|
||||
import Button from '@material-ui/core/Button';
|
||||
import FormControl from '@material-ui/core/FormControl';
|
||||
import Divider from '@material-ui/core/Divider';
|
||||
import Link from '@material-ui/core/Link';
|
||||
import Input from '@material-ui/core/Input';
|
||||
import InputLabel from '@material-ui/core/InputLabel';
|
||||
import KeyIcon from '@material-ui/icons/VpnKeyOutlined';
|
||||
import Paper from '@material-ui/core/Paper';
|
||||
import Avatar from '@material-ui/core/Avatar';
|
||||
import { toggleSnackbar, } from "../../actions/index"
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import axios from 'axios'
|
||||
const styles = theme => ({
|
||||
layout: {
|
||||
width: 'auto',
|
||||
marginTop: '110px',
|
||||
marginLeft: theme.spacing.unit * 3,
|
||||
marginRight: theme.spacing.unit * 3,
|
||||
[theme.breakpoints.up(1100 + theme.spacing.unit * 3 * 2)]: {
|
||||
width: 400,
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
},
|
||||
},
|
||||
paper: {
|
||||
marginTop: theme.spacing.unit * 8,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
padding: `${theme.spacing.unit * 2}px ${theme.spacing.unit * 3}px ${theme.spacing.unit * 3}px`,
|
||||
},
|
||||
avatar: {
|
||||
margin: theme.spacing.unit,
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
},
|
||||
form: {
|
||||
width: '100%', // Fix IE 11 issue.
|
||||
marginTop: theme.spacing.unit,
|
||||
},
|
||||
submit: {
|
||||
marginTop: theme.spacing.unit * 3,
|
||||
},
|
||||
link: {
|
||||
marginTop: "10px",
|
||||
display:"flex",
|
||||
width: "100%",
|
||||
justifyContent: "space-between",
|
||||
},
|
||||
captchaContainer:{
|
||||
display:"flex",
|
||||
marginTop: "10px",
|
||||
}
|
||||
})
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
toggleSnackbar: (vertical, horizontal, msg, color) => {
|
||||
dispatch(toggleSnackbar(vertical, horizontal, msg, color))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
class ResetPwdFormCompoment extends Component {
|
||||
|
||||
state={
|
||||
pwd:"",
|
||||
pwdRepeat:"",
|
||||
loading:false,
|
||||
}
|
||||
|
||||
login = e=>{
|
||||
e.preventDefault();
|
||||
if(this.state.pwdRepeat !== this.state.pwd){
|
||||
this.props.toggleSnackbar("top","right","两次密码输入不一致","warning");
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
loading:true,
|
||||
});
|
||||
axios.post('/Member/Reset',{
|
||||
pwd:this.state.pwd,
|
||||
key:window.resetKey,
|
||||
}).then( (response)=> {
|
||||
if(response.data.code!=="200"){
|
||||
this.setState({
|
||||
loading:false,
|
||||
});
|
||||
this.props.toggleSnackbar("top","right",response.data.message,"warning");
|
||||
}else{
|
||||
this.setState({
|
||||
loading:false,
|
||||
pwd:"",
|
||||
pwdRepeat:"",
|
||||
});
|
||||
this.props.toggleSnackbar("top","right","密码重设成功","success");
|
||||
}
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.setState({
|
||||
loading:false,
|
||||
});
|
||||
this.props.toggleSnackbar("top","right",error.message,"error");
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
handleChange = name => event => {
|
||||
this.setState({ [name]: event.target.value });
|
||||
};
|
||||
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
|
||||
|
||||
return (
|
||||
<div className={classes.layout}>
|
||||
<Paper className={classes.paper}>
|
||||
<Avatar className={classes.avatar}>
|
||||
<KeyIcon />
|
||||
</Avatar>
|
||||
<Typography component="h1" variant="h5">
|
||||
找回密码
|
||||
</Typography>
|
||||
<form className={classes.form} onSubmit={this.login}>
|
||||
<FormControl margin="normal" required fullWidth>
|
||||
<InputLabel htmlFor="email">新密码</InputLabel>
|
||||
<Input
|
||||
id="pwd"
|
||||
type="password"
|
||||
name="pwd"
|
||||
onChange={this.handleChange("pwd")}
|
||||
autoComplete
|
||||
value={this.state.pwd}
|
||||
autoFocus />
|
||||
</FormControl>
|
||||
<FormControl margin="normal" required fullWidth>
|
||||
<InputLabel htmlFor="email">重复新密码</InputLabel>
|
||||
<Input
|
||||
id="pwdRepeat"
|
||||
type="password"
|
||||
name="pwdRepeat"
|
||||
onChange={this.handleChange("pwdRepeat")}
|
||||
autoComplete
|
||||
value={this.state.pwdRepeat}
|
||||
autoFocus />
|
||||
</FormControl>
|
||||
<Button
|
||||
type="submit"
|
||||
fullWidth
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={this.state.loading}
|
||||
className={classes.submit}
|
||||
>
|
||||
重设密码
|
||||
</Button> </form> <Divider/>
|
||||
<div className={classes.link}>
|
||||
<div>
|
||||
<Link href={"/Login"}>
|
||||
返回登录
|
||||
</Link>
|
||||
</div>
|
||||
<div>
|
||||
<Link href={"/SignUp"}>
|
||||
注册账号
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</Paper>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const ResetPwdForm = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(withStyles(styles)(ResetPwdFormCompoment))
|
||||
|
||||
export default ResetPwdForm
|
||||
|
|
@ -0,0 +1,160 @@
|
|||
import React, { Component } from 'react'
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import { connect } from 'react-redux'
|
||||
import Button from '@material-ui/core/Button';
|
||||
import FormControl from '@material-ui/core/FormControl';
|
||||
import Divider from '@material-ui/core/Divider';
|
||||
import Input from '@material-ui/core/Input';
|
||||
import InputLabel from '@material-ui/core/InputLabel';
|
||||
import VpnIcon from '@material-ui/icons/VpnKeyOutlined';
|
||||
import Paper from '@material-ui/core/Paper';
|
||||
import Avatar from '@material-ui/core/Avatar';
|
||||
import { toggleSnackbar, } from "../../actions/index"
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import axios from 'axios'
|
||||
const styles = theme => ({
|
||||
layout: {
|
||||
width: 'auto',
|
||||
marginTop: '110px',
|
||||
marginLeft: theme.spacing.unit * 3,
|
||||
marginRight: theme.spacing.unit * 3,
|
||||
[theme.breakpoints.up(1100 + theme.spacing.unit * 3 * 2)]: {
|
||||
width: 400,
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
},
|
||||
},
|
||||
paper: {
|
||||
marginTop: theme.spacing.unit * 8,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
padding: `${theme.spacing.unit * 2}px ${theme.spacing.unit * 3}px ${theme.spacing.unit * 3}px`,
|
||||
},
|
||||
avatar: {
|
||||
margin: theme.spacing.unit,
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
},
|
||||
form: {
|
||||
width: '100%', // Fix IE 11 issue.
|
||||
marginTop: theme.spacing.unit,
|
||||
},
|
||||
submit: {
|
||||
marginTop: theme.spacing.unit * 3,
|
||||
},
|
||||
link: {
|
||||
marginTop: "10px",
|
||||
display:"flex",
|
||||
width: "100%",
|
||||
justifyContent: "space-between",
|
||||
},
|
||||
captchaContainer:{
|
||||
display:"flex",
|
||||
marginTop: "10px",
|
||||
}
|
||||
})
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
toggleSnackbar: (vertical, horizontal, msg, color) => {
|
||||
dispatch(toggleSnackbar(vertical, horizontal, msg, color))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
class TwoStepCompoment extends Component {
|
||||
|
||||
state={
|
||||
code:"",
|
||||
loading:false,
|
||||
}
|
||||
|
||||
login = e=>{
|
||||
e.preventDefault();
|
||||
this.setState({
|
||||
loading:true,
|
||||
});
|
||||
axios.post('/Member/TwoStepCheck',{
|
||||
code:this.state.code,
|
||||
}).then( (response)=> {
|
||||
if(response.data.code!=="200"){
|
||||
this.setState({
|
||||
loading:false,
|
||||
});
|
||||
this.props.toggleSnackbar("top","right","验证代码不正确","warning");
|
||||
}else{
|
||||
this.setState({
|
||||
loading:false,
|
||||
});
|
||||
window.location.href="/Home";
|
||||
this.props.toggleSnackbar("top","right","登录成功","success");
|
||||
}
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.setState({
|
||||
loading:false,
|
||||
});
|
||||
this.props.toggleSnackbar("top","right",error.message,"error");
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
handleChange = name => event => {
|
||||
this.setState({ [name]: event.target.value });
|
||||
};
|
||||
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
|
||||
|
||||
return (
|
||||
<div className={classes.layout}>
|
||||
<Paper className={classes.paper}>
|
||||
<Avatar className={classes.avatar}>
|
||||
<VpnIcon />
|
||||
</Avatar>
|
||||
<Typography component="h1" variant="h5">
|
||||
二步验证
|
||||
</Typography>
|
||||
<form className={classes.form} onSubmit={this.login}>
|
||||
<FormControl margin="normal" required fullWidth>
|
||||
<InputLabel htmlFor="code">请输入六位二步验证代码</InputLabel>
|
||||
<Input
|
||||
id="code"
|
||||
type="number"
|
||||
name="code"
|
||||
onChange={this.handleChange("code")}
|
||||
autoComplete
|
||||
value={this.state.code}
|
||||
autoFocus />
|
||||
</FormControl>
|
||||
<Button
|
||||
type="submit"
|
||||
fullWidth
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={this.state.loading}
|
||||
className={classes.submit}
|
||||
>
|
||||
继续登录
|
||||
</Button> </form> <Divider/>
|
||||
|
||||
</Paper>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const TwoStep = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(withStyles(styles)(TwoStepCompoment))
|
||||
|
||||
export default TwoStep
|
||||
|
|
@ -0,0 +1,270 @@
|
|||
import React, { Component } from 'react'
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import { connect } from 'react-redux'
|
||||
import Tooltip from '@material-ui/core/Tooltip';
|
||||
import Card from '@material-ui/core/Card';
|
||||
import Avatar from '@material-ui/core/Avatar';
|
||||
import CardHeader from '@material-ui/core/CardHeader';
|
||||
import CardActions from '@material-ui/core/CardActions';
|
||||
import { toggleSnackbar,}from "../actions/index"
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import axios from 'axios'
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import OpenIcon from '@material-ui/icons/OpenInNew';
|
||||
import FileIcon from '@material-ui/icons/InsertDriveFile';
|
||||
import FolderIcon from '@material-ui/icons/Folder';
|
||||
import LockIcon from '@material-ui/icons/Lock';
|
||||
import UnlockIcon from '@material-ui/icons/LockOpen';
|
||||
import EyeIcon from '@material-ui/icons/RemoveRedEye';
|
||||
import DeleteIcon from '@material-ui/icons/Delete';
|
||||
import Dialog from '@material-ui/core/Dialog';
|
||||
import DialogActions from '@material-ui/core/DialogActions';
|
||||
import DialogContent from '@material-ui/core/DialogContent';
|
||||
import DialogTitle from '@material-ui/core/DialogTitle';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
|
||||
const styles = theme => ({
|
||||
card: {
|
||||
maxWidth: 400,
|
||||
margin: "0 auto",
|
||||
},
|
||||
actions: {
|
||||
display: 'flex',
|
||||
},
|
||||
layout: {
|
||||
width: 'auto',
|
||||
marginTop:'50px',
|
||||
marginLeft: theme.spacing.unit * 3,
|
||||
marginRight: theme.spacing.unit * 3,
|
||||
[theme.breakpoints.up(1100 + theme.spacing.unit * 3 * 2)]: {
|
||||
width: 1100,
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
},
|
||||
},
|
||||
shareTitle:{
|
||||
maxWidth:"200px",
|
||||
},
|
||||
avatarFile:{
|
||||
backgroundColor: theme.palette.primary.light,
|
||||
},
|
||||
avatarFolder:{
|
||||
backgroundColor: theme.palette.secondary.light,
|
||||
},
|
||||
gird:{
|
||||
marginTop:"30px",
|
||||
},
|
||||
loadMore:{
|
||||
textAlign:"center",
|
||||
marginTop:"20px",
|
||||
marginBottom:"20px",
|
||||
}
|
||||
})
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
toggleSnackbar:(vertical,horizontal,msg,color)=>{
|
||||
dispatch(toggleSnackbar(vertical,horizontal,msg,color))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
class MyShareCompoment extends Component {
|
||||
|
||||
state={
|
||||
page:1,
|
||||
shareList:[],
|
||||
showPwd:null,
|
||||
}
|
||||
|
||||
componentDidMount = ()=>{
|
||||
this.loadList(1);
|
||||
}
|
||||
|
||||
loadMore = ()=>{
|
||||
this.loadList(this.state.page+1);
|
||||
}
|
||||
|
||||
showPwd = (pwd)=>{
|
||||
this.setState({showPwd:pwd});
|
||||
}
|
||||
|
||||
handleClose = ()=>{
|
||||
this.setState({showPwd:null});
|
||||
}
|
||||
|
||||
removeShare = id=>{
|
||||
axios.post('/Share/Delete', {
|
||||
id:id,
|
||||
}).then( (response)=> {
|
||||
if(response.data.error!==1){
|
||||
let oldList = this.state.shareList;
|
||||
oldList = oldList.filter(value=>{
|
||||
return value.share_key !== id;
|
||||
});
|
||||
this.setState({
|
||||
shareList:oldList
|
||||
});
|
||||
this.props.toggleSnackbar("top","right","分享已取消","success");
|
||||
}
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.props.toggleSnackbar("top","right","请求失败","error");
|
||||
});
|
||||
}
|
||||
|
||||
changePermission = id=>{
|
||||
axios.post('/Share/ChangePromission', {
|
||||
id:id,
|
||||
}).then( (response)=> {
|
||||
if(response.data.error!==1){
|
||||
let oldList = this.state.shareList;
|
||||
let shareIndex = oldList.findIndex(value=>{
|
||||
return value.share_key === id;
|
||||
});
|
||||
oldList[shareIndex].type = (oldList[shareIndex].type==="public")?"private":"public";
|
||||
oldList[shareIndex].share_pwd = response.data.newPwd;
|
||||
this.setState({
|
||||
shareList:oldList
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.props.toggleSnackbar("top","right","请求失败","error");
|
||||
});
|
||||
}
|
||||
|
||||
loadList= page=>{
|
||||
axios.post('/Share/ListMyShare', {
|
||||
page:page,
|
||||
}).then( (response)=> {
|
||||
if(response.data.length===0){
|
||||
this.props.toggleSnackbar("top","right","没有更多了","info");
|
||||
}
|
||||
this.setState({
|
||||
page:page,
|
||||
shareList:this.state.shareList.concat(response.data),
|
||||
})
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.props.toggleSnackbar("top","right","加载失败","error");
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
|
||||
|
||||
return (
|
||||
<div className={classes.layout}>
|
||||
<Typography color="textSecondary" variant="h3">我的分享</Typography>
|
||||
<Grid container spacing={24} className={classes.gird}>
|
||||
{this.state.shareList.map(value=>(
|
||||
<Grid item xs={12} sm={4} key={value.id}>
|
||||
<Card className={classes.card}>
|
||||
<CardHeader
|
||||
style={{paddingBottom: "0px"}}
|
||||
avatar={
|
||||
<div>
|
||||
{value.source_type==="file"&&
|
||||
<Avatar className={classes.avatarFile}>
|
||||
<FileIcon/>
|
||||
</Avatar>
|
||||
}
|
||||
{value.source_type==="dir"&&
|
||||
<Avatar className={classes.avatarFolder}>
|
||||
<FolderIcon/>
|
||||
</Avatar>
|
||||
}
|
||||
|
||||
</div>
|
||||
}
|
||||
title={<Tooltip placement="top" title={value.fileData}><Typography noWrap className={classes.shareTitle}>{value.fileData}</Typography></Tooltip>}
|
||||
subheader={value.share_time}
|
||||
/>
|
||||
|
||||
<CardActions disableActionSpacing style={{textAlign:"right"}}>
|
||||
<Tooltip placement="top" title="打开">
|
||||
<IconButton onClick={()=>window.open("/s/"+value.share_key)}>
|
||||
<OpenIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
{value.type==="private"&&
|
||||
<div>
|
||||
<Tooltip placement="top" title="变更为公开分享" onClick={()=>this.changePermission(value.share_key)}>
|
||||
<IconButton>
|
||||
<LockIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip placement="top" title="查看密码" onClick={()=>this.showPwd(value.share_pwd)}>
|
||||
<IconButton>
|
||||
<EyeIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
}
|
||||
{value.type==="public"&&
|
||||
<Tooltip placement="top" title="变更为私密分享" onClick={()=>this.changePermission(value.share_key)}>
|
||||
<IconButton>
|
||||
<UnlockIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
}
|
||||
|
||||
<Tooltip placement="top" title="取消分享" onClick={()=>this.removeShare(value.share_key)}>
|
||||
<IconButton>
|
||||
<DeleteIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
|
||||
</CardActions>
|
||||
</Card>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
<div className={classes.loadMore}>
|
||||
<Button size="large"
|
||||
className={classes.margin}
|
||||
disabled={this.state.shareList.length<18}
|
||||
onClick={this.loadMore}
|
||||
>
|
||||
继续加载
|
||||
</Button>
|
||||
</div>
|
||||
<Dialog
|
||||
open={this.state.showPwd!==null}
|
||||
onClose={this.handleClose}
|
||||
>
|
||||
<DialogTitle>分享密码</DialogTitle>
|
||||
<DialogContent>
|
||||
<TextField
|
||||
id="standard-name"
|
||||
value={this.state.showPwd}
|
||||
margin="normal"
|
||||
autoFocus
|
||||
/>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={this.handleClose} color="default">
|
||||
关闭
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const MyShare = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)( withStyles(styles)(MyShareCompoment))
|
||||
|
||||
export default MyShare
|
||||
|
|
@ -0,0 +1,678 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import AppBar from '@material-ui/core/AppBar';
|
||||
import Toolbar from '@material-ui/core/Toolbar';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import { withTheme } from '@material-ui/core/styles';
|
||||
import classNames from 'classnames';
|
||||
import { connect } from 'react-redux'
|
||||
import VideoIcon from '@material-ui/icons/VideoLibrary';
|
||||
import MusicIcon from '@material-ui/icons/LibraryMusic';
|
||||
import ImageIcon from '@material-ui/icons/Collections';
|
||||
import AddIcon from '@material-ui/icons/Add';
|
||||
import DocIcon from '@material-ui/icons/FileCopy';
|
||||
import ShareIcon from '@material-ui/icons/Share';
|
||||
import BackIcon from '@material-ui/icons/ArrowBack';
|
||||
import OpenIcon from '@material-ui/icons/OpenInNew'
|
||||
import DownloadIcon from '@material-ui/icons/CloudDownload'
|
||||
import OpenFolderIcon from '@material-ui/icons/FolderOpen'
|
||||
import RenameIcon from '@material-ui/icons/BorderColor'
|
||||
import MoveIcon from '@material-ui/icons/Input'
|
||||
import DeleteIcon from '@material-ui/icons/Delete'
|
||||
import Button from '@material-ui/core/Button';
|
||||
import Drawer from '@material-ui/core/Drawer';
|
||||
import SwipeableDrawer from '@material-ui/core/SwipeableDrawer'
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import Hidden from '@material-ui/core/Hidden';
|
||||
import Avatar from '@material-ui/core/Avatar';
|
||||
import Divider from '@material-ui/core/Divider';
|
||||
import ListItem from '@material-ui/core/ListItem';
|
||||
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
||||
import ListItemText from '@material-ui/core/ListItemText';
|
||||
import UploadIcon from '@material-ui/icons/CloudUpload';
|
||||
import FolderShared from '@material-ui/icons/FolderShared';
|
||||
import SaveIcon from '@material-ui/icons/Save';
|
||||
import List from '@material-ui/core/List';
|
||||
import MenuIcon from '@material-ui/icons/Menu';
|
||||
import Badge from '@material-ui/core/Badge';
|
||||
import Grow from '@material-ui/core/Grow';
|
||||
import Tooltip from '@material-ui/core/Tooltip';
|
||||
import {isPreviewable} from "../config"
|
||||
import {
|
||||
drawerToggleAction,
|
||||
setSelectedTarget,
|
||||
navitateTo,
|
||||
openCreateFolderDialog,
|
||||
changeContextMenu,
|
||||
searchMyFile,
|
||||
saveFile,
|
||||
openMusicDialog,
|
||||
showImgPreivew,
|
||||
toggleSnackbar,
|
||||
openMoveDialog,
|
||||
openRemoveDialog,
|
||||
openShareDialog,
|
||||
openRenameDialog,
|
||||
} from "../actions/index"
|
||||
import {allowSharePreview,checkGetParameters,changeThemeColor} from "../untils/index"
|
||||
import Uploader from "./Uploader.js"
|
||||
import {sizeToString} from "../untils/index"
|
||||
import SezrchBar from "./SearchBar"
|
||||
import StorageBar from "./StorageBar"
|
||||
import UserAvatar from "./UserAvatar"
|
||||
import UserInfo from "./UserInfo"
|
||||
import {
|
||||
AccountArrowRight,
|
||||
AccountPlus
|
||||
} from 'mdi-material-ui'
|
||||
const drawerWidth = 240;
|
||||
const drawerWidthMobile = 270;
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
desktopOpen: state.viewUpdate.open,
|
||||
selected:state.explorer.selected,
|
||||
isMultiple:state.explorer.selectProps.isMultiple,
|
||||
withFolder:state.explorer.selectProps.withFolder,
|
||||
withFile:state.explorer.selectProps.withFile,
|
||||
path:state.navigator.path,
|
||||
keywords:state.explorer.keywords,
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
handleDesktopToggle: open => {
|
||||
dispatch(drawerToggleAction(open))
|
||||
},
|
||||
setSelectedTarget:targets=>{
|
||||
dispatch(setSelectedTarget(targets))
|
||||
},
|
||||
navitateTo:path => {
|
||||
dispatch(navitateTo(path))
|
||||
},
|
||||
openCreateFolderDialog:()=>{
|
||||
dispatch(openCreateFolderDialog())
|
||||
},
|
||||
changeContextMenu:(type,open)=>{
|
||||
dispatch(changeContextMenu(type,open))
|
||||
},
|
||||
searchMyFile:(keywords)=>{
|
||||
dispatch(searchMyFile(keywords));
|
||||
},
|
||||
saveFile:()=>{
|
||||
dispatch(saveFile())
|
||||
},
|
||||
openMusicDialog:()=>{
|
||||
dispatch(openMusicDialog())
|
||||
},
|
||||
showImgPreivew:(first)=>{
|
||||
dispatch(showImgPreivew(first))
|
||||
},
|
||||
toggleSnackbar:(vertical,horizontal,msg,color)=>{
|
||||
dispatch(toggleSnackbar(vertical,horizontal,msg,color))
|
||||
},
|
||||
openRenameDialog:()=>{
|
||||
dispatch(openRenameDialog())
|
||||
},
|
||||
openMoveDialog:()=>{
|
||||
dispatch(openMoveDialog())
|
||||
},
|
||||
openRemoveDialog:()=>{
|
||||
dispatch(openRemoveDialog())
|
||||
},
|
||||
openShareDialog:()=>{
|
||||
dispatch(openShareDialog())
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const styles = theme => ({
|
||||
appBar: {
|
||||
marginLeft: drawerWidth,
|
||||
[theme.breakpoints.down('xs')]: {
|
||||
marginLeft: drawerWidthMobile,
|
||||
},
|
||||
zIndex: theme.zIndex.drawer + 1,
|
||||
transition:" background-color 250ms" ,
|
||||
},
|
||||
|
||||
drawer: {
|
||||
width: 0,
|
||||
flexShrink: 0,
|
||||
},
|
||||
drawerDesktop:{
|
||||
width: drawerWidth,
|
||||
flexShrink: 0,
|
||||
},
|
||||
icon: {
|
||||
marginRight: theme.spacing.unit * 2,
|
||||
},
|
||||
menuButton: {
|
||||
marginRight: 20,
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
display: 'none',
|
||||
},
|
||||
},
|
||||
menuButtonDesktop:{
|
||||
marginRight: 20,
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
display: 'none',
|
||||
},
|
||||
},
|
||||
menuIcon:{
|
||||
marginRight: 20,
|
||||
},
|
||||
toolbar: theme.mixins.toolbar,
|
||||
drawerPaper:{
|
||||
width:drawerWidthMobile,
|
||||
},
|
||||
drawerOpen: {
|
||||
width: drawerWidth,
|
||||
transition: theme.transitions.create('width', {
|
||||
easing: theme.transitions.easing.sharp,
|
||||
duration: theme.transitions.duration.enteringScreen,
|
||||
}),
|
||||
},
|
||||
drawerClose: {
|
||||
transition: theme.transitions.create('width', {
|
||||
easing: theme.transitions.easing.sharp,
|
||||
duration: theme.transitions.duration.leavingScreen,
|
||||
}),
|
||||
overflowX: 'hidden',
|
||||
width: 0,
|
||||
|
||||
},
|
||||
content: {
|
||||
flexGrow: 1,
|
||||
padding: theme.spacing.unit * 3,
|
||||
},
|
||||
hiddenButton: {
|
||||
display: "none",
|
||||
},
|
||||
grow: {
|
||||
flexGrow: 1,
|
||||
},
|
||||
badge: {
|
||||
top: 1,
|
||||
right:-15,
|
||||
|
||||
},
|
||||
nested: {
|
||||
paddingLeft: theme.spacing.unit * 4,
|
||||
},
|
||||
sectionForFile:{
|
||||
|
||||
|
||||
display: 'flex',
|
||||
|
||||
},
|
||||
extendedIcon: {
|
||||
marginRight: theme.spacing.unit,
|
||||
},
|
||||
addButton:{
|
||||
marginLeft: "40px",
|
||||
marginTop: "25px",
|
||||
marginBottom: "15px",
|
||||
},
|
||||
fabButton:{
|
||||
borderRadius:"100px",
|
||||
},
|
||||
badgeFix:{
|
||||
right:"10px",
|
||||
},
|
||||
iconFix:{
|
||||
marginLeft: "16px",
|
||||
},
|
||||
dividerFix:{
|
||||
marginTop: "8px",
|
||||
},
|
||||
folderShareIcon:{
|
||||
verticalAlign: "sub",
|
||||
marginRight: "5px",
|
||||
},
|
||||
shareInfoContainer:{
|
||||
display:"flex",
|
||||
marginTop: "15px",
|
||||
marginBottom: "20px",
|
||||
marginLeft: "28px",
|
||||
textDecoration:"none",
|
||||
},
|
||||
shareAvatar:{
|
||||
width:"40px",
|
||||
height:"40px",
|
||||
},
|
||||
stickFooter:{
|
||||
bottom: "0px",
|
||||
position: "absolute",
|
||||
backgroundColor:theme.palette.background.paper,
|
||||
width: "100%",
|
||||
},
|
||||
ownerInfo:{
|
||||
marginLeft: "10px",
|
||||
width: "150px",
|
||||
}
|
||||
});
|
||||
class NavbarCompoment extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
mobileOpen: false,
|
||||
queued: 0,
|
||||
};
|
||||
this.UploaderRef = React.createRef();
|
||||
}
|
||||
|
||||
componentDidMount=()=>{
|
||||
changeThemeColor((this.props.selected.length <=1 && ! (!this.props.isMultiple&&this.props.withFile))?this.props.theme.palette.primary.main:this.props.theme.palette.background.default);
|
||||
}
|
||||
|
||||
componentWillReceiveProps = (nextProps)=>{
|
||||
if((this.props.selected.length <=1 && ! (!this.props.isMultiple&&this.props.withFile))!==(nextProps.selected.length <=1 && ! (!nextProps.isMultiple&&nextProps.withFile))){
|
||||
changeThemeColor(!(this.props.selected.length <=1 && ! (!this.props.isMultiple&&this.props.withFile))?this.props.theme.palette.primary.main:this.props.theme.palette.background.default);
|
||||
}
|
||||
}
|
||||
|
||||
handleDrawerToggle = () => {
|
||||
this.setState(state => ({ mobileOpen: !state.mobileOpen }));
|
||||
};
|
||||
|
||||
clickUpload = () => {
|
||||
if (this.state.queued === 0) {
|
||||
//document.getElementsByClassName("uploadForm")[0].click();
|
||||
this.props.changeContextMenu("empty",true);
|
||||
} else {
|
||||
this.UploaderRef.current.getWrappedInstance().openFileList();
|
||||
}
|
||||
}
|
||||
|
||||
updateQueueStatus = (queued) => {
|
||||
this.setState({ queued: queued });
|
||||
}
|
||||
|
||||
loadUploader() {
|
||||
if (window.isHomePage) {
|
||||
return (<Uploader queueChange={queued => this.updateQueueStatus(queued)} ref={this.UploaderRef} />)
|
||||
}
|
||||
}
|
||||
|
||||
filterFile = (type)=>{
|
||||
this.props.searchMyFile("{filterType:"+type+"}")
|
||||
}
|
||||
|
||||
openPreview = ()=>{
|
||||
if(!allowSharePreview()){
|
||||
this.props.toggleSnackbar("top","right","未登录用户无法预览","warning");
|
||||
return;
|
||||
}
|
||||
this.props.changeContextMenu("file",false);
|
||||
let previewPath = this.props.selected[0].path === "/" ? this.props.selected[0].path+this.props.selected[0].name:this.props.selected[0].path+"/"+this.props.selected[0].name;
|
||||
switch(isPreviewable(this.props.selected[0].name)){
|
||||
case 'img':
|
||||
this.props.showImgPreivew(this.props.selected[0]);
|
||||
return;
|
||||
case 'msDoc':
|
||||
window.open(window.apiURL.docPreiview+"/?path="+encodeURIComponent(previewPath));
|
||||
return;
|
||||
case 'audio':
|
||||
this.props.openMusicDialog();
|
||||
return;
|
||||
case 'open':
|
||||
window.open(window.apiURL.preview+"/?action=preview&path="+encodeURIComponent(previewPath));
|
||||
return;
|
||||
case 'video':
|
||||
if(window.isSharePage){
|
||||
window.location.href=("/Viewer/Video?share=true&shareKey="+window.shareInfo.shareId+"&path="+encodeURIComponent(previewPath));
|
||||
return;
|
||||
}
|
||||
window.location.href=("/Viewer/Video?path="+encodeURIComponent(previewPath));
|
||||
return;
|
||||
case 'edit':
|
||||
if(window.isSharePage){
|
||||
window.location.href=("/Viewer/Markdown?share=true&shareKey="+window.shareInfo.shareId+"&path="+encodeURIComponent(previewPath));
|
||||
return;
|
||||
}
|
||||
window.location.href=("/Viewer/Markdown?path="+encodeURIComponent(previewPath));
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
openDownload = ()=>{
|
||||
if(!allowSharePreview()){
|
||||
this.props.toggleSnackbar("top","right","未登录用户无法预览","warning");
|
||||
return;
|
||||
}
|
||||
let downloadPath = this.props.selected[0].path === "/" ? this.props.selected[0].path+this.props.selected[0].name:this.props.selected[0].path+"/"+this.props.selected[0].name;
|
||||
window.open(window.apiURL.download+"?action=download&path="+encodeURIComponent(downloadPath));
|
||||
}
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
|
||||
const drawer = (
|
||||
<div id="container">
|
||||
{window.isMobile&&
|
||||
<UserInfo/>
|
||||
}
|
||||
{window.isHomePage&&
|
||||
<div className={classes.addButton}>
|
||||
<Badge badgeContent={this.state.queued} classes={{ badge: classes.badgeFix }} invisible={this.state.queued === 0} color="secondary">
|
||||
<Button
|
||||
disabled={this.props.keywords!==null}
|
||||
variant="outlined"
|
||||
size="large"
|
||||
color="primary"
|
||||
onClick = {this.clickUpload}
|
||||
className={classes.fabButton}
|
||||
>
|
||||
<AddIcon className={classes.extendedIcon} /> 新建项目
|
||||
|
||||
|
||||
</Button>
|
||||
</Badge>
|
||||
</div>
|
||||
}
|
||||
{(!window.isHomePage&&(window.userInfo.uid!==-1))&&
|
||||
<div>
|
||||
<ListItem button key="我的文件" onClick={()=>window.location.href="/"}>
|
||||
<ListItemIcon>
|
||||
<FolderShared className={classes.iconFix}/>
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="我的文件" />
|
||||
</ListItem>
|
||||
</div>
|
||||
}
|
||||
|
||||
{window.isHomePage&&<div>
|
||||
<List>
|
||||
<Divider/>
|
||||
<ListItem button id="pickfiles" className={classes.hiddenButton}>
|
||||
<ListItemIcon><UploadIcon /></ListItemIcon>
|
||||
<ListItemText />
|
||||
</ListItem>
|
||||
</List>
|
||||
<ListItem button key="视频" onClick={()=>this.filterFile("video")}>
|
||||
<ListItemIcon>
|
||||
<VideoIcon className={[classes.iconFix,classes.iconVideo]}/>
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="视频" />
|
||||
</ListItem>
|
||||
|
||||
<ListItem button key="图片" onClick={()=>this.filterFile("image")}>
|
||||
<ListItemIcon>
|
||||
<ImageIcon className={[classes.iconFix,classes.iconImg]} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="图片" />
|
||||
</ListItem>
|
||||
|
||||
<ListItem button key="音频" onClick={()=>this.filterFile("audio")}>
|
||||
<ListItemIcon>
|
||||
<MusicIcon className={[classes.iconFix,classes.iconAudio]} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="音频" />
|
||||
</ListItem>
|
||||
|
||||
<ListItem button key="文档" onClick={()=>this.filterFile("doc")}>
|
||||
<ListItemIcon>
|
||||
<DocIcon className={[classes.iconFix,classes.iconDoc]} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="文档" />
|
||||
</ListItem> <Divider className={classes.dividerFix}/></div>}
|
||||
|
||||
{window.userInfo.uid!==-1&&<div>
|
||||
<ListItem button key="我的分享" onClick={()=>window.location.href="/Share/My"}>
|
||||
<ListItemIcon>
|
||||
<ShareIcon className={classes.iconFix} />
|
||||
</ListItemIcon>
|
||||
<ListItemText inset primary="我的分享" />
|
||||
</ListItem>
|
||||
<ListItem button key="离线下载" onClick={()=>window.location.href="/Home/Download"}>
|
||||
<ListItemIcon>
|
||||
<DownloadIcon className={classes.iconFix} />
|
||||
</ListItemIcon>
|
||||
<ListItemText inset primary="离线下载" />
|
||||
</ListItem>
|
||||
{!window.isSharePage&&
|
||||
<div>
|
||||
<StorageBar></StorageBar>
|
||||
</div>
|
||||
}
|
||||
|
||||
</div>
|
||||
}
|
||||
{window.userInfo.uid===-1&&
|
||||
<div>
|
||||
<ListItem button key="登录" onClick={()=>window.location.href="/Login"}>
|
||||
<ListItemIcon>
|
||||
<AccountArrowRight className={classes.iconFix} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="登录" />
|
||||
</ListItem>
|
||||
<ListItem button key="注册" onClick={()=>window.location.href="/Signup"}>
|
||||
<ListItemIcon>
|
||||
<AccountPlus className={classes.iconFix} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="注册" />
|
||||
</ListItem>
|
||||
</div>
|
||||
}
|
||||
{window.isSharePage&&
|
||||
<div className={classes.stickFooter}>
|
||||
<Divider/>
|
||||
<a className={classes.shareInfoContainer} href={"/Profile/"+window.shareInfo.ownerUid}>
|
||||
<Avatar src={"/Member/Avatar/"+window.shareInfo.ownerUid+"/l"} className={classes.shareAvatar}/><div className={classes.ownerInfo}>
|
||||
<Typography noWrap>{window.shareInfo.ownerNick}</Typography>
|
||||
<Typography noWrap variant="caption" color="textSecondary">分享于{window.shareInfo.shareDate }</Typography>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
</div>}
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
);
|
||||
const iOS = process.browser && /iPad|iPhone|iPod/.test(navigator.userAgent);
|
||||
return (
|
||||
<div>
|
||||
<AppBar position="fixed" className={classes.appBar} color={(this.props.selected.length <=1 && ! (!this.props.isMultiple&&this.props.withFile))?"primary":"default"}>
|
||||
<Toolbar>
|
||||
{(((this.props.selected.length <=1 && !(!this.props.isMultiple&&this.props.withFile))||!window.isHomePage)&&!window.isSharePage)&&
|
||||
<IconButton
|
||||
color="inherit"
|
||||
aria-label="Open drawer"
|
||||
onClick={this.handleDrawerToggle}
|
||||
className={classes.menuButton}
|
||||
>
|
||||
<MenuIcon />
|
||||
</IconButton>
|
||||
}
|
||||
{(((this.props.selected.length <=1 && !(!this.props.isMultiple&&this.props.withFile))||!window.isHomePage)&&!window.isSharePage)&&<IconButton
|
||||
color="inherit"
|
||||
aria-label="Open drawer"
|
||||
onClick={()=>this.props.handleDesktopToggle(!this.props.desktopOpen)}
|
||||
className={classes.menuButtonDesktop}
|
||||
>
|
||||
<MenuIcon />
|
||||
</IconButton>}
|
||||
{((this.props.selected.length >1 || (!this.props.isMultiple&&this.props.withFile) )&& (window.isHomePage||window.isSharePage))&&
|
||||
<Grow in={(this.props.selected.length >1) || (!this.props.isMultiple&&this.props.withFile)}>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
className={classes.menuIcon}
|
||||
onClick = {()=>this.props.setSelectedTarget([])}
|
||||
>
|
||||
<BackIcon />
|
||||
</IconButton>
|
||||
</Grow>
|
||||
}
|
||||
{(this.props.selected.length <=1 && !(!this.props.isMultiple&&this.props.withFile))&&
|
||||
<Typography variant="h6" color="inherit" noWrap>
|
||||
{window.isSharePage&&window.pageId===""&&<FolderShared className={classes.folderShareIcon}/>}{window.siteInfo.mainTitle}
|
||||
</Typography>
|
||||
}
|
||||
|
||||
{(!this.props.isMultiple&&this.props.withFile&&!window.isMobile)&&
|
||||
<Typography variant="h6" color="inherit" noWrap>
|
||||
{this.props.selected[0].name} {(window.isHomePage||window.isSharePage)&&"("+sizeToString(this.props.selected[0].size)+")"}
|
||||
</Typography>
|
||||
}
|
||||
|
||||
{(this.props.selected.length >1&&!window.isMobile)&&
|
||||
<Typography variant="h6" color="inherit" noWrap>
|
||||
{this.props.selected.length}个对象
|
||||
</Typography>
|
||||
}
|
||||
{(this.props.selected.length <=1 && !(!this.props.isMultiple&&this.props.withFile))&&
|
||||
<SezrchBar/>
|
||||
}
|
||||
<div className={classes.grow} />
|
||||
{((this.props.selected.length>1 || (!this.props.isMultiple&&this.props.withFile)) && !window.isHomePage&&!window.isSharePage && window.userInfo.uid!==-1&&!checkGetParameters("share"))&&
|
||||
<div className={classes.sectionForFile}>
|
||||
<Tooltip title="保存">
|
||||
<IconButton color="inherit" onClick={()=>this.props.saveFile()}>
|
||||
<SaveIcon/>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
}
|
||||
{((this.props.selected.length>1 || (!this.props.isMultiple&&this.props.withFile) )&& (window.isHomePage||window.isSharePage))&&
|
||||
<div className={classes.sectionForFile}>
|
||||
{(!this.props.isMultiple&&this.props.withFile&&isPreviewable(this.props.selected[0].name))&&
|
||||
<Grow in={(!this.props.isMultiple&&this.props.withFile&&isPreviewable(this.props.selected[0].name))}>
|
||||
<Tooltip title="打开">
|
||||
<IconButton color="inherit"
|
||||
onClick = {()=>this.openPreview()}
|
||||
>
|
||||
<OpenIcon/>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Grow>
|
||||
}
|
||||
{(!this.props.isMultiple&&this.props.withFile)&&
|
||||
<Grow in={(!this.props.isMultiple&&this.props.withFile)}>
|
||||
<Tooltip title="下载">
|
||||
<IconButton color="inherit"
|
||||
onClick = {()=>this.openDownload()}
|
||||
>
|
||||
<DownloadIcon/>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Grow>
|
||||
}
|
||||
{(!this.props.isMultiple && this.props.withFolder)&&
|
||||
<Grow in={(!this.props.isMultiple && this.props.withFolder)}>
|
||||
<Tooltip title="进入目录">
|
||||
<IconButton color="inherit"
|
||||
onClick = {()=>this.props.navitateTo(this.props.path==="/"?this.props.path+this.props.selected[0].name:this.props.path+"/"+this.props.selected[0].name) }
|
||||
>
|
||||
<OpenFolderIcon/>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Grow>
|
||||
}
|
||||
{(!this.props.isMultiple&&!window.isSharePage)&&
|
||||
<Grow in={(!this.props.isMultiple)}>
|
||||
<Tooltip title="分享">
|
||||
<IconButton color="inherit" onClick={()=>this.props.openShareDialog()}>
|
||||
<ShareIcon/>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Grow>
|
||||
}
|
||||
{(!this.props.isMultiple&&!window.isSharePage)&&
|
||||
<Grow in={(!this.props.isMultiple)}>
|
||||
<Tooltip title="重命名">
|
||||
<IconButton color="inherit" onClick={()=>this.props.openRenameDialog()}>
|
||||
<RenameIcon/>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Grow>
|
||||
}
|
||||
{!window.isSharePage&&<div>
|
||||
{!window.isMobile&&<Grow in={(this.props.selected.length!==0)&&!window.isMobile}>
|
||||
<Tooltip title="移动">
|
||||
<IconButton color="inherit" onClick={()=>this.props.openMoveDialog()}>
|
||||
<MoveIcon/>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Grow>}
|
||||
|
||||
<Grow in={(this.props.selected.length!==0)}>
|
||||
<Tooltip title="删除">
|
||||
<IconButton color="inherit" onClick={()=>this.props.openRemoveDialog()}>
|
||||
<DeleteIcon/>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Grow>
|
||||
</div>}
|
||||
|
||||
|
||||
</div>
|
||||
}
|
||||
{(this.props.selected.length <=1 && !(!this.props.isMultiple&&this.props.withFile))&&
|
||||
<UserAvatar/>
|
||||
}
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
{this.loadUploader()}
|
||||
|
||||
<Hidden smUp implementation="css">
|
||||
<SwipeableDrawer
|
||||
container={this.props.container}
|
||||
variant="temporary"
|
||||
classes={{
|
||||
paper: classes.drawerPaper,
|
||||
}}
|
||||
anchor="left"
|
||||
open={this.state.mobileOpen}
|
||||
onClose={this.handleDrawerToggle}
|
||||
onOpen={()=>this.setState(state => ({ mobileOpen: true}))}
|
||||
disableDiscovery={iOS}
|
||||
ModalProps={{
|
||||
keepMounted: true, // Better open performance on mobile.
|
||||
}}
|
||||
>
|
||||
{drawer}
|
||||
</SwipeableDrawer>
|
||||
</Hidden>
|
||||
<Hidden xsDown implementation="css">
|
||||
<Drawer
|
||||
classes={{
|
||||
paper: classNames({
|
||||
[classes.drawerOpen]: this.props.desktopOpen,
|
||||
[classes.drawerClose]: !this.props.desktopOpen,
|
||||
}),
|
||||
}}
|
||||
className={classNames(classes.drawer, {
|
||||
[classes.drawerOpen]: this.props.desktopOpen,
|
||||
[classes.drawerClose]: !this.props.desktopOpen,
|
||||
})}
|
||||
variant="persistent"
|
||||
anchor="left"
|
||||
open={this.props.desktopOpen}
|
||||
><div className={classes.toolbar} />
|
||||
{drawer}
|
||||
</Drawer>
|
||||
</Hidden>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
NavbarCompoment.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
theme: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
const Navbar = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)( withTheme()(withStyles(styles)(NavbarCompoment)))
|
||||
|
||||
export default Navbar
|
||||
|
|
@ -0,0 +1,253 @@
|
|||
import React, { Component } from 'react'
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import { connect } from 'react-redux'
|
||||
import Paper from '@material-ui/core/Paper';
|
||||
import Avatar from '@material-ui/core/Avatar';
|
||||
import { toggleSnackbar,}from "../actions/index"
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import axios from 'axios'
|
||||
import Tabs from '@material-ui/core/Tabs';
|
||||
import Tab from '@material-ui/core/Tab';
|
||||
import Table from '@material-ui/core/Table';
|
||||
import TableBody from '@material-ui/core/TableBody';
|
||||
import TableCell from '@material-ui/core/TableCell';
|
||||
import TableHead from '@material-ui/core/TableHead';
|
||||
import TableRow from '@material-ui/core/TableRow';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import LeftIcon from '@material-ui/icons/KeyboardArrowLeft'
|
||||
import RighttIcon from '@material-ui/icons/KeyboardArrowRight'
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
|
||||
const styles = theme => ({
|
||||
layout: {
|
||||
width: 'auto',
|
||||
marginTop:'50px',
|
||||
marginLeft: theme.spacing.unit * 3,
|
||||
marginRight: theme.spacing.unit * 3,
|
||||
marginBottom: "30px",
|
||||
[theme.breakpoints.up("sm")]: {
|
||||
width: 700,
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
},
|
||||
},
|
||||
userNav:{
|
||||
height:"270px",
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
padding: "20px 20px 2em",
|
||||
backgroundImage: "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1600 900'%3E%3Cpolygon fill='"+theme.palette.primary.light.replace("#","%23")+"' points='957 450 539 900 1396 900'/%3E%3Cpolygon fill='"+theme.palette.primary.dark.replace("#","%23")+"' points='957 450 872.9 900 1396 900'/%3E%3Cpolygon fill='"+theme.palette.secondary.main.replace("#","%23")+"' points='-60 900 398 662 816 900'/%3E%3Cpolygon fill='"+theme.palette.secondary.dark.replace("#","%23")+"' points='337 900 398 662 816 900'/%3E%3Cpolygon fill='"+theme.palette.secondary.light.replace("#","%23")+"' points='1203 546 1552 900 876 900'/%3E%3Cpolygon fill='"+theme.palette.secondary.main.replace("#","%23")+"' points='1203 546 1552 900 1162 900'/%3E%3Cpolygon fill='"+theme.palette.primary.dark.replace("#","%23")+"' points='641 695 886 900 367 900'/%3E%3Cpolygon fill='"+theme.palette.primary.main.replace("#","%23")+"' points='587 900 641 695 886 900'/%3E%3Cpolygon fill='"+theme.palette.secondary.light.replace("#","%23")+"' points='1710 900 1401 632 1096 900'/%3E%3Cpolygon fill='"+theme.palette.secondary.dark.replace("#","%23")+"' points='1710 900 1401 632 1365 900'/%3E%3Cpolygon fill='"+theme.palette.secondary.main.replace("#","%23")+"' points='1210 900 971 687 725 900'/%3E%3Cpolygon fill='"+theme.palette.secondary.dark.replace("#","%23")+"' points='943 900 1210 900 971 687'/%3E%3C/svg%3E\")",
|
||||
backgroundSize: "cover",
|
||||
backgroundPosition: "bottom",
|
||||
},
|
||||
avatarContainer:{
|
||||
height: "80px",
|
||||
width: "80px",
|
||||
borderRaidus:"50%",
|
||||
margin: "auto",
|
||||
marginTop: "50px",
|
||||
boxShadow: "0 2px 5px 0 rgba(0,0,0,0.16), 0 2px 10px 0 rgba(0,0,0,0.12)",
|
||||
border: "2px solid #fff",
|
||||
},
|
||||
nickName:{
|
||||
width: "200px",
|
||||
margin: "auto",
|
||||
textAlign: "center",
|
||||
marginTop: "1px",
|
||||
fontSize: "25px",
|
||||
color: "#ffffffcf",
|
||||
},
|
||||
th:{
|
||||
minWidth: "106px",
|
||||
},
|
||||
mobileHide:{
|
||||
[theme.breakpoints.down("md")]: {
|
||||
display:"none",
|
||||
}
|
||||
},
|
||||
tableLink:{
|
||||
cursor: "pointer",
|
||||
},
|
||||
navigator:{
|
||||
display:"flex",
|
||||
justifyContent:"space-between",
|
||||
},
|
||||
pageInfo:{
|
||||
marginTop: "14px",
|
||||
marginLeft: "23px",
|
||||
},
|
||||
infoItem:{
|
||||
paddingLeft: "46px!important",
|
||||
paddingBottom: "20px!important",
|
||||
},
|
||||
infoContainer:{
|
||||
marginTop:"30px",
|
||||
}
|
||||
})
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
|
||||
return {
|
||||
toggleSnackbar:(vertical,horizontal,msg,color)=>{
|
||||
dispatch(toggleSnackbar(vertical,horizontal,msg,color))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
class ProfileCompoment extends Component {
|
||||
|
||||
state={
|
||||
listType:0,
|
||||
shareList:[],
|
||||
page:1,
|
||||
}
|
||||
|
||||
handleChange = (event, listType) => {
|
||||
this.setState({ listType });
|
||||
if(listType===1){
|
||||
this.loadList(1,"hot");
|
||||
}else if(listType===0){
|
||||
this.loadList(1,"default");
|
||||
}
|
||||
};
|
||||
|
||||
componentDidMount = ()=>{
|
||||
this.loadList(1,"default");
|
||||
}
|
||||
|
||||
loadList = (page,shareType) => {
|
||||
axios.post('/Profile/getList', {
|
||||
uid:window.taegetUserInfo.uid,
|
||||
type:shareType,
|
||||
page:page,
|
||||
}).then( (response)=> {
|
||||
this.setState({
|
||||
page:page,
|
||||
shareList:response.data,
|
||||
})
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.props.toggleSnackbar("top","right","加载失败","error");
|
||||
});
|
||||
}
|
||||
|
||||
loadNext = ()=>{
|
||||
this.loadList(this.state.page+1,this.state.listType===0?"default":"hot");
|
||||
}
|
||||
|
||||
loadPrev = ()=>{
|
||||
this.loadList(this.state.page-1,this.state.listType===0?"default":"hot");
|
||||
}
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
|
||||
|
||||
return (
|
||||
<div className={classes.layout}>
|
||||
<Paper square>
|
||||
<div className={classes.userNav}>
|
||||
<div >
|
||||
<Avatar className={classes.avatarContainer} src ={"/Member/Avatar/"+window.taegetUserInfo.uid+"/l"}></Avatar>
|
||||
</div>
|
||||
<div>
|
||||
<Typography className={classes.nickName} noWrap>{window.taegetUserInfo.nickname}</Typography>
|
||||
</div>
|
||||
</div>
|
||||
<Tabs
|
||||
value={this.state.listType}
|
||||
indicatorColor="primary"
|
||||
textColor="primary"
|
||||
onChange={this.handleChange}
|
||||
centered
|
||||
>
|
||||
<Tab label="全部分享" />
|
||||
<Tab label="热门分享"/>
|
||||
<Tab label="个人资料" />
|
||||
</Tabs>
|
||||
{this.state.listType===2&&
|
||||
<div className={classes.infoContainer}>
|
||||
<Grid container spacing={24}>
|
||||
<Grid item md={4} xs={12} className={classes.infoItem}>
|
||||
<Typography color="textSecondary" variant="h6">UID</Typography>
|
||||
<Typography>{window.taegetUserInfo.uid}</Typography>
|
||||
</Grid>
|
||||
<Grid item md={4} xs={12} className={classes.infoItem}>
|
||||
<Typography color="textSecondary" variant="h6">昵称</Typography>
|
||||
<Typography>{window.taegetUserInfo.nickname}</Typography>
|
||||
</Grid>
|
||||
<Grid item md={4} xs={12} className={classes.infoItem}>
|
||||
<Typography color="textSecondary" variant="h6">用户组</Typography>
|
||||
<Typography>{window.taegetUserInfo.group}</Typography>
|
||||
</Grid>
|
||||
<Grid item md={4} xs={12} className={classes.infoItem}>
|
||||
<Typography color="textSecondary" variant="h6">分享总数</Typography>
|
||||
<Typography>{window.taegetUserInfo.shareCount}</Typography>
|
||||
</Grid>
|
||||
<Grid item md={4} xs={12} className={classes.infoItem}>
|
||||
<Typography color="textSecondary" variant="h6">注册日期</Typography>
|
||||
<Typography>{window.taegetUserInfo.regDate}</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</div>}
|
||||
{(this.state.listType===0||this.state.listType===1)&&<div>
|
||||
<Table className={classes.table}>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>文件名</TableCell>
|
||||
<TableCell className={classes.mobileHide}>分享日期</TableCell>
|
||||
<TableCell className={[classes.th,classes.mobileHide]}>下载次数</TableCell>
|
||||
<TableCell className={[classes.th,classes.mobileHide]}>浏览次数</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{this.state.shareList.map(row => (
|
||||
<TableRow
|
||||
key={row.id}
|
||||
className={classes.tableLink}
|
||||
onClick = {()=>window.open("/s/"+row.share_key)}
|
||||
>
|
||||
<TableCell><Typography>{row.fileData}</Typography></TableCell>
|
||||
<TableCell className={classes.mobileHide}>{row.share_time}</TableCell>
|
||||
<TableCell className={classes.mobileHide}>{row.download_num}</TableCell>
|
||||
<TableCell className={classes.mobileHide}>{row.view_num}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
{(this.state.shareList.length!==0 && this.state.listType===0)&&
|
||||
<div className={classes.navigator}>
|
||||
<Typography color="textSecondary" className={classes.pageInfo}>第{this.state.page}页</Typography>
|
||||
<div>
|
||||
<IconButton
|
||||
disabled={this.state.page===1}
|
||||
onClick={this.loadPrev}
|
||||
>
|
||||
<LeftIcon/>
|
||||
</IconButton>
|
||||
<IconButton
|
||||
disabled={this.state.shareList.length<10}
|
||||
onClick={this.loadNext}
|
||||
>
|
||||
<RighttIcon/>
|
||||
</IconButton>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>}
|
||||
</Paper>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const Profile = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)( withStyles(styles)(ProfileCompoment))
|
||||
|
||||
export default Profile
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
import React, { Component } from 'react'
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import { connect } from 'react-redux'
|
||||
import Tooltip from '@material-ui/core/Tooltip';
|
||||
import Card from '@material-ui/core/Card';
|
||||
import Avatar from '@material-ui/core/Avatar';
|
||||
import CardHeader from '@material-ui/core/CardHeader';
|
||||
import { toggleSnackbar,}from "../actions/index"
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import OpenIcon from '@material-ui/icons/OpenInNew';
|
||||
import FileIcon from '@material-ui/icons/InsertDriveFile';
|
||||
import FolderIcon from '@material-ui/icons/Folder';
|
||||
|
||||
|
||||
const styles = theme => ({
|
||||
card: {
|
||||
maxWidth: 400,
|
||||
margin: "0 auto",
|
||||
},
|
||||
actions: {
|
||||
display: 'flex',
|
||||
},
|
||||
layout: {
|
||||
width: 'auto',
|
||||
marginTop:'50px',
|
||||
marginLeft: theme.spacing.unit * 3,
|
||||
marginRight: theme.spacing.unit * 3,
|
||||
[theme.breakpoints.up(1100 + theme.spacing.unit * 3 * 2)]: {
|
||||
width: 1100,
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
},
|
||||
},
|
||||
shareTitle:{
|
||||
maxWidth:"200px",
|
||||
},
|
||||
avatarFile:{
|
||||
backgroundColor: theme.palette.primary.light,
|
||||
},
|
||||
avatarFolder:{
|
||||
backgroundColor: theme.palette.secondary.light,
|
||||
},
|
||||
gird:{
|
||||
marginTop:"30px",
|
||||
},
|
||||
})
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
toggleSnackbar:(vertical,horizontal,msg,color)=>{
|
||||
dispatch(toggleSnackbar(vertical,horizontal,msg,color))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
class SearchCompoment extends Component {
|
||||
|
||||
state={
|
||||
shareList:[],
|
||||
}
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
|
||||
|
||||
return (
|
||||
<div className={classes.layout}>
|
||||
<Typography color="textSecondary" variant="h3">搜索结果</Typography>
|
||||
<Grid container spacing={24} className={classes.gird}>
|
||||
{window.list.map(value=>(
|
||||
<Grid item xs={12} sm={4} key={value.id}>
|
||||
<Card className={classes.card}>
|
||||
<CardHeader
|
||||
|
||||
avatar={
|
||||
<div>
|
||||
{value.source_type==="file"&&
|
||||
<Avatar className={classes.avatarFile}>
|
||||
<FileIcon/>
|
||||
</Avatar>
|
||||
}
|
||||
{value.source_type==="dir"&&
|
||||
<Avatar className={classes.avatarFolder}>
|
||||
<FolderIcon/>
|
||||
</Avatar>
|
||||
}
|
||||
|
||||
</div>
|
||||
}
|
||||
action={<Tooltip placement="top" title="打开">
|
||||
<IconButton onClick={()=>window.open("/s/"+value.share_key)}>
|
||||
<OpenIcon />
|
||||
</IconButton>
|
||||
</Tooltip>}
|
||||
title={<Tooltip placement="top" title={value.fileData}><Typography noWrap className={classes.shareTitle}>{value.fileData}</Typography></Tooltip>}
|
||||
subheader={value.share_time}
|
||||
/>
|
||||
|
||||
</Card>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const Search = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)( withStyles(styles)(SearchCompoment))
|
||||
|
||||
export default Search
|
||||
|
|
@ -0,0 +1,180 @@
|
|||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import SearchIcon from '@material-ui/icons/Search';
|
||||
import { fade } from '@material-ui/core/styles/colorManipulator';
|
||||
import InputBase from '@material-ui/core/InputBase';
|
||||
import Popper from '@material-ui/core/Popper';
|
||||
import Fade from '@material-ui/core/Fade';
|
||||
import Paper from '@material-ui/core/Paper';
|
||||
import MenuItem from '@material-ui/core/MenuItem';
|
||||
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
||||
import ListItemText from '@material-ui/core/ListItemText';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import FileIcon from '@material-ui/icons/InsertDriveFile'
|
||||
import ShareIcon from '@material-ui/icons/Share'
|
||||
import { connect } from 'react-redux'
|
||||
import {
|
||||
searchMyFile,
|
||||
}from "../actions/index"
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
searchMyFile:(keywords)=>{
|
||||
dispatch(searchMyFile(keywords));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const styles = theme => ({
|
||||
search: {
|
||||
[theme.breakpoints.down('sm')]: {
|
||||
display:"none",
|
||||
},
|
||||
position: 'relative',
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
backgroundColor: fade(theme.palette.common.white, 0.15),
|
||||
'&:hover': {
|
||||
backgroundColor: fade(theme.palette.common.white, 0.25),
|
||||
},
|
||||
marginRight: theme.spacing.unit * 2,
|
||||
marginLeft: 0,
|
||||
width: '100%',
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
marginLeft: theme.spacing.unit * 7.2,
|
||||
width: 'auto',
|
||||
},
|
||||
},
|
||||
searchIcon: {
|
||||
width: theme.spacing.unit * 9,
|
||||
height: '100%',
|
||||
position: 'absolute',
|
||||
pointerEvents: 'none',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
inputRoot: {
|
||||
color: 'inherit',
|
||||
width: '100%',
|
||||
},
|
||||
inputInput: {
|
||||
paddingTop: theme.spacing.unit,
|
||||
paddingRight: theme.spacing.unit,
|
||||
paddingBottom: theme.spacing.unit,
|
||||
paddingLeft: theme.spacing.unit * 7,
|
||||
transition: theme.transitions.create('width'),
|
||||
width: '100%',
|
||||
[theme.breakpoints.up('md')]: {
|
||||
width: 200,
|
||||
'&:focus': {
|
||||
width: 300,
|
||||
}
|
||||
},
|
||||
},
|
||||
suggestBox:{
|
||||
zIndex: "9999",
|
||||
width:364,
|
||||
}
|
||||
})
|
||||
|
||||
class SearchBarCompoment extends Component {
|
||||
|
||||
state = {
|
||||
anchorEl: null,
|
||||
input:"",
|
||||
};
|
||||
|
||||
handleChange = (event)=>{
|
||||
const { currentTarget } = event;
|
||||
this.input = event.target.value;
|
||||
this.setState({
|
||||
anchorEl:currentTarget,
|
||||
input:event.target.value,
|
||||
});
|
||||
}
|
||||
|
||||
cancelSuggest = ()=>{
|
||||
this.setState({
|
||||
input:"",
|
||||
});
|
||||
}
|
||||
|
||||
searchMyFile = ()=>{
|
||||
this.props.searchMyFile(this.input);
|
||||
}
|
||||
|
||||
searchShare = ()=>{
|
||||
window.location.href="/Explore/Search/"+this.input;
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
const { classes} = this.props;
|
||||
const { anchorEl } = this.state;
|
||||
const id = this.state.input!=="" ? 'simple-popper' : null;
|
||||
|
||||
return (
|
||||
<div className={classes.search}>
|
||||
<div className={classes.searchIcon}>
|
||||
<SearchIcon />
|
||||
</div>
|
||||
<InputBase
|
||||
placeholder="搜索..."
|
||||
classes={{
|
||||
root: classes.inputRoot,
|
||||
input: classes.inputInput,
|
||||
}}
|
||||
onChange={this.handleChange}
|
||||
onBlur = {this.cancelSuggest}
|
||||
value ={this.state.input}
|
||||
/>
|
||||
<Popper id={id} open={this.state.input!==""} anchorEl={anchorEl} className={classes.suggestBox} transition>
|
||||
{({ TransitionProps }) => (
|
||||
<Fade {...TransitionProps} timeout={350}>
|
||||
<Paper
|
||||
square={true}
|
||||
>
|
||||
{window.isHomePage&&
|
||||
<MenuItem onClick={this.searchMyFile}>
|
||||
<ListItemIcon className={classes.icon}>
|
||||
<FileIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText classes={{ primary: classes.primary }} primary={<Typography noWrap>
|
||||
在我的文件中搜索 <strong>{this.state.input}</strong>
|
||||
</Typography>} />
|
||||
</MenuItem>
|
||||
}
|
||||
|
||||
<MenuItem onClick={this.searchShare}>
|
||||
<ListItemIcon className={classes.icon}>
|
||||
<ShareIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText classes={{ primary: classes.primary }} primary={<Typography noWrap>
|
||||
在全站分享中搜索 <strong>{this.state.input}</strong>
|
||||
</Typography>} />
|
||||
</MenuItem>
|
||||
</Paper>
|
||||
</Fade>
|
||||
)}
|
||||
</Popper>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SearchBarCompoment.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
const SearchBar = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)( withStyles(styles)(SearchBarCompoment))
|
||||
|
||||
export default SearchBar
|
||||
|
|
@ -0,0 +1,178 @@
|
|||
import React, { Component } from 'react'
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import { connect } from 'react-redux'
|
||||
import FileIcon from "../component/FileManager/FileIcon"
|
||||
import PreviewIcon from "@material-ui/icons/RemoveRedEye"
|
||||
import InfoIcon from "@material-ui/icons/Info"
|
||||
import DownloadIcon from "@material-ui/icons/CloudDownload"
|
||||
import Button from '@material-ui/core/Button';
|
||||
import {allowSharePreview,sizeToString} from "../untils/index"
|
||||
import { toggleSnackbar,}from "../actions/index"
|
||||
import { isPreviewable,}from "../config"
|
||||
import Popper from '@material-ui/core/Popper';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import Fade from '@material-ui/core/Fade';
|
||||
import Paper from '@material-ui/core/Paper';
|
||||
import axios from 'axios'
|
||||
const styles = theme => ({
|
||||
layout: {
|
||||
width: 'auto',
|
||||
marginTop:'110px',
|
||||
marginLeft: theme.spacing.unit * 3,
|
||||
marginRight: theme.spacing.unit * 3,
|
||||
[theme.breakpoints.up(1100 + theme.spacing.unit * 3 * 2)]: {
|
||||
width: 1100,
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
},
|
||||
},
|
||||
player:{
|
||||
borderRadius: "4px",
|
||||
},
|
||||
fileCotainer:{
|
||||
width:"200px",
|
||||
margin:"0 auto",
|
||||
},
|
||||
buttonCotainer:{
|
||||
width:"400px",
|
||||
margin:"0 auto",
|
||||
textAlign: "center",
|
||||
marginTop: "20px",
|
||||
},
|
||||
button: {
|
||||
margin: theme.spacing.unit,
|
||||
},
|
||||
paper: {
|
||||
padding: theme.spacing.unit * 2,
|
||||
},
|
||||
icon:{
|
||||
marginRight: theme.spacing.unit,
|
||||
}
|
||||
})
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
toggleSnackbar:(vertical,horizontal,msg,color)=>{
|
||||
dispatch(toggleSnackbar(vertical,horizontal,msg,color))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const allowDownload = allowSharePreview();
|
||||
|
||||
class SharedFileCompoment extends Component {
|
||||
|
||||
state = {
|
||||
anchorEl: null,
|
||||
open: false,
|
||||
};
|
||||
|
||||
preview = ()=>{
|
||||
if(!allowDownload){
|
||||
this.props.toggleSnackbar("top","right","未登录用户无法下载","warning");
|
||||
return;
|
||||
}
|
||||
switch(isPreviewable(window.shareInfo.fileName)){
|
||||
case 'img':
|
||||
window.open(window.apiURL.preview);
|
||||
return;
|
||||
case 'msDoc':
|
||||
window.open(window.apiURL.docPreiview);
|
||||
return;
|
||||
case 'audio':
|
||||
//this.props.openMusicDialog();
|
||||
return;
|
||||
case 'open':
|
||||
window.open(window.apiURL.preview);
|
||||
return;
|
||||
case 'video':
|
||||
window.location.href=("/Viewer/Video?single=true&shareKey="+window.shareInfo.shareId+"&path=/"+window.shareInfo.fileName);
|
||||
return ;
|
||||
case 'edit':
|
||||
window.location.href=("/Viewer/Markdown?single=true&shareKey="+window.shareInfo.shareId+"&path=/"+window.shareInfo.fileName);
|
||||
return;
|
||||
default:
|
||||
this.props.toggleSnackbar("top","right","此文件无法预览","warning");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
download = ()=>{
|
||||
if(!allowDownload){
|
||||
this.props.toggleSnackbar("top","right","未登录用户无法下载","warning");
|
||||
return;
|
||||
}
|
||||
axios.post("/Share/getDownloadUrl",{
|
||||
key: window.shareInfo.shareId
|
||||
})
|
||||
.then( (response)=> {
|
||||
if(response.data.error!==0){
|
||||
this.props.toggleSnackbar("top","right",response.data.msg ,"warning");
|
||||
}else{
|
||||
window.location.href=response.data.result;
|
||||
}
|
||||
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.props.toggleSnackbar("top","right",error.message ,"error");
|
||||
});
|
||||
}
|
||||
|
||||
handleOpen = event => {
|
||||
const { currentTarget } = event;
|
||||
this.setState(state => ({
|
||||
anchorEl: currentTarget,
|
||||
open: !state.open,
|
||||
}));
|
||||
};
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
const file={
|
||||
name:window.shareInfo.fileName,
|
||||
path:"/",
|
||||
type:"file",
|
||||
pic:"",
|
||||
};
|
||||
const id = this.state.open ? 'simple-popper' : null;
|
||||
|
||||
return (
|
||||
<div className={classes.layout}>
|
||||
<div className={classes.fileCotainer}>
|
||||
<FileIcon file={file} share={true}/></div>
|
||||
<div className={classes.buttonCotainer}>
|
||||
<Button variant="contained" color="secondary" className={classes.button} onClick={this.download}>
|
||||
<DownloadIcon className={classes.icon}/> 下载 ({sizeToString(window.shareInfo.fileSize)})
|
||||
</Button>
|
||||
<Button variant="outlined" className={classes.button} onClick={this.preview}>
|
||||
<PreviewIcon className={classes.icon}/> 预览
|
||||
</Button>
|
||||
<Button variant="outlined" className={classes.button} onClick={this.handleOpen}>
|
||||
<InfoIcon className={classes.icon}/> 信息
|
||||
</Button>
|
||||
<Popper id={id} open={this.state.open} anchorEl={this.state.anchorEl} transition>
|
||||
{({ TransitionProps }) => (
|
||||
<Fade {...TransitionProps} timeout={350}>
|
||||
<Paper className={classes.paper}>
|
||||
<Typography >此分享被浏览{window.shareInfo.ViewNum}次,被下载{window.shareInfo.downloadNum}次</Typography>
|
||||
</Paper>
|
||||
</Fade>
|
||||
)}
|
||||
</Popper>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const SharedFile = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)( withStyles(styles)(SharedFileCompoment))
|
||||
|
||||
export default SharedFile
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Drawer from '@material-ui/core/Drawer';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import Divider from '@material-ui/core/Divider';
|
||||
import ListItem from '@material-ui/core/ListItem';
|
||||
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
||||
import ListItemText from '@material-ui/core/ListItemText';
|
||||
import UploadIcon from '@material-ui/icons/CloudUpload';
|
||||
import List from '@material-ui/core/List';
|
||||
const drawerWidth = 240;
|
||||
const styles = theme => ({
|
||||
drawer: {
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
width: drawerWidth,
|
||||
flexShrink: 0,
|
||||
},
|
||||
},
|
||||
drawerPaper: {
|
||||
width: drawerWidth,
|
||||
},
|
||||
toolbar: theme.mixins.toolbar,
|
||||
});
|
||||
class SideDrawer extends Component {
|
||||
|
||||
state = {
|
||||
mobileOpen: false,
|
||||
};
|
||||
|
||||
handleDrawerToggle = () => {
|
||||
this.setState(state => ({ mobileOpen: !state.mobileOpen }));
|
||||
};
|
||||
|
||||
upload(){
|
||||
alert("");
|
||||
}
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
|
||||
const drawer = (
|
||||
<div><div className={classes.toolbar} />
|
||||
<List>
|
||||
<ListItem button key="上传文d件" onClick={this.upload}>
|
||||
<ListItemIcon><UploadIcon /></ListItemIcon>
|
||||
<ListItemText primary="上传文d件" />
|
||||
</ListItem>
|
||||
|
||||
</List>
|
||||
<Divider />
|
||||
<List>
|
||||
|
||||
</List></div>
|
||||
);
|
||||
|
||||
return (
|
||||
<nav className={classes.drawer}>
|
||||
<Hidden smUp implementation="css">
|
||||
<Drawer
|
||||
container={this.props.container}
|
||||
variant="temporary"
|
||||
classes={{
|
||||
paper: classes.drawerPaper,
|
||||
}}
|
||||
anchor={theme.direction === 'rtl' ? 'right' : 'left'}
|
||||
open={this.state.mobileOpen}
|
||||
onClose={this.handleDrawerToggle}
|
||||
classes={{
|
||||
paper: classes.drawerPaper,
|
||||
}}
|
||||
ModalProps={{
|
||||
keepMounted: true, // Better open performance on mobile.
|
||||
}}
|
||||
>
|
||||
{drawer}
|
||||
</Drawer>
|
||||
</Hidden>
|
||||
<Hidden xsDown implementation="css">
|
||||
<Drawer
|
||||
classes={{
|
||||
paper: classes.drawerPaper,
|
||||
}}
|
||||
variant="permanent"
|
||||
open
|
||||
>
|
||||
{drawer}
|
||||
</Drawer>
|
||||
</Hidden>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
SideDrawer.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default withStyles(styles)(SideDrawer);
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux'
|
||||
import {
|
||||
} from "../actions/index"
|
||||
import classNames from 'classnames';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import SnackbarContent from '@material-ui/core/SnackbarContent';
|
||||
import Snackbar from '@material-ui/core/Snackbar'
|
||||
import ErrorIcon from '@material-ui/icons/Error';
|
||||
import InfoIcon from '@material-ui/icons/Info';
|
||||
import CloseIcon from '@material-ui/icons/Close';
|
||||
import green from '@material-ui/core/colors/green';
|
||||
import CheckCircleIcon from '@material-ui/icons/CheckCircle';
|
||||
import amber from '@material-ui/core/colors/amber';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import WarningIcon from '@material-ui/icons/Warning';
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
snackbar:state.viewUpdate.snackbar,
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
}
|
||||
}
|
||||
|
||||
const variantIcon = {
|
||||
success: CheckCircleIcon,
|
||||
warning: WarningIcon,
|
||||
error: ErrorIcon,
|
||||
info: InfoIcon,
|
||||
};
|
||||
|
||||
const styles1 = theme => ({
|
||||
success: {
|
||||
backgroundColor: green[600],
|
||||
},
|
||||
error: {
|
||||
backgroundColor: theme.palette.error.dark,
|
||||
},
|
||||
info: {
|
||||
backgroundColor: theme.palette.primary.dark,
|
||||
},
|
||||
warning: {
|
||||
backgroundColor: amber[700],
|
||||
},
|
||||
icon: {
|
||||
fontSize: 20,
|
||||
},
|
||||
iconVariant: {
|
||||
opacity: 0.9,
|
||||
marginRight: theme.spacing.unit,
|
||||
},
|
||||
message: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
},
|
||||
})
|
||||
|
||||
function MySnackbarContent(props) {
|
||||
const { classes, className, message, onClose, variant, ...other } = props;
|
||||
const Icon = variantIcon[variant];
|
||||
|
||||
return (
|
||||
<SnackbarContent
|
||||
className={classNames(classes[variant], className)}
|
||||
aria-describedby="client-snackbar"
|
||||
message={
|
||||
<span id="client-snackbar" className={classes.message}>
|
||||
<Icon className={classNames(classes.icon, classes.iconVariant)} />
|
||||
{message}
|
||||
</span>
|
||||
}
|
||||
action={[
|
||||
<IconButton
|
||||
key="close"
|
||||
aria-label="Close"
|
||||
color="inherit"
|
||||
className={classes.close}
|
||||
onClick={onClose}
|
||||
>
|
||||
<CloseIcon className={classes.icon} />
|
||||
</IconButton>,
|
||||
]}
|
||||
{...other}
|
||||
/>
|
||||
);
|
||||
}
|
||||
MySnackbarContent.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
className: PropTypes.string,
|
||||
message: PropTypes.node,
|
||||
onClose: PropTypes.func,
|
||||
variant: PropTypes.oneOf(['success', 'warning', 'error', 'info']).isRequired,
|
||||
};
|
||||
|
||||
const MySnackbarContentWrapper = withStyles(styles1)(MySnackbarContent);
|
||||
const styles = theme => ({
|
||||
margin: {
|
||||
margin: theme.spacing.unit,
|
||||
},
|
||||
})
|
||||
class SnackbarCompoment extends Component {
|
||||
|
||||
state={
|
||||
open:false,
|
||||
}
|
||||
|
||||
componentWillReceiveProps = (nextProps)=>{
|
||||
if(nextProps.snackbar.toggle !== this.props.snackbar.toggle){
|
||||
this.setState({open:true});
|
||||
}
|
||||
}
|
||||
|
||||
handleClose= ()=>{
|
||||
this.setState({open:false});
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
return (
|
||||
<Snackbar
|
||||
anchorOrigin={{
|
||||
vertical: this.props.snackbar.vertical,
|
||||
horizontal: this.props.snackbar.horizontal,
|
||||
}}
|
||||
open={this.state.open}
|
||||
autoHideDuration={6000}
|
||||
onClose={this.handleClose}
|
||||
>
|
||||
<MySnackbarContentWrapper
|
||||
onClose={this.handleClose}
|
||||
variant={this.props.snackbar.color}
|
||||
message={this.props.snackbar.msg}
|
||||
/>
|
||||
</Snackbar>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const AlertBar = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)( withStyles(styles)(SnackbarCompoment))
|
||||
|
||||
export default AlertBar
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import LinearProgress from '@material-ui/core/LinearProgress';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import Divider from '@material-ui/core/Divider';
|
||||
import StorageIcon from '@material-ui/icons/Storage'
|
||||
import { connect } from 'react-redux'
|
||||
import axios from 'axios'
|
||||
import Tooltip from '@material-ui/core/Tooltip';
|
||||
import {
|
||||
toggleSnackbar,
|
||||
}from "../actions/index"
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
refresh:state.viewUpdate.storageRefresh,
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
toggleSnackbar:(vertical,horizontal,msg,color)=>{
|
||||
dispatch(toggleSnackbar(vertical,horizontal,msg,color))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const styles = theme => ({
|
||||
iconFix:{
|
||||
marginLeft: "32px",
|
||||
marginRight: "32px",
|
||||
color: theme.palette.text.secondary,
|
||||
marginTop: "2px",
|
||||
},
|
||||
textFix:{
|
||||
"padding":" 0 0 0 16px",
|
||||
},
|
||||
storageContainer:{
|
||||
display:"flex",
|
||||
marginTop: "15px",
|
||||
|
||||
marginBottom: "20px",
|
||||
},
|
||||
detail:{
|
||||
width: "100%",
|
||||
marginRight: "20px",
|
||||
},
|
||||
info:{
|
||||
width:"131px",
|
||||
marginTop:"5px",
|
||||
},
|
||||
bar:{
|
||||
marginTop: "5px",
|
||||
},
|
||||
stickFooter:{
|
||||
bottom: "0px",
|
||||
position: "absolute",
|
||||
backgroundColor:theme.palette.background.paper,
|
||||
}
|
||||
})
|
||||
|
||||
class StorageBarCompoment extends Component {
|
||||
|
||||
state={
|
||||
percent:0,
|
||||
used:null,
|
||||
total:null,
|
||||
}
|
||||
|
||||
firstLoad = true;
|
||||
|
||||
componentDidMount = ()=>{
|
||||
if(this.firstLoad){
|
||||
this.updateStatus();
|
||||
this.firstLoad = !this.firstLoad;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
componentWillReceiveProps = (nextProps)=>{
|
||||
if(this.props.refresh!==nextProps.refresh){
|
||||
this.updateStatus();
|
||||
}
|
||||
}
|
||||
|
||||
updateStatus = ()=>{
|
||||
let percent = 0;
|
||||
axios.get('/Member/Memory')
|
||||
.then( (response)=> {
|
||||
if(response.data.rate>=100){
|
||||
percent = 100;
|
||||
this.props.toggleSnackbar("top","right","您的已用容量已超过容量配额,请尽快删除多余文件或购买容量","warning");
|
||||
}else{
|
||||
percent = response.data.rate;
|
||||
}
|
||||
this.setState({
|
||||
percent:percent,
|
||||
used:response.data.used,
|
||||
total:response.data.total,
|
||||
});
|
||||
})
|
||||
.catch((error) =>{
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { classes} = this.props;
|
||||
if(!window.isMobile){
|
||||
return (
|
||||
<div className={classes.stickFooter}><Divider/>
|
||||
<div className={classes.storageContainer}>
|
||||
<StorageIcon className={classes.iconFix} />
|
||||
<div className={classes.detail}>
|
||||
存储空间
|
||||
<LinearProgress className={classes.bar} color="secondary" variant="determinate" value={this.state.percent} />
|
||||
<div className={classes.info}>
|
||||
<Tooltip title={"已使用"+((this.state.used===null)?" -- ":this.state.used)+",共"+((this.state.total===null)?" -- ":this.state.total)} placement="top">
|
||||
<Typography variant="caption" noWrap color="textSecondary">已使用{(this.state.used===null)?" -- ":this.state.used},共{(this.state.total===null)?" -- ":this.state.total}</Typography></Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}else{
|
||||
return (
|
||||
<div className={classes.storageContainer}>
|
||||
<StorageIcon className={classes.iconFix} />
|
||||
<div className={classes.detail}>
|
||||
存储空间
|
||||
<LinearProgress className={classes.bar} color="secondary" variant="determinate" value={this.state.percent} />
|
||||
<div className={classes.info}>
|
||||
<Tooltip title={"已使用"+((this.state.used===null)?" -- ":this.state.used)+",共"+((this.state.total===null)?" -- ":this.state.total)} placement="top">
|
||||
<Typography variant="caption" noWrap color="textSecondary">已使用{(this.state.used===null)?" -- ":this.state.used},共{(this.state.total===null)?" -- ":this.state.total}</Typography></Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StorageBarCompoment.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
const StorageBar = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)( withStyles(styles)(StorageBarCompoment))
|
||||
|
||||
export default StorageBar
|
||||
|
|
@ -0,0 +1,253 @@
|
|||
import React, { Component } from 'react';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import Dialog from '@material-ui/core/Dialog';
|
||||
import ListItemText from '@material-ui/core/ListItemText';
|
||||
import ListItem from '@material-ui/core/ListItem';
|
||||
import List from '@material-ui/core/List';
|
||||
import Divider from '@material-ui/core/Divider';
|
||||
import AppBar from '@material-ui/core/AppBar';
|
||||
import Toolbar from '@material-ui/core/Toolbar';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import CloseIcon from '@material-ui/icons/Close';
|
||||
import FileIcon from '@material-ui/icons/InsertDriveFile';
|
||||
import PhotoIcon from '@material-ui/icons/MusicNote';
|
||||
import VideoIcon from '@material-ui/icons/Videocam';
|
||||
import AddIcon from '@material-ui/icons/AddCircleOutline';
|
||||
import MusicIcon from '@material-ui/icons/MusicNote';
|
||||
import LinearProgress from '@material-ui/core/LinearProgress';
|
||||
import Slide from '@material-ui/core/Slide';
|
||||
import Avatar from '@material-ui/core/Avatar';
|
||||
import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction';
|
||||
import DeleteIcon from '@material-ui/icons/Delete';
|
||||
import withWidth, { isWidthDown } from '@material-ui/core/withWidth';
|
||||
import DialogContent from '@material-ui/core/DialogContent';
|
||||
|
||||
const styles = theme => ({
|
||||
appBar: {
|
||||
position: 'relative',
|
||||
},
|
||||
flex: {
|
||||
flex: 1,
|
||||
},
|
||||
progressBar:{
|
||||
marginTop:5,
|
||||
},
|
||||
minHight:{
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
minWidth:500,
|
||||
}
|
||||
},
|
||||
dialogContent:{
|
||||
padding:0,
|
||||
},
|
||||
successStatus:{
|
||||
marginBottom:10,
|
||||
color:"#4caf50",
|
||||
},
|
||||
errorStatus:{
|
||||
marginBottom:10,
|
||||
color:"#ff5722",
|
||||
},
|
||||
});
|
||||
class FileList extends Component {
|
||||
|
||||
state = {
|
||||
open: false,
|
||||
files: [
|
||||
],
|
||||
};
|
||||
|
||||
//入队
|
||||
enQueue(files) {
|
||||
var filesNow = this.state.files;
|
||||
if (filesNow.findIndex((file) => { return file.id === files.id }) === -1) {
|
||||
filesNow.push(files);
|
||||
this.setState({
|
||||
files: filesNow,
|
||||
});
|
||||
}
|
||||
console.log(this.state);
|
||||
|
||||
}
|
||||
|
||||
deQueue(file){
|
||||
var filesNow = this.state.files;
|
||||
var fileID = filesNow.findIndex((f) => { return f.id === file.id });
|
||||
if (fileID !== -1) {
|
||||
filesNow.splice(fileID, 1);
|
||||
this.setState({
|
||||
files: filesNow,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
updateStatus(file){
|
||||
var filesNow = this.state.files;
|
||||
var fileID = filesNow.findIndex((f) => { return f.id === file.id });
|
||||
if (fileID !== -1) {
|
||||
if(filesNow[fileID].status!==4){
|
||||
filesNow[fileID] = file;
|
||||
this.setState({
|
||||
files: filesNow,
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
setComplete(file){
|
||||
var filesNow = this.state.files;
|
||||
var fileID = filesNow.findIndex((f) => { return f.id === file.id });
|
||||
if (fileID !== -1) {
|
||||
if(filesNow[fileID].status!==4){
|
||||
filesNow[fileID].status = 5;
|
||||
this.setState({
|
||||
files: filesNow,
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
setError(file,errMsg){
|
||||
var filesNow = this.state.files;
|
||||
var fileID = filesNow.findIndex((f) => { return f.id === file.id });
|
||||
if (fileID !== -1) {
|
||||
filesNow[fileID].status = 4;
|
||||
filesNow[fileID].errMsg = errMsg;
|
||||
}else{
|
||||
file.status = 4;
|
||||
file.errMsg = errMsg;
|
||||
filesNow.push(file);
|
||||
}
|
||||
this.setState({
|
||||
files: filesNow,
|
||||
});
|
||||
}
|
||||
|
||||
Transition(props) {
|
||||
return <Slide direction="up" {...props} />;
|
||||
}
|
||||
openFileList = () => {
|
||||
if(!this.state.open){
|
||||
this.setState({ open: true });
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
cancelUpload = file =>{
|
||||
this.props.cancelUpload(file);
|
||||
this.deQueue(file);
|
||||
}
|
||||
|
||||
handleClose = () => {
|
||||
this.setState({ open: false });
|
||||
|
||||
};
|
||||
|
||||
addNewFile = () => {
|
||||
document.getElementsByClassName("uploadForm")[0].click();
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
const { classes } = this.props;
|
||||
const { width } = this.props;
|
||||
|
||||
const fileIcon = {
|
||||
"image":["jpg","bpm","png","gif","jpeg","webp","svg"],
|
||||
"video":["mp4","rmvb","flv","avi"],
|
||||
"audio":["mp3","ogg","flac","aac"],
|
||||
};
|
||||
|
||||
this.props.inRef({
|
||||
"openFileList":this.openFileList.bind(this),
|
||||
"enQueue":this.enQueue.bind(this),
|
||||
"updateStatus":this.updateStatus.bind(this),
|
||||
"setComplete":this.setComplete.bind(this),
|
||||
"setError":this.setError.bind(this),
|
||||
});
|
||||
|
||||
var listContent = (
|
||||
this.state.files.map(function(item, i){
|
||||
var progressItem;
|
||||
var queueIcon;
|
||||
|
||||
if(fileIcon["image"].indexOf(item.name.split(".").pop())!==-1){
|
||||
queueIcon = (<PhotoIcon></PhotoIcon>);
|
||||
}else if(fileIcon["video"].indexOf(item.name.split(".").pop())!==-1){
|
||||
queueIcon = (<VideoIcon></VideoIcon>);
|
||||
}else if(fileIcon["audio"].indexOf(item.name.split(".").pop())!==-1){
|
||||
queueIcon = (<MusicIcon></MusicIcon>);
|
||||
}else{
|
||||
queueIcon = (<FileIcon></FileIcon>);
|
||||
}
|
||||
|
||||
if(item.status ===5){
|
||||
progressItem = (<ListItemText primary={item.name} secondary={<div className={classes.successStatus}>已完成<br/></div>} />);
|
||||
}else if (item.status ===2){
|
||||
progressItem = (<ListItemText primary={item.name} secondary={<div>{window.plupload.formatSize(item.speed).toUpperCase()}/s 已上传 {window.plupload.formatSize(item.loaded).toUpperCase()} , 共 {window.plupload.formatSize(item.size).toUpperCase()} - {item.percent}% <br/><LinearProgress variant="determinate" value={item.percent} className={classes.progressBar} /></div>}/>);
|
||||
}else if (item.status ===1){
|
||||
progressItem = (<ListItemText primary={item.name} secondary={<div>排队中<br/><LinearProgress className={classes.progressBar}/></div>} />);
|
||||
}else if (item.status ===4){
|
||||
progressItem = (<ListItemText primary={item.name} secondary={<div className={classes.errorStatus}>{item.errMsg}<br/></div>} />);
|
||||
}else{
|
||||
progressItem = (<ListItemText primary={item.name} secondary={item.status} />);
|
||||
}
|
||||
return (
|
||||
<div key={i}>
|
||||
<ListItem button >
|
||||
<Avatar>
|
||||
{queueIcon}
|
||||
</Avatar>
|
||||
{progressItem}
|
||||
|
||||
<ListItemSecondaryAction>
|
||||
<IconButton aria-label="Delete" onClick={()=>this.cancelUpload(item)}>
|
||||
<DeleteIcon />
|
||||
</IconButton>
|
||||
</ListItemSecondaryAction>
|
||||
|
||||
</ListItem>
|
||||
<Divider /></div>
|
||||
);
|
||||
},this)
|
||||
|
||||
);
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
fullScreen={isWidthDown("sm", width)}
|
||||
open={this.state.open}
|
||||
onClose={this.handleClose}
|
||||
TransitionComponent={this.Transition}
|
||||
>
|
||||
<AppBar className={classes.appBar}>
|
||||
<Toolbar>
|
||||
<IconButton color="inherit" onClick={this.handleClose} aria-label="Close">
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
<Typography variant="h6" color="inherit" className={classes.flex}>
|
||||
上传队列
|
||||
</Typography>
|
||||
<IconButton color="inherit" onClick={this.addNewFile}>
|
||||
<AddIcon/>
|
||||
</IconButton>
|
||||
</Toolbar>
|
||||
|
||||
</AppBar>
|
||||
<DialogContent className={classes.dialogContent}>
|
||||
<List className={classes.minHight}>
|
||||
{listContent}
|
||||
</List>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
FileList.propTypes = {
|
||||
};
|
||||
|
||||
export default withStyles(styles)(withWidth()(FileList));
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
import React, { Component } from 'react'
|
||||
import scriptLoader from '../loader/index.js'
|
||||
import { connect } from 'react-redux'
|
||||
import {
|
||||
refreshFileList,
|
||||
refreshStorage
|
||||
} from "../actions/index"
|
||||
import FileList from "./Upload/FileList.js"
|
||||
|
||||
let loaded = false;
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
path:state.navigator.path,
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
refreshFileList:()=>{
|
||||
dispatch(refreshFileList())
|
||||
},
|
||||
refreshStorage:()=>{
|
||||
dispatch(refreshStorage())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class UploaderCompoment extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state={
|
||||
queued:0,
|
||||
}
|
||||
}
|
||||
|
||||
setRef(val){
|
||||
this.fileList=val;
|
||||
}
|
||||
|
||||
cancelUpload(file){
|
||||
this.uploader.removeFile(file);
|
||||
}
|
||||
shouldComponentUpdate(nextProps,nextState){
|
||||
if(nextState.queued !== this.state.queued){
|
||||
this.props.queueChange(nextState.queued);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
componentWillReceiveProps({ isScriptLoaded, isScriptLoadSucceed }) {
|
||||
if (isScriptLoaded && !this.props.isScriptLoaded) { // load finished
|
||||
if (isScriptLoadSucceed) {
|
||||
if(loaded){
|
||||
return;
|
||||
}
|
||||
loaded = true;
|
||||
this.uploader = window.Qiniu.uploader({
|
||||
runtimes: 'html5',
|
||||
browse_button: 'pickfiles',
|
||||
container: 'container',
|
||||
drop_element: 'container',
|
||||
max_file_size: window.uploadConfig.maxSize,
|
||||
dragdrop: true,
|
||||
chunk_size: window.ChunkSize,
|
||||
filters: {
|
||||
mime_types: window.uploadConfig.allowedType,
|
||||
},
|
||||
multi_selection: !(window.moxie.core.utils.Env.OS.toLowerCase() === "ios"),
|
||||
uptoken_url: "/Upload/Token",
|
||||
domain: "s",
|
||||
get_new_uptoken: true,
|
||||
auto_start: true,
|
||||
log_level: 5,
|
||||
init: {
|
||||
'FilesAdded':({up, files})=>{
|
||||
this.fileList["openFileList"]();
|
||||
window.plupload.each(files, (files)=> {
|
||||
window.pathCache[files.id] = this.props.path;
|
||||
this.fileList["enQueue"](files);
|
||||
})
|
||||
console.log(window.pathCache);
|
||||
},
|
||||
|
||||
|
||||
'BeforeUpload': function (up, file) {
|
||||
},
|
||||
"QueueChanged":(up=>{
|
||||
this.setState({queued:up.total.queued});
|
||||
}),
|
||||
'UploadProgress': (up, file)=>{
|
||||
this.fileList["updateStatus"](file);
|
||||
},
|
||||
'UploadComplete': (up, file)=>{
|
||||
if(file.length===0){
|
||||
return
|
||||
}
|
||||
if(file[0].status === 5){
|
||||
this.fileList["setComplete"](file[0]);
|
||||
this.props.refreshFileList();
|
||||
this.props.refreshStorage();
|
||||
}
|
||||
|
||||
},
|
||||
'FileUploaded': function (up, file, info) {
|
||||
|
||||
},
|
||||
'Error': (up, err, errTip)=>{
|
||||
this.fileList["openFileList"]();
|
||||
this.fileList["setError"](err.file,errTip);
|
||||
},
|
||||
"FilesRemoved":(up, files)=>{
|
||||
},
|
||||
}
|
||||
});
|
||||
// this.fileList["openFileList"]();
|
||||
}
|
||||
else this.onError()
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { isScriptLoaded, isScriptLoadSucceed } = this.props
|
||||
if (isScriptLoaded && isScriptLoadSucceed) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
onError(){
|
||||
|
||||
}
|
||||
|
||||
openFileList=()=>{
|
||||
this.fileList["openFileList"]();
|
||||
};
|
||||
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<FileList inRef= {this.setRef.bind(this)} cancelUpload={this.cancelUpload.bind(this)}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const Uploader = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps,
|
||||
null,
|
||||
{forwardRef : true}
|
||||
)( scriptLoader(
|
||||
['/static/js/uploader/moxie.js'],
|
||||
['/static/js/uploader/plupload.dev.js'],
|
||||
['/static/js/uploader/i18n/zh_CN.js'],
|
||||
['/static/js/uploader/ui.js'],
|
||||
['/static/js/uploader/uploader.js'],
|
||||
|
||||
)(UploaderCompoment))
|
||||
|
||||
export default Uploader
|
||||
|
|
@ -0,0 +1,189 @@
|
|||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import Grow from '@material-ui/core/Grow';
|
||||
import { connect } from 'react-redux'
|
||||
import Avatar from '@material-ui/core/Avatar';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import Popover from '@material-ui/core/Popover';
|
||||
import SettingIcon from '@material-ui/icons/Settings'
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import Chip from '@material-ui/core/Chip';
|
||||
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
||||
import MenuItem from '@material-ui/core/MenuItem';
|
||||
import Divider from '@material-ui/core/Divider';
|
||||
import {
|
||||
LogoutVariant,
|
||||
HomeAccount,
|
||||
DesktopMacDashboard,
|
||||
AccountCircle,
|
||||
AccountArrowRight,
|
||||
AccountPlus
|
||||
} from 'mdi-material-ui'
|
||||
import {
|
||||
|
||||
}from "../actions/index"
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
selected:state.explorer.selected,
|
||||
isMultiple:state.explorer.selectProps.isMultiple,
|
||||
withFolder:state.explorer.selectProps.withFolder,
|
||||
withFile:state.explorer.selectProps.withFile,
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const styles = theme => ({
|
||||
mobileHidden:{
|
||||
[theme.breakpoints.down('xs')]: {
|
||||
display: 'none',
|
||||
},
|
||||
},
|
||||
avatar:{
|
||||
width:"30px",
|
||||
height:"30px",
|
||||
},
|
||||
header:{
|
||||
display:"flex",
|
||||
padding: "20px 20px 20px 20px",
|
||||
},
|
||||
largeAvatar:{
|
||||
height:"90px",
|
||||
width:"90px",
|
||||
},
|
||||
info:{
|
||||
marginLeft: "10px",
|
||||
width: "139px",
|
||||
},
|
||||
badge:{
|
||||
marginTop:"10px",
|
||||
},
|
||||
visitorMenu:{
|
||||
width:200,
|
||||
}
|
||||
})
|
||||
|
||||
class UserAvatarCompoment extends Component {
|
||||
|
||||
state={
|
||||
anchorEl:null,
|
||||
}
|
||||
|
||||
showUserInfo = e=>{
|
||||
this.setState({
|
||||
anchorEl:e.currentTarget
|
||||
});
|
||||
}
|
||||
|
||||
handleClose=()=>{
|
||||
this.setState({
|
||||
anchorEl:null,
|
||||
});
|
||||
}
|
||||
|
||||
openURL = (url)=>{
|
||||
window.location.href=url;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { classes} = this.props;
|
||||
return (
|
||||
<div className={classes.mobileHidden}>
|
||||
|
||||
<Grow in={((this.props.selected.length <=1) && !(!this.props.isMultiple&&this.props.withFile))}>
|
||||
<div>
|
||||
{(window.userInfo.uid!==-1)&&<IconButton onClick={()=>window.location.href="/Member/Setting"} color="inherit"
|
||||
>
|
||||
<SettingIcon/>
|
||||
</IconButton>}
|
||||
|
||||
<IconButton color="inherit" onClick={this.showUserInfo}>
|
||||
{window.userInfo.uid===-1&&
|
||||
<AccountCircle/>
|
||||
}
|
||||
{window.userInfo.uid!==-1&&<Avatar src={"/Member/Avatar/"+window.userInfo.uid+"/s"} className={classes.avatar} />}
|
||||
|
||||
</IconButton> </div>
|
||||
</Grow>
|
||||
<Popover
|
||||
open = {this.state.anchorEl!==null}
|
||||
onClose={this.handleClose}
|
||||
anchorEl={this.state.anchorEl}
|
||||
anchorOrigin={{
|
||||
vertical: 'bottom',
|
||||
horizontal: 'right',
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: 'top',
|
||||
horizontal: 'right',
|
||||
}}
|
||||
>
|
||||
{window.userInfo.uid===-1&&
|
||||
<div className={classes.visitorMenu}>
|
||||
<Divider/>
|
||||
<MenuItem onClick={()=>this.openURL("/Login")}>
|
||||
<ListItemIcon><AccountArrowRight/></ListItemIcon>
|
||||
登录
|
||||
</MenuItem>
|
||||
<MenuItem onClick={()=>this.openURL("/Signup")}>
|
||||
<ListItemIcon><AccountPlus/></ListItemIcon>
|
||||
注册
|
||||
</MenuItem>
|
||||
</div>
|
||||
}
|
||||
{window.userInfo.uid!==-1&&
|
||||
<div>
|
||||
<div className={classes.header}>
|
||||
<div className={classes.largeAvatarContainer}>
|
||||
<Avatar className={classes.largeAvatar} src={"/Member/Avatar/"+window.userInfo.uid+"/l"} />
|
||||
</div>
|
||||
<div className={classes.info}>
|
||||
<Typography noWrap>{window.userInfo.nick}</Typography>
|
||||
<Typography color="textSecondary" noWrap>{window.userInfo.email}</Typography>
|
||||
<Chip
|
||||
className={classes.badge}
|
||||
color={window.userInfo.groupId === 1?"secondary":"default"}
|
||||
label={window.userInfo.group}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<Divider/>
|
||||
<MenuItem onClick={()=>this.openURL("/Profile/"+window.userInfo.uid)}>
|
||||
<ListItemIcon><HomeAccount/></ListItemIcon>
|
||||
个人主页
|
||||
</MenuItem>
|
||||
{(window.userInfo.groupId === 1)&&
|
||||
<MenuItem onClick={()=>this.openURL("/Admin")}>
|
||||
<ListItemIcon><DesktopMacDashboard/></ListItemIcon>
|
||||
管理面板
|
||||
</MenuItem>
|
||||
}
|
||||
|
||||
<MenuItem onClick={()=>this.openURL("/Member/LogOut")}>
|
||||
<ListItemIcon><LogoutVariant/></ListItemIcon>
|
||||
退出
|
||||
</MenuItem>
|
||||
</div></div>}
|
||||
</Popover>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
UserAvatarCompoment.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
const UserAvatar = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)( withStyles(styles)(UserAvatarCompoment))
|
||||
|
||||
export default UserAvatar
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import { connect } from 'react-redux'
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import {
|
||||
}from "../actions/index"
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
}
|
||||
}
|
||||
|
||||
const styles = theme => ({
|
||||
userNav:{
|
||||
height:"170px",
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
padding: "20px 20px 2em",
|
||||
backgroundImage: "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1600 900'%3E%3Cpolygon fill='"+theme.palette.primary.light.replace("#","%23")+"' points='957 450 539 900 1396 900'/%3E%3Cpolygon fill='"+theme.palette.primary.dark.replace("#","%23")+"' points='957 450 872.9 900 1396 900'/%3E%3Cpolygon fill='"+theme.palette.secondary.main.replace("#","%23")+"' points='-60 900 398 662 816 900'/%3E%3Cpolygon fill='"+theme.palette.secondary.dark.replace("#","%23")+"' points='337 900 398 662 816 900'/%3E%3Cpolygon fill='"+theme.palette.secondary.light.replace("#","%23")+"' points='1203 546 1552 900 876 900'/%3E%3Cpolygon fill='"+theme.palette.secondary.main.replace("#","%23")+"' points='1203 546 1552 900 1162 900'/%3E%3Cpolygon fill='"+theme.palette.primary.dark.replace("#","%23")+"' points='641 695 886 900 367 900'/%3E%3Cpolygon fill='"+theme.palette.primary.main.replace("#","%23")+"' points='587 900 641 695 886 900'/%3E%3Cpolygon fill='"+theme.palette.secondary.light.replace("#","%23")+"' points='1710 900 1401 632 1096 900'/%3E%3Cpolygon fill='"+theme.palette.secondary.dark.replace("#","%23")+"' points='1710 900 1401 632 1365 900'/%3E%3Cpolygon fill='"+theme.palette.secondary.main.replace("#","%23")+"' points='1210 900 971 687 725 900'/%3E%3Cpolygon fill='"+theme.palette.secondary.dark.replace("#","%23")+"' points='943 900 1210 900 971 687'/%3E%3C/svg%3E\")",
|
||||
backgroundSize: "cover",
|
||||
},
|
||||
avatar:{
|
||||
display: "block",
|
||||
width: "80px",
|
||||
height: "80px",
|
||||
border:" 2px solid #fff",
|
||||
borderRadius: "50%",
|
||||
overflow: "hidden",
|
||||
boxShadow: "0 2px 5px 0 rgba(0,0,0,0.16), 0 2px 10px 0 rgba(0,0,0,0.12)",
|
||||
},
|
||||
avatarImg:{
|
||||
width: "80px",
|
||||
height: "80px",
|
||||
},
|
||||
nickName:{
|
||||
color: "#fff",
|
||||
marginLeft: "10px",
|
||||
marginTop: "15px",
|
||||
fontSize: "17px",
|
||||
},
|
||||
flexAvatar:{
|
||||
display:"flex",
|
||||
},
|
||||
groupName:{
|
||||
marginLeft: "10px",
|
||||
color:"#ffffff8a",
|
||||
},
|
||||
storageCircle:{
|
||||
width: "200px",
|
||||
}
|
||||
})
|
||||
|
||||
class UserInfoCompoment extends Component {
|
||||
|
||||
render() {
|
||||
const { classes} = this.props;
|
||||
|
||||
return (
|
||||
<div className={classes.userNav}>
|
||||
<div className={classes.flexAvatar}>
|
||||
<a href={"/Profile/"+window.userInfo.uid} className={classes.avatar}>
|
||||
{(window.userInfo.uid!==-1)&&<img alt="avatar" src={"/Member/Avatar/"+window.userInfo.uid+"/l"} className={classes.avatarImg}></img>}
|
||||
{(window.userInfo.uid===-1)&&<img alt="avatar" src={"/Member/Avatar/0/l"} className={classes.avatarImg}></img>}
|
||||
</a>
|
||||
|
||||
</div>
|
||||
<div className={classes.storageCircle}><Typography className={classes.nickName} component="h2" noWrap>{window.userInfo.nick}</Typography>
|
||||
<Typography className={classes.groupName} component="h2" color="textSecondary" noWrap>{window.userInfo.group}</Typography></div>
|
||||
</div>
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
UserInfoCompoment.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
const UserInfo = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)( withStyles(styles)(UserInfoCompoment))
|
||||
|
||||
export default UserInfo
|
||||
|
|
@ -0,0 +1,775 @@
|
|||
import React, { Component } from 'react'
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import { connect } from 'react-redux'
|
||||
import Button from '@material-ui/core/Button';
|
||||
import Divider from '@material-ui/core/Divider';
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import PhotoIcon from '@material-ui/icons/InsertPhoto'
|
||||
import GroupIcon from '@material-ui/icons/Group'
|
||||
import DateIcon from '@material-ui/icons/DateRange'
|
||||
import EmailIcon from '@material-ui/icons/Email'
|
||||
import HomeIcon from '@material-ui/icons/Home'
|
||||
import LinkIcon from '@material-ui/icons/Phonelink'
|
||||
import InputIcon from '@material-ui/icons/Input'
|
||||
import SecurityIcon from '@material-ui/icons/Security'
|
||||
import NickIcon from '@material-ui/icons/PermContactCalendar'
|
||||
import LockIcon from '@material-ui/icons/Lock'
|
||||
import VerifyIcon from '@material-ui/icons/VpnKey'
|
||||
import ColorIcon from '@material-ui/icons/Palette'
|
||||
import Avatar from '@material-ui/core/Avatar';
|
||||
import Paper from '@material-ui/core/Paper';
|
||||
import { toggleSnackbar,}from "../actions/index"
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import axios from 'axios'
|
||||
import FingerprintIcon from '@material-ui/icons/Fingerprint'
|
||||
import List from '@material-ui/core/List';
|
||||
import ToggleButton from '@material-ui/lab/ToggleButton';
|
||||
import ToggleButtonGroup from '@material-ui/lab/ToggleButtonGroup';
|
||||
import ListItem from '@material-ui/core/ListItem';
|
||||
import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction';
|
||||
import ListItemText from '@material-ui/core/ListItemText';
|
||||
import ListItemAvatar from '@material-ui/core/ListItemAvatar';
|
||||
import RightIcon from '@material-ui/icons/KeyboardArrowRight'
|
||||
import Dialog from '@material-ui/core/Dialog';
|
||||
import DialogActions from '@material-ui/core/DialogActions';
|
||||
import DialogContent from '@material-ui/core/DialogContent';
|
||||
import DialogTitle from '@material-ui/core/DialogTitle';
|
||||
import blue from '@material-ui/core/colors/blue';
|
||||
import yellow from '@material-ui/core/colors/yellow';
|
||||
import { ListItemIcon } from '@material-ui/core';
|
||||
import Switch from '@material-ui/core/Switch';
|
||||
|
||||
const styles = theme => ({
|
||||
|
||||
layout: {
|
||||
width: 'auto',
|
||||
marginLeft: theme.spacing.unit * 3,
|
||||
marginRight: theme.spacing.unit * 3,
|
||||
[theme.breakpoints.up(1100 + theme.spacing.unit * 3 * 2)]: {
|
||||
width: 700,
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
},
|
||||
},
|
||||
sectionTitle:{
|
||||
paddingBottom: "10px",
|
||||
paddingTop: "30px",
|
||||
},
|
||||
rightIcon:{
|
||||
marginTop: "4px",
|
||||
marginRight: "10px",
|
||||
color:theme.palette.text.secondary,
|
||||
},
|
||||
uploadFromFile:{
|
||||
backgroundColor: blue[100],
|
||||
color: blue[600],
|
||||
},
|
||||
userGravatar:{
|
||||
backgroundColor: yellow[100],
|
||||
color: yellow[800],
|
||||
},
|
||||
infoText:{
|
||||
marginRight: "17px",
|
||||
},
|
||||
infoTextWithIcon:{
|
||||
marginRight: "17px",
|
||||
marginTop: "1px",
|
||||
},
|
||||
rightIconWithText:{
|
||||
marginTop: "0px",
|
||||
marginRight: "10px",
|
||||
color:theme.palette.text.secondary,
|
||||
},
|
||||
iconFix:{
|
||||
marginRight: "11px",
|
||||
marginLeft: "7px",
|
||||
},
|
||||
flexContainer:{
|
||||
display:"flex",
|
||||
},
|
||||
desenList:{
|
||||
paddingTop:0,
|
||||
paddingBottom:0,
|
||||
},
|
||||
flexContainerResponse:{
|
||||
display:"flex",
|
||||
[theme.breakpoints.down("sm")]: {
|
||||
display:"initial",
|
||||
},
|
||||
},
|
||||
desText:{
|
||||
marginTop:"10px",
|
||||
},
|
||||
secondColor:{
|
||||
height: "20px",
|
||||
width: "20px",
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
borderRadius: "50%",
|
||||
marginRight: "17px",
|
||||
},
|
||||
firstColor:{
|
||||
height: "20px",
|
||||
width: "20px",
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
borderRadius: "50%",
|
||||
marginRight: "6px",
|
||||
},
|
||||
themeBlock:{
|
||||
height: "20px",
|
||||
width: "20px",
|
||||
},
|
||||
paddingBottom:{
|
||||
marginBottom:"30px",
|
||||
}
|
||||
})
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
toggleSnackbar:(vertical,horizontal,msg,color)=>{
|
||||
dispatch(toggleSnackbar(vertical,horizontal,msg,color))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
class UserSettingCompoment extends Component {
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
this.fileInput = React.createRef();
|
||||
}
|
||||
|
||||
state={
|
||||
avatarModal:false,
|
||||
nickModal:false,
|
||||
changePassword:false,
|
||||
loading:"",
|
||||
oldPwd:"",
|
||||
newPwd:"",
|
||||
webdavPwd:"",
|
||||
newPwdRepeat:"",
|
||||
homePage:window.userInfo.homePage,
|
||||
nick:window.userInfo.nick,
|
||||
twoFactor:false,
|
||||
authCode:"",
|
||||
changeTheme:false,
|
||||
chosenTheme:null,
|
||||
showWebDavUrl:false,
|
||||
showWebDavUserName:false,
|
||||
changeWebDavPwd:false,
|
||||
}
|
||||
|
||||
handleClose = () => {
|
||||
this.setState({
|
||||
avatarModal: false,
|
||||
nickModal:false,
|
||||
changePassword:false,
|
||||
loading:"",
|
||||
twoFactor:false,
|
||||
changeTheme:false,
|
||||
showWebDavUrl:false,
|
||||
showWebDavUserName:false,
|
||||
changeWebDavPwd:false,
|
||||
});
|
||||
};
|
||||
|
||||
useGravatar = ()=>{
|
||||
this.setState({
|
||||
loading:"gravatar",
|
||||
})
|
||||
axios.post('/Member/SetGravatar', {
|
||||
t:"comfirm",
|
||||
}).then( (response)=> {
|
||||
window.location.reload();
|
||||
this.setState({
|
||||
loading:"",
|
||||
})
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.props.toggleSnackbar("top","right",error.message ,"error");
|
||||
this.setState({
|
||||
loading:"",
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
changeNick = ()=>{
|
||||
this.setState({
|
||||
loading:"nick",
|
||||
})
|
||||
axios.post('/Member/Nick', {
|
||||
nick:this.state.nick,
|
||||
}).then( (response)=> {
|
||||
if(response.data.error==="1"){
|
||||
this.props.toggleSnackbar("top","right",response.data.msg ,"error");
|
||||
}else{
|
||||
window.location.reload();
|
||||
}
|
||||
this.setState({
|
||||
loading:"",
|
||||
})
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.props.toggleSnackbar("top","right",error.message ,"error");
|
||||
this.setState({
|
||||
loading:"",
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
uploadAvatar = ()=>{
|
||||
this.setState({
|
||||
loading:"avatar",
|
||||
})
|
||||
var formData = new FormData();
|
||||
formData.append("avatar", this.fileInput.current.files[0]);
|
||||
axios.post('/Member/SaveAvatar', formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
}).then( (response)=> {
|
||||
if(response.data.result==="error"){
|
||||
this.props.toggleSnackbar("top","right",response.data.msg ,"warning");
|
||||
}else{
|
||||
window.location.reload();
|
||||
}
|
||||
this.setState({
|
||||
loading:"",
|
||||
})
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.props.toggleSnackbar("top","right",error.message ,"error");
|
||||
this.setState({
|
||||
loading:"",
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
handleToggle = () =>{
|
||||
axios.post('/Member/HomePage', {
|
||||
status:this.state.homePage==="1"?"false":"true",
|
||||
}).then( (response)=> {
|
||||
if(response.data.error==="1"){
|
||||
this.props.toggleSnackbar("top","right",response.data.msg ,"error");
|
||||
}else{
|
||||
this.props.toggleSnackbar("top","right","设置已保存" ,"success");
|
||||
}
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.props.toggleSnackbar("top","right",error.message ,"error");
|
||||
});
|
||||
this.setState({
|
||||
homePage:this.state.homePage==="1"?"0":"1",
|
||||
});
|
||||
}
|
||||
|
||||
changhePwd =()=>{
|
||||
if(this.state.newPwd!==this.state.newPwdRepeat){
|
||||
this.props.toggleSnackbar("top","right","两次密码输入不一致" ,"warning");
|
||||
}
|
||||
this.setState({
|
||||
loading:"changePassword",
|
||||
});
|
||||
axios.post('/Member/ChangePwd', {
|
||||
origin: this.state.oldPwd,
|
||||
new: this.state.newPwd
|
||||
}).then( (response)=> {
|
||||
if(response.data.error==="1"){
|
||||
this.props.toggleSnackbar("top","right",response.data.msg ,"error");
|
||||
this.setState({
|
||||
loading:"",
|
||||
});
|
||||
}else{
|
||||
window.location.reload();
|
||||
}
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.props.toggleSnackbar("top","right",error.message ,"error");
|
||||
this.setState({
|
||||
loading:"",
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
changeTheme = ()=>{
|
||||
this.setState({
|
||||
loading:"changeTheme",
|
||||
});
|
||||
axios.post('/Member/ChangeThemeColor', {
|
||||
theme:this.state.chosenTheme,
|
||||
}).then( (response)=> {
|
||||
if(response.data.error==="1"){
|
||||
this.props.toggleSnackbar("top","right",response.data.msg ,"error");
|
||||
this.setState({
|
||||
loading:"",
|
||||
});
|
||||
}else{
|
||||
window.location.reload();
|
||||
}
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.props.toggleSnackbar("top","right",error.message ,"error");
|
||||
this.setState({
|
||||
loading:"",
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
changheWebdavPwd = ()=>{
|
||||
this.setState({
|
||||
loading:"changheWebdavPwd",
|
||||
});
|
||||
axios.post('/Member/setWebdavPwd', {
|
||||
pwd: this.state.webdavPwd,
|
||||
}).then( (response)=> {
|
||||
if(response.data.error==="1"){
|
||||
this.props.toggleSnackbar("top","right",response.data.msg ,"error");
|
||||
this.setState({
|
||||
loading:"",
|
||||
});
|
||||
}else{
|
||||
this.props.toggleSnackbar("top","right",response.data.msg ,"success");
|
||||
this.setState({
|
||||
loading:"",
|
||||
changeWebDavPwd:false,
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.props.toggleSnackbar("top","right",error.message ,"error");
|
||||
this.setState({
|
||||
loading:"",
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
twoFactor = ()=>{
|
||||
this.setState({
|
||||
loading:"twoFactor",
|
||||
});
|
||||
axios.post('/Member/TwoFactorConfirm', {
|
||||
code:this.state.authCode,
|
||||
}).then( (response)=> {
|
||||
if(response.data.error==="1"){
|
||||
this.props.toggleSnackbar("top","right",response.data.msg ,"error");
|
||||
this.setState({
|
||||
loading:"",
|
||||
});
|
||||
}else{
|
||||
window.location.reload();
|
||||
}
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.props.toggleSnackbar("top","right",error.message ,"error");
|
||||
this.setState({
|
||||
loading:"",
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
handleChange = name => event => {
|
||||
this.setState({ [name]: event.target.value });
|
||||
};
|
||||
|
||||
handleAlignment = (event, chosenTheme) => this.setState({ chosenTheme });
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={classes.layout}>
|
||||
<Typography className={classes.sectionTitle} variant="subtitle2">个人资料</Typography>
|
||||
<Paper>
|
||||
|
||||
<List className={classes.desenList}>
|
||||
<ListItem button onClick={()=>this.setState({avatarModal:true})}>
|
||||
<ListItemAvatar>
|
||||
<Avatar src={'/Member/Avatar/'+window.userInfo.uid+"/l?cache=no"}/>
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary="头像" />
|
||||
<ListItemSecondaryAction>
|
||||
<RightIcon className={classes.rightIcon}/>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
<Divider/>
|
||||
<ListItem button>
|
||||
<ListItemIcon className={classes.iconFix}><FingerprintIcon/></ListItemIcon>
|
||||
<ListItemText primary="UID" />
|
||||
|
||||
<ListItemSecondaryAction>
|
||||
<Typography className={classes.infoTextWithIcon} color="textSecondary">{window.userInfo.uid}</Typography>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
<Divider/>
|
||||
<ListItem button onClick={()=>this.setState({nickModal:true})}>
|
||||
<ListItemIcon className={classes.iconFix}><NickIcon/></ListItemIcon>
|
||||
<ListItemText primary="昵称" />
|
||||
|
||||
<ListItemSecondaryAction className={classes.flexContainer}>
|
||||
<Typography className={classes.infoTextWithIcon} color="textSecondary">{window.userInfo.nick}</Typography><RightIcon className={classes.rightIconWithText}/>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
<Divider/>
|
||||
<ListItem button>
|
||||
<ListItemIcon className={classes.iconFix}><EmailIcon/></ListItemIcon>
|
||||
<ListItemText primary="Email" />
|
||||
|
||||
<ListItemSecondaryAction>
|
||||
<Typography className={classes.infoText} color="textSecondary">{window.userInfo.email}</Typography>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
<Divider/>
|
||||
<ListItem button>
|
||||
<ListItemIcon className={classes.iconFix}><GroupIcon/></ListItemIcon>
|
||||
<ListItemText primary="用户组" />
|
||||
|
||||
<ListItemSecondaryAction>
|
||||
<Typography className={classes.infoText} color="textSecondary">{window.userInfo.group}</Typography>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
<Divider/>
|
||||
<ListItem button>
|
||||
<ListItemIcon className={classes.iconFix}><DateIcon/></ListItemIcon>
|
||||
<ListItemText primary="注册时间" />
|
||||
|
||||
<ListItemSecondaryAction>
|
||||
<Typography className={classes.infoText} color="textSecondary">{window.userInfo.regTime}</Typography>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
</List>
|
||||
</Paper>
|
||||
<Typography className={classes.sectionTitle} variant="subtitle2">安全隐私</Typography>
|
||||
<Paper>
|
||||
<List className={classes.desenList}>
|
||||
<ListItem button>
|
||||
<ListItemIcon className={classes.iconFix}><HomeIcon/></ListItemIcon>
|
||||
<ListItemText primary="个人主页" />
|
||||
|
||||
<ListItemSecondaryAction>
|
||||
<Switch
|
||||
onChange={this.handleToggle}
|
||||
checked={this.state.homePage==="1"}
|
||||
/>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
<Divider/>
|
||||
<ListItem button onClick={()=>this.setState({changePassword:true})}>
|
||||
<ListItemIcon className={classes.iconFix}><LockIcon/></ListItemIcon>
|
||||
<ListItemText primary="登录密码" />
|
||||
|
||||
<ListItemSecondaryAction className={classes.flexContainer}>
|
||||
<RightIcon className={classes.rightIcon}/>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
<Divider/>
|
||||
<ListItem button onClick={()=>window.userInfo.twoFactor==="0"?this.setState({twoFactor:true}):""}>
|
||||
<ListItemIcon className={classes.iconFix}><VerifyIcon/></ListItemIcon>
|
||||
<ListItemText primary="二步验证" />
|
||||
|
||||
<ListItemSecondaryAction className={classes.flexContainer}>
|
||||
<Typography className={classes.infoTextWithIcon} color="textSecondary">{window.userInfo.twoFactor==="0"?"未开启":"已开启"}</Typography><RightIcon className={classes.rightIconWithText}/>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
</List>
|
||||
</Paper>
|
||||
|
||||
<Typography className={classes.sectionTitle} variant="subtitle2">个性化</Typography>
|
||||
<Paper>
|
||||
<List className={classes.desenList}>
|
||||
<ListItem button onClick={()=>this.setState({changeTheme:true})}>
|
||||
<ListItemIcon className={classes.iconFix}><ColorIcon/></ListItemIcon>
|
||||
<ListItemText primary="主题配色" />
|
||||
|
||||
<ListItemSecondaryAction className={classes.flexContainer}>
|
||||
<div className={classes.firstColor}></div>
|
||||
<div className={classes.secondColor}></div>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
</List>
|
||||
</Paper>
|
||||
{window.userInfo.webdav==="1"&&<div>
|
||||
<Typography className={classes.sectionTitle} variant="subtitle2">WebDAV</Typography>
|
||||
<Paper>
|
||||
<List className={classes.desenList}>
|
||||
<ListItem button onClick={()=>this.setState({showWebDavUrl:true})}>
|
||||
<ListItemIcon className={classes.iconFix}><LinkIcon/></ListItemIcon>
|
||||
<ListItemText primary="连接地址" />
|
||||
|
||||
<ListItemSecondaryAction className={classes.flexContainer}>
|
||||
<RightIcon className={classes.rightIcon}/>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
<Divider/>
|
||||
<ListItem button onClick={()=>this.setState({showWebDavUserName:true})}>
|
||||
<ListItemIcon className={classes.iconFix}><InputIcon/></ListItemIcon>
|
||||
<ListItemText primary="用户名" />
|
||||
|
||||
<ListItemSecondaryAction className={classes.flexContainer}>
|
||||
<RightIcon className={classes.rightIcon}/>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
<Divider/>
|
||||
<ListItem button onClick={()=>this.setState({changeWebDavPwd:true})}>
|
||||
<ListItemIcon className={classes.iconFix}><SecurityIcon/></ListItemIcon>
|
||||
<ListItemText primary="登录密码" />
|
||||
|
||||
<ListItemSecondaryAction className={classes.flexContainer}>
|
||||
<RightIcon className={classes.rightIcon}/>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
</List>
|
||||
</Paper>
|
||||
</div>}
|
||||
<div className={classes.paddingBottom}></div>
|
||||
|
||||
</div>
|
||||
<Dialog
|
||||
open={this.state.avatarModal}
|
||||
onClose={this.handleClose}
|
||||
>
|
||||
<DialogTitle>修改头像</DialogTitle>
|
||||
<List>
|
||||
<ListItem button component="label" disabled={(this.state.loading==="avatar")}>
|
||||
<input
|
||||
type="file"
|
||||
accept="image/*"
|
||||
style={{ display: "none" }}
|
||||
ref={this.fileInput}
|
||||
onChange={this.uploadAvatar}
|
||||
/>
|
||||
<ListItemAvatar>
|
||||
<Avatar className={classes.uploadFromFile}>
|
||||
<PhotoIcon />
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary="从文件上传" />
|
||||
</ListItem>
|
||||
<ListItem button onClick={this.useGravatar} disabled={(this.state.loading==="gravatar")}>
|
||||
<ListItemAvatar>
|
||||
<Avatar className={classes.userGravatar}>
|
||||
<FingerprintIcon />
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary="使用Gravatar头像" />
|
||||
</ListItem>
|
||||
</List>
|
||||
<DialogActions>
|
||||
<Button onClick={this.handleClose} color="primary">
|
||||
取消
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
<Dialog
|
||||
open={this.state.nickModal}
|
||||
onClose={this.handleClose}
|
||||
>
|
||||
<DialogTitle>修改昵称</DialogTitle>
|
||||
<DialogContent>
|
||||
<TextField
|
||||
id="standard-name"
|
||||
label="昵称"
|
||||
className={classes.textField}
|
||||
value={this.state.nick}
|
||||
onChange={this.handleChange('nick')}
|
||||
margin="normal"
|
||||
autoFocus
|
||||
/>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={this.handleClose} color="default">
|
||||
取消
|
||||
</Button>
|
||||
<Button onClick={this.changeNick} color="primary" disabled={this.state.loading==="nick"||this.state.nick===""}>
|
||||
保存
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
<Dialog
|
||||
open={this.state.changePassword}
|
||||
onClose={this.handleClose}
|
||||
>
|
||||
<DialogTitle>修改登录密码</DialogTitle>
|
||||
<DialogContent>
|
||||
<div>
|
||||
<TextField
|
||||
id="standard-name"
|
||||
label="原密码"
|
||||
type="password"
|
||||
className={classes.textField}
|
||||
value={this.state.oldPwd}
|
||||
onChange={this.handleChange('oldPwd')}
|
||||
margin="normal"
|
||||
autoFocus
|
||||
/></div>
|
||||
<div>
|
||||
<TextField
|
||||
id="standard-name"
|
||||
label="新密码"
|
||||
type="password"
|
||||
className={classes.textField}
|
||||
value={this.state.newPwd}
|
||||
onChange={this.handleChange('newPwd')}
|
||||
margin="normal"
|
||||
/></div>
|
||||
<div>
|
||||
<TextField
|
||||
id="standard-name"
|
||||
label="确认新密码"
|
||||
type="password"
|
||||
className={classes.textField}
|
||||
value={this.state.newPwdRepeat}
|
||||
onChange={this.handleChange('newPwdRepeat')}
|
||||
margin="normal"
|
||||
/></div>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={this.handleClose} color="default">
|
||||
取消
|
||||
</Button>
|
||||
<Button onClick={this.changhePwd} color="primary" disabled={this.state.loading==="changePassword"||this.state.oldPwd===""||this.state.newPwdRepeat===""||this.state.newPwd===""}>
|
||||
保存
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
<Dialog
|
||||
open={this.state.twoFactor}
|
||||
onClose={this.handleClose}
|
||||
>
|
||||
<DialogTitle>启用二步验证</DialogTitle>
|
||||
<DialogContent>
|
||||
<div className={classes.flexContainerResponse}>
|
||||
<img alt="qrcode" src="/Member/EnableTwoFactor"></img>
|
||||
<div className={classes.desText}>
|
||||
<Typography>请使用任意二步验证APP或者支持二步验证的密码管理软件扫描左侧二维码添加本站。扫描完成后请填写二步验证APP给出的6位验证码以开启二步验证。</Typography>
|
||||
<TextField
|
||||
id="standard-name"
|
||||
label="6位验证码"
|
||||
type="number"
|
||||
className={classes.textField}
|
||||
value={this.state.authCode}
|
||||
onChange={this.handleChange('authCode')}
|
||||
margin="normal"
|
||||
autoFocus
|
||||
fullWidth
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={this.handleClose} color="default">
|
||||
取消
|
||||
</Button>
|
||||
<Button onClick={this.twoFactor} color="primary" disabled={this.state.loading==="twoFactor"||this.state.authCode===""}>
|
||||
开启二步验证
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
<Dialog
|
||||
open={this.state.changeTheme}
|
||||
onClose={this.handleClose}
|
||||
>
|
||||
<DialogTitle>更改主题配色</DialogTitle>
|
||||
<DialogContent>
|
||||
<ToggleButtonGroup value={this.state.chosenTheme} exclusive onChange={this.handleAlignment}>
|
||||
{Object.keys(window.colorThemeOptions).map((value,key)=>(
|
||||
<ToggleButton value={value} key={key}>
|
||||
<div
|
||||
className={classes.themeBlock}
|
||||
style={{backgroundColor:value}}
|
||||
></div>
|
||||
</ToggleButton>
|
||||
))}
|
||||
</ToggleButtonGroup>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={this.handleClose} color="default">
|
||||
取消
|
||||
</Button>
|
||||
<Button onClick={this.changeTheme} color="primary" disabled={this.state.loading==="changeTheme"||this.state.chosenTheme===null}>
|
||||
保存
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
<Dialog
|
||||
open={this.state.showWebDavUrl}
|
||||
onClose={this.handleClose}
|
||||
>
|
||||
<DialogTitle>WebDAV连接地址</DialogTitle>
|
||||
<DialogContent>
|
||||
<TextField
|
||||
id="standard-name"
|
||||
className={classes.textField}
|
||||
value={window.siteUrl+"WebDav/Api/uid/"+window.userInfo.uid}
|
||||
margin="normal"
|
||||
autoFocus
|
||||
/>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={this.handleClose} color="default">
|
||||
关闭
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
<Dialog
|
||||
open={this.state.showWebDavUserName}
|
||||
onClose={this.handleClose}
|
||||
>
|
||||
<DialogTitle>WebDAV用户名</DialogTitle>
|
||||
<DialogContent>
|
||||
<TextField
|
||||
id="standard-name"
|
||||
className={classes.textField}
|
||||
value={window.userInfo.email}
|
||||
margin="normal"
|
||||
autoFocus
|
||||
/>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={this.handleClose} color="default">
|
||||
关闭
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
<Dialog
|
||||
open={this.state.changeWebDavPwd}
|
||||
onClose={this.handleClose}
|
||||
>
|
||||
<DialogTitle>修改/设置WebDAV密码</DialogTitle>
|
||||
<DialogContent>
|
||||
<TextField
|
||||
id="standard-name"
|
||||
className={classes.textField}
|
||||
value={this.state.webdavPwd}
|
||||
margin="normal"
|
||||
type="password"
|
||||
onChange={this.handleChange('webdavPwd')}
|
||||
autoFocus
|
||||
fullWidth
|
||||
/>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={this.handleClose} color="default">
|
||||
取消
|
||||
</Button>
|
||||
<Button onClick={this.changheWebdavPwd} color="primary" disabled={this.state.loading==="changheWebdavPwd"||this.state.webdavPwd===""}>
|
||||
保存
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const UserSetting = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)( withStyles(styles)(UserSettingCompoment))
|
||||
|
||||
export default UserSetting
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
import React, { Component } from 'react'
|
||||
import Paper from '@material-ui/core/Paper';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import {
|
||||
toggleSnackbar,
|
||||
} from "../../actions/index"
|
||||
import axios from 'axios'
|
||||
import { connect } from 'react-redux'
|
||||
import {editSuffix} from "../../config"
|
||||
const styles = theme => ({
|
||||
layout: {
|
||||
width: 'auto',
|
||||
marginTop:'30px',
|
||||
marginLeft: theme.spacing.unit * 3,
|
||||
marginRight: theme.spacing.unit * 3,
|
||||
[theme.breakpoints.up(1100 + theme.spacing.unit * 3 * 2)]: {
|
||||
width: 1100,
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
},
|
||||
},
|
||||
})
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
save:state.explorer.fileSave,
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
toggleSnackbar:(vertical,horizontal,msg,color)=>{
|
||||
dispatch(toggleSnackbar(vertical,horizontal,msg,color))
|
||||
},
|
||||
}
|
||||
}
|
||||
const codeSuffix = {
|
||||
"html":"text/html",
|
||||
"sql":"text/html",
|
||||
"go":"go",
|
||||
"py":"python",
|
||||
"js":"javascript",
|
||||
"json":"text/json",
|
||||
"c":"clike",
|
||||
"cpp":"clike",
|
||||
"css":"css",
|
||||
"txt":"text/html"
|
||||
};
|
||||
class MarkdownViewerCompoment extends Component {
|
||||
|
||||
state = {
|
||||
val:"",
|
||||
}
|
||||
|
||||
componentWillReceiveProps = (nextProps)=>{
|
||||
if(this.props.save!==nextProps.save){
|
||||
this.save();
|
||||
}
|
||||
}
|
||||
|
||||
save = ()=>{
|
||||
axios.post("/File/Edit",{
|
||||
item:window.fileInfo.path,
|
||||
content:window.document.getElementById("val").value,
|
||||
})
|
||||
.then( (response)=> {
|
||||
if(!response.data.result.success){
|
||||
this.props.toggleSnackbar("top","right",response.data.result.error ,"error");
|
||||
}else{
|
||||
this.props.toggleSnackbar("top","right","文件已保存" ,"success");
|
||||
}
|
||||
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.props.toggleSnackbar("top","right",error.message ,"error");
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount = ()=>{
|
||||
let suffix = window.fileInfo.name.split(".").pop().toLowerCase();
|
||||
if(suffix === "md"){
|
||||
// eslint-disable-next-line
|
||||
var editor = window.editormd("editormd", {
|
||||
path : "/static/js/mdeditor/lib/",
|
||||
height: 740,
|
||||
tex : true,
|
||||
toolbarIcons : function() {
|
||||
return [
|
||||
"undo", "redo", "|",
|
||||
"bold", "del", "italic", "quote", "|",
|
||||
"h1", "h2", "h3", "h4", "h5", "h6", "|",
|
||||
"list-ul", "list-ol", "hr", "|",
|
||||
"link", "reference-link", "image", "code", "preformatted-text", "code-block", "table", "datetime", "html-entities", "pagebreak", "|",
|
||||
"goto-line", "watch", "clear", "search", "|",
|
||||
"help", "info"
|
||||
];
|
||||
},
|
||||
});
|
||||
}else if(editSuffix.indexOf(suffix)!==-1){
|
||||
// eslint-disable-next-line
|
||||
var editor = window.editormd("editormd", {
|
||||
path : "/static/js/mdeditor/lib/",
|
||||
height: 740,
|
||||
watch : false,
|
||||
toolbar : false,
|
||||
codeFold : true,
|
||||
searchReplace : true,
|
||||
placeholder : "Enjoy coding!",
|
||||
mode:codeSuffix[suffix],
|
||||
});
|
||||
}
|
||||
|
||||
axios.get(window.fileInfo.url)
|
||||
.then( (response)=> {
|
||||
if(response.data.result.hasOwnProperty("success")){
|
||||
this.props.toggleSnackbar("top","right",response.data.result.error ,"error");
|
||||
}else{
|
||||
this.setState({
|
||||
val:response.data.result,
|
||||
});
|
||||
}
|
||||
|
||||
})
|
||||
.catch((error) =>{
|
||||
this.props.toggleSnackbar("top","right",error.message ,"error");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
handleChange(event) {
|
||||
this.setState({val: event.target.value});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
return (
|
||||
<div className={classes.layout}>
|
||||
<Paper className={classes.root} elevation={1}>
|
||||
<div id="editormd">
|
||||
<textarea
|
||||
id="val"
|
||||
value={this.state.val}
|
||||
onChange={this.handleChange}
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
</Paper>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const MarkdownViewer = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)( withStyles(styles)(MarkdownViewerCompoment))
|
||||
|
||||
export default MarkdownViewer
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
import React, { Component } from 'react'
|
||||
import Paper from '@material-ui/core/Paper';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import DPlayer from "react-dplayer";
|
||||
|
||||
|
||||
const styles = theme => ({
|
||||
layout: {
|
||||
width: 'auto',
|
||||
marginTop:'30px',
|
||||
marginLeft: theme.spacing.unit * 3,
|
||||
marginRight: theme.spacing.unit * 3,
|
||||
[theme.breakpoints.up(1100 + theme.spacing.unit * 3 * 2)]: {
|
||||
width: 1100,
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
},
|
||||
},
|
||||
player:{
|
||||
borderRadius: "4px",
|
||||
}
|
||||
})
|
||||
|
||||
class VideoViewer extends Component {
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
return (
|
||||
<div className={classes.layout}>
|
||||
<Paper className={classes.root} elevation={1}>
|
||||
|
||||
<DPlayer className={classes.player} video={{url: window.videoInfo.url}}/>
|
||||
</Paper>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
VideoViewer.propTypes = {
|
||||
};
|
||||
|
||||
export default withStyles(styles)(VideoViewer);
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
export const imgPreviewSuffix = ["bmp","png","gif","jpg","jpeg","svg","webp"];
|
||||
export const msDocPreviewSuffix = ["ppt","pptx","pps","doc","docx","xlsx","xls"];
|
||||
export const audioPreviewSuffix = ["mp3","ogg"];
|
||||
export const videoPreviewSuffix = ["mp4"];
|
||||
export const directOpenPreviewSuffix = ["pdf"];
|
||||
export const editSuffix = ["md","html","sql","go","py","js","json","c","cpp","css","txt"];
|
||||
export const mediaType = {
|
||||
audio:["mp3","flac","ape","wav","acc","ogg"],
|
||||
video:["mp4","flv","avi","wmv","mkv","rm","rmvb","mov","ogv"],
|
||||
image:["bmp","iff","png","gif","jpg","jpeg","psd","svg","webp"],
|
||||
pdf:["pdf"],
|
||||
word:["doc","docx"],
|
||||
ppt:["ppt","pptx"],
|
||||
excel:["xls","xlsx","csv"],
|
||||
text:["txt","md","html"],
|
||||
torrent:["torrent"],
|
||||
zip:["zip","gz","tar","rar","7z"],
|
||||
excute:["exe"],
|
||||
android:["apk"],
|
||||
};
|
||||
export const isPreviewable = name=>{
|
||||
let suffix = name.split(".").pop().toLowerCase();
|
||||
if(imgPreviewSuffix.indexOf(suffix)!==-1){
|
||||
return "img";
|
||||
}else if(msDocPreviewSuffix.indexOf(suffix)!==-1){
|
||||
return "msDoc";
|
||||
}else if(audioPreviewSuffix.indexOf(suffix)!==-1){
|
||||
return "audio";
|
||||
}else if(directOpenPreviewSuffix.indexOf(suffix)!==-1){
|
||||
return "open";
|
||||
}else if(videoPreviewSuffix.indexOf(suffix)!==-1){
|
||||
return "video";
|
||||
}else if(editSuffix.indexOf(suffix)!==-1){
|
||||
return "edit";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
export const isTorrent = name=>{
|
||||
let suffix = name.split(".").pop().toLowerCase();
|
||||
if(mediaType.torrent.indexOf(suffix)!==-1){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import App from './App';
|
||||
import * as serviceWorker from './serviceWorker';
|
||||
|
||||
import { Provider } from 'react-redux'
|
||||
import { createStore } from 'redux'
|
||||
import cloureveApp from './reducers'
|
||||
|
||||
const defaultStatus = {
|
||||
navigator:{
|
||||
path:window.path,
|
||||
refresh:true,
|
||||
},
|
||||
viewUpdate:{
|
||||
open:true,
|
||||
explorerViewMethod: "icon",
|
||||
sortMethod:"timePos",
|
||||
contextType:"none",
|
||||
menuOpen:false,
|
||||
navigatorLoading:true,
|
||||
navigatorError:false,
|
||||
navigatorErrorMsg:null,
|
||||
modalsLoading:false,
|
||||
storageRefresh:false,
|
||||
modals:{
|
||||
createNewFolder:false,
|
||||
rename:false,
|
||||
move:false,
|
||||
remove:false,
|
||||
share:false,
|
||||
music:false,
|
||||
remoteDownload:false,
|
||||
torrentDownload:false,
|
||||
getSource:false,
|
||||
},
|
||||
snackbar:{
|
||||
toggle:false,
|
||||
vertical:"top",
|
||||
horizontal:"center",
|
||||
msg:"",
|
||||
color:"",
|
||||
}
|
||||
},
|
||||
explorer:{
|
||||
fileList:[],
|
||||
dirList:[
|
||||
],
|
||||
selected:[],
|
||||
selectProps:{
|
||||
isMultiple:false,
|
||||
withFolder:false,
|
||||
withFile:false,
|
||||
},
|
||||
imgPreview:{
|
||||
first:null,
|
||||
other:[],
|
||||
},
|
||||
keywords:null,
|
||||
}
|
||||
};
|
||||
|
||||
let store = createStore(cloureveApp,defaultStatus)
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<App />
|
||||
</Provider>
|
||||
, document.getElementById('root'));
|
||||
|
||||
|
||||
|
||||
// If you want your app to work offline and load faster, you can change
|
||||
// unregister() to register() below. Note this comes with some pitfalls.
|
||||
// Learn more about service workers: http://bit.ly/CRA-PWA
|
||||
serviceWorker.unregister();
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import hoistStatics from 'hoist-non-react-statics'
|
||||
import { newScript, series, noop } from './utils'
|
||||
|
||||
const loadedScript = []
|
||||
const pendingScripts = {}
|
||||
let failedScript = []
|
||||
|
||||
export function startLoadingScripts(scripts, onComplete = noop) {
|
||||
// sequence load
|
||||
const loadNewScript = (script) => {
|
||||
const src = typeof script === 'object' ? script.src : script
|
||||
if (loadedScript.indexOf(src) < 0) {
|
||||
return taskComplete => {
|
||||
const callbacks = pendingScripts[src] || []
|
||||
callbacks.push(taskComplete)
|
||||
pendingScripts[src] = callbacks
|
||||
if (callbacks.length === 1) {
|
||||
return newScript(script)(err => {
|
||||
pendingScripts[src].forEach(cb => cb(err, src))
|
||||
delete pendingScripts[src]
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const tasks = scripts.map(src => {
|
||||
if (Array.isArray(src)) {
|
||||
return src.map(loadNewScript)
|
||||
}
|
||||
else return loadNewScript(src)
|
||||
})
|
||||
|
||||
series(...tasks)((err, src) => {
|
||||
if (err) {
|
||||
failedScript.push(src)
|
||||
}
|
||||
else {
|
||||
if (Array.isArray(src)) {
|
||||
src.forEach(addCache)
|
||||
}
|
||||
else addCache(src)
|
||||
}
|
||||
})(err => {
|
||||
removeFailedScript()
|
||||
onComplete(err)
|
||||
})
|
||||
}
|
||||
|
||||
const addCache = (entry) => {
|
||||
if (loadedScript.indexOf(entry) < 0) {
|
||||
loadedScript.push(entry)
|
||||
}
|
||||
}
|
||||
|
||||
const removeFailedScript = () => {
|
||||
if (failedScript.length > 0) {
|
||||
failedScript.forEach((script) => {
|
||||
const node = document.querySelector(`script[src='${script}']`)
|
||||
if (node != null) {
|
||||
node.parentNode.removeChild(node)
|
||||
}
|
||||
})
|
||||
|
||||
failedScript = []
|
||||
}
|
||||
}
|
||||
|
||||
const scriptLoader = (...scripts) => (WrappedComponent) => {
|
||||
class ScriptLoader extends Component {
|
||||
static propTypes = {
|
||||
onScriptLoaded: PropTypes.func
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
onScriptLoaded: noop
|
||||
}
|
||||
|
||||
constructor (props, context) {
|
||||
super(props, context)
|
||||
|
||||
this.state = {
|
||||
isScriptLoaded: false,
|
||||
isScriptLoadSucceed: false
|
||||
}
|
||||
|
||||
this._isMounted = false;
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
this._isMounted = true;
|
||||
startLoadingScripts(scripts, err => {
|
||||
if(this._isMounted) {
|
||||
this.setState({
|
||||
isScriptLoaded: true,
|
||||
isScriptLoadSucceed: !err
|
||||
}, () => {
|
||||
if (!err) {
|
||||
this.props.onScriptLoaded()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
this._isMounted = false;
|
||||
}
|
||||
|
||||
getWrappedInstance () {
|
||||
return this.refs.wrappedInstance;
|
||||
}
|
||||
|
||||
render () {
|
||||
const props = {
|
||||
...this.props,
|
||||
...this.state,
|
||||
ref: 'wrappedInstance'
|
||||
}
|
||||
|
||||
return (
|
||||
<WrappedComponent {...props} />
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return hoistStatics(ScriptLoader, WrappedComponent)
|
||||
}
|
||||
|
||||
export default scriptLoader
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
export const isDefined = val => val != null
|
||||
export const isFunction = val => typeof val === 'function'
|
||||
export const noop = _ => { }
|
||||
|
||||
export const newScript = (src) => (cb) => {
|
||||
const scriptElem = document.createElement('script')
|
||||
if (typeof src === 'object') {
|
||||
// copy every property to the element
|
||||
for (var key in src) {
|
||||
if (Object.prototype.hasOwnProperty.call(src, key)) {
|
||||
scriptElem[key] = src[key];
|
||||
}
|
||||
}
|
||||
src = src.src;
|
||||
} else {
|
||||
scriptElem.src = src
|
||||
}
|
||||
scriptElem.addEventListener('load', () => cb(null, src))
|
||||
scriptElem.addEventListener('error', () => cb(true, src))
|
||||
document.body.appendChild(scriptElem)
|
||||
return scriptElem
|
||||
}
|
||||
|
||||
const keyIterator = (cols) => {
|
||||
const keys = Object.keys(cols)
|
||||
let i = -1
|
||||
return {
|
||||
next () {
|
||||
i++ // inc
|
||||
if (i >= keys.length) return null
|
||||
else return keys[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// tasks should be a collection of thunk
|
||||
export const parallel = (...tasks) => (each) => (cb) => {
|
||||
let hasError = false
|
||||
let successed = 0
|
||||
const ret = []
|
||||
tasks = tasks.filter(isFunction)
|
||||
|
||||
if (tasks.length <= 0) cb(null)
|
||||
else {
|
||||
tasks.forEach((task, i) => {
|
||||
const thunk = task
|
||||
thunk((err, ...args) => {
|
||||
if (err) hasError = true
|
||||
else {
|
||||
// collect result
|
||||
if (args.length <= 1) args = args[0]
|
||||
|
||||
ret[i] = args
|
||||
successed ++
|
||||
}
|
||||
|
||||
if (isFunction(each)) each.call(null, err, args, i)
|
||||
|
||||
if (hasError) cb(true)
|
||||
else if (tasks.length === successed) {
|
||||
cb(null, ret)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// tasks should be a collection of thunk
|
||||
export const series = (...tasks) => (each) => (cb) => {
|
||||
tasks = tasks.filter(val => val != null)
|
||||
const nextKey = keyIterator(tasks)
|
||||
const nextThunk = () => {
|
||||
const key = nextKey.next()
|
||||
let thunk = tasks[key]
|
||||
if (Array.isArray(thunk)) thunk = parallel.apply(null, thunk).call(null, each)
|
||||
return [ +key, thunk ] // convert `key` to number
|
||||
}
|
||||
let key, thunk
|
||||
let next = nextThunk()
|
||||
key = next[0]
|
||||
thunk = next[1]
|
||||
if (thunk == null) return cb(null)
|
||||
|
||||
const ret = []
|
||||
const iterator = () => {
|
||||
thunk((err, ...args) => {
|
||||
if (args.length <= 1) args = args[0]
|
||||
if (isFunction(each)) each.call(null, err, args, key)
|
||||
|
||||
if (err) cb(err)
|
||||
else {
|
||||
// collect result
|
||||
ret.push(args)
|
||||
|
||||
next = nextThunk()
|
||||
key = next[0]
|
||||
thunk = next[1]
|
||||
if (thunk == null) return cb(null, ret) // finished
|
||||
else iterator()
|
||||
}
|
||||
})
|
||||
}
|
||||
iterator()
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import CssBaseline from '@material-ui/core/CssBaseline';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import Navbar from "../component/Navbar.js"
|
||||
import AlertBar from "../component/Snackbar"
|
||||
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles';
|
||||
import Download from '../component/Download'
|
||||
const theme = createMuiTheme(window.colorTheme);
|
||||
const styles = theme => ({
|
||||
|
||||
root: {
|
||||
display: 'flex',
|
||||
},
|
||||
content: {
|
||||
flexGrow: 1,
|
||||
padding: theme.spacing.unit * 0,
|
||||
minWidth: 0,
|
||||
},
|
||||
toolbar: theme.mixins.toolbar,
|
||||
});
|
||||
|
||||
class DownloadList extends Component {
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
return (
|
||||
<React.Fragment>
|
||||
<MuiThemeProvider theme={theme}>
|
||||
<div className={classes.root} id="container">
|
||||
<CssBaseline />
|
||||
<AlertBar/>
|
||||
<Navbar />
|
||||
<main className={classes.content}>
|
||||
<div className={classes.toolbar} />
|
||||
<Download/>
|
||||
</main>
|
||||
</div></MuiThemeProvider>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
DownloadList.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default withStyles(styles)(DownloadList);
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import { Provider } from 'react-redux'
|
||||
import { createStore } from 'redux'
|
||||
import DownloadApp from "./download.app"
|
||||
import cloureveApp from '../reducers'
|
||||
|
||||
const defaultStatus = {
|
||||
navigator:{
|
||||
path:window.path,
|
||||
refresh:true,
|
||||
},
|
||||
viewUpdate:{
|
||||
open:window.isHomePage,
|
||||
explorerViewMethod: "icon",
|
||||
sortMethod:"timePos",
|
||||
contextType:"none",
|
||||
menuOpen:false,
|
||||
navigatorLoading:true,
|
||||
navigatorError:false,
|
||||
navigatorErrorMsg:null,
|
||||
modalsLoading:false,
|
||||
storageRefresh:false,
|
||||
modals:{
|
||||
createNewFolder:false,
|
||||
rename:false,
|
||||
move:false,
|
||||
remove:false,
|
||||
share:false,
|
||||
music:false,
|
||||
remoteDownload:false,
|
||||
torrentDownload:false,
|
||||
},
|
||||
snackbar:{
|
||||
toggle:false,
|
||||
vertical:"top",
|
||||
horizontal:"center",
|
||||
msg:"",
|
||||
color:"",
|
||||
}
|
||||
},
|
||||
explorer:{
|
||||
fileList:[],
|
||||
dirList:[
|
||||
],
|
||||
selected:[],
|
||||
selectProps:{
|
||||
isMultiple:false,
|
||||
withFolder:false,
|
||||
withFile:false,
|
||||
},
|
||||
imgPreview:{
|
||||
first:null,
|
||||
other:[],
|
||||
},
|
||||
keywords:null,
|
||||
}
|
||||
};
|
||||
|
||||
let store = createStore(cloureveApp,defaultStatus)
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<DownloadApp/>
|
||||
</Provider>
|
||||
, document.getElementById('root'));
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import CssBaseline from '@material-ui/core/CssBaseline';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import Navbar from "../component/Navbar.js"
|
||||
import AlertBar from "../component/Snackbar"
|
||||
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles';
|
||||
import SharedFile from '../component/SharedFile'
|
||||
const theme = createMuiTheme(window.colorTheme);
|
||||
const styles = theme => ({
|
||||
|
||||
root: {
|
||||
display: 'flex',
|
||||
},
|
||||
content: {
|
||||
flexGrow: 1,
|
||||
padding: theme.spacing.unit * 0,
|
||||
minWidth: 0,
|
||||
},
|
||||
toolbar: theme.mixins.toolbar,
|
||||
});
|
||||
|
||||
class FileShareApp extends Component {
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
return (
|
||||
<React.Fragment>
|
||||
<MuiThemeProvider theme={theme}>
|
||||
<div className={classes.root} id="container">
|
||||
<CssBaseline />
|
||||
<AlertBar/>
|
||||
<Navbar />
|
||||
<main className={classes.content}>
|
||||
<div className={classes.toolbar} />
|
||||
<SharedFile/>
|
||||
</main>
|
||||
</div></MuiThemeProvider>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
FileShareApp.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default withStyles(styles)(FileShareApp);
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import { Provider } from 'react-redux'
|
||||
import { createStore } from 'redux'
|
||||
import FileShareApp from "./fileShare.app"
|
||||
import cloureveApp from '../reducers'
|
||||
|
||||
const defaultStatus = {
|
||||
navigator:{
|
||||
path:window.path,
|
||||
refresh:true,
|
||||
},
|
||||
viewUpdate:{
|
||||
open:window.isHomePage,
|
||||
explorerViewMethod: "icon",
|
||||
sortMethod:"timePos",
|
||||
contextType:"none",
|
||||
menuOpen:false,
|
||||
navigatorLoading:true,
|
||||
navigatorError:false,
|
||||
navigatorErrorMsg:null,
|
||||
modalsLoading:false,
|
||||
storageRefresh:false,
|
||||
modals:{
|
||||
createNewFolder:false,
|
||||
rename:false,
|
||||
move:false,
|
||||
remove:false,
|
||||
share:false,
|
||||
music:false,
|
||||
remoteDownload:false,
|
||||
torrentDownload:false,
|
||||
},
|
||||
snackbar:{
|
||||
toggle:false,
|
||||
vertical:"top",
|
||||
horizontal:"center",
|
||||
msg:"",
|
||||
color:"",
|
||||
}
|
||||
},
|
||||
explorer:{
|
||||
fileList:[],
|
||||
dirList:[
|
||||
],
|
||||
selected:[],
|
||||
selectProps:{
|
||||
isMultiple:false,
|
||||
withFolder:false,
|
||||
withFile:false,
|
||||
},
|
||||
imgPreview:{
|
||||
first:null,
|
||||
other:[],
|
||||
},
|
||||
keywords:null,
|
||||
}
|
||||
};
|
||||
|
||||
let store = createStore(cloureveApp,defaultStatus)
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<FileShareApp/>
|
||||
</Provider>
|
||||
, document.getElementById('root'));
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import CssBaseline from '@material-ui/core/CssBaseline';
|
||||
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
|
||||
import Navbar from "../component/Navbar.js"
|
||||
import AlertBar from "../component/Snackbar"
|
||||
import FileManager from "../component/FileManager/FileManager"
|
||||
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles';
|
||||
|
||||
const theme = createMuiTheme(window.colorTheme);
|
||||
const styles = theme => ({
|
||||
|
||||
root: {
|
||||
display: 'flex',
|
||||
},
|
||||
content: {
|
||||
flexGrow: 1,
|
||||
padding: theme.spacing.unit * 0,
|
||||
minWidth: 0,
|
||||
},
|
||||
toolbar: theme.mixins.toolbar,
|
||||
});
|
||||
|
||||
class FolderShareApp extends Component {
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
return (
|
||||
<React.Fragment>
|
||||
<MuiThemeProvider theme={theme}>
|
||||
<div className={classes.root} id="container">
|
||||
<CssBaseline />
|
||||
<AlertBar/>
|
||||
<Navbar />
|
||||
<main className={classes.content}>
|
||||
<div className={classes.toolbar} />
|
||||
<FileManager/>
|
||||
</main>
|
||||
</div></MuiThemeProvider>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
FolderShareApp.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default withStyles(styles)(FolderShareApp);
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import { Provider } from 'react-redux'
|
||||
import { createStore } from 'redux'
|
||||
import FolderShareApp from "./folderShare.app"
|
||||
import cloureveApp from '../reducers'
|
||||
const defaultStatus = {
|
||||
navigator:{
|
||||
path:window.path,
|
||||
refresh:true,
|
||||
},
|
||||
viewUpdate:{
|
||||
open:window.isHomePage,
|
||||
explorerViewMethod: "icon",
|
||||
sortMethod:"timePos",
|
||||
contextType:"none",
|
||||
menuOpen:false,
|
||||
navigatorLoading:true,
|
||||
navigatorError:false,
|
||||
navigatorErrorMsg:null,
|
||||
modalsLoading:false,
|
||||
storageRefresh:false,
|
||||
modals:{
|
||||
createNewFolder:false,
|
||||
rename:false,
|
||||
move:false,
|
||||
remove:false,
|
||||
share:false,
|
||||
music:false,
|
||||
remoteDownload:false,
|
||||
torrentDownload:false,
|
||||
getSource:false,
|
||||
},
|
||||
snackbar:{
|
||||
toggle:false,
|
||||
vertical:"top",
|
||||
horizontal:"center",
|
||||
msg:"",
|
||||
color:"",
|
||||
}
|
||||
},
|
||||
explorer:{
|
||||
fileList:[],
|
||||
fileSave:false,
|
||||
dirList:[
|
||||
],
|
||||
selected:[],
|
||||
selectProps:{
|
||||
isMultiple:false,
|
||||
withFolder:false,
|
||||
withFile:false,
|
||||
},
|
||||
imgPreview:{
|
||||
first:null,
|
||||
other:[],
|
||||
},
|
||||
keywords:null,
|
||||
}
|
||||
};
|
||||
|
||||
let store = createStore(cloureveApp,defaultStatus)
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<FolderShareApp/>
|
||||
</Provider>
|
||||
, document.getElementById('root'));
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import CssBaseline from '@material-ui/core/CssBaseline';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import Navbar from "../component/Navbar.js"
|
||||
import AlertBar from "../component/Snackbar"
|
||||
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles';
|
||||
import LockedFile from '../component/LockedFile'
|
||||
const theme = createMuiTheme(window.colorTheme);
|
||||
const styles = theme => ({
|
||||
|
||||
root: {
|
||||
display: 'flex',
|
||||
},
|
||||
content: {
|
||||
flexGrow: 1,
|
||||
padding: theme.spacing.unit * 0,
|
||||
minWidth: 0,
|
||||
},
|
||||
toolbar: theme.mixins.toolbar,
|
||||
});
|
||||
|
||||
class LockApp extends Component {
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
return (
|
||||
<React.Fragment>
|
||||
<MuiThemeProvider theme={theme}>
|
||||
<div className={classes.root} id="container">
|
||||
<CssBaseline />
|
||||
<AlertBar/>
|
||||
<Navbar />
|
||||
<main className={classes.content}>
|
||||
<div className={classes.toolbar} />
|
||||
<LockedFile/>
|
||||
</main>
|
||||
</div></MuiThemeProvider>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
LockApp.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default withStyles(styles)(LockApp);
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import { Provider } from 'react-redux'
|
||||
import { createStore } from 'redux'
|
||||
import LockApp from "./lock.app"
|
||||
import cloureveApp from '../reducers'
|
||||
|
||||
const defaultStatus = {
|
||||
navigator:{
|
||||
path:window.path,
|
||||
refresh:true,
|
||||
},
|
||||
viewUpdate:{
|
||||
open:window.isHomePage,
|
||||
explorerViewMethod: "icon",
|
||||
sortMethod:"timePos",
|
||||
contextType:"none",
|
||||
menuOpen:false,
|
||||
navigatorLoading:true,
|
||||
navigatorError:false,
|
||||
navigatorErrorMsg:null,
|
||||
modalsLoading:false,
|
||||
storageRefresh:false,
|
||||
modals:{
|
||||
createNewFolder:false,
|
||||
rename:false,
|
||||
move:false,
|
||||
remove:false,
|
||||
share:false,
|
||||
music:false,
|
||||
remoteDownload:false,
|
||||
torrentDownload:false,
|
||||
},
|
||||
snackbar:{
|
||||
toggle:false,
|
||||
vertical:"top",
|
||||
horizontal:"center",
|
||||
msg:"",
|
||||
color:"",
|
||||
}
|
||||
},
|
||||
explorer:{
|
||||
fileList:[],
|
||||
dirList:[
|
||||
],
|
||||
selected:[],
|
||||
selectProps:{
|
||||
isMultiple:false,
|
||||
withFolder:false,
|
||||
withFile:false,
|
||||
},
|
||||
imgPreview:{
|
||||
first:null,
|
||||
other:[],
|
||||
},
|
||||
keywords:null,
|
||||
}
|
||||
};
|
||||
|
||||
let store = createStore(cloureveApp,defaultStatus)
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<LockApp/>
|
||||
</Provider>
|
||||
, document.getElementById('root'));
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import CssBaseline from '@material-ui/core/CssBaseline';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import Navbar from "../component/Navbar.js"
|
||||
import AlertBar from "../component/Snackbar"
|
||||
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles';
|
||||
import LoginForm from "../component/Login/LoginForm"
|
||||
import TwoStep from "../component/Login/TwoStep"
|
||||
import RegisterForm from "../component/Login/RegisterForm"
|
||||
import EmailActivication from "../component/Login/EmailActivication"
|
||||
import ResetPwd from "../component/Login/ResetPwd"
|
||||
import ResetPwdForm from "../component/Login/ResetPwdForm"
|
||||
|
||||
const theme = createMuiTheme(window.colorTheme);
|
||||
const styles = theme => ({
|
||||
|
||||
root: {
|
||||
display: 'flex',
|
||||
},
|
||||
content: {
|
||||
flexGrow: 1,
|
||||
padding: theme.spacing.unit * 0,
|
||||
minWidth: 0,
|
||||
},
|
||||
toolbar: theme.mixins.toolbar,
|
||||
});
|
||||
|
||||
class LoginApp extends Component {
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
return (
|
||||
<React.Fragment>
|
||||
<MuiThemeProvider theme={theme}>
|
||||
<div className={classes.root} id="container">
|
||||
<CssBaseline />
|
||||
<AlertBar/>
|
||||
<Navbar />
|
||||
<main className={classes.content}>
|
||||
<div className={classes.toolbar} />
|
||||
{window.pageId==="login"&&<LoginForm/>}
|
||||
{window.pageId==="TwoStep"&&<TwoStep/>}
|
||||
{window.pageId==="register"&&<RegisterForm/>}
|
||||
{window.pageId==="emailActivate"&&<EmailActivication/>}
|
||||
{window.pageId==="resetPwd"&&<ResetPwd/>}
|
||||
{window.pageId==="resetPwdForm"&&<ResetPwdForm/>}
|
||||
</main>
|
||||
</div></MuiThemeProvider>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
LoginApp.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default withStyles(styles)(LoginApp);
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import { Provider } from 'react-redux'
|
||||
import { createStore } from 'redux'
|
||||
import LoginApp from "./login.app"
|
||||
import cloureveApp from '../reducers'
|
||||
|
||||
const defaultStatus = {
|
||||
navigator:{
|
||||
path:window.path,
|
||||
refresh:true,
|
||||
},
|
||||
viewUpdate:{
|
||||
open:window.isHomePage,
|
||||
explorerViewMethod: "icon",
|
||||
sortMethod:"timePos",
|
||||
contextType:"none",
|
||||
menuOpen:false,
|
||||
navigatorLoading:true,
|
||||
navigatorError:false,
|
||||
navigatorErrorMsg:null,
|
||||
modalsLoading:false,
|
||||
storageRefresh:false,
|
||||
modals:{
|
||||
createNewFolder:false,
|
||||
rename:false,
|
||||
move:false,
|
||||
remove:false,
|
||||
share:false,
|
||||
music:false,
|
||||
remoteDownload:false,
|
||||
torrentDownload:false,
|
||||
},
|
||||
snackbar:{
|
||||
toggle:false,
|
||||
vertical:"top",
|
||||
horizontal:"center",
|
||||
msg:"",
|
||||
color:"",
|
||||
}
|
||||
},
|
||||
explorer:{
|
||||
fileList:[],
|
||||
dirList:[
|
||||
],
|
||||
selected:[],
|
||||
selectProps:{
|
||||
isMultiple:false,
|
||||
withFolder:false,
|
||||
withFile:false,
|
||||
},
|
||||
imgPreview:{
|
||||
first:null,
|
||||
other:[],
|
||||
},
|
||||
keywords:null,
|
||||
}
|
||||
};
|
||||
|
||||
let store = createStore(cloureveApp,defaultStatus)
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<LoginApp/>
|
||||
</Provider>
|
||||
, document.getElementById('root'));
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import CssBaseline from '@material-ui/core/CssBaseline';
|
||||
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
|
||||
import Navbar from "../component/Navbar.js"
|
||||
import AlertBar from "../component/Snackbar"
|
||||
import MarkdownViewer from "../component/Viewer/markdown"
|
||||
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles';
|
||||
|
||||
const theme = createMuiTheme(window.colorTheme);
|
||||
const styles = theme => ({
|
||||
|
||||
root: {
|
||||
display: 'flex',
|
||||
},
|
||||
content: {
|
||||
flexGrow: 1,
|
||||
padding: theme.spacing.unit * 0,
|
||||
minWidth: 0,
|
||||
},
|
||||
toolbar: theme.mixins.toolbar,
|
||||
});
|
||||
|
||||
class MarkdownApp extends Component {
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
return (
|
||||
<React.Fragment>
|
||||
<MuiThemeProvider theme={theme}>
|
||||
<div className={classes.root} id="container">
|
||||
<CssBaseline />
|
||||
<AlertBar/>
|
||||
<Navbar />
|
||||
<main className={classes.content}>
|
||||
<div className={classes.toolbar} />
|
||||
<MarkdownViewer/>
|
||||
</main>
|
||||
</div></MuiThemeProvider>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
MarkdownApp.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default withStyles(styles)(MarkdownApp);
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import { Provider } from 'react-redux'
|
||||
import { createStore } from 'redux'
|
||||
import cloureveApp from '../reducers'
|
||||
import MarkdownApp from "./markdown.app"
|
||||
const defaultStatus = {
|
||||
navigator:{
|
||||
path:window.path,
|
||||
refresh:true,
|
||||
},
|
||||
viewUpdate:{
|
||||
open:window.isHomePage,
|
||||
explorerViewMethod: "icon",
|
||||
sortMethod:"timePos",
|
||||
contextType:"none",
|
||||
menuOpen:false,
|
||||
navigatorLoading:true,
|
||||
navigatorError:false,
|
||||
navigatorErrorMsg:null,
|
||||
modalsLoading:false,
|
||||
storageRefresh:false,
|
||||
modals:{
|
||||
createNewFolder:false,
|
||||
rename:false,
|
||||
move:false,
|
||||
remove:false,
|
||||
share:false,
|
||||
music:false,
|
||||
remoteDownload:false,
|
||||
torrentDownload:false,
|
||||
},
|
||||
snackbar:{
|
||||
toggle:false,
|
||||
vertical:"top",
|
||||
horizontal:"center",
|
||||
msg:"",
|
||||
color:"",
|
||||
}
|
||||
},
|
||||
explorer:{
|
||||
fileList:[],
|
||||
fileSave:false,
|
||||
dirList:[
|
||||
],
|
||||
selected:[{path:"/",name:window.fileInfo.name,type:"file"}],
|
||||
selectProps:{
|
||||
isMultiple:false,
|
||||
withFolder:false,
|
||||
withFile:true,
|
||||
},
|
||||
imgPreview:{
|
||||
first:null,
|
||||
other:[],
|
||||
},
|
||||
keywords:null,
|
||||
}
|
||||
};
|
||||
|
||||
let store = createStore(cloureveApp,defaultStatus)
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<MarkdownApp/>
|
||||
</Provider>
|
||||
, document.getElementById('root'));
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import CssBaseline from '@material-ui/core/CssBaseline';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import Navbar from "../component/Navbar.js"
|
||||
import AlertBar from "../component/Snackbar"
|
||||
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles';
|
||||
import MyShare from '../component/MyShare'
|
||||
const theme = createMuiTheme(window.colorTheme);
|
||||
const styles = theme => ({
|
||||
|
||||
root: {
|
||||
display: 'flex',
|
||||
},
|
||||
content: {
|
||||
flexGrow: 1,
|
||||
padding: theme.spacing.unit * 0,
|
||||
minWidth: 0,
|
||||
},
|
||||
toolbar: theme.mixins.toolbar,
|
||||
});
|
||||
|
||||
class MyShareApp extends Component {
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
return (
|
||||
<React.Fragment>
|
||||
<MuiThemeProvider theme={theme}>
|
||||
<div className={classes.root} id="container">
|
||||
<CssBaseline />
|
||||
<AlertBar/>
|
||||
<Navbar />
|
||||
<main className={classes.content}>
|
||||
<div className={classes.toolbar} />
|
||||
<MyShare/>
|
||||
</main>
|
||||
</div></MuiThemeProvider>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
MyShareApp.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default withStyles(styles)(MyShareApp);
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import { Provider } from 'react-redux'
|
||||
import { createStore } from 'redux'
|
||||
import MyShareApp from "./myShare.app"
|
||||
import cloureveApp from '../reducers'
|
||||
|
||||
const defaultStatus = {
|
||||
navigator:{
|
||||
path:window.path,
|
||||
refresh:true,
|
||||
},
|
||||
viewUpdate:{
|
||||
open:window.isHomePage,
|
||||
explorerViewMethod: "icon",
|
||||
sortMethod:"timePos",
|
||||
contextType:"none",
|
||||
menuOpen:false,
|
||||
navigatorLoading:true,
|
||||
navigatorError:false,
|
||||
navigatorErrorMsg:null,
|
||||
modalsLoading:false,
|
||||
storageRefresh:false,
|
||||
modals:{
|
||||
createNewFolder:false,
|
||||
rename:false,
|
||||
move:false,
|
||||
remove:false,
|
||||
share:false,
|
||||
music:false,
|
||||
remoteDownload:false,
|
||||
torrentDownload:false,
|
||||
},
|
||||
snackbar:{
|
||||
toggle:false,
|
||||
vertical:"top",
|
||||
horizontal:"center",
|
||||
msg:"",
|
||||
color:"",
|
||||
}
|
||||
},
|
||||
explorer:{
|
||||
fileList:[],
|
||||
dirList:[
|
||||
],
|
||||
selected:[],
|
||||
selectProps:{
|
||||
isMultiple:false,
|
||||
withFolder:false,
|
||||
withFile:false,
|
||||
},
|
||||
imgPreview:{
|
||||
first:null,
|
||||
other:[],
|
||||
},
|
||||
keywords:null,
|
||||
}
|
||||
};
|
||||
|
||||
let store = createStore(cloureveApp,defaultStatus)
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<MyShareApp/>
|
||||
</Provider>
|
||||
, document.getElementById('root'));
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import CssBaseline from '@material-ui/core/CssBaseline';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import Navbar from "../component/Navbar.js"
|
||||
import AlertBar from "../component/Snackbar"
|
||||
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles';
|
||||
import Profile from '../component/Profile'
|
||||
const theme = createMuiTheme(window.colorTheme);
|
||||
const styles = theme => ({
|
||||
|
||||
root: {
|
||||
display: 'flex',
|
||||
},
|
||||
content: {
|
||||
flexGrow: 1,
|
||||
padding: theme.spacing.unit * 0,
|
||||
minWidth: 0,
|
||||
},
|
||||
toolbar: theme.mixins.toolbar,
|
||||
});
|
||||
|
||||
class ProfileApp extends Component {
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
return (
|
||||
<React.Fragment>
|
||||
<MuiThemeProvider theme={theme}>
|
||||
<div className={classes.root} id="container">
|
||||
<CssBaseline />
|
||||
<AlertBar/>
|
||||
<Navbar />
|
||||
<main className={classes.content}>
|
||||
<div className={classes.toolbar} />
|
||||
<Profile/>
|
||||
</main>
|
||||
</div></MuiThemeProvider>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ProfileApp.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default withStyles(styles)(ProfileApp);
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import { Provider } from 'react-redux'
|
||||
import { createStore } from 'redux'
|
||||
import ProfileApp from "./profile.app"
|
||||
import cloureveApp from '../reducers'
|
||||
|
||||
const defaultStatus = {
|
||||
navigator:{
|
||||
path:window.path,
|
||||
refresh:true,
|
||||
},
|
||||
viewUpdate:{
|
||||
open:window.isHomePage,
|
||||
explorerViewMethod: "icon",
|
||||
sortMethod:"timePos",
|
||||
contextType:"none",
|
||||
menuOpen:false,
|
||||
navigatorLoading:true,
|
||||
navigatorError:false,
|
||||
navigatorErrorMsg:null,
|
||||
modalsLoading:false,
|
||||
storageRefresh:false,
|
||||
modals:{
|
||||
createNewFolder:false,
|
||||
rename:false,
|
||||
move:false,
|
||||
remove:false,
|
||||
share:false,
|
||||
music:false,
|
||||
remoteDownload:false,
|
||||
torrentDownload:false,
|
||||
},
|
||||
snackbar:{
|
||||
toggle:false,
|
||||
vertical:"top",
|
||||
horizontal:"center",
|
||||
msg:"",
|
||||
color:"",
|
||||
}
|
||||
},
|
||||
explorer:{
|
||||
fileList:[],
|
||||
dirList:[
|
||||
],
|
||||
selected:[],
|
||||
selectProps:{
|
||||
isMultiple:false,
|
||||
withFolder:false,
|
||||
withFile:false,
|
||||
},
|
||||
imgPreview:{
|
||||
first:null,
|
||||
other:[],
|
||||
},
|
||||
keywords:null,
|
||||
}
|
||||
};
|
||||
|
||||
let store = createStore(cloureveApp,defaultStatus)
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<ProfileApp/>
|
||||
</Provider>
|
||||
, document.getElementById('root'));
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import CssBaseline from '@material-ui/core/CssBaseline';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import Navbar from "../component/Navbar.js"
|
||||
import AlertBar from "../component/Snackbar"
|
||||
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles';
|
||||
import Search from '../component/Search'
|
||||
const theme = createMuiTheme(window.colorTheme);
|
||||
const styles = theme => ({
|
||||
|
||||
root: {
|
||||
display: 'flex',
|
||||
},
|
||||
content: {
|
||||
flexGrow: 1,
|
||||
padding: theme.spacing.unit * 0,
|
||||
minWidth: 0,
|
||||
},
|
||||
toolbar: theme.mixins.toolbar,
|
||||
});
|
||||
|
||||
class SearchApp extends Component {
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
return (
|
||||
<React.Fragment>
|
||||
<MuiThemeProvider theme={theme}>
|
||||
<div className={classes.root} id="container">
|
||||
<CssBaseline />
|
||||
<AlertBar/>
|
||||
<Navbar />
|
||||
<main className={classes.content}>
|
||||
<div className={classes.toolbar} />
|
||||
<Search/>
|
||||
</main>
|
||||
</div></MuiThemeProvider>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SearchApp.propTypes = {
|
||||
classes: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default withStyles(styles)(SearchApp);
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import { Provider } from 'react-redux'
|
||||
import { createStore } from 'redux'
|
||||
import SearchApp from "./search.app"
|
||||
import cloureveApp from '../reducers'
|
||||
|
||||
const defaultStatus = {
|
||||
navigator:{
|
||||
path:window.path,
|
||||
refresh:true,
|
||||
},
|
||||
viewUpdate:{
|
||||
open:window.isHomePage,
|
||||
explorerViewMethod: "icon",
|
||||
sortMethod:"timePos",
|
||||
contextType:"none",
|
||||
menuOpen:false,
|
||||
navigatorLoading:true,
|
||||
navigatorError:false,
|
||||
navigatorErrorMsg:null,
|
||||
modalsLoading:false,
|
||||
storageRefresh:false,
|
||||
modals:{
|
||||
createNewFolder:false,
|
||||
rename:false,
|
||||
move:false,
|
||||
remove:false,
|
||||
share:false,
|
||||
music:false,
|
||||
remoteDownload:false,
|
||||
torrentDownload:false,
|
||||
},
|
||||
snackbar:{
|
||||
toggle:false,
|
||||
vertical:"top",
|
||||
horizontal:"center",
|
||||
msg:"",
|
||||
color:"",
|
||||
}
|
||||
},
|
||||
explorer:{
|
||||
fileList:[],
|
||||
dirList:[
|
||||
],
|
||||
selected:[],
|
||||
selectProps:{
|
||||
isMultiple:false,
|
||||
withFolder:false,
|
||||
withFile:false,
|
||||
},
|
||||
imgPreview:{
|
||||
first:null,
|
||||
other:[],
|
||||
},
|
||||
keywords:null,
|
||||
}
|
||||
};
|
||||
|
||||
let store = createStore(cloureveApp,defaultStatus)
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<SearchApp/>
|
||||
</Provider>
|
||||
, document.getElementById('root'));
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue