Commit 4a33873b by zhanghaozhe

prettier

parent 212a67b6
build
node_modules
public
\ No newline at end of file
{
}
\ No newline at end of file
"semi": false
}
const postcssNormalize = require('postcss-normalize')
const path = require('path')
const postcssNormalize = require("postcss-normalize")
const path = require("path")
module.exports = {
stories: ['../src/common/**/*.stories.tsx'],
stories: ["../src/common/**/*.stories.tsx"],
addons: [
{
name: '@storybook/preset-typescript',
name: "@storybook/preset-typescript",
options: {
tsLoaderOptions: {
configFile: path.resolve(__dirname, '../tsconfig.json'),
configFile: path.resolve(__dirname, "../tsconfig.json"),
},
},
},
'@storybook/addon-actions',
'@storybook/addon-links',
'@storybook/addon-knobs',
"@storybook/addon-actions",
"@storybook/addon-links",
"@storybook/addon-knobs",
],
webpackFinal: async config => {
webpackFinal: async (config) => {
config.module.rules.push({
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
"style-loader",
"css-loader",
{
loader: require.resolve('postcss-loader'),
loader: require.resolve("postcss-loader"),
options: {
ident: 'postcss',
ident: "postcss",
plugins: () => [
require('postcss-flexbugs-fixes'),
require('postcss-preset-env')({
require("postcss-flexbugs-fixes"),
require("postcss-preset-env")({
autoprefixer: {
flexbox: 'no-2009',
flexbox: "no-2009",
},
stage: 3,
}),
......@@ -45,10 +45,10 @@ module.exports = {
},
},
{
loader: 'sass-loader',
loader: "sass-loader",
},
],
})
return config;
return config
},
};
}
import './style.scss'
import '../src/assets/font/iconfont.css'
import '@csstools/normalize.css/normalize.css'
\ No newline at end of file
import "./style.scss"
import "../src/assets/font/iconfont.css"
import "@csstools/normalize.css/normalize.css"
......@@ -22,4 +22,4 @@
width: 375px;
height: 667px;
background: #fff;
}
\ No newline at end of file
}
新m端前端项目
\ No newline at end of file
新 m 端前端项目
'use strict';
"use strict"
const fs = require('fs');
const path = require('path');
const paths = require('./paths');
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')];
delete require.cache[require.resolve("./paths")]
const NODE_ENV = process.env.NODE_ENV;
const NODE_ENV = process.env.NODE_ENV
if (!NODE_ENV) {
throw new Error(
'The NODE_ENV environment variable is required but was not specified.'
);
"The NODE_ENV environment variable is required but was not specified."
)
}
// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
......@@ -21,24 +21,24 @@ const dotenvFiles = [
// 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`,
NODE_ENV !== "test" && `${paths.dotenv}.local`,
paths.dotenv,
].filter(Boolean);
].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 => {
dotenvFiles.forEach((dotenvFile) => {
if (fs.existsSync(dotenvFile)) {
require('dotenv-expand')(
require('dotenv').config({
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:
......@@ -49,29 +49,29 @@ dotenvFiles.forEach(dotenvFile => {
// 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 || '')
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);
.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;
const REACT_APP = /^REACT_APP_/i
function getClientEnvironment(publicUrl) {
const raw = Object.keys(process.env)
.filter(key => REACT_APP.test(key))
.filter((key) => REACT_APP.test(key))
.reduce(
(env, key) => {
env[key] = process.env[key];
return env;
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',
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
......@@ -86,16 +86,16 @@ function getClientEnvironment(publicUrl) {
WDS_SOCKET_PATH: process.env.WDS_SOCKET_PATH,
WDS_SOCKET_PORT: process.env.WDS_SOCKET_PORT,
}
);
)
// 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;
"process.env": Object.keys(raw).reduce((env, key) => {
env[key] = JSON.stringify(raw[key])
return env
}, {}),
};
}
return { raw, stringified };
return { raw, stringified }
}
module.exports = getClientEnvironment;
module.exports = getClientEnvironment
'use strict';
"use strict"
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const chalk = require('react-dev-utils/chalk');
const paths = require('./paths');
const fs = require("fs")
const path = require("path")
const crypto = require("crypto")
const chalk = require("react-dev-utils/chalk")
const paths = require("./paths")
// Ensure the certificate and key provided are valid and if not
// throw an easy to debug error
function validateKeyAndCerts({ cert, key, keyFile, crtFile }) {
let encrypted;
let encrypted
try {
// publicEncrypt will throw an error with an invalid cert
encrypted = crypto.publicEncrypt(cert, Buffer.from('test'));
encrypted = crypto.publicEncrypt(cert, Buffer.from("test"))
} catch (err) {
throw new Error(
`The certificate "${chalk.yellow(crtFile)}" is invalid.\n${err.message}`
);
)
}
try {
// privateDecrypt will throw an error with an invalid key
crypto.privateDecrypt(key, encrypted);
crypto.privateDecrypt(key, encrypted)
} catch (err) {
throw new Error(
`The certificate key "${chalk.yellow(keyFile)}" is invalid.\n${
err.message
}`
);
)
}
}
......@@ -38,29 +38,29 @@ function readEnvFile(file, type) {
`You specified ${chalk.cyan(
type
)} in your env, but the file "${chalk.yellow(file)}" can't be found.`
);
)
}
return fs.readFileSync(file);
return fs.readFileSync(file)
}
// Get the https config
// Return cert files if provided in env, otherwise just true or false
function getHttpsConfig() {
const { SSL_CRT_FILE, SSL_KEY_FILE, HTTPS } = process.env;
const isHttps = HTTPS === 'true';
const { SSL_CRT_FILE, SSL_KEY_FILE, HTTPS } = process.env
const isHttps = HTTPS === "true"
if (isHttps && SSL_CRT_FILE && SSL_KEY_FILE) {
const crtFile = path.resolve(paths.appPath, SSL_CRT_FILE);
const keyFile = path.resolve(paths.appPath, SSL_KEY_FILE);
const crtFile = path.resolve(paths.appPath, SSL_CRT_FILE)
const keyFile = path.resolve(paths.appPath, SSL_KEY_FILE)
const config = {
cert: readEnvFile(crtFile, 'SSL_CRT_FILE'),
key: readEnvFile(keyFile, 'SSL_KEY_FILE'),
};
cert: readEnvFile(crtFile, "SSL_CRT_FILE"),
key: readEnvFile(keyFile, "SSL_KEY_FILE"),
}
validateKeyAndCerts({ ...config, keyFile, crtFile });
return config;
validateKeyAndCerts({ ...config, keyFile, crtFile })
return config
}
return isHttps;
return isHttps
}
module.exports = getHttpsConfig;
module.exports = getHttpsConfig
'use strict';
"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 = {};';
return "module.exports = {};"
},
getCacheKey() {
// The output is always the same.
return 'cssTransform';
return "cssTransform"
},
};
}
'use strict';
"use strict"
const path = require('path');
const camelcase = require('camelcase');
const path = require("path")
const camelcase = require("camelcase")
// 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));
const assetFilename = JSON.stringify(path.basename(filename))
if (filename.match(/\.svg$/)) {
// Based on how SVGR generates a component name:
// https://github.com/smooth-code/svgr/blob/01b194cf967347d43d4cbe6b434404731b87cf27/packages/core/src/state.js#L6
const pascalCaseFilename = camelcase(path.parse(filename).name, {
pascalCase: true,
});
const componentName = `Svg${pascalCaseFilename}`;
})
const componentName = `Svg${pascalCaseFilename}`
return `const React = require('react');
module.exports = {
__esModule: true,
......@@ -32,9 +32,9 @@ module.exports = {
})
};
}),
};`;
};`
}
return `module.exports = ${assetFilename};`;
return `module.exports = ${assetFilename};`
},
};
}
'use strict';
"use strict"
const fs = require('fs');
const path = require('path');
const paths = require('./paths');
const chalk = require('react-dev-utils/chalk');
const resolve = require('resolve');
const fs = require("fs")
const path = require("path")
const paths = require("./paths")
const chalk = require("react-dev-utils/chalk")
const resolve = require("resolve")
/**
* Get additional module paths based on the baseUrl of a compilerOptions object.
......@@ -12,7 +12,7 @@ const resolve = require('resolve');
* @param {Object} options
*/
function getAdditionalModulePaths(options = {}) {
const baseUrl = options.baseUrl;
const baseUrl = options.baseUrl
// We need to explicitly check for null and undefined (and not a falsy value) because
// TypeScript treats an empty string as `.`.
......@@ -21,21 +21,21 @@ function getAdditionalModulePaths(options = {}) {
// Note that NODE_PATH is deprecated and will be removed
// in the next major release of create-react-app.
const nodePath = process.env.NODE_PATH || '';
return nodePath.split(path.delimiter).filter(Boolean);
const nodePath = process.env.NODE_PATH || ""
return nodePath.split(path.delimiter).filter(Boolean)
}
const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
const baseUrlResolved = path.resolve(paths.appPath, baseUrl)
// We don't need to do anything if `baseUrl` is set to `node_modules`. This is
// the default behavior.
if (path.relative(paths.appNodeModules, baseUrlResolved) === '') {
return null;
if (path.relative(paths.appNodeModules, baseUrlResolved) === "") {
return null
}
// Allow the user set the `baseUrl` to `appSrc`.
if (path.relative(paths.appSrc, baseUrlResolved) === '') {
return [paths.appSrc];
if (path.relative(paths.appSrc, baseUrlResolved) === "") {
return [paths.appSrc]
}
// If the path is equal to the root directory we ignore it here.
......@@ -43,17 +43,17 @@ function getAdditionalModulePaths(options = {}) {
// not transpiled outside of `src`. We do allow importing them with the
// absolute path (e.g. `src/Components/Button.js`) but we set that up with
// an alias.
if (path.relative(paths.appPath, baseUrlResolved) === '') {
return null;
if (path.relative(paths.appPath, baseUrlResolved) === "") {
return null
}
// Otherwise, throw an error.
throw new Error(
chalk.red.bold(
"Your project's `baseUrl` can only be set to `src` or `node_modules`." +
' Create React App does not support other values at this time.'
" Create React App does not support other values at this time."
)
);
)
}
/**
......@@ -62,18 +62,18 @@ function getAdditionalModulePaths(options = {}) {
* @param {*} options
*/
function getWebpackAliases(options = {}) {
const baseUrl = options.baseUrl;
const baseUrl = options.baseUrl
if (!baseUrl) {
return {};
return {}
}
const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
const baseUrlResolved = path.resolve(paths.appPath, baseUrl)
if (path.relative(paths.appPath, baseUrlResolved) === '') {
if (path.relative(paths.appPath, baseUrlResolved) === "") {
return {
src: paths.appSrc,
};
}
}
}
......@@ -83,59 +83,59 @@ function getWebpackAliases(options = {}) {
* @param {*} options
*/
function getJestAliases(options = {}) {
const baseUrl = options.baseUrl;
const baseUrl = options.baseUrl
if (!baseUrl) {
return {};
return {}
}
const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
const baseUrlResolved = path.resolve(paths.appPath, baseUrl)
if (path.relative(paths.appPath, baseUrlResolved) === '') {
if (path.relative(paths.appPath, baseUrlResolved) === "") {
return {
'^src/(.*)$': '<rootDir>/src/$1',
};
"^src/(.*)$": "<rootDir>/src/$1",
}
}
}
function getModules() {
// Check if TypeScript is setup
const hasTsConfig = fs.existsSync(paths.appTsConfig);
const hasJsConfig = fs.existsSync(paths.appJsConfig);
const hasTsConfig = fs.existsSync(paths.appTsConfig)
const hasJsConfig = fs.existsSync(paths.appJsConfig)
if (hasTsConfig && hasJsConfig) {
throw new Error(
'You have both a tsconfig.json and a jsconfig.json. If you are using TypeScript please remove your jsconfig.json file.'
);
"You have both a tsconfig.json and a jsconfig.json. If you are using TypeScript please remove your jsconfig.json file."
)
}
let config;
let config
// If there's a tsconfig.json we assume it's a
// TypeScript project and set up the config
// based on tsconfig.json
if (hasTsConfig) {
const ts = require(resolve.sync('typescript', {
const ts = require(resolve.sync("typescript", {
basedir: paths.appNodeModules,
}));
config = ts.readConfigFile(paths.appTsConfig, ts.sys.readFile).config;
}))
config = ts.readConfigFile(paths.appTsConfig, ts.sys.readFile).config
// Otherwise we'll check if there is jsconfig.json
// for non TS projects.
} else if (hasJsConfig) {
config = require(paths.appJsConfig);
config = require(paths.appJsConfig)
}
config = config || {};
const options = config.compilerOptions || {};
config = config || {}
const options = config.compilerOptions || {}
const additionalModulePaths = getAdditionalModulePaths(options);
const additionalModulePaths = getAdditionalModulePaths(options)
return {
additionalModulePaths: additionalModulePaths,
webpackAliases: getWebpackAliases(options),
jestAliases: getJestAliases(options),
hasTsConfig,
};
}
}
module.exports = getModules();
module.exports = getModules()
'use strict';
"use strict"
const path = require('path');
const fs = require('fs');
const getPublicUrlOrPath = require('react-dev-utils/getPublicUrlOrPath');
const path = require("path")
const fs = require("fs")
const getPublicUrlOrPath = require("react-dev-utils/getPublicUrlOrPath")
// 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 appDirectory = fs.realpathSync(process.cwd())
const resolveApp = (relativePath) => path.resolve(appDirectory, relativePath)
// We use `PUBLIC_URL` environment variable or "homepage" field to infer
// "public path" at which the app is served.
......@@ -16,57 +16,55 @@ const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
// 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.
const publicUrlOrPath = getPublicUrlOrPath(
process.env.NODE_ENV === 'development',
require(resolveApp('package.json')).homepage,
process.env.NODE_ENV === "development",
require(resolveApp("package.json")).homepage,
process.env.PUBLIC_URL
);
)
const moduleFileExtensions = [
'web.mjs',
'mjs',
'web.js',
'js',
'web.ts',
'ts',
'web.tsx',
'tsx',
'json',
'web.jsx',
'jsx',
];
"web.mjs",
"mjs",
"web.js",
"js",
"web.ts",
"ts",
"web.tsx",
"tsx",
"json",
"web.jsx",
"jsx",
]
// Resolve file paths in the same order as webpack
const resolveModule = (resolveFn, filePath) => {
const extension = moduleFileExtensions.find(extension =>
const extension = moduleFileExtensions.find((extension) =>
fs.existsSync(resolveFn(`${filePath}.${extension}`))
);
)
if (extension) {
return resolveFn(`${filePath}.${extension}`);
return resolveFn(`${filePath}.${extension}`)
}
return resolveFn(`${filePath}.js`);
};
return resolveFn(`${filePath}.js`)
}
// 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: resolveModule(resolveApp, 'src/index'),
appPackageJson: resolveApp('package.json'),
appSrc: resolveApp('src'),
appTsConfig: resolveApp('tsconfig.json'),
appJsConfig: resolveApp('jsconfig.json'),
yarnLockFile: resolveApp('yarn.lock'),
testsSetup: resolveModule(resolveApp, 'src/setupTests'),
proxySetup: resolveApp('src/setupProxy.js'),
appNodeModules: resolveApp('node_modules'),
dotenv: resolveApp(".env"),
appPath: resolveApp("."),
appBuild: resolveApp("build"),
appPublic: resolveApp("public"),
appHtml: resolveApp("public/index.html"),
appIndexJs: resolveModule(resolveApp, "src/index"),
appPackageJson: resolveApp("package.json"),
appSrc: resolveApp("src"),
appTsConfig: resolveApp("tsconfig.json"),
appJsConfig: resolveApp("jsconfig.json"),
yarnLockFile: resolveApp("yarn.lock"),
testsSetup: resolveModule(resolveApp, "src/setupTests"),
proxySetup: resolveApp("src/setupProxy.js"),
appNodeModules: resolveApp("node_modules"),
publicUrlOrPath,
};
}
module.exports.moduleFileExtensions = moduleFileExtensions;
module.exports.moduleFileExtensions = moduleFileExtensions
'use strict';
"use strict"
const { resolveModuleName } = require('ts-pnp');
const { resolveModuleName } = require("ts-pnp")
exports.resolveModuleName = (
typescript,
......@@ -15,8 +15,8 @@ exports.resolveModuleName = (
compilerOptions,
resolutionHost,
typescript.resolveModuleName
);
};
)
}
exports.resolveTypeReferenceDirective = (
typescript,
......@@ -31,5 +31,5 @@ exports.resolveTypeReferenceDirective = (
compilerOptions,
resolutionHost,
typescript.resolveTypeReferenceDirective
);
};
)
}
'use strict';
"use strict"
const fs = require('fs');
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 redirectServedPath = require('react-dev-utils/redirectServedPathMiddleware');
const paths = require('./paths');
const getHttpsConfig = require('./getHttpsConfig');
const fs = require("fs")
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 redirectServedPath = require("react-dev-utils/redirectServedPathMiddleware")
const paths = require("./paths")
const getHttpsConfig = require("./getHttpsConfig")
const host = process.env.HOST || '0.0.0.0';
const sockHost = process.env.WDS_SOCKET_HOST;
const sockPath = process.env.WDS_SOCKET_PATH; // default: '/sockjs-node'
const sockPort = process.env.WDS_SOCKET_PORT;
const host = process.env.HOST || "0.0.0.0"
const sockHost = process.env.WDS_SOCKET_HOST
const sockPath = process.env.WDS_SOCKET_PATH // default: '/sockjs-node'
const sockPort = process.env.WDS_SOCKET_PORT
module.exports = function(proxy, allowedHost) {
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:
......@@ -33,12 +33,12 @@ module.exports = function(proxy, allowedHost) {
// 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',
!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',
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
......@@ -65,7 +65,7 @@ module.exports = function(proxy, allowedHost) {
hot: true,
// Use 'ws' instead of 'sockjs-node' on server since we're using native
// websockets in `webpackHotDevClient`.
transportMode: 'ws',
transportMode: "ws",
// Prevent a WS client from getting injected as we're already including
// `webpackHotDevClient`.
injectClient: false,
......@@ -106,25 +106,25 @@ module.exports = function(proxy, allowedHost) {
// Keep `evalSourceMapMiddleware` and `errorOverlayMiddleware`
// middlewares before `redirectServedPath` otherwise will not have any effect
// This lets us fetch source contents from webpack for the error overlay
app.use(evalSourceMapMiddleware(server));
app.use(evalSourceMapMiddleware(server))
// This lets us open files from the runtime error overlay.
app.use(errorOverlayMiddleware());
app.use(errorOverlayMiddleware())
if (fs.existsSync(paths.proxySetup)) {
// This registers user provided middleware for proxy reasons
require(paths.proxySetup)(app);
require(paths.proxySetup)(app)
}
},
after(app) {
// Redirect to `PUBLIC_URL` or `homepage` from `package.json` if url not match
app.use(redirectServedPath(paths.publicUrlOrPath));
app.use(redirectServedPath(paths.publicUrlOrPath))
// 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(paths.publicUrlOrPath));
app.use(noopServiceWorkerMiddleware(paths.publicUrlOrPath))
},
};
};
}
}
'use strict';
"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';
process.env.REACT_APP_BUILD_ENV = 'development';
process.env.BABEL_ENV = "development"
process.env.NODE_ENV = "development"
process.env.REACT_APP_BUILD_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;
});
process.on("unhandledRejection", (err) => {
throw err
})
// Ensure environment variables are read.
require('../config/env');
require("../config/env")
const fs = require('fs');
const chalk = require('react-dev-utils/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 fs = require("fs")
const chalk = require("react-dev-utils/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 configFactory = require('../config/webpack.config');
const createDevServerConfig = require('../config/webpackDevServer.config');
} = require("react-dev-utils/WebpackDevServerUtils")
const openBrowser = require("react-dev-utils/openBrowser")
const paths = require("../config/paths")
const configFactory = require("../config/webpack.config")
const createDevServerConfig = require("../config/webpackDevServer.config")
const useYarn = fs.existsSync(paths.yarnLockFile);
const isInteractive = process.stdout.isTTY;
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);
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';
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000
const HOST = process.env.HOST || "0.0.0.0"
if (process.env.HOST) {
console.log(
......@@ -52,41 +51,41 @@ if (process.env.HOST) {
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('https://bit.ly/CRA-advanced-config')}`
);
console.log();
`Learn more here: ${chalk.yellow("https://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');
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);
return choosePort(HOST, DEFAULT_PORT)
})
.then(port => {
.then((port) => {
if (port == null) {
// We have not found a port.
return;
return
}
const config = configFactory('development');
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
const appName = require(paths.appPackageJson).name;
const useTypeScript = fs.existsSync(paths.appTsConfig);
const urls = prepareUrls(protocol, HOST, port);
const config = configFactory("development")
const protocol = process.env.HTTPS === "true" ? "https" : "http"
const appName = require(paths.appPackageJson).name
const useTypeScript = fs.existsSync(paths.appTsConfig)
const urls = prepareUrls(protocol, HOST, port)
const devSocket = {
warnings: warnings =>
devServer.sockWrite(devServer.sockets, 'warnings', warnings),
errors: errors =>
devServer.sockWrite(devServer.sockets, 'errors', errors),
};
warnings: (warnings) =>
devServer.sockWrite(devServer.sockets, "warnings", warnings),
errors: (errors) =>
devServer.sockWrite(devServer.sockets, "errors", errors),
}
// Create a webpack compiler that is configured with custom messages.
const compiler = createCompiler({
appName,
......@@ -96,38 +95,38 @@ checkBrowsers(paths.appPath, isInteractive)
useYarn,
useTypeScript,
webpack,
});
})
// Load proxy config
const proxySetting = require(paths.appPackageJson).proxy;
const proxyConfig = prepareProxy(proxySetting, paths.appPublic);
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);
)
const devServer = new WebpackDevServer(compiler, serverConfig)
// Launch WebpackDevServer.
devServer.listen(port, HOST, err => {
devServer.listen(port, HOST, (err) => {
if (err) {
return console.log(err);
return console.log(err)
}
if (isInteractive) {
clearConsole();
clearConsole()
}
console.log(chalk.cyan('Starting the development server...\n'));
openBrowser(urls.localUrlForBrowser);
});
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();
});
});
;["SIGINT", "SIGTERM"].forEach(function (sig) {
process.on(sig, function () {
devServer.close()
process.exit()
})
})
})
.catch(err => {
.catch((err) => {
if (err && err.message) {
console.log(err.message);
console.log(err.message)
}
process.exit(1);
});
process.exit(1)
})
'use strict';
"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 = '';
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;
});
process.on("unhandledRejection", (err) => {
throw err
})
// Ensure environment variables are read.
require('../config/env');
require("../config/env")
const jest = require('jest');
const execSync = require('child_process').execSync;
let argv = process.argv.slice(2);
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;
execSync("git rev-parse --is-inside-work-tree", { stdio: "ignore" })
return true
} catch (e) {
return false;
return false
}
}
function isInMercurialRepository() {
try {
execSync('hg --cwd . root', { stdio: 'ignore' });
return true;
execSync("hg --cwd . root", { stdio: "ignore" })
return true
} catch (e) {
return false;
return false
}
}
......@@ -42,19 +41,18 @@ function isInMercurialRepository() {
// or explicitly running all tests
if (
!process.env.CI &&
argv.indexOf('--coverage') === -1 &&
argv.indexOf('--no-watch') === -1 &&
argv.indexOf('--watchAll') === -1
argv.indexOf("--coverage") === -1 &&
argv.indexOf("--no-watch") === -1 &&
argv.indexOf("--watchAll") === -1
) {
// https://github.com/facebook/create-react-app/issues/5210
const hasSourceControl = isInGitRepository() || isInMercurialRepository();
argv.push(hasSourceControl ? '--watch' : '--watchAll');
const hasSourceControl = isInGitRepository() || isInMercurialRepository()
argv.push(hasSourceControl ? "--watch" : "--watchAll")
}
// Jest doesn't have this option so we'll remove it
if (argv.indexOf('--no-watch') !== -1) {
argv = argv.filter(arg => arg !== '--no-watch');
if (argv.indexOf("--no-watch") !== -1) {
argv = argv.filter((arg) => arg !== "--no-watch")
}
jest.run(argv);
jest.run(argv)
import React, { PureComponent } from 'react';
import React, { PureComponent } from "react"
function setSize() {
document.body.style.height = `${window.innerHeight}px`
document.getElementById('root').style.height = `${window.innerHeight}px`
document.documentElement.style.height = `${window.innerHeight}px`
document.body.style.height = `${window.innerHeight}px`
document.getElementById("root").style.height = `${window.innerHeight}px`
document.documentElement.style.height = `${window.innerHeight}px`
}
export default function (WrappedComponent) {
return class extends PureComponent {
componentDidMount() {
setSize()
window.addEventListener('resize', setSize)
}
componentWillUnmount() {
document.body.style.height = `auto`
document.getElementById('root').style.height = `auto`
document.documentElement.style.height = 'auto'
window.removeEventListener('resize', setSize)
}
return class extends PureComponent {
componentDidMount() {
setSize()
window.addEventListener("resize", setSize)
}
componentWillUnmount() {
document.body.style.height = `auto`
document.getElementById("root").style.height = `auto`
document.documentElement.style.height = "auto"
window.removeEventListener("resize", setSize)
}
render() {
return (
<WrappedComponent {...this.props}/>
);
}
render() {
return <WrappedComponent {...this.props} />
}
}
}
import React, { PureComponent } from 'react'
import NavBar from 'src/common/NavBar'
import React, { PureComponent } from "react"
import NavBar from "src/common/NavBar"
export default function WithTab(WrappedComponent) {
return class extends PureComponent {
render() {
return (
<>
<WrappedComponent {...this.props}/>
<NavBar/>
</>
)
}
return class extends PureComponent {
render() {
return (
<>
<WrappedComponent {...this.props} />
<NavBar />
</>
)
}
}
\ No newline at end of file
}
}
export {default as WithTab} from './WithTab'
export {default as WithFullSize} from './WithFullSize'
\ No newline at end of file
export { default as WithTab } from "./WithTab"
export { default as WithFullSize } from "./WithFullSize"
......@@ -11,7 +11,7 @@ $main-color: #09f; // 主体颜色
// 字体
$font-family-zh: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB",
"Microsoft YaHei", "微软雅黑", Arial, sans-serif;
"Microsoft YaHei", "微软雅黑", Arial, sans-serif;
$font-family-en: Arial, sans-serif !default;
// 盒子模型
......@@ -131,7 +131,7 @@ body {
padding-bottom: constant(safe-area-inset-bottom);
}
img{
img {
max-width: 100%;
}
......@@ -328,13 +328,13 @@ input[type="radio"]:checked:before {
height: 48px;
box-shadow: 0 0 3px #9a9a9a;
.label, .track, .button {
.label,
.track,
.button {
height: 48px;
}
}
}
}
.close {
......
......@@ -4,7 +4,7 @@
// 行内元素也可以使用 flex 布局
// .box-example { display: inline-flex; }
// 以下6个属性设置在容器上
// 以下 6 个属性设置在容器上
// 1. flex-direction --> 子项目排列的方向
// row 默认,水平从左到右
......@@ -31,7 +31,7 @@
// flex-end 交叉轴的终点对齐
// center 交叉轴的中点对齐
// baseline 子项目的第一行文字的基线对齐
// stretch 默认值,如果子项目未设置高度或设为auto,将占满整个容器的高度
// stretch 默认值,如果子项目未设置高度或设为 auto,将占满整个容器的高度
// 6. align-content 定义了多根轴线的对齐方式,如果子项目只有一根轴线,则该属性无效。
// flex-start 与交叉轴的起点对齐。
......@@ -41,28 +41,28 @@
// space-around 每根轴线两侧的间隔都相等,所以轴线之间的间隔比轴线与边框的间隔大一倍
// stretch 默认值,轴线占满整个交叉轴
// 以下6个属性设置在子项目上。
// 以下 6 个属性设置在子项目上。
// 1. order 定义子项目的排列顺序,数值越小,排位越靠前。默认值为0.
// 1. order 定义子项目的排列顺序,数值越小,排位越靠前。默认值为 0.
// 2. flex-grow 定义子项目放大比例,默认为0,即如果存在剩余空间,也不放大。
// 如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。
// 如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍
// 2. flex-grow 定义子项目放大比例,默认为 0,即如果存在剩余空间,也不放大。
// 如果所有项目的 flex-grow 属性都为 1,则它们将等分剩余空间(如果有的话)。
// 如果一个项目的 flex-grow 属性为 2,其他项目都为 1,则前者占据的剩余空间将比其他项多一倍
// 3. flex-shrink 定义了子项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。
// 如果所有项目的flex-shrink属性都为1,当空间不足时,都将等比例缩小。
// 如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小。
// 3. flex-shrink 定义了子项目的缩小比例,默认为 1,即如果空间不足,该项目将缩小。
// 如果所有项目的 flex-shrink 属性都为 1,当空间不足时,都将等比例缩小。
// 如果一个项目的 flex-shrink 属性为 0,其他项目都为 1,则空间不足时,前者不缩小。
// 4. flex-basis 属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。
// 浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。
// 它可以设为跟width或height属性一样的值(比如350px),则项目将占据固定空间。
// 浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为 auto,即项目的本来大小。
// 它可以设为跟 width 或 height 属性一样的值(比如 350px),则项目将占据固定空间。
// 5. flex 该属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。
// 5. flex 该属性是 flex-grow, flex-shrink 和 flex-basis 的简写,默认值为 0 1 auto。后两个属性可选。
// 该属性有两个快捷值:auto (1 1 auto) 和 none (0 0 auto)
// 建议优先使用这个 flex 属性,而不是单独写三个分离的属性,因为浏览器会推算相关值。
// align-self 允许单个项目有与其他项目不一样的对齐方式,可覆盖 align-items 属性。
// 默认值为 auto,表示继承父元素的 align-items 属性,如果没有父元素,则等同于 stretch
// 该属性可能取6个值,除了 auto ,其他都与 align-items 属性完全一致。
// 该属性可能取 6 个值,除了 auto ,其他都与 align-items 属性完全一致。
// ------------------------------------------------------------
\ No newline at end of file
// ------------------------------------------------------------
@mixin fontFamily($font){
font-family: $font, "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB",
"Microsoft YaHei", "微软雅黑", Arial, sans-serif;;
}
\ No newline at end of file
@mixin fontFamily($font) {
font-family: $font, "Helvetica Neue", Helvetica, "PingFang SC",
"Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
}
......@@ -4,7 +4,7 @@
$active: #09f;
$white: #fff;
$black: #000;
$red: #FF2121;
$red: #ff2121;
$redprice: #ff3131;
$color_333: #333;
$color_555: #555;
......@@ -12,14 +12,13 @@ $color_666: #666;
$color_888: #888;
$color_999: #999;
$color_606: #606060;
$color_bbb: #BBB;
$color_bbb: #bbb;
$color_202426: #202426;
$color_4B4B4B: #4B4B4B;
$color_FE2F2F: #FE2F2F;
$color_FF4000: #FF4000;
$color_FF0000: #FF0000;
$color_525B65: #525B65;
$color_4B4B4B: #4b4b4b;
$color_FE2F2F: #fe2f2f;
$color_FF4000: #ff4000;
$color_FF0000: #ff0000;
$color_525B65: #525b65;
/*
* @ 文字大小
......@@ -35,48 +34,46 @@ $font_16: 16px;
$font_14: 14px;
$font_12: 12px;
/*
* @ 背景颜色
*/
$bg_active: #09f;
$bg_0078FF: #0078FF;
$bg_0080FF: #0080FF;
$bg_0078FF: #0078ff;
$bg_0080FF: #0080ff;
$bg_fff: #fff;
$bg_000: #000;
$bg_f4f4f4: #f4f4f4;
$bg_f5f5f5: #f5f5f5;
$bg_f7f9fc: #f7f9fc;
$bg_EBEFF5: #EBEFF5;
$bg_EBEFF5: #ebeff5;
$bg_ccc: #ccc;
$bg_333: #333;
$bg_666: #666;
$bg_999: #999;
$bg_82BBFB: #82BBFB;
$bg_EBC05A: #EBC05A;
$bg_EBA216: #EBA216;
$bg_82BBFB: #82bbfb;
$bg_EBC05A: #ebc05a;
$bg_EBA216: #eba216;
$bg_ff9898: #ff9898;
$bg_ff3131: #ff3131;
$bg_FFF8EB: #FFF8EB;
$bg_FFE400: #FFE400;
$bg_FFA200: #FFA200;
$bg_FE2F2F: #FE2F2F;
$bg_FADD29: #FADD29;
$bg_E7E7E7: #E7E7E7;
$bg_18B4ED: #18B4ED;
$bg_FF4000: #FF4000;
$bg_FD7700: #FD7700;
$bg_FCCD05: #FCCD05;
$bg_FF9500: #FF9500;
$bg_077FD0: #077FD0;
$bg_0198FE: #0198FE;
$bg_F4AAA7: #F4AAA7;
$bg_E02E24: #E02E24;
$bg_007FD0: #007FD0;
$bg_FF0000: #FF0000;
$bg_FFF4CE: #FFF4CE;
$bg_FAFAFA: #FAFAFA;
$bg_FFF8EB: #fff8eb;
$bg_FFE400: #ffe400;
$bg_FFA200: #ffa200;
$bg_FE2F2F: #fe2f2f;
$bg_FADD29: #fadd29;
$bg_E7E7E7: #e7e7e7;
$bg_18B4ED: #18b4ed;
$bg_FF4000: #ff4000;
$bg_FD7700: #fd7700;
$bg_FCCD05: #fccd05;
$bg_FF9500: #ff9500;
$bg_077FD0: #077fd0;
$bg_0198FE: #0198fe;
$bg_F4AAA7: #f4aaa7;
$bg_E02E24: #e02e24;
$bg_007FD0: #007fd0;
$bg_FF0000: #ff0000;
$bg_FFF4CE: #fff4ce;
$bg_FAFAFA: #fafafa;
/*
* @ 分割线颜色
......@@ -84,17 +81,15 @@ $bg_FAFAFA: #FAFAFA;
$sp_ddd: #ddd;
$sp_e7eaf1: #e7eaf1;
/*
* @ 边框颜色
*/
$border_ddd: #ddd;
$border_e7eaf1: #E7EAF1;
$border_e7eaf1: #e7eaf1;
$border_f31: #f31;
$border_ccc: #ccc;
/*
* @ 标签颜色
*/
$E0B97B: #E0B97B;
\ No newline at end of file
$E0B97B: #e0b97b;
This source diff could not be displayed because it is too large. You can view the blob instead.
module.exports = function() {
return {
"@brand-primary": 'green',
"@color-text-base": '#333'
}
}
\ No newline at end of file
module.exports = function () {
return {
"@brand-primary": "green",
"@color-text-base": "#333",
}
}
import React, { Component } from 'react';
import CallApp from 'callapp-lib'
import React, { Component } from "react"
import CallApp from "callapp-lib"
const options = {
scheme: {
protocol: 'julyedu',
host: '',
port: ''
},
intent: {
package: "com.julyapp.julyonline",
scheme: "julyedu",
action: 'julyapp.julyedu',
category: 'category_julyedu'
},
universal: {
host: "api.julyedu.com/action",
pathKey: 'page'
},
appstore: "https://itunes.apple.com/cn/app/id1102275343?mt=8",
yingyongbao: "http://android.myapp.com/myapp/detail.htm?apkName=com.julyapp.julyonline",
fallback: "http://android.myapp.com/myapp/detail.htm?apkName=com.julyapp.julyonline"
scheme: {
protocol: "julyedu",
host: "",
port: "",
},
intent: {
package: "com.julyapp.julyonline",
scheme: "julyedu",
action: "julyapp.julyedu",
category: "category_julyedu",
},
universal: {
host: "api.julyedu.com/action",
pathKey: "page",
},
appstore: "https://itunes.apple.com/cn/app/id1102275343?mt=8",
yingyongbao:
"http://android.myapp.com/myapp/detail.htm?apkName=com.julyapp.julyonline",
fallback:
"http://android.myapp.com/myapp/detail.htm?apkName=com.julyapp.julyonline",
}
class OpenApp extends Component {
callApp = new CallApp(options)
// callApp = null
static defaultProps = {
text: '在APP打开'
}
handleClick = () => {
this.callApp.open({
path: '',
param: {
},
callback: () => {
window.location.href = "http://android.myapp.com/myapp/detail.htm?apkName=com.julyapp.julyonline";
}
});
}
render() {
return (
<div className={this.props.className} onClick={this.handleClick}>{this.props.text}</div>
);
}
callApp = new CallApp(options)
// callApp = null
static defaultProps = {
text: "在APP打开",
}
handleClick = () => {
this.callApp.open({
path: "",
param: {},
callback: () => {
window.location.href =
"http://android.myapp.com/myapp/detail.htm?apkName=com.julyapp.julyonline"
},
})
}
render() {
return (
<div className={this.props.className} onClick={this.handleClick}>
{this.props.text}
</div>
)
}
}
export default OpenApp;
export default OpenApp
import React, { Component } from 'react';
import './index.scss'
import React, { Component } from "react"
import "./index.scss"
import { initCaptchaNC } from "src/utils"
const appkey = 'FFFF0N000000000090FC'
const scene = 'nc_login_h5'
const appkey = "FFFF0N000000000090FC"
const scene = "nc_login_h5"
class CaptchaAli extends Component {
nc = null
el = null
state = {
isLoaded: false
isLoaded: false,
}
componentDidMount() {
const _this = this
this.el && initCaptchaNC(() => {
const nc_token = [appkey, (new Date()).getTime(), Math.random()].join(':');
this.nc = NoCaptcha.init({
renderTo: '#nc',
appkey,
scene,
token: nc_token,
elementID: ['tel'],
bannerHidden: false,
callback(data) {
_this.props.onVerify({
app_key: appkey,
scene,
token: nc_token,
session_id: data.csessionid,
sig: data.sig
})
},
error(s) {
console.log(s)
}
this.el &&
initCaptchaNC(() => {
const nc_token = [appkey, new Date().getTime(), Math.random()].join(":")
this.nc = NoCaptcha.init({
renderTo: "#nc",
appkey,
scene,
token: nc_token,
elementID: ["tel"],
bannerHidden: false,
callback(data) {
_this.props.onVerify({
app_key: appkey,
scene,
token: nc_token,
session_id: data.csessionid,
sig: data.sig,
})
},
error(s) {
console.log(s)
},
})
NoCaptcha.setEnabled(true)
this.nc.reset()
this.props.getInstance(this.nc)
})
NoCaptcha.setEnabled(true);
this.nc.reset()
this.props.getInstance(this.nc)
})
}
render() {
const {mb = 30} = this.props
const { mb = 30 } = this.props
return (
<div id={'captcha'} style={{marginBottom: `${mb}px`}}>
<div id="nc" ref={el => this.el = el}></div>
<div id={"captcha"} style={{ marginBottom: `${mb}px` }}>
<div id="nc" ref={(el) => (this.el = el)}></div>
</div>
);
)
}
}
export default CaptchaAli;
\ No newline at end of file
export default CaptchaAli
......@@ -23,4 +23,4 @@
}
}
}
}
\ No newline at end of file
}
import React, { Component } from 'react';
import { initCaptcha } from 'src/utils';
import { BarLoader } from 'react-spinners';
import './index.scss';
const CAPTCHAID = '6b0f5f6c8f334f3693ee754ba5692e36'
import React, { Component } from "react"
import { initCaptcha } from "src/utils"
import { BarLoader } from "react-spinners"
import "./index.scss"
const CAPTCHAID = "6b0f5f6c8f334f3693ee754ba5692e36"
class Captcha extends Component {
state = {
isReady: false,
}
state = {
isReady: false
}
componentDidMount() {
const {getInstance, handleError, onVerify} = this.props;
const _this = this;
const el = document.getElementById('captcha');
el && initCaptcha(function () {
initNECaptcha({
element: el,
captchaId: CAPTCHAID,
mode: 'float',
width: 'auto',
onReady: function (instance) {
// 验证码一切准备就绪,此时可正常使用验证码的相关功能
_this.setState({
isReady: true
});
},
onVerify: function (err, data) {
onVerify(err,data)
}
},
instance => {
getInstance && getInstance(instance)
},
err => {
handleError && handleError(err)
}
)
})
}
componentDidMount() {
const { getInstance, handleError, onVerify } = this.props
const _this = this
const el = document.getElementById("captcha")
el &&
initCaptcha(function () {
initNECaptcha(
{
element: el,
captchaId: CAPTCHAID,
mode: "float",
width: "auto",
onReady: function (instance) {
// 验证码一切准备就绪,此时可正常使用验证码的相关功能
_this.setState({
isReady: true,
})
},
onVerify: function (err, data) {
onVerify(err, data)
},
},
(instance) => {
getInstance && getInstance(instance)
},
(err) => {
handleError && handleError(err)
}
)
})
}
render() {
return (
<div
className="captcha-container"
style={{
'marginBottom': this.props.mrBtm
}}
>
{
!this.state.isReady &&
<div className="captcha-animation">
<BarLoader />
</div>
}
<div
id={'captcha'}
style={{
'marginBottom': this.props.mrBtm
}}
/>
</div>
);
}
render() {
return (
<div
className="captcha-container"
style={{
marginBottom: this.props.mrBtm,
}}
>
{!this.state.isReady && (
<div className="captcha-animation">
<BarLoader />
</div>
)}
<div
id={"captcha"}
style={{
marginBottom: this.props.mrBtm,
}}
/>
</div>
)
}
}
export default Captcha;
\ No newline at end of file
export default Captcha
......@@ -13,4 +13,4 @@
left: 0;
width: 100%;
height: 100%;
}
\ No newline at end of file
}
import React from 'react'
import './index.scss'
import React from "react"
import "./index.scss"
const Tag = (props) => {
return (
<span className={`state ${props.className}`}>
{props.children}
</span>
)
return <span className={`state ${props.className}`}>{props.children}</span>
}
export default Tag
\ No newline at end of file
export default Tag
.state {
box-sizing: border-box;
border-radius: 0 10px 10px 0;
padding: 1px 5px;
}
\ No newline at end of file
box-sizing: border-box;
border-radius: 0 10px 10px 0;
padding: 1px 5px;
}
@import "src/assets/css/variable";
.clearable-input-wrapper {
position: relative;
position: relative;
input {
width: 300px;
height: 46px;
padding: 15px 0 15px 34px;
border: 1px solid $border_ccc;
border-radius: 3px;
-webkit-appearance: none;
font-size: 15px;
input {
width: 300px;
height: 46px;
padding: 15px 0 15px 34px;
border: 1px solid $border_ccc;
border-radius: 3px;
-webkit-appearance: none;
font-size: 15px;
&::-webkit-input-placeholder {
color: $color_999;
font-size: $font_16;
}
&::-webkit-input-placeholder {
color: $color_999;
font-size: $font_16;
}
}
.iconfont {
position: absolute;
top: 50%;
transform: translateY(-50%);
font-size: 21px;
color: $color_bbb;
}
.iconfont {
position: absolute;
top: 50%;
transform: translateY(-50%);
font-size: 21px;
color: $color_bbb;
}
.clear {
right: 13px;
}
}
\ No newline at end of file
.clear {
right: 13px;
}
}
import React, { Component } from 'react';
import './clearable-input.scss'
import classnames from 'classnames'
import React, { Component } from "react"
import "./clearable-input.scss"
import classnames from "classnames"
class ClearableInput extends Component {
render() {
let {
value,
name,
wrapperClass,
inputClass,
type = 'text',
icon,
setFieldValue,
...rest
} = this.props
let clearIconStyle = {
display: value && value.length ? 'block' : 'none'
}
return (
<div className={classnames('clearable-input-wrapper', wrapperClass)}>
<input
type={type}
value={value}
className={inputClass}
{...rest}
name={name}
/>
{icon}
<i
className={'iconfont icondanseshixintubiao-3 clear'}
onClick={() => {
setFieldValue(name,'')
}}
style={clearIconStyle}
/>
</div>
);
render() {
let {
value,
name,
wrapperClass,
inputClass,
type = "text",
icon,
setFieldValue,
...rest
} = this.props
let clearIconStyle = {
display: value && value.length ? "block" : "none",
}
return (
<div className={classnames("clearable-input-wrapper", wrapperClass)}>
<input
type={type}
value={value}
className={inputClass}
{...rest}
name={name}
/>
{icon}
<i
className={"iconfont icondanseshixintubiao-3 clear"}
onClick={() => {
setFieldValue(name, "")
}}
style={clearIconStyle}
/>
</div>
)
}
}
export default ClearableInput;
\ No newline at end of file
export default ClearableInput
......@@ -11,7 +11,7 @@
border-radius: 4px;
vertical-align: bottom;
}
.course-status{
.course-status {
width: 100%;
height: 24px;
position: absolute;
......@@ -21,8 +21,8 @@
line-height: 24px;
color: $white;
font-size: 13px;
background-color: #E02E24;
opacity: .6;
background-color: #e02e24;
opacity: 0.6;
}
.course-title {
......
import React from 'react'
import './course.scss'
import {Link} from "react-router-dom"
import React from "react"
import "./course.scss"
import { Link } from "react-router-dom"
const Course = (props) => {
return (
<li className={`course-item ${props.className}`}>
{props.top}
<a onClick={() => props.toDetail(props.id)}>
{/* <Link to={`/detail?id=${props.id}`}> */}
<img src={props.img} alt=""/>
{props.status}
<p className={`course-title ${props.className}`}>{props.title}</p>
{/* </Link> */}
</a>
{props.bottom}
</li>
);
};
export default Course;
return (
<li className={`course-item ${props.className}`}>
{props.top}
<a onClick={() => props.toDetail(props.id)}>
{/* <Link to={`/detail?id=${props.id}`}> */}
<img src={props.img} alt="" />
{props.status}
<p className={`course-title ${props.className}`}>{props.title}</p>
{/* </Link> */}
</a>
{props.bottom}
</li>
)
}
export default Course
import React, {Component} from 'react'
import './index.scss';
import {withRouter} from 'react-router-dom'
import {browser,getParam} from "src/utils";
import React, { Component } from "react"
import "./index.scss"
import { withRouter } from "react-router-dom"
import { browser, getParam } from "src/utils"
class HeaderBar extends Component {
constructor(props) {
super(props);
}
constructor(props) {
super(props)
}
goBack = () => {
const {state, hash} = this.props.location
if(hash.includes('goback')){
return window.history.go(-1)
}
if(browser.isWeixin && getParam('code') && getParam('state')){
window.history.go(-2)
}
if(state.records && state.records.length > 1){
window.history.go(-1);
}else if(state.from && state.from.pathname) {
location.replace(`${state.from.pathname}${state.from.search}`)
}else{
window.location.href = window.location.origin
}
goBack = () => {
const { state, hash } = this.props.location
if (hash.includes("goback")) {
return window.history.go(-1)
}
toLink = () => {
const { toHref } = this.props;
// console.log(toHref);
location.replace(toHref)
if (browser.isWeixin && getParam("code") && getParam("state")) {
window.history.go(-2)
}
goShop = () => {
this.props.history.push('/shopcart')
if (state.records && state.records.length > 1) {
window.history.go(-1)
} else if (state.from && state.from.pathname) {
location.replace(`${state.from.pathname}${state.from.search}`)
} else {
window.location.href = window.location.origin
}
}
render() {
const { toHref, home } = this.props;
return (
<div className="detail-header" style={{...this.props.style}}>
{
!toHref && this.props.arrow &&
<i className='iconfont iconiconfront-68' onClick={this.props.goBack || this.goBack}></i>
}
{
toHref && typeof toHref === 'function' &&
<i className='iconfont iconiconfront-68' onClick={toHref}></i>
}
{
toHref && typeof toHref === 'string' &&
<i className='iconfont iconiconfront-68' onClick={this.toLink}></i>
}
<span className='herder'>{this.props.title}</span>
{
this.props.cart &&
<i className='iconfont icongouwuche-xianxing' onClick={this.goShop}></i>
}
{
this.props.delete &&
<i className='iconfont iconiconfront-56' onClick={this.props.toDelete}></i>
}
{
home &&
<i className="iconfont iconshouye-xianxing"></i>
}
</div>
);
}
};
toLink = () => {
const { toHref } = this.props
// console.log(toHref);
location.replace(toHref)
}
goShop = () => {
this.props.history.push("/shopcart")
}
render() {
const { toHref, home } = this.props
return (
<div className="detail-header" style={{ ...this.props.style }}>
{!toHref && this.props.arrow && (
<i
className="iconfont iconiconfront-68"
onClick={this.props.goBack || this.goBack}
></i>
)}
{toHref && typeof toHref === "function" && (
<i className="iconfont iconiconfront-68" onClick={toHref}></i>
)}
{toHref && typeof toHref === "string" && (
<i className="iconfont iconiconfront-68" onClick={this.toLink}></i>
)}
<span className="herder">{this.props.title}</span>
{this.props.cart && (
<i
className="iconfont icongouwuche-xianxing"
onClick={this.goShop}
></i>
)}
{this.props.delete && (
<i
className="iconfont iconiconfront-56"
onClick={this.props.toDelete}
></i>
)}
{home && <i className="iconfont iconshouye-xianxing"></i>}
</div>
)
}
}
export default withRouter(HeaderBar);
export default withRouter(HeaderBar)
......@@ -18,9 +18,8 @@
float: right;
}
.herder {
font-size: 16px;
color: $color_202426;
}
}
\ No newline at end of file
}
import React, {Component} from 'react'
import {SearchBar} from 'antd-mobile'
import './index.scss'
import React, { Component } from "react"
import { SearchBar } from "antd-mobile"
import "./index.scss"
class HeaderBar extends Component {
toSearch() {
window.location.href = '/search';
}
toSearch() {
window.location.href = "/search"
}
return() {
window.location.href = '/';
}
return() {
window.location.href = "/"
}
goShop = () => {
const { isLogin = false } = this.props;
let url = isLogin? '/shopcart' : '/passport';
window.location.replace(url);
}
render() {
return (
<div className='preferential'>
<div className="search-nav">
{
!this.props.toHref &&
<i
className={'iconfont iconiconfront-68 return'}
onClick={this.return.bind(this)}
/>
}
{
this.props.toHref &&
<i
className={'iconfont iconiconfront-68 return'}
onClick={this.props.toHref}
/>
}
<SearchBar
placeholder="搜索课程"
cancelText={" "}
onFocus={this.toSearch.bind(this)}
showCancelButton={false}
/>
<i
className={'iconfont icongouwuche-xianxing shopping-cart'}
onClick={this.goShop}
/>
</div>
</div>
)
}
goShop = () => {
const { isLogin = false } = this.props
let url = isLogin ? "/shopcart" : "/passport"
window.location.replace(url)
}
render() {
return (
<div className="preferential">
<div className="search-nav">
{!this.props.toHref && (
<i
className={"iconfont iconiconfront-68 return"}
onClick={this.return.bind(this)}
/>
)}
{this.props.toHref && (
<i
className={"iconfont iconiconfront-68 return"}
onClick={this.props.toHref}
/>
)}
<SearchBar
placeholder="搜索课程"
cancelText={" "}
onFocus={this.toSearch.bind(this)}
showCancelButton={false}
/>
<i
className={"iconfont icongouwuche-xianxing shopping-cart"}
onClick={this.goShop}
/>
</div>
</div>
)
}
}
export default HeaderBar;
export default HeaderBar
......@@ -12,7 +12,9 @@
background-color: $bg_f7f9fc;
}
.am-search-input, .am-search-synthetic-ph, .am-search-value {
.am-search-input,
.am-search-synthetic-ph,
.am-search-value {
text-align: left;
padding-left: 15px;
height: 26px;
......@@ -24,7 +26,8 @@
border-radius: 13px;
}
.shopping-cart, .return {
.shopping-cart,
.return {
font-size: 20px;
}
}
\ No newline at end of file
}
import React, { Component } from 'react';
import ReactDOM from 'react-dom'
import { HashLoader } from "react-spinners";
import './loading.scss'
import React, { Component } from "react"
import ReactDOM from "react-dom"
import { HashLoader } from "react-spinners"
import "./loading.scss"
const container = document.body
class Loading extends Component {
static defaultProps = {
text: "加载中",
fake: 0,
}
static defaultProps = {
text: '加载中',
fake: 0
}
state = {
isLoading: true,
}
state = {
isLoading: true
componentDidMount() {
if (!this.props.isLoading) {
this.setState({
isLoading: false,
})
}
}
componentDidMount() {
if(!this.props.isLoading){
this.setState({
isLoading: false
})
componentDidUpdate(prevProps) {
let { isLoading, fake } = this.props
if (!isLoading) {
if (fake) {
setTimeout(() => {
this.setState({
isLoading,
})
}, fake)
} else {
if (prevProps.isLoading) {
this.setState(() => ({
isLoading: false,
}))
}
}
} else {
if (prevProps.isLoading !== isLoading) {
this.setState(() => ({
isLoading: true,
}))
}
}
}
render() {
const innerLoading = (
<div className="loading">
<div className="loading-wrapper">
<HashLoader
css={{
display: "block",
marginTop: "-100px",
}}
size={50}
color={"#09f"}
/>
<p>{this.props.text}</p>
</div>
</div>
)
componentDidUpdate(prevProps) {
let {isLoading, fake} = this.props
if (!isLoading) {
if(fake){
setTimeout(() => {
this.setState({
isLoading
})
}, fake)
}else {
if(prevProps.isLoading) {
this.setState(()=>({
isLoading: false
}))
}
}
}else{
if(prevProps.isLoading !== isLoading) {
this.setState(()=>({
isLoading: true
}))
}
}
}
render() {
const innerLoading =
<div className="loading">
<div className="loading-wrapper">
<HashLoader
css={{
display: 'block',
marginTop: '-100px'
}}
size={50}
color={'#09f'}
/>
<p>{this.props.text}</p>
</div>
</div>
return (
this.state.isLoading ? ReactDOM.createPortal(innerLoading, container) : this.props.children
);
}
return this.state.isLoading
? ReactDOM.createPortal(innerLoading, container)
: this.props.children
}
}
export default Loading;
\ No newline at end of file
export default Loading
@import "src/assets/css/variable";
.loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
.loading-wrapper {
display: flex;
flex-flow: column;
justify-content: center;
align-items: center;
p {
font-size: 14px;
margin-top: 12px;
color: $active;
}
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
.loading-wrapper {
display: flex;
flex-flow: column;
justify-content: center;
align-items: center;
p {
font-size: 14px;
margin-top: 12px;
color: $active;
}
}
\ No newline at end of file
}
}
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import classnames from 'classnames';
import './index.scss';
import React, { Component } from "react"
import ReactDOM from "react-dom"
import classnames from "classnames"
import "./index.scss"
const Root = document.querySelector('body');
const events = ['touchmove', 'mousewheel'];
const Root = document.querySelector("body")
const events = ["touchmove", "mousewheel"]
class Mask extends Component {
constructor(props) {
super(props);
if(!this.el) {
this.el = document.createElement('div');
super(props)
if (!this.el) {
this.el = document.createElement("div")
}
}
componentDidMount() {
events.forEach(item => {
events.forEach((item) => {
this.el.addEventListener(item, this.preventEvent, {
passive: false
passive: false,
})
})
Root.appendChild(this.el);
Root.appendChild(this.el)
}
componentWillUnmount() {
Root.removeChild(this.el);
Root.removeChild(this.el)
}
preventEvent = e => {
e.preventDefault();
preventEvent = (e) => {
e.preventDefault()
}
render() {
const { visible, handleToHide, className } = this.props;
if(visible) {
const { visible, handleToHide, className } = this.props
if (visible) {
return ReactDOM.createPortal(
(
<div className="mask">
<div className={classnames("mask-content", className)}>
{this.props.children}
</div>
<div className="mask-footer">
<i className="mask-button__close" onClick={handleToHide}></i>
</div>
<div className="mask">
<div className={classnames("mask-content", className)}>
{this.props.children}
</div>
<div className="mask-footer">
<i className="mask-button__close" onClick={handleToHide}></i>
</div>
),
</div>,
this.el
);
}else {
return null;
)
} else {
return null
}
}
}
export default Mask;
\ No newline at end of file
export default Mask
......@@ -8,8 +8,8 @@
left: 0;
width: 100%;
height: 100%;
color:#fff;
background-color: rgba(0, 0, 0, .5);
color: #fff;
background-color: rgba(0, 0, 0, 0.5);
z-index: 999;
}
......@@ -31,5 +31,5 @@
width: 33px;
height: 33px;
background-size: cover;
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/close-btn.png');
}
\ No newline at end of file
background-image: url("https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/close-btn.png");
}
import React from 'react';
import { NavLink, withRouter } from 'react-router-dom'
import './index.scss'
import React from "react"
import { NavLink, withRouter } from "react-router-dom"
import "./index.scss"
const navLinkConfig = [
{
to: '/',
exact: true,
icon: 'index-icon',
activeIcon: 'index-icon-active',
text: '首页'
},
{
to: '/classify',
exact: false,
icon: 'classify-icon',
activeIcon: 'classify-icon-active',
text: '分类'
},
{
to: '/study',
exact: false,
icon: 'study-icon',
activeIcon: 'study-icon-active',
text: '学习'
},
{
to: '/my',
exact: false,
icon: 'my-icon',
activeIcon: 'my-icon-active',
text: '我的'
}
{
to: "/",
exact: true,
icon: "index-icon",
activeIcon: "index-icon-active",
text: "首页",
},
{
to: "/classify",
exact: false,
icon: "classify-icon",
activeIcon: "classify-icon-active",
text: "分类",
},
{
to: "/study",
exact: false,
icon: "study-icon",
activeIcon: "study-icon-active",
text: "学习",
},
{
to: "/my",
exact: false,
icon: "my-icon",
activeIcon: "my-icon-active",
text: "我的",
},
]
const NavBar = React.memo(({location}) => {
return (
<div className="nav-bar">
{
navLinkConfig.map(item => {
let {icon, text, activeIcon, ...rest} = item
return (
<NavLink
activeClassName={'active'}
className={'nav-item'}
key={icon}
{...rest}
>
<i className={`icon ${item.to.length > 1 ? location.pathname.startsWith(item.to) ? activeIcon : icon : location.pathname === item.to ? activeIcon : icon}`}/>
<span>{text}</span>
</NavLink>
)
})
}
<div className={'click-able'}></div>
</div>
)
const NavBar = React.memo(({ location }) => {
return (
<div className="nav-bar">
{navLinkConfig.map((item) => {
let { icon, text, activeIcon, ...rest } = item
return (
<NavLink
activeClassName={"active"}
className={"nav-item"}
key={icon}
{...rest}
>
<i
className={`icon ${
item.to.length > 1
? location.pathname.startsWith(item.to)
? activeIcon
: icon
: location.pathname === item.to
? activeIcon
: icon
}`}
/>
<span>{text}</span>
</NavLink>
)
})}
<div className={"click-able"}></div>
</div>
)
})
export default withRouter(NavBar)
\ No newline at end of file
export default withRouter(NavBar)
......@@ -78,7 +78,3 @@
background-image: linear-gradient(0deg, #ddd 50%, transparent 50%);
}
}
import React from 'react';
import './orderlist.scss';
import {Link} from "react-router-dom";
import React from "react"
import "./orderlist.scss"
import { Link } from "react-router-dom"
/**
* @OrderList 组件内容
......@@ -13,30 +12,33 @@ import {Link} from "react-router-dom";
* @constructor
*/
const OrderItem = ({ info, tab, children, src,id, isaist, toDetail, ...restProps }) => {
return (
<div className='public-list-item'>
<div className="public-content">
{tab}
<div className="public-cover" >
{/* <Link to={`/detail?id=${id}`}> */}
<img src={src} alt="" onClick={() => toDetail(id)} />
{/* </Link> */}
{
(isaist &&
<span className='return_cash'></span>
)
}
</div>
{info}
</div>
{React.Children.map(
children,
child => (child ? React.cloneElement(child, {}) : child)
)}
</div>
)
const OrderItem = ({
info,
tab,
children,
src,
id,
isaist,
toDetail,
...restProps
}) => {
return (
<div className="public-list-item">
<div className="public-content">
{tab}
<div className="public-cover">
{/* <Link to={`/detail?id=${id}`}> */}
<img src={src} alt="" onClick={() => toDetail(id)} />
{/* </Link> */}
{isaist && <span className="return_cash"></span>}
</div>
{info}
</div>
{React.Children.map(children, (child) =>
child ? React.cloneElement(child, {}) : child
)}
</div>
)
}
export default OrderItem;
\ No newline at end of file
export default OrderItem
......@@ -38,7 +38,6 @@
background: url("./image/return.icon.png") no-repeat;
background-size: 100% 100%;
}
}
.order-info {
......
import React, { PureComponent } from 'react'
import './tag.scss'
import React, { PureComponent } from "react"
import "./tag.scss"
export default class Tag extends PureComponent {
render() {
return (
<span className={this.props.name} {...this.props}>
{this.props.children}
</span>
)
}
render() {
return (
<span className={this.props.name} {...this.props}>
{this.props.children}
</span>
)
}
}
.tagLately, .tagHot {
display: block;
max-width: 100%;
overflow: hidden;
margin-right: 10px;
margin-bottom: 10px;
font-size: 12px;
padding: 4px 10px;
border-radius: 14px;
float: left;
background-color: #F5F5F5;
line-height: 20px;
color: #666;
.tagLately,
.tagHot {
display: block;
max-width: 100%;
overflow: hidden;
margin-right: 10px;
margin-bottom: 10px;
font-size: 12px;
padding: 4px 10px;
border-radius: 14px;
float: left;
background-color: #f5f5f5;
line-height: 20px;
color: #666;
}
.tagHot {
color: #333;
}
\ No newline at end of file
color: #333;
}
import React, {Component} from 'react'
import './index.scss'
import {http} from 'src/utils'
import React, { Component } from "react"
import "./index.scss"
import { http } from "src/utils"
class UserGift extends Component {
state = {
user_gift: ''
}
state = {
user_gift: "",
}
componentDidMount() {
http.get(`${API['base-api']}/web/home/popup`).then((res) => {
const {errno, data} = res.data
if (errno === 200) {
this.setState({
user_gift: data.new_user_gift.prize_img
})
}
componentDidMount() {
http.get(`${API["base-api"]}/web/home/popup`).then((res) => {
const { errno, data } = res.data
if (errno === 200) {
this.setState({
user_gift: data.new_user_gift.prize_img,
})
}
}
})
}
get_newerModal = () => {
this.props.get_newerModal()
}
close = () => {
this.props.close()
}
get_newerModal = () => {
this.props.get_newerModal()
}
close = () => {
this.props.close()
}
render() {
const {user_gift} = this.state
return (
<div className={'user-gift-popup'}>
<div className={'user-gift-bgimg'}>
<img onClick={this.get_newerModal} src={user_gift} alt=""/>
<img className={'close_gift_box'}
src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/tinypng-common/close_icon.png"
onClick={this.close} alt=""/>
</div>
</div>
)
}
render() {
const { user_gift } = this.state
return (
<div className={"user-gift-popup"}>
<div className={"user-gift-bgimg"}>
<img onClick={this.get_newerModal} src={user_gift} alt="" />
<img
className={"close_gift_box"}
src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/tinypng-common/close_icon.png"
onClick={this.close}
alt=""
/>
</div>
</div>
)
}
}
export default UserGift
\ No newline at end of file
export default UserGift
.user-gift-popup {
background: rgba(0, 0, 0, .3);
background: rgba(0, 0, 0, 0.3);
position: fixed;
left: 0;
top: 0;
......@@ -21,4 +21,4 @@
bottom: -45px;
}
}
}
\ No newline at end of file
}
import React from 'react';
import './index.scss'
import React from "react"
import "./index.scss"
const VList = (props) => {
return (
<li
className='v-list-item'
onClick={() => {
typeof props.toDetail === 'function' && props.toDetail(props.id)
}}
>
<div className="content">
<div className="cover">
{props.status}
{props.courseExpire}
{props.toDetail
? (<img src={props.img} alt=""/>)
: (<img src={props.img} alt=""/>)
}
</div>
{props.info}
</div>
{props.tab}
</li>
);
};
return (
<li
className="v-list-item"
onClick={() => {
typeof props.toDetail === "function" && props.toDetail(props.id)
}}
>
<div className="content">
<div className="cover">
{props.status}
{props.courseExpire}
{props.toDetail ? (
<img src={props.img} alt="" />
) : (
<img src={props.img} alt="" />
)}
</div>
{props.info}
</div>
{props.tab}
</li>
)
}
export default VList;
\ No newline at end of file
export default VList
@import "src/assets/css/variable";
.v-list-item {
height: 138px;
padding: 15px 15px 0;
height: 138px;
padding: 15px 15px 0;
.content {
display: flex;
height: 100%;
padding-bottom: 15px;
border-bottom: 1px solid $sp_e7eaf1;
.cover {
flex: 0 0 auto;
margin-right: 16px;
position: relative;
width: 150px;
img {
width: 150px;
height: 108px;
border-radius: 4px;
}
}
.course-status {
width: 100%;
height: 24px;
position: absolute;
bottom: -1px;
border-radius: 0 0 3px 3px;
text-align: center;
line-height: 24px;
color: $white;
font-size: 13px;
}
.content {
display: flex;
height: 100%;
padding-bottom: 15px;
border-bottom: 1px solid $sp_e7eaf1;
.cover {
flex: 0 0 auto;
margin-right: 16px;
position: relative;
width: 150px;
img {
width: 150px;
height: 108px;
border-radius: 4px;
}
}
.course-status {
width: 100%;
height: 24px;
position: absolute;
bottom: -1px;
border-radius: 0 0 3px 3px;
text-align: center;
line-height: 24px;
color: $white;
font-size: 13px;
}
}
}
import React, {Component} from 'react'
import './index.scss'
import React, { Component } from "react"
import "./index.scss"
class WxLogin extends Component {
constructor(props) {
super(props)
}
constructor(props) {
super(props)
}
// 提示微信登录还是账号登录,微信授权登录不需要绑定手机号
wxLogin = () => {
let url = window.location.href
if (url.includes('code=') && url.includes('state=STATE')) {
let index = url.lastIndexOf('code=')
url = url.substr(0, index - 1)
}
window.location.href = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx23dac6775ac82877&redirect_uri=" + encodeURIComponent(url + "&aa=bb").toLowerCase() + "&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect"
}
zhLogin = () => {
this.props.history.push('/passport')
// 提示微信登录还是账号登录,微信授权登录不需要绑定手机号
wxLogin = () => {
let url = window.location.href
if (url.includes("code=") && url.includes("state=STATE")) {
let index = url.lastIndexOf("code=")
url = url.substr(0, index - 1)
}
window.location.href =
"https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx23dac6775ac82877&redirect_uri=" +
encodeURIComponent(url + "&aa=bb").toLowerCase() +
"&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect"
}
zhLogin = () => {
this.props.history.push("/passport")
}
render() {
return (
<div className="change-login-type">
<div className="login-type-content">
<div className="wx-login" onClick={this.wxLogin}>
<img src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/mlCourse/m/wx-icon.png" alt=""/>
<span>微信登录</span>
</div>
<div className="zh-login" onClick={this.zhLogin}>
<img src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/mlCourse/m/zh-icon.png" alt=""/>
<span>账号登录</span>
</div>
</div>
</div>
)
}
render() {
return (
<div className="change-login-type">
<div className="login-type-content">
<div className="wx-login" onClick={this.wxLogin}>
<img
src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/mlCourse/m/wx-icon.png"
alt=""
/>
<span>微信登录</span>
</div>
<div className="zh-login" onClick={this.zhLogin}>
<img
src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/mlCourse/m/zh-icon.png"
alt=""
/>
<span>账号登录</span>
</div>
</div>
</div>
)
}
}
export default WxLogin
.change-login-type {
background: rgba(0, 0, 0, .5);
background: rgba(0, 0, 0, 0.5);
position: fixed;
left: 0;
top: 0;
......@@ -22,7 +22,8 @@
justify-content: space-between;
}
.wx-login, .zh-login {
.wx-login,
.zh-login {
text-align: center;
img {
width: 34px;
......@@ -31,9 +32,9 @@
span {
display: block;
color: #525C65;
color: #525c65;
font-size: 14px;
margin-top: 3px;
}
}
}
\ No newline at end of file
}
import React from 'react'
import Address from "./index";
import {text, boolean, withKnobs} from '@storybook/addon-knobs'
import {action} from '@storybook/addon-actions'
import React from "react"
import Address from "./index"
import { text, boolean, withKnobs } from "@storybook/addon-knobs"
import { action } from "@storybook/addon-actions"
export default {
title: 'address',
component: Address,
decorators: [withKnobs]
title: "address",
component: Address,
decorators: [withKnobs],
}
let visible = true,
title = '收货地址',
subtitle = '获奖用户(以最终榜单为准)请及时填写收货信息',
address = '金域国际中心',
phone = '1331234123',
name = '某某某'
title = "收货地址",
subtitle = "获奖用户(以最终榜单为准)请及时填写收货信息",
address = "金域国际中心",
phone = "1331234123",
name = "某某某"
export const Default = () => {
visible = boolean('visible', visible)
name = text('name', name)
phone = text('phone', phone)
address = text('address', address)
title = text('title(optional)', title)
subtitle = text('subtitle(optional)', subtitle)
visible = boolean("visible", visible)
name = text("name", name)
phone = text("phone", phone)
address = text("address", address)
title = text("title(optional)", title)
subtitle = text("subtitle(optional)", subtitle)
return <Address visible={visible}
subtitle={subtitle}
title={title}
name={name}
phone={phone}
address={address}
onClose={action('onClose')}
validate={() => ({name: '姓名'})}
onError={(errors) => {
console.log(errors);}}
onSubmit={(values, formikHelpers) => {
console.log(formikHelpers);
}}
return (
<Address
visible={visible}
subtitle={subtitle}
title={title}
name={name}
phone={phone}
address={address}
onClose={action("onClose")}
validate={() => ({ name: "姓名" })}
onError={(errors) => {
console.log(errors)
}}
onSubmit={(values, formikHelpers) => {
console.log(formikHelpers)
}}
/>
}
\ No newline at end of file
)
}
......@@ -12,14 +12,14 @@
.title {
margin-bottom: 8px;
color: #525C65;
color: #525c65;
font-size: 16px;
}
.subtitle {
margin-bottom: 15px;
font-size: 13px;
color: #ED6A1D;
color: #ed6a1d;
text-align: left;
}
......@@ -27,13 +27,13 @@
width: 250px;
height: 40px;
line-height: 40px;
border: 1px solid #DDD;
border: 1px solid #ddd;
font-size: 13px;
color: #999;
outline: 0;
-webkit-appearance: none;
&:nth-child(n+2) {
&:nth-child(n + 2) {
margin-top: 10px;
}
......@@ -55,7 +55,7 @@
border: 0;
}
.close{
.close {
position: absolute;
left: 50%;
bottom: -56px;
......@@ -63,4 +63,4 @@
font-size: 26px;
color: #fff;
}
}
\ No newline at end of file
}
import React, {Component} from 'react'
import './index.scss'
import MaskCover from "../cover";
import {Formik, Form, Field, FormikHelpers, FormikErrors} from "formik";
import React, { Component } from "react"
import "./index.scss"
import MaskCover from "../cover"
import { Formik, Form, Field, FormikHelpers, FormikErrors } from "formik"
interface PersonalInfo {
name: string
phone: string
address: string
name: string
phone: string
address: string
}
interface Props extends PersonalInfo {
subtitle?: string
title?: string
onClose: () => void
visible: boolean
validate: () => void
onSubmit: (values: PersonalInfo, formikHelpers: FormikHelpers<PersonalInfo>) => void
onError: (errors: FormikErrors<PersonalInfo>) => void
subtitle?: string
title?: string
onClose: () => void
visible: boolean
validate: () => void
onSubmit: (
values: PersonalInfo,
formikHelpers: FormikHelpers<PersonalInfo>
) => void
onError: (errors: FormikErrors<PersonalInfo>) => void
}
const Address: React.FC<Props> = ({name, phone, address, title, subtitle, visible, onClose, validate, onSubmit, onError}) => {
return (
visible ?
<MaskCover>
<div className="common-address-container">
<div className="title">{title}</div>
<div className="subtitle">{subtitle}</div>
<Formik initialValues={{name, phone, address}}
enableReinitialize={true}
onSubmit={onSubmit}
validate={validate}
>
{
(props) => {
if (props.errors) {
onError(props.errors)
}
return <Form className={'form'}>
<Field placeholder={'姓名'} name='name'></Field>
<Field placeholder={'手机号'} name='phone'></Field>
<Field placeholder={'地址'} name='address'></Field>
<button type={'submit'} className={'submit'}>提交</button>
</Form>
}
}
</Formik>
<i className={'iconfont iconiconfront-2 close'} onClick={onClose}></i>
</div>
</MaskCover>
: null
)
const Address: React.FC<Props> = ({
name,
phone,
address,
title,
subtitle,
visible,
onClose,
validate,
onSubmit,
onError,
}) => {
return visible ? (
<MaskCover>
<div className="common-address-container">
<div className="title">{title}</div>
<div className="subtitle">{subtitle}</div>
<Formik
initialValues={{ name, phone, address }}
enableReinitialize={true}
onSubmit={onSubmit}
validate={validate}
>
{(props) => {
if (props.errors) {
onError(props.errors)
}
return (
<Form className={"form"}>
<Field placeholder={"姓名"} name="name"></Field>
<Field placeholder={"手机号"} name="phone"></Field>
<Field placeholder={"地址"} name="address"></Field>
<button type={"submit"} className={"submit"}>
提交
</button>
</Form>
)
}}
</Formik>
<i className={"iconfont iconiconfront-2 close"} onClick={onClose}></i>
</div>
</MaskCover>
) : null
}
Address.defaultProps = {
title: '收货信息',
subtitle: '获奖用户(以最终榜单为准)请及时填写收货信息'
title: "收货信息",
subtitle: "获奖用户(以最终榜单为准)请及时填写收货信息",
}
export default Address
import React, { Component } from 'react';
import { http } from 'src/utils';
import { Formik, Form, Field } from 'formik';
import { Toast } from "antd-mobile";
import './index.scss';
import React, { Component } from "react"
import { http } from "src/utils"
import { Formik, Form, Field } from "formik"
import { Toast } from "antd-mobile"
import "./index.scss"
class AddressPopup extends Component {
constructor(props) {
......@@ -10,22 +10,22 @@ class AddressPopup extends Component {
this.state = {
isLoading: false,
addressInfo: {
name: '',
phone: '',
address: '',
name: "",
phone: "",
address: "",
},
}
}
componentDidMount() {
this.fetchUserAddress();
this.fetchUserAddress()
}
// 获取收货信息
fetchUserAddress = () => {
const {addressInfo} = this.state;
http.get(`${API.home}/sys/user_address_info`).then(res => {
const {code, data, msg} = res.data;
const { addressInfo } = this.state
http.get(`${API.home}/sys/user_address_info`).then((res) => {
const { code, data, msg } = res.data
if (code === 200) {
this.setState({
addressInfo: Object.assign({}, addressInfo, {
......@@ -34,139 +34,137 @@ class AddressPopup extends Component {
address: data.address,
}),
isLoading: true,
});
})
}
});
})
}
handleToSubmit = (params = {}) => {
const {successBindAddress} = this.props;
http.post(`${API.home}/sys/update_address`, {
act_type: 'treasure',
...params,
}).then(res => {
const {code, msg} = res.data;
if (code === 200) {
successBindAddress();
} else {
Toast.info(msg, 2, null, false);
}
});
const { successBindAddress } = this.props
http
.post(`${API.home}/sys/update_address`, {
act_type: "treasure",
...params,
})
.then((res) => {
const { code, msg } = res.data
if (code === 200) {
successBindAddress()
} else {
Toast.info(msg, 2, null, false)
}
})
}
render() {
const {isLoading, addressInfo} = this.state;
const {tip, prize, skip = 'default'} = this.props;
const { isLoading, addressInfo } = this.state
const { tip, prize, skip = "default" } = this.props
return (
<>
{
isLoading &&
{isLoading && (
<Formik
initialValues={{
...addressInfo,
}}
validate={({name, phone, address}) => {
const errors = {};
validate={({ name, phone, address }) => {
const errors = {}
if (!name) {
errors.name = '请输入收件人';
errors.name = "请输入收件人"
}
if (!/^1[3-9]\d{9}$/.test(phone)) {
errors.phone = '请填写正确格式的手机号';
errors.phone = "请填写正确格式的手机号"
}
if (!address) {
errors.address = '请输入收货地址';
errors.address = "请输入收货地址"
}
return errors;
return errors
}}
validateOnBlur={false}
validateOnChange={false}
onSubmit={(values) => {
this.handleToSubmit(values);
this.handleToSubmit(values)
}}
>
{
({errors}) => (
<Form className="address-form" data-skip={skip}>
<h2 className="address-form__title">收货信息</h2>
{
prize ? (
<p className='address__prize'>
您抽中了
<span style={{'color': '#FF4000'}}>{prize}</span>
</p>
) : (null)
}
{
tip ? (<div className="address-form__subtitle">{tip}</div>) : (
<p className="address-form__desc">请及时填写收货信息,获得实物奖品后将第一时间为您邮寄</p>)
}
<Field
name="name"
render={({field}) => (
<div className="address-form__item">
<input
{...field}
className="address-form__ipt"
type="text"
placeholder="收件人"
/>
{
errors.name &&
<p className="address-form__tip">{errors.name}</p>
}
</div>
)}
/>
<Field
name="phone"
render={({field}) => (
<div className="address-form__item">
<input
{...field}
className="address-form__ipt"
type="text"
placeholder="联系方式"
/>
{
errors.phone &&
<p className="address-form__tip">{errors.phone}</p>
}
</div>
)}
/>
<Field
name="address"
render={({field}) => (
<div className="address-form__item">
<input
{...field}
className="address-form__ipt"
type="text"
placeholder="收货地址"
/>
{
errors.address &&
<p className="address-form__tip">{errors.address}</p>
}
</div>
)}
/>
<button
className="address-form__submit"
data-status="do"
type="submit"
>提交
</button>
</Form>
)
}
{({ errors }) => (
<Form className="address-form" data-skip={skip}>
<h2 className="address-form__title">收货信息</h2>
{prize ? (
<p className="address__prize">
您抽中了
<span style={{ color: "#FF4000" }}>{prize}</span>
</p>
) : null}
{tip ? (
<div className="address-form__subtitle">{tip}</div>
) : (
<p className="address-form__desc">
请及时填写收货信息,获得实物奖品后将第一时间为您邮寄
</p>
)}
<Field
name="name"
render={({ field }) => (
<div className="address-form__item">
<input
{...field}
className="address-form__ipt"
type="text"
placeholder="收件人"
/>
{errors.name && (
<p className="address-form__tip">{errors.name}</p>
)}
</div>
)}
/>
<Field
name="phone"
render={({ field }) => (
<div className="address-form__item">
<input
{...field}
className="address-form__ipt"
type="text"
placeholder="联系方式"
/>
{errors.phone && (
<p className="address-form__tip">{errors.phone}</p>
)}
</div>
)}
/>
<Field
name="address"
render={({ field }) => (
<div className="address-form__item">
<input
{...field}
className="address-form__ipt"
type="text"
placeholder="收货地址"
/>
{errors.address && (
<p className="address-form__tip">{errors.address}</p>
)}
</div>
)}
/>
<button
className="address-form__submit"
data-status="do"
type="submit"
>
提交
</button>
</Form>
)}
</Formik>
}
)}
</>
);
)
}
}
export default AddressPopup;
\ No newline at end of file
export default AddressPopup
// 地址弹窗
[data-skip="default"] {
.address-form__item {
width: 250px;
}
......@@ -15,13 +14,12 @@
background-color: rgba(82, 92, 101, 0.3);
&[data-status="do"] {
background-color: #0099FF;
background-color: #0099ff;
}
}
}
[data-skip="year"] {
.address-form__title {
margin: 10px 0 0;
font-size: 18px;
......@@ -38,7 +36,7 @@
width: 270px;
margin: 0 15px 10px;
}
.address-form__ipt {
border-radius: 3px;
}
......@@ -50,7 +48,7 @@
border: 1px solid #090909;
border-radius: 5px;
color: #090909;
background-color: #FFE319;
background-color: #ffe319;
}
}
......@@ -93,4 +91,4 @@
font-weight: 500;
cursor: pointer;
outline: none;
}
\ No newline at end of file
}
......@@ -14,7 +14,7 @@
}
.popup-form__button--num {
border: 1px solid #99D6FF;
border: 1px solid #99d6ff;
border-right-style: none;
border-radius: 6px 0 0 6px;
}
......@@ -31,7 +31,7 @@
}
.popup-form__ipt {
border: 1px solid #99D6FF;
border: 1px solid #99d6ff;
border-radius: 6px;
&[data-type="tel"] {
......@@ -56,7 +56,7 @@
}
.popup-form__button--num {
border: 1px solid #CDCDCD;
border: 1px solid #cdcdcd;
border-right-style: none;
border-radius: 3px 0 0 3px;
}
......@@ -74,7 +74,7 @@
}
.popup-form__ipt {
border: 1px solid #CDCDCD;
border: 1px solid #cdcdcd;
border-radius: 3px;
&[data-type="tel"] {
......@@ -117,11 +117,11 @@
.button {
width: 40px;
height: 40px;
.icon{
.icon {
left: 5px;
}
}
.bg-green{
.bg-green {
height: 40px;
line-height: 40px;
}
......@@ -162,7 +162,7 @@
&::after {
display: block;
content: '';
content: "";
position: absolute;
top: 0;
right: 0;
......@@ -170,7 +170,7 @@
width: 1px;
height: 14px;
margin: auto 0;
background-color: #AAAAAA;
background-color: #aaaaaa;
}
.iconfont {
......@@ -196,11 +196,11 @@
.popup-form__tip {
margin: 0;
font-size: 12px;
color: #FF3131;
color: #ff3131;
.iconfont {
font-size: 15px;
color: #FF3131;
color: #ff3131;
}
}
......@@ -208,7 +208,7 @@
width: 110px;
height: 36px;
padding: 0;
border: 1px solid #E5E5E5;
border: 1px solid #e5e5e5;
box-sizing: border-box;
font-size: 13px;
color: #999;
......@@ -216,9 +216,9 @@
line-height: 36px;
background-color: transparent;
&[data-status='do'] {
border-color: #0099FF;
color: #0099FF;
&[data-status="do"] {
border-color: #0099ff;
color: #0099ff;
}
}
......@@ -227,17 +227,17 @@
padding: 0;
margin: 0 auto;
border-style: none;
color: #2B2B2B;
background-color: #F9DB4A;
color: #2b2b2b;
background-color: #f9db4a;
cursor: pointer;
&[data-status="done"] {
color: #fff;
background-color: #ABABAB;
background-color: #ababab;
}
&[data-status='do'] {
&[data-status="do"] {
color: #fff;
background-color: #0099FF;
background-color: #0099ff;
}
}
\ No newline at end of file
}
.closable-popup-mask {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.6);
z-index: 999;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.6);
z-index: 999;
.popup-container {
position: absolute;
top: 165px;
left: 50%;
transform: translateX(-50%);
width: 300px;
padding: 20px 10px;
border-radius: 10px;
background: #fff;
.popup-container {
position: absolute;
top: 165px;
left: 50%;
transform: translateX(-50%);
width: 300px;
padding: 20px 10px;
border-radius: 10px;
background: #fff;
.title {
font-size: 16px;
color: #525C65;
text-align: center;
}
.title {
font-size: 16px;
color: #525c65;
text-align: center;
}
.close {
position: absolute;
bottom: -74px;
left: 50%;
transform: translateX(-50%);
font-size: 36px;
color: #fff;
}
.close {
position: absolute;
bottom: -74px;
left: 50%;
transform: translateX(-50%);
font-size: 36px;
color: #fff;
}
.close-icon {
position: absolute;
bottom: -66px;
left: 50%;
width: 33px;
height: 33px;
transform: translateX(-50%);
font-size: 36px;
color: #fff;
}
.close-icon {
position: absolute;
bottom: -66px;
left: 50%;
width: 33px;
height: 33px;
transform: translateX(-50%);
font-size: 36px;
color: #fff;
}
}
}
import React from 'react'
import ReactDOM from 'react-dom'
import './index.scss'
import classnames from 'classnames'
import React from "react"
import ReactDOM from "react-dom"
import "./index.scss"
import classnames from "classnames"
const re = /(https?|ftp):\/\/[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]/
interface Props {
title: string
content: React.ReactNode
className?: string
closable?: boolean
clickMaskClose?: boolean
close?: () => void | Promise<void>
closeIcon?: string
remove?: () => void
afterClose?: () => void
title: string
content: React.ReactNode
className?: string
closable?: boolean
clickMaskClose?: boolean
close?: () => void | Promise<void>
closeIcon?: string
remove?: () => void
afterClose?: () => void
}
function ClosablePopup({
title,
content,
className,
closable = true,
close = function () {
},
clickMaskClose = true,
closeIcon = 'iconiconfront-2',
afterClose = function () {
},
remove = function () {
}
title,
content,
className,
closable = true,
close = function () {},
clickMaskClose = true,
closeIcon = "iconiconfront-2",
afterClose = function () {},
remove = function () {},
}: Props) {
function unmountComponent() {
ReactDOM.unmountComponentAtNode(div)
if (div && div.parentNode) {
div.parentNode.removeChild(div)
}
function unmountComponent() {
ReactDOM.unmountComponentAtNode(div)
if (div && div.parentNode) {
div.parentNode.removeChild(div)
}
}
function _close() {
let _c = close()
if (_c && _c.then) {
_c.then(() => {
unmountComponent()
afterClose()
})
} else {
unmountComponent()
afterClose()
}
function _close() {
let _c = close()
if (_c && _c.then) {
_c.then(() => {
unmountComponent()
afterClose()
})
} else {
unmountComponent()
afterClose()
}
}
function clickMask() {
if (closable) {
return
}
if (!clickMaskClose) {
return
}
_close()
function clickMask() {
if (closable) {
return
}
if (!clickMaskClose) {
return
}
_close()
}
const closablePopup = (
<div className={'closable-popup-mask'} onClick={clickMask}>
<div className={classnames(['popup-container', className])}>
<div className="title">{title}</div>
<div className="content">
{content}
</div>
{
closable &&
(re.test(closeIcon)
? <img src={closeIcon} alt="" className={'close-icon'} onClick={_close} />
: <i className={`close iconfont ${closeIcon}`} onClick={_close} />)
}
</div>
</div>
)
const div = document.createElement('div')
document.body.appendChild(div)
const closablePopup = (
<div className={"closable-popup-mask"} onClick={clickMask}>
<div className={classnames(["popup-container", className])}>
<div className="title">{title}</div>
<div className="content">{content}</div>
{closable &&
(re.test(closeIcon) ? (
<img
src={closeIcon}
alt=""
className={"close-icon"}
onClick={_close}
/>
) : (
<i className={`close iconfont ${closeIcon}`} onClick={_close} />
))}
</div>
</div>
)
const div = document.createElement("div")
document.body.appendChild(div)
ReactDOM.render(closablePopup, div)
ReactDOM.render(closablePopup, div)
return {
close: _close,
remove: unmountComponent
}
return {
close: _close,
remove: unmountComponent,
}
}
export default ClosablePopup
\ No newline at end of file
export default ClosablePopup
import React, { Component } from 'react';
import { Toast } from 'antd-mobile';
import { http } from 'src/utils';
import './index.scss';
import React, { Component } from "react"
import { Toast } from "antd-mobile"
import { http } from "src/utils"
import "./index.scss"
class ConfirmPhone extends Component {
continueBindPhone = () => {
const { data, successBindPhone } = this.props;
http.post(
`${API.home}/sys/v2/user/bindMobile`,
{
const { data, successBindPhone } = this.props
http
.post(`${API.home}/sys/v2/user/bindMobile`, {
...data,
type: 1, // 1:绑定,2:修改绑定
is_valid: 0, // is_valid 是否验证 1:验证(默认),0不验证
}
).then(res => {
const { code, msg } = res.data;
if(code === 200 ) {
successBindPhone();
}else {
Toast.info(msg, 2, null, false);
}
});
})
.then((res) => {
const { code, msg } = res.data
if (code === 200) {
successBindPhone()
} else {
Toast.info(msg, 2, null, false)
}
})
}
render() {
const {
bindInfo = { },
desc,
skip = 'year',
handleToCancle
} = this.props;
const { bindInfo = {}, desc, skip = "year", handleToCancle } = this.props
return (
<div className="popup-bind" data-skip={skip}>
<h2 className="popup-bind__title">绑定手机号</h2>
{
desc
? <div className="popup-bind__desc">{desc}</div>
: <p className="popup-bind__desc">该手机号已绑定到以下账号,继续绑定将解除以下绑定状态</p>
}
{desc ? (
<div className="popup-bind__desc">{desc}</div>
) : (
<p className="popup-bind__desc">
该手机号已绑定到以下账号,继续绑定将解除以下绑定状态
</p>
)}
<ul className="popup-bind__list">
{
bindInfo['email'] &&
{bindInfo["email"] && (
<li className="popup-bind__account">
{/* 邮箱 */}
<i className="popup-bind__icon" data-plat="mail"></i>
<p className="popup-bind__account--name">{bindInfo['email']}</p>
<p className="popup-bind__account--name">{bindInfo["email"]}</p>
</li>
}
{
bindInfo['wechat_nickname'] &&
)}
{bindInfo["wechat_nickname"] && (
<li className="popup-bind__account">
{/* wechat */}
<i className="popup-bind__icon" data-plat="wachat"></i>
<p className="popup-bind__account--name">{bindInfo['wechat_nickname']}</p>
<p className="popup-bind__account--name">
{bindInfo["wechat_nickname"]}
</p>
</li>
}
{
bindInfo['qq_nickname'] &&
)}
{bindInfo["qq_nickname"] && (
<li className="popup-bind__account">
{/* qq */}
<i className="popup-bind__icon" data-plat="qq"></i>
<p className="popup-bind__account--name">{bindInfo['qq_nickname']}</p>
<p className="popup-bind__account--name">
{bindInfo["qq_nickname"]}
</p>
</li>
}
{
bindInfo['sina_nickname'] &&
)}
{bindInfo["sina_nickname"] && (
<li className="popup-bind__account">
{/* 微博 */}
<i className="popup-bind__icon" data-plat="sina"></i>
<p className="popup-bind__account--name">{bindInfo['sina_nickname']}</p>
<p className="popup-bind__account--name">
{bindInfo["sina_nickname"]}
</p>
</li>
}
)}
</ul>
<div className="popup-bind__footer">
<button
className="popup-bind__button popup-bind__button--cancle"
onClick={handleToCancle}>取消</button>
className="popup-bind__button popup-bind__button--cancle"
onClick={handleToCancle}
>
取消
</button>
<button
className="popup-bind__button popup-bind__button--confirm"
onClick={this.continueBindPhone}>继续绑定</button>
className="popup-bind__button popup-bind__button--confirm"
onClick={this.continueBindPhone}
>
继续绑定
</button>
</div>
</div>
)
}
}
export default ConfirmPhone;
\ No newline at end of file
export default ConfirmPhone
......@@ -24,7 +24,7 @@
.popup-bind__footer {
padding: 0 18px;
}
.popup-bind__button {
width: 105px;
height: 30px;
......@@ -33,14 +33,14 @@
}
.popup-bind__button--cancle {
border: 1px solid #0099FF;
color: #0099FF;
border: 1px solid #0099ff;
color: #0099ff;
}
.popup-bind__button--confirm {
border-style: none;
color: #fff;
background-color: #0099FF;
background-color: #0099ff;
}
}
......@@ -56,7 +56,7 @@
.popup-bind__desc {
width: 269px;
font-size: 12px;
color: #FF2121;
color: #ff2121;
line-height: 18px;
}
......@@ -79,14 +79,14 @@
padding: 0 15px;
margin-bottom: 14px;
}
.popup-bind__button {
width: 130px;
height: 44px;
border-radius: 5px;
font-size: 16px;
}
.popup-bind__button--cancle {
border: 1px solid #090909;
color: #090909;
......@@ -95,11 +95,10 @@
.popup-bind__button--confirm {
border: 1px solid #090909;
color: #090909;
background-color: #FFE319;
background-color: #ffe319;
}
}
.popup-bind {
text-align: center;
}
......@@ -119,8 +118,8 @@
margin: 0 52px;
text-align: left;
&:nth-child(n+2) {
border-top: 1px solid #E5E5E5;
&:nth-child(n + 2) {
border-top: 1px solid #e5e5e5;
}
}
......@@ -135,19 +134,19 @@
background-position: center;
&[data-plat="mail"] {
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/icon-mail.png');
background-image: url("https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/icon-mail.png");
}
&[data-plat="sina"] {
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/icon-sina.png');
background-image: url("https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/icon-sina.png");
}
&[data-plat="qq"] {
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/icon-qq.png');
background-image: url("https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/icon-qq.png");
}
&[data-plat="wachat"] {
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/icon-wechat.png');
background-image: url("https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/icon-wechat.png");
}
}
......@@ -165,4 +164,4 @@
.popup-bind__button--cancle {
background-color: transparent;
}
\ No newline at end of file
}
import React from 'react'
import './course-base.scss'
import React from "react"
import "./course-base.scss"
const Course = (props) => {
return (
<li className={`course-base-item ${props.className}`} onClick={props.handleClick.bind(this, props.id)}>
{props.top}
<img src={props.img} alt=""/>
<p className="course-title">{props.title}</p>
{props.bottom}
</li>
);
};
export default Course;
return (
<li
className={`course-base-item ${props.className}`}
onClick={props.handleClick.bind(this, props.id)}
>
{props.top}
<img src={props.img} alt="" />
<p className="course-title">{props.title}</p>
{props.bottom}
</li>
)
}
export default Course
......@@ -51,4 +51,4 @@
width: 100%;
}
}
}
\ No newline at end of file
}
import React, {ReactNode, ReactElement} from 'react';
import {handleNavigation, Navigation} from "../index";
import {RequireAtLeastOne} from 'src/utils/types'
import {History} from "history";
import './index.scss'
import React, { ReactNode, ReactElement } from "react"
import { handleNavigation, Navigation } from "../index"
import { RequireAtLeastOne } from "src/utils/types"
import { History } from "history"
import "./index.scss"
export interface CoursePropsBasic {
image: string
title: string
courseId: number
status: ReactNode
navigate?: (courseId: number) => void
history?: History
subtitle?: string
tag?: ReactElement
marketing?: string
image: string
title: string
courseId: number
status: ReactNode
navigate?: (courseId: number) => void
history?: History
subtitle?: string
tag?: ReactElement
marketing?: string
}
export type CourseProps = RequireAtLeastOne<CoursePropsBasic, 'history' | 'navigate'>
const CourseCardH: React.FC<CourseProps> = ({image, title, subtitle, status, navigate, courseId, tag, history, marketing}) => {
return (
<div className={'course-card course-card-h'} onClick={(e) => {
if (navigate) {
handleNavigation({e, courseId, navigate})
} else {
handleNavigation({e, courseId, history} as Navigation)
}
}}>
<div className="show">
<img src={image} alt={title}/>
{marketing && <div className="marketing">{marketing}</div>}
{tag}
</div>
<div className="info">
<div className="title">{title}</div>
{subtitle && <div className="subtitle">{subtitle}</div>}
<div className="status">
{status}
</div>
</div>
</div>
);
export type CourseProps = RequireAtLeastOne<
CoursePropsBasic,
"history" | "navigate"
>
const CourseCardH: React.FC<CourseProps> = ({
image,
title,
subtitle,
status,
navigate,
courseId,
tag,
history,
marketing,
}) => {
return (
<div
className={"course-card course-card-h"}
onClick={(e) => {
if (navigate) {
handleNavigation({ e, courseId, navigate })
} else {
handleNavigation({ e, courseId, history } as Navigation)
}
}}
>
<div className="show">
<img src={image} alt={title} />
{marketing && <div className="marketing">{marketing}</div>}
{tag}
</div>
<div className="info">
<div className="title">{title}</div>
{subtitle && <div className="subtitle">{subtitle}</div>}
<div className="status">{status}</div>
</div>
</div>
)
}
CourseCardH.displayName = 'CourseCardH'
CourseCardH.displayName = "CourseCardH"
export default CourseCardH;
\ No newline at end of file
export default CourseCardH
......@@ -20,11 +20,11 @@
.title {
margin-bottom: 30px;
font-size: 15px;
color: #525C65;
color: #525c65;
display: -webkit-box;
-webkit-box-orient: vertical;
overflow: hidden;
-webkit-line-clamp: 2;
@include fontFamily('PingFangSC-Regular');
@include fontFamily("PingFangSC-Regular");
}
}
\ No newline at end of file
}
import React from 'react'
import {CourseProps} from '../course-card-h'
import {handleNavigation, Navigation} from "../index";
import React from "react"
import { CourseProps } from "../course-card-h"
import { handleNavigation, Navigation } from "../index"
import './index.scss'
import "./index.scss"
const CourseCardV: React.FC<CourseProps> = ({title, image, courseId, status, tag, navigate, history, marketing}) => {
return <div className={'course-card-v'} onClick={(e) => {
navigate ? handleNavigation({e, courseId, navigate})
: handleNavigation({e, courseId, history} as Navigation)
}}>
<div className="show">
<img src={image} alt={title}/>
{marketing && <div className="marketing">{marketing}</div>}
{tag}
</div>
<div className="title">{title}</div>
<div className="status">{status}</div>
const CourseCardV: React.FC<CourseProps> = ({
title,
image,
courseId,
status,
tag,
navigate,
history,
marketing,
}) => {
return (
<div
className={"course-card-v"}
onClick={(e) => {
navigate
? handleNavigation({ e, courseId, navigate })
: handleNavigation({ e, courseId, history } as Navigation)
}}
>
<div className="show">
<img src={image} alt={title} />
{marketing && <div className="marketing">{marketing}</div>}
{tag}
</div>
<div className="title">{title}</div>
<div className="status">{status}</div>
</div>
)
}
export default CourseCardV
\ No newline at end of file
export default CourseCardV
import React from "react";
import {withKnobs, number, text} from "@storybook/addon-knobs";
import {action} from "@storybook/addon-actions";
import React from "react"
import { withKnobs, number, text } from "@storybook/addon-knobs"
import { action } from "@storybook/addon-actions"
import CourseCardH from "./course-card-h";
import CourseCardV from "./course-card-v";
import CourseCardH from "./course-card-h"
import CourseCardV from "./course-card-v"
export const courseData = {
courseId: 140,
title: '三月面试求职班',
subtitle: '搞定算法 直通BAT',
image: 'https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/20a86c1353.jpg',
marketing: '拼团减100元'
courseId: 140,
title: "三月面试求职班",
subtitle: "搞定算法 直通BAT",
image:
"https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/20a86c1353.jpg",
marketing: "拼团减100元",
}
export default {
title: 'course-card',
component: CourseCardH,
decorators: [withKnobs, (story: () => React.ReactElement) => <div className={'shadow'}>{story()}</div>],
excludeStories: /.*Data$/
title: "course-card",
component: CourseCardH,
decorators: [
withKnobs,
(story: () => React.ReactElement) => (
<div className={"shadow"}>{story()}</div>
),
],
excludeStories: /.*Data$/,
}
let {title, courseId, image, subtitle, marketing} = courseData
let { title, courseId, image, subtitle, marketing } = courseData
let navigate = action(`navigate to /detail?id=${courseId}`)
const status = <button className={'purchase'}>立即购买</button>
const status = <button className={"purchase"}>立即购买</button>
export const Default = () => {
title = text('title', title)
subtitle = text('subtitle', subtitle)
image = text('image', image)
courseId = number('courseId', courseId)
marketing = text('marketing', marketing)
return <CourseCardH title={title} status={status} courseId={courseId} subtitle={subtitle} image={image}
navigate={navigate} marketing={marketing}></CourseCardH>
title = text("title", title)
subtitle = text("subtitle", subtitle)
image = text("image", image)
courseId = number("courseId", courseId)
marketing = text("marketing", marketing)
return (
<CourseCardH
title={title}
status={status}
courseId={courseId}
subtitle={subtitle}
image={image}
navigate={navigate}
marketing={marketing}
></CourseCardH>
)
}
export const V = () => {
title = text('title', title)
image = text('image', image)
courseId = number('courseId', courseId)
return <CourseCardV image={image} courseId={courseId} status={status} title={title}
navigate={navigate} marketing={marketing}></CourseCardV>
}
\ No newline at end of file
title = text("title", title)
image = text("image", image)
courseId = number("courseId", courseId)
return (
<CourseCardV
image={image}
courseId={courseId}
status={status}
title={title}
navigate={navigate}
marketing={marketing}
></CourseCardV>
)
}
......@@ -6,7 +6,7 @@
height: 24px;
color: #fff;
font-size: 13px;
background: rgba(224, 46, 36, .6);
background: rgba(224, 46, 36, 0.6);
text-align: center;
line-height: 24px;
}
\ No newline at end of file
}
import React from "react";
import { History } from "history";
import { RequireAtLeastOne } from 'src/utils/types'
import CourseCardV from "./course-card-v";
import CourseCardH from "./course-card-h";
import React from "react"
import { History } from "history"
import { RequireAtLeastOne } from "src/utils/types"
import CourseCardV from "./course-card-v"
import CourseCardH from "./course-card-h"
interface BaseNavigation {
e: React.MouseEvent
courseId: number
navigate?: (courseId: number) => void
history?: History
e: React.MouseEvent
courseId: number
navigate?: (courseId: number) => void
history?: History
}
export type Navigation = RequireAtLeastOne<BaseNavigation, 'history' | 'navigate'>
export type Navigation = RequireAtLeastOne<
BaseNavigation,
"history" | "navigate"
>
export const handleNavigation: (navigationArgs: Navigation) => void = ({ e, courseId, navigate, history }) => {
const _n = navigate || function (courseId: number) {
history!.push(`/detail?id=${courseId}`)
}
let nodeName = (e.target as HTMLElement).nodeName.toLowerCase()
if (nodeName === 'a' || nodeName === 'button') {
return
export const handleNavigation: (navigationArgs: Navigation) => void = ({
e,
courseId,
navigate,
history,
}) => {
const _n =
navigate ||
function (courseId: number) {
history!.push(`/detail?id=${courseId}`)
}
_n(courseId)
let nodeName = (e.target as HTMLElement).nodeName.toLowerCase()
if (nodeName === "a" || nodeName === "button") {
return
}
_n(courseId)
}
export const H = CourseCardH
export const V = CourseCardV
export default CourseCardH
\ No newline at end of file
export default CourseCardH
......@@ -4,6 +4,6 @@
right: 0;
bottom: 0;
left: 0;
background: rgba(0, 0, 0, .6);
background: rgba(0, 0, 0, 0.6);
z-index: 999;
}
\ No newline at end of file
}
import React from 'react';
import './index.scss'
import React from "react"
import "./index.scss"
const MaskCover:React.FC = ({children}) => {
return (
<div className={'mask-cover'}>
{children}
</div>
);
};
const MaskCover: React.FC = ({ children }) => {
return <div className={"mask-cover"}>{children}</div>
}
export default MaskCover;
\ No newline at end of file
export default MaskCover
import React from 'react'
import { Modal } from 'antd-mobile'
import './index.scss'
import React from "react"
import { Modal } from "antd-mobile"
import "./index.scss"
export default function ({
amount,
limit_amount,
onCancel = () => {
},
onConfirm
}) {
const content = (
<>
<div className="end-expansion-alert-ques">
{`你的${amount}元优惠券正在膨胀中,
amount,
limit_amount,
onCancel = () => {},
onConfirm,
}) {
const content = (
<>
<div className="end-expansion-alert-ques">
{`你的${amount}元优惠券正在膨胀中,
确定要结束膨胀吗?`}
</div>
<div className="end-expansion-alert-hint">
{`离${limit_amount}元只差一点点了!继续膨胀,优惠更多哦`}
</div>
</>
)
Modal.alert('温馨提示', content, [
{text: '再考虑下', onPress: onCancel, style: {color: '#333'}},
{text: '确定结束膨胀', onPress: onConfirm}
])
</div>
<div className="end-expansion-alert-hint">
{`离${limit_amount}元只差一点点了!继续膨胀,优惠更多哦`}
</div>
</>
)
Modal.alert("温馨提示", content, [
{ text: "再考虑下", onPress: onCancel, style: { color: "#333" } },
{ text: "确定结束膨胀", onPress: onConfirm },
])
}
.am-modal {
width: 300px;
width: 300px;
&-title {
font-size: 15px;
}
&-title {
font-size: 15px;
}
}
.end-expansion-alert {
&-ques {
width: 200px;
margin: 0 auto 20px;
text-align: center;
color: #666;
font-size: 15px;
}
&-ques {
width: 200px;
margin: 0 auto 20px;
text-align: center;
color: #666;
font-size: 15px;
}
&-hint {
color: #999;
font-size: 12px;
}
&-hint {
color: #999;
font-size: 12px;
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment