From 3159c6ddea66b1c37e956b0b1e23225a6d9c4596 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8F=AA=E6=8D=B1=E5=AE=85?= Date: Wed, 11 Dec 2019 19:12:56 +0800 Subject: [PATCH] chore: remove business (#358) * chore: remove business * ci: remove business * chore: remove useless file --- .github/workflows/test.yml | 24 - .vscode/launch.json | 3 +- ecosystem.config.js | 1 - package.json | 11 +- scripts/build-business-dev.js | 43 - scripts/build-business.js | 33 - scripts/utils.js | 18 - server/controller/ToyController.ts | 86 - .../__tests__/ToyController.test.ts | 29 - server/index.ts | 9 +- server/middleware/CheckSqlTomlResource.ts | 81 - server/resource/database.toml | 22 - server/resource/dump-structure.sql | 104 - server/resource/server.toml | 3 + server/resource/sql/goods-in-out.toml | 45 - server/resource/sql/test1.toml | 6 - server/resource/sql/test2.toml | 3 - server/service/ToyService.ts | 72 - server/service/__tests__/ToyService.test.ts | 19 - .../StockAndShipmentDataController.tsx | 452 -- .../StockAndShipmentDataController.test.tsx | 72 - src/pages/Inbound.tsx | 65 - src/pages/MUILoading.tsx | 29 - src/pages/Outbound.tsx | 135 - src/pages/__tests__/Inbound.test.tsx | 137 - src/pages/__tests__/MUILoading.test.tsx | 10 - .../__snapshots__/Inbound.test.tsx.snap | 3853 ----------------- .../__snapshots__/MUILoading.test.tsx.snap | 54 - src/router/StockAndShipmentDataController.tsx | 21 - src/utils/boundUtil.tsx | 479 -- 30 files changed, 11 insertions(+), 5908 deletions(-) delete mode 100644 scripts/build-business-dev.js delete mode 100644 scripts/build-business.js delete mode 100644 server/controller/ToyController.ts delete mode 100644 server/controller/__tests__/ToyController.test.ts delete mode 100644 server/middleware/CheckSqlTomlResource.ts delete mode 100644 server/resource/database.toml delete mode 100644 server/resource/dump-structure.sql delete mode 100644 server/resource/sql/goods-in-out.toml delete mode 100644 server/resource/sql/test1.toml delete mode 100644 server/resource/sql/test2.toml delete mode 100644 server/service/ToyService.ts delete mode 100644 server/service/__tests__/ToyService.test.ts delete mode 100644 src/controller/StockAndShipmentDataController.tsx delete mode 100644 src/controller/__tests__/StockAndShipmentDataController.test.tsx delete mode 100644 src/pages/Inbound.tsx delete mode 100644 src/pages/MUILoading.tsx delete mode 100644 src/pages/Outbound.tsx delete mode 100644 src/pages/__tests__/Inbound.test.tsx delete mode 100644 src/pages/__tests__/MUILoading.test.tsx delete mode 100644 src/pages/__tests__/__snapshots__/Inbound.test.tsx.snap delete mode 100644 src/pages/__tests__/__snapshots__/MUILoading.test.tsx.snap delete mode 100644 src/router/StockAndShipmentDataController.tsx delete mode 100644 src/utils/boundUtil.tsx diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6e617f772..681453579 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -110,30 +110,6 @@ jobs: needs: setup - site-business: - runs-on: ubuntu-latest - - steps: - - name: checkout - uses: actions/checkout@master - - - name: restore cache from package-lock.json - uses: actions/cache@v1 - with: - path: package-temp-dir - key: lock-${{ github.sha }} - - - name: restore cache from node_modules - uses: actions/cache@v1 - with: - path: node_modules - key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }} - - - name: build - run: npm run build:business - - needs: setup - case: runs-on: ubuntu-latest diff --git a/.vscode/launch.json b/.vscode/launch.json index 3cc1e98b3..1b8d56943 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -8,8 +8,7 @@ "type": "node", "request": "launch", "name": "Launch Program", - "program": "${workspaceFolder}/bin/index.js", - "env": { "BUILD_ENV": "toy" } + "program": "${workspaceFolder}/bin/index.js" } ] } diff --git a/ecosystem.config.js b/ecosystem.config.js index 105040b55..a73ef610b 100644 --- a/ecosystem.config.js +++ b/ecosystem.config.js @@ -7,7 +7,6 @@ module.exports = { autorestart: true, watch: ['bin', 'dist'], max_memory_restart: '512M', - env: { BUILD_ENV: 'toy' }, out_file: 'server/log/app-out.log', error_file: 'server/log/app-error.log', }, diff --git a/package.json b/package.json index 4eb47267a..d276f2512 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,6 @@ "scripts": { "build": "rimraf dist && cross-env BUILD_ENV=netlify nino koei", "build:analyse": "rimraf dist && cross-env BUILD_ENV=analyse nino koei", - "build:business": "rimraf dist && cross-env BUILD_ENV=business nino koei", "build:gh-pages": "rimraf dist && cross-env BUILD_ENV=gh-pages nino koei", "clean": "rimraf node_modules package-lock.json bin dist", "codecov": "nino test --codecov", @@ -26,7 +25,6 @@ "d": "npm run compile:server -- --watch", "deploy": "npm-run-all clean build:gh-pages pub", "dev": "rimraf dist && cross-env BUILD_ENV=dev nino koei -w -d", - "dev:business": "rimraf dist && cross-env BUILD_ENV=business-dev nino koei -w -d", "go": "pm2 start", "lint": "nino eslint", "lint-staged": "lint-staged", @@ -39,11 +37,9 @@ "server": "npm-run-all compile:server run:server", "sort": "npx sort-package-json", "start": "npm-run-all --parallel server dev", - "start:business": "npm-run-all --parallel server dev:business", "stop": "pm2 stop memo-server", "test": "nino test", - "tsc": "tsc", - "update-sql": "node scripts/copy-resource && npm run restart" + "tsc": "tsc" }, "pre-commit": [ "lint-staged" @@ -56,9 +52,6 @@ ] }, "devDependencies": { - "@material-ui/core": "^4.6.0", - "@material-ui/icons": "^4.5.1", - "@material-ui/lab": "^4.0.0-alpha.30", "@testing-library/react-hooks": "^3.2.1", "@types/blueimp-md5": "^2.7.0", "@types/enzyme": "^3.10.3", @@ -69,7 +62,6 @@ "@types/koa-router": "^7.0.42", "@types/koa-static": "^4.0.1", "@types/marked": "^0.7.0", - "@types/mysql": "^2.15.7", "@types/prettier": "^1.19.0", "@types/puppeteer-core": "^2.0.0", "@types/react": "^16.9.14", @@ -98,7 +90,6 @@ "marked": "^0.7.0", "mini-xmind": "^1.4.2", "mockdate": "^2.0.5", - "mysql": "^2.17.1", "nino-cli": "^1.3.6", "node-fetch": "^2.6.0", "npm-run-all": "^4.1.5", diff --git a/scripts/build-business-dev.js b/scripts/build-business-dev.js deleted file mode 100644 index e6149cd2a..000000000 --- a/scripts/build-business-dev.js +++ /dev/null @@ -1,43 +0,0 @@ -const PostCompile = require('post-compile-webpack-plugin'); -const path = require('path'); -const { compressJSON, getHtmlPluginProps, getEntry } = require(path.join(__dirname, './utils')); -const IO = require('socket.io-client'); -const open = require('open'); - -const socket = IO('http://localhost:9099'); -let isBrowserExists = false; - -const commonHtmlWebpackProps = { - minify: { - minifyJS: true, - minifyCSS: true, - removeComments: true, - collapseWhitespace: true, - }, - environment: '', - baseTag: '', - socket: '', - inject: 'body', - hotjar: '', - googleAnalytics: '', -}; - -// Don't merge these plugins into utils, for customed plugins -const htmlPluginProps = getHtmlPluginProps(commonHtmlWebpackProps); - -const plugins = [ - ...htmlPluginProps, - new PostCompile(async () => { - socket.emit('refresh'); - compressJSON(); - if (!isBrowserExists) { - isBrowserExists = true; - await open('http://localhost:9099/stock-shipment'); - } - }), -]; - -module.exports = { - entry: getEntry(), - plugins, -}; diff --git a/scripts/build-business.js b/scripts/build-business.js deleted file mode 100644 index 596992922..000000000 --- a/scripts/build-business.js +++ /dev/null @@ -1,33 +0,0 @@ -const PostCompile = require('post-compile-webpack-plugin'); -const path = require('path'); -const { compressJSON, getHtmlPluginProps, getEntry } = require(path.join(__dirname, './utils')); - -const commonHtmlWebpackProps = { - minify: { - minifyJS: true, - minifyCSS: true, - removeComments: true, - collapseWhitespace: true, - }, - environment: '', - baseTag: '', - socket: '', - inject: 'body', - hotjar: '', - googleAnalytics: '', -}; - -// Don't merge these plugins into utils, for customed plugins -const htmlPluginProps = getHtmlPluginProps(commonHtmlWebpackProps); - -const plugins = [ - ...htmlPluginProps, - new PostCompile(() => { - compressJSON(); - }), -]; - -module.exports = { - entry: getEntry(), - plugins, -}; diff --git a/scripts/utils.js b/scripts/utils.js index 5db8463ed..f47a3a10c 100644 --- a/scripts/utils.js +++ b/scripts/utils.js @@ -20,7 +20,6 @@ const getEntry = () => { 'markdown-editor': handleWithPrefix('src/router/MarkdownEditorDataController.tsx'), 'mapping-detail': handleWithPrefix('src/router/MappingDetailDataController.tsx'), 'mapping-editor': handleWithPrefix('src/router/MappingDetailDataController.tsx'), - 'stock-shipment': handleWithPrefix('src/router/StockAndShipmentDataController.tsx'), ninoninoni: handleWithPrefix('src'), }; const result = { @@ -28,8 +27,6 @@ const getEntry = () => { analyse: common, 'gh-pages': common, dev: common, - business: { 'stock-shipment': handleWithPrefix('src/router/StockAndShipmentDataController.tsx') }, - 'business-dev': { 'stock-shipment': handleWithPrefix('src/router/StockAndShipmentDataController.tsx') }, }; return result[buildEnv]; }; @@ -38,17 +35,6 @@ const getHtmlPluginProps = customedHtmlWebpackProps => { const commonHtmlWebpackProps = { template: handleWithPrefix('src/index.html'), }; - const HtmlWebpackPropsForBusiness = new HtmlWebpackPlugin({ - ...commonHtmlWebpackProps, - ...customedHtmlWebpackProps, - filename: 'stock-shipment/index.html', - chunks: ['stock-shipment'], - title: `${author}'s business`, - description: `${author}'s business`, - }); - if (buildEnv === 'business' || buildEnv === 'business-dev') { - return [HtmlWebpackPropsForBusiness]; - } const mainPageProps = [ new HtmlWebpackPlugin({ @@ -60,10 +46,6 @@ const getHtmlPluginProps = customedHtmlWebpackProps => { description: `${author}'s ${name}`, }), ]; - // Build `stock-shipment` only in dev and business - if (buildEnv === 'dev') { - mainPageProps.push(HtmlWebpackPropsForBusiness); - } const detailPageProps = []; const editorPageProps = []; diff --git a/server/controller/ToyController.ts b/server/controller/ToyController.ts deleted file mode 100644 index 80c009055..000000000 --- a/server/controller/ToyController.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { Controller, Request } from '../utils/decorator'; -import ToyService from '../service/ToyService'; -import { Context } from 'koa'; - -@Controller('/toy') -export default class ToyController { - constructor(private service: ToyService) { - this.service = new ToyService(); - } - - @Request({ url: '/get/:key', method: 'get' }) - async getDataByGet(ctx: Context) { - const { key } = ctx.params; - const { result } = await this.service.getDataBySqlKey(key, ctx.query); - return result; - } - - @Request({ url: '/post/:key', method: 'post' }) - async getDataByPost(ctx: Context) { - const { key } = ctx.params; - const { result } = await this.service.getDataBySqlKey(key, ctx.request.body); - return result; - } - - @Request({ url: '/put/:key', method: 'put' }) - async getDataByPut(ctx: Context) { - const { key } = ctx.params; - const { result } = await this.service.getDataBySqlKey(key, ctx.request.body); - return result; - } - - @Request({ url: '/delete/:key', method: 'delete' }) - async getDataByDelete(ctx: Context) { - const { key } = ctx.params; - const { result } = await this.service.getDataBySqlKey(key, ctx.request.body); - return result; - } - - // 入 / 出库更新数据 - // 先查到原有库存,然后确定是加还是减 - // 页面传过来的高度为垂直于截面的长度,对应库表中的长度 - @Request({ url: '/good/in', method: 'post' }) - async addGood(ctx: Context) { - const params = ctx.request.body; - const materialDetail = await this.service.getDataBySqlKey('get-detail-by-material-id', { - materialId: params.materialId, - }); - const originWeight = materialDetail.result[0]['库存重量']; - // type == 0 为入库,库存增加;type == 1 为出库,库存减少 - const updateStatus = params.type ? -1 : 1; - params.newWeight = originWeight + params.weight * updateStatus; - await this.service.getDataBySqlKey('goods-in', params); - } - - // 更新材料类型 - // 入库前先检查目标数据是否已经存在 - @Request({ url: '/good/type/in', method: 'post' }) - async addMaterialType(ctx: Context) { - const params = ctx.request.body; - const realParams = Object.assign( - { - 材质: 0, - 长: 0, - 宽: 0, - 高: 0, - 卖出方式: 0, - 制作标准: 0, - 制作方式: 0, - 处理工艺: 0, - 单价: 0, - 锯费: 0, - 产地: '', - 类别1: 0, - 类别2: 0, - 类别3: 0, - 类别4: 0, - }, - params, - ); - const materialDetail = await this.service.getDataBySqlKey('get-material-type-by-detail', realParams); - if (materialDetail.result.length) { - return '当前规格已存在'; - } - await this.service.getDataBySqlKey('add-material-type', realParams); - } -} diff --git a/server/controller/__tests__/ToyController.test.ts b/server/controller/__tests__/ToyController.test.ts deleted file mode 100644 index 8f3cf2796..000000000 --- a/server/controller/__tests__/ToyController.test.ts +++ /dev/null @@ -1,29 +0,0 @@ -import Controller from '../ToyController'; - -const defaultPostCtx = { - request: { body: {} }, - response: { body: '' }, - params: { key: 'test1' }, - query: { id: 1 }, -}; -describe('ToyController', () => { - it('/get/:key', async () => { - const result = await (Controller as any).stack[0].stack[0](defaultPostCtx); - expect(result).toBe('result'); - }); - - it('/post/:key', async () => { - const result = await (Controller as any).stack[1].stack[0](defaultPostCtx); - expect(result).toBe('result'); - }); - - it('/put/:key', async () => { - const result = await (Controller as any).stack[2].stack[0](defaultPostCtx); - expect(result).toBe('result'); - }); - - it('/delete/:key', async () => { - const result = await (Controller as any).stack[3].stack[0](defaultPostCtx); - expect(result).toBe('result'); - }); -}); diff --git a/server/index.ts b/server/index.ts index 193c388de..254ee011a 100644 --- a/server/index.ts +++ b/server/index.ts @@ -6,7 +6,9 @@ import { createServer } from 'http'; import IO from 'socket.io'; import path from 'path'; import DecoratorRouter from './middleware/DecoratorRouter'; -import CheckSqlTomlResource from './middleware/CheckSqlTomlResource'; +import { info } from './utils/log'; +import { getTargetResource } from './utils/resource'; +const config = getTargetResource('server'); const app = new Koa(); const server = createServer(app.callback()); @@ -21,8 +23,9 @@ io.on('connection', socket => { app.use(BodyParser()); app.use(DecoratorRouter(path.join(__dirname, 'controller'))); app.use(KoaStatic(joinWithRootPath('dist'))); -app.use(CheckSqlTomlResource(path.join(__dirname, 'resource/sql'))); -server.listen(9099); +const port = config.server.port; +server.listen(port); +info(`listen at ${port}.`); export { server }; diff --git a/server/middleware/CheckSqlTomlResource.ts b/server/middleware/CheckSqlTomlResource.ts deleted file mode 100644 index 73c69ea53..000000000 --- a/server/middleware/CheckSqlTomlResource.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { Context } from 'koa'; -import toml from 'toml'; -import fs from 'fs-extra'; -import path from 'path'; -import { HttpMehtod } from '../utils/decorator'; -import { error } from '../utils/log'; - -export interface SqlInstanceProps { - sql: string; - method: HttpMehtod; - path?: string; -} - -const initResourcePath = (resourcePath: string | string[]) => { - let paths = []; - if (typeof resourcePath === 'string') { - paths.push(resourcePath); - } else { - paths = resourcePath; - } - return paths; -}; - -export const getAllSqlInstances = (paths: string[], isInjectPath = true): SqlInstanceProps[] => { - const instances = []; - for (const dirPath of paths) { - const resourcePath = fs.readdirSync(dirPath); - for (const fileUrls of resourcePath) { - const fileUrl = path.join(dirPath, fileUrls); - const resourceFile = fs.readFileSync(fileUrl, 'utf-8'); - const result = toml.parse(resourceFile); - if (isInjectPath) { - result.path = fileUrl; - } - instances.push(result); - } - } - return instances; -}; - -const checkRepeatedKey = (instances: SqlInstanceProps[]) => { - let keys = []; - let repeatedKeys = []; - for (const instance of instances) { - keys.push(Object.keys(instance)[0]); - } - - const len = keys.length; - keys = keys.sort(); - for (let i = 0; i < len - 1; i++) { - if (keys[i] === keys[i + 1]) { - repeatedKeys.push(keys[i]); - } - } - repeatedKeys = Array.from(new Set(repeatedKeys)); - - for (const instance of instances) { - const key = Object.keys(instance)[0]; - for (const item of repeatedKeys) { - if (key === item) { - error(`repeated key ${key} in ${instance.path}`); - } - } - } - - if (repeatedKeys.length) { - throw Error('please check keys in sql files'); - } -}; - -const CheckSqlTomlResource = (resourcePath: string | string[]) => { - const paths = initResourcePath(resourcePath); - const sqls = getAllSqlInstances(paths); - checkRepeatedKey(sqls); - - return async (_: Context, next: Function) => { - await next(); - }; -}; - -export default CheckSqlTomlResource; diff --git a/server/resource/database.toml b/server/resource/database.toml deleted file mode 100644 index 80cf4f9eb..000000000 --- a/server/resource/database.toml +++ /dev/null @@ -1,22 +0,0 @@ -[mysql] -host = 'localhost' -user = 'orzyyyy' -password = 'test123456' -database = 'toy-box' -multipleStatements = true - -[sign] -'出入库' = 0 -# 圆钢、方钢、模套、模具钢、合金钢 -'材料类别' = 1 -'圆钢材料组' = 2 -'方钢材料组' = 3 -# 管子、炮筒 -'模套分类' = 4 -# 冷作、热作 -'制作方式' = 5 -# 进口、国标 -'制作标准' = 6 -# 淬火、未淬火 -'处理工艺' = 7 -'产地' = 8 diff --git a/server/resource/dump-structure.sql b/server/resource/dump-structure.sql deleted file mode 100644 index 2d778c54d..000000000 --- a/server/resource/dump-structure.sql +++ /dev/null @@ -1,104 +0,0 @@ -CREATE DATABASE IF NOT EXISTS `toy-box` /*!40100 DEFAULT CHARACTER SET utf8mb4 */; -USE `toy-box`; --- MySQL dump 10.16 Distrib 10.1.37-MariaDB, for debian-linux-gnu (x86_64) --- --- Host: localhost Database: toy-box --- ------------------------------------------------------ --- Server version 10.1.37-MariaDB-0+deb9u1 - -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; -/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; -/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; -/*!40101 SET NAMES utf8 */; -/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; -/*!40103 SET TIME_ZONE='+00:00' */; -/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; -/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; -/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; - --- --- Table structure for table `dictionary` --- - -DROP TABLE IF EXISTS `dictionary`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `dictionary` ( - `sign` int(11) DEFAULT NULL, - `text` varchar(100) DEFAULT NULL, - `value` varchar(100) DEFAULT NULL, - `description` text, - `id` int(11) NOT NULL AUTO_INCREMENT, - PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=47 DEFAULT CHARSET=utf8mb4; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Table structure for table `goods_in_and_out` --- - -DROP TABLE IF EXISTS `goods_in_and_out`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `goods_in_and_out` ( - `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '批号。每批只会有一次运输消耗', - `type` int(11) DEFAULT NULL COMMENT '入库 / 出库', - `material_id` int(11) DEFAULT NULL COMMENT '材料类别', - `weight` decimal(10,2) DEFAULT NULL, - `patch` varchar(45) DEFAULT NULL, - `description` varchar(45) DEFAULT NULL, - `create_time` datetime DEFAULT CURRENT_TIMESTAMP, - `modify_time` datetime DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8mb4; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Table structure for table `material_detail` --- - -DROP TABLE IF EXISTS `material_detail`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `material_detail` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `类别1` int(11) DEFAULT '0' COMMENT 'sign = 1', - `类别2` int(11) DEFAULT '0', - `类别3` int(11) DEFAULT '0', - `类别4` int(11) DEFAULT '0', - `材质` varchar(45) DEFAULT '0', - `制作方式` int(11) DEFAULT '0', - `制作标准` int(11) DEFAULT '0', - `处理工艺` int(11) DEFAULT '0', - `单价` varchar(50) DEFAULT '0.00', - `锯费` decimal(9,2) DEFAULT '0.00', - `长` decimal(9,2) DEFAULT '0.00', - `宽` decimal(9,2) DEFAULT '0.00', - `产地` varchar(45) DEFAULT '', - `库存长度` decimal(9,2) DEFAULT '0.00', - `库存重量` decimal(9,2) DEFAULT '0.00', - `卖出方式` int(11) DEFAULT '0', - `是否校准` int(11) DEFAULT '0', - PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=3209 DEFAULT CHARSET=utf8mb4; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping events for database 'toy-box' --- - --- --- Dumping routines for database 'toy-box' --- -/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; - -/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; -/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; -/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; -/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; - --- Dump completed on 2019-12-06 10:20:50 diff --git a/server/resource/server.toml b/server/resource/server.toml index 86a6e2b44..9c64aa5ae 100644 --- a/server/resource/server.toml +++ b/server/resource/server.toml @@ -21,3 +21,6 @@ dateFormat = 'yyyy-MM-dd HH:mm:ss' [document] mappingFilePath = 'src/assets/mapping.json' + +[server] +port = 9099 diff --git a/server/resource/sql/goods-in-out.toml b/server/resource/sql/goods-in-out.toml deleted file mode 100644 index 4a7713a4f..000000000 --- a/server/resource/sql/goods-in-out.toml +++ /dev/null @@ -1,45 +0,0 @@ -[goods-in] -sql = """ - insert into `goods_in_and_out` (type, weight, patch, description, material_id) - values (@type, @weight, @@dateStamp, @description, @materialId); - - update `material_detail` set 库存重量 = @newWeight - where id = @materialId; -""" -method = 'post' - -[add-material-type] -sql = """ - insert into `material_detail` (类别1, 类别2, 类别3, 类别4, 材质, 单价, 锯费, 长, 宽, 卖出方式, 制作标准, 制作方式, 产地, 处理工艺) - values (@类别1, @类别2, @类别3, @类别4, @材质, @单价, @锯费, @长, @宽, @卖出方式, @制作标准, @制作方式, @产地, @处理工艺) -""" -method = 'post' - -[get-material-type-by-detail] -sql = """ - select * from `material_detail` - where 长 = @长 and 宽 = @宽 and 类别1 = @类别1 and 类别2 = @类别2 and 类别3 = @类别3 and 类别4 = @类别4 and 材质 = @材质 and 卖出方式 = @卖出方式 and 制作标准 = @制作标准 and 制作方式 = @制作方式 and 产地 = @产地 and 处理工艺 = @处理工艺 and 产地 = @产地 -""" -method = 'get' - -[get-detail-by-material-id] -sql = """ - select * from material_detail where id = @materialId -""" -method = 'get' - -[get-detail] -sql = """ - select * from material_detail where 类别1 = @materialType -""" - -[get-detail-info] -sql = """ - select id as value, 材质 as text, 单价 as price, 锯费 as costFee from material_detail - where 类别1 = @materialType and 卖出方式 = @sellType and 长 = @length and 宽 = @width -""" - -[get-material-type] -sql = """ - select text, value from dictionary where sign = @sign -""" diff --git a/server/resource/sql/test1.toml b/server/resource/sql/test1.toml deleted file mode 100644 index c5ae3a5f6..000000000 --- a/server/resource/sql/test1.toml +++ /dev/null @@ -1,6 +0,0 @@ -[test1] -sql = """ - SELECT * FROM dictionary where value = @value and - id = @id; -""" -method = 'post' diff --git a/server/resource/sql/test2.toml b/server/resource/sql/test2.toml deleted file mode 100644 index 8cc5cbd48..000000000 --- a/server/resource/sql/test2.toml +++ /dev/null @@ -1,3 +0,0 @@ -[test2] -sql = 'SELECT * FROM dictionary where value = 1;' -method = 'get' diff --git a/server/service/ToyService.ts b/server/service/ToyService.ts deleted file mode 100644 index 54b81e218..000000000 --- a/server/service/ToyService.ts +++ /dev/null @@ -1,72 +0,0 @@ -import mysql, { Connection, FieldInfo } from 'mysql'; -import { getTargetResource } from '../utils/resource'; -import path from 'path'; -import { getAllSqlInstances, SqlInstanceProps } from '../middleware/CheckSqlTomlResource'; -import { replacePlaceholderWithParams } from '../utils/sql'; - -export default class ToyService { - private static connectionInstance: Connection; - private static sqlIns: { [key: string]: SqlInstanceProps }; - connection: Connection; - sqlInstance: { [key: string]: SqlInstanceProps }; - - // To use this.connection instead of ToyService.connectionInstance - // in class body - constructor() { - if (!ToyService.connectionInstance) { - const connect = this.createConnection(); - connect.connect(); - - const sqlInstance = {}; - getAllSqlInstances([path.join(__dirname, '../resource/sql')], false).map(item => - Object.assign(sqlInstance, item), - ); - - ToyService.connectionInstance = connect; - ToyService.sqlIns = sqlInstance; - this.connection = connect; - this.sqlInstance = sqlInstance; - } else { - this.connection = ToyService.connectionInstance; - this.sqlInstance = ToyService.sqlIns; - } - } - - public static getConnection() { - if (!ToyService.connectionInstance) { - ToyService.connectionInstance = new ToyService().createConnection(); - ToyService.connectionInstance.connect(); - } - return ToyService.connectionInstance; - } - - private createConnection = () => { - const config = getTargetResource('database').mysql; - return mysql.createConnection(config); - }; - - getDataBySqlKey = (key: string, query: any): Promise<{ result: any; fields: FieldInfo[] | undefined }> => { - let { sql } = this.sqlInstance[key]; - if (Object.keys(query).length && sql) { - sql = replacePlaceholderWithParams(sql, query); - } - const connection = this.connection; - return new Promise(resolve => { - connection.query(sql, (error, result, fields) => { - if (error) { - return connection.rollback(() => { - throw error; - }); - } - connection.commit(error => { - if (error) { - return connection.rollback(() => { - throw error; - }); - } - resolve({ result, fields }); - }); - }); - }); - }; -} diff --git a/server/service/__tests__/ToyService.test.ts b/server/service/__tests__/ToyService.test.ts deleted file mode 100644 index a33c92ea4..000000000 --- a/server/service/__tests__/ToyService.test.ts +++ /dev/null @@ -1,19 +0,0 @@ -import Service from '../ToyService'; -const { innerMock } = require('../__mocks__/mysql'); - -describe('ToyService', () => { - let service: Service; - - beforeEach(async () => { - service = new Service(); - }); - - it('getDataBySqlKey', async () => { - const result = await service.getDataBySqlKey('test1', { id: 1 }); - expect(result).toEqual({ fields: 'fields', result: 'result' }); - }); - - it('single connected instance', () => { - expect(Service.getConnection()).toEqual(innerMock); - }); -}); diff --git a/src/controller/StockAndShipmentDataController.tsx b/src/controller/StockAndShipmentDataController.tsx deleted file mode 100644 index 8740f70f7..000000000 --- a/src/controller/StockAndShipmentDataController.tsx +++ /dev/null @@ -1,452 +0,0 @@ -import React, { useEffect, useReducer } from 'react'; -import Inbound from '../pages/Inbound'; -import Outbound from '../pages/Outbound'; -import { AppBar, Toolbar, IconButton, Typography } from '@material-ui/core'; -import { - FormControlType, - renderMessage, - SelectFormItemProps, - InputFormItemProps, - FormOptionsProps, -} from '../utils/boundUtil'; -import MenuIcon from '@material-ui/icons/Menu'; - -const ERROR_MESSAGE = '该项不能为空'; -const SELECT_FORM_ITEM_DEFAULT_VALUE = { value: -1, error: false, message: '' }; -const INPUT_FORM_ITEM_DEFAULT_VALUE = { value: '', error: false, message: '' }; - -export type FormItemStatus = 'stateful' | 'stateless'; - -// 控制页面返回状态的属性 -export interface ViewProps { - loading: boolean; - submitSuccess: boolean; - submitFailed: boolean; -} - -export interface OnChangeProps { - item: any; - controllType: FormControlType; - key: FormStatelessFields | FormStatefulFields; - stateType: FormItemStatus; -} - -export interface FormStatelessProps { - // 出库为 1,入库为 0 - type: number; - // 预估重量 - predictWeight: number; - // 其他费用 - extraCost: number; - // 备注 - description: string; - // 锯费 - costFee: number; - // 预估总价 - predictPrice: number; - // 出库时的单价 - materialCost: string; -} - -export interface FormStatefulProps { - // 类别 - materialType: SelectFormItemProps; - // 材质 - materialId: { value: { text: string; value: any }; error: boolean; message: string }; - // 长宽重 - length: InputFormItemProps; - width: InputFormItemProps; - weight: InputFormItemProps; - // 数量。出库用 - materialQuantity: InputFormItemProps; - // 卖出方式。零售 / 批量 - sellType: SelectFormItemProps; -} - -export type FormStatefulFields = - | 'materialType' // 类别 - | 'length' // 长宽重 - | 'width' - | 'weight' - | 'sellType' // 卖出方式 - | 'materialId' // 材质 - | 'materialQuantity'; // 数量。出库用 - -export type FormStatelessFields = - | 'type' // 出库为 1,入库为 0 - | 'description' // 备注 - | 'costFee' // 锯费 - | 'predictPrice' // 预估总价 - | 'materialCost'; // 出库时单价 - -// 需要管理表单状态的业务属性 -const initialStateful: FormStatefulProps = { - // 类别 - materialType: SELECT_FORM_ITEM_DEFAULT_VALUE, - // 材质 - materialId: Object.assign({}, SELECT_FORM_ITEM_DEFAULT_VALUE, { value: { text: '', value: -1 } }), - // 长宽重 - length: INPUT_FORM_ITEM_DEFAULT_VALUE, - width: INPUT_FORM_ITEM_DEFAULT_VALUE, - weight: INPUT_FORM_ITEM_DEFAULT_VALUE, - // 数量。出库用 - materialQuantity: INPUT_FORM_ITEM_DEFAULT_VALUE, - // 卖出方式 - sellType: SELECT_FORM_ITEM_DEFAULT_VALUE, -}; - -// 不需要表单状态的业务属性 -const initialStateless: FormStatelessProps = { - // 出库为 1,入库为 0 - type: 0, - // 预估重量 - predictWeight: '' as any, - // 其他费用 - extraCost: '' as any, - // 备注 - description: '' as any, - // 锯费 - costFee: '' as any, - // 预估总价 - predictPrice: '' as any, - // 出库时的单价 - materialCost: '', -}; - -const initialViewState: ViewProps = { - loading: false, - submitSuccess: false, - submitFailed: false, -}; - -// 菜单项 -const initialMenuOptionState: FormOptionsProps = { - // 类别菜单项 - materialTypeOption: [], - // 材质菜单项 - materialIdOption: [], - // 卖出方式菜单项 - sellTypeOption: [], - materialCostOption: [], -}; - -const statefulReducer = ( - state: FormStatefulProps, - action: { - data: any; - type: FormControlType; - key: FormStatefulFields; - }, -) => { - const getReturn = (validStr: string | number) => { - if (action.data.value === validStr) { - return { ...state, [action.key]: { value: validStr, error: true, message: ERROR_MESSAGE } }; - } - const result = { - ...state, - [action.key]: { - value: - action.type === 'autoComplete' ? { text: action.data.text, value: action.data.value } : action.data.value, - error: action.data.value === validStr, - message: action.data.value === validStr ? ERROR_MESSAGE : '', - }, - }; - return result; - }; - - switch (action.type) { - case 'input': - return getReturn(''); - - case 'select': - case 'autoComplete': - return getReturn(-1); - - default: - throw new Error(`Unknown type "${action.type}" in statefulReducer.`); - } -}; - -const statelessReducer = ( - state: FormStatelessProps, - action: { - type: FormStatelessFields; - data: any; - }, -) => ({ ...state, [action.type]: action.data }); - -const viewStateReducer = (state: ViewProps, action: { type: 'reset' | 'success' | 'failed' | 'loading' }) => { - switch (action.type) { - case 'loading': - return { loading: true, submitSuccess: false, submitFailed: false }; - - case 'reset': - return { loading: false, submitSuccess: false, submitFailed: false }; - - case 'success': - return { ...state, submitSuccess: true }; - - case 'failed': - return { ...state, submitFailed: true }; - - default: - throw new Error(`Unknown type "${action.type}" in viewStateReducer.`); - } -}; - -const menuOptionReducer = ( - state: FormOptionsProps, - action: { - type: - | 'materialTypeOption' // 类别 - | 'sellTypeOption' // 卖出方式 - | 'materialIdOption' // 材质 - | 'materialCostOption'; // 单价区间 - data: any; - }, -) => ({ ...state, [action.type]: action.data }); - -const StockAndShipmentDataController = () => { - const [stateful, statefulDispatch] = useReducer(statefulReducer, initialStateful as any); - const [stateless, statelessDispatch] = useReducer(statelessReducer, initialStateless as any); - const [viewState, viewStateDispatch] = useReducer(viewStateReducer, initialViewState as any); - const [menuOptionState, menuOptionDispatch] = useReducer(menuOptionReducer, initialMenuOptionState as any); - - useEffect(() => { - const fetcher = async (sign: number, callback: (result: any) => void) => { - const response = await fetch('/toy/get/get-material-type?sign=' + sign); - const result = await response.json(); - callback(await result); - }; - - fetcher(1, data => menuOptionDispatch({ type: 'materialTypeOption', data })); - fetcher(9, data => menuOptionDispatch({ type: 'sellTypeOption', data })); - }, []); - - const verifySubmitParams = () => { - const { materialType, length, width, weight, sellType, materialId, materialQuantity } = stateful; - statefulDispatch({ type: 'select', key: 'materialType', data: materialType }); - statefulDispatch({ type: 'input', key: 'length', data: length }); - if (width.value === '' && materialType.value !== -1) { - statefulDispatch({ type: 'input', key: 'width', data: width }); - } - statefulDispatch({ type: 'input', key: 'weight', data: weight }); - statefulDispatch({ type: 'input', key: 'materialQuantity', data: materialQuantity }); - statefulDispatch({ type: 'select', key: 'sellType', data: sellType }); - statefulDispatch({ type: 'autoComplete', key: 'materialId', data: materialId.value }); - - const params = { - type: stateless.type, - materialId: materialId.value.value, - weight: weight.value, - description: stateless.description, - }; - - // todo: 本来应该遍历 stateful,看 error 是否为 true 来判断表单项是否有误 - // 但因为 stateful 此时尚未更新,所以暂时用硬编码来判断 - let hasError = false; - if (params.materialId === '' || params.materialId === -1) { - hasError = true; - } - if (!weight.value) { - hasError = true; - } - - return { hasError, params }; - }; - - const handleSubmit = async () => { - const { hasError, params } = verifySubmitParams(); - if (hasError) { - return; - } - - viewStateDispatch({ type: 'loading' }); - const response = await fetch('/toy/good/in', { - body: JSON.stringify(params), - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - }); - const result = await response.text(); - viewStateDispatch({ type: result === 'success' ? 'success' : 'failed' }); - return params; - }; - - const calcuteForPredictPrice = (weight: number, costFee: number, materialCost: number, materialQuantity: number) => { - const price = weight * materialCost + materialQuantity * costFee; - return price; - }; - - const handleSpecificationInputBlur = () => { - const { materialQuantity, weight } = stateful; - const price = calcuteForPredictPrice( - parseFloat(weight.value) || 0, - stateless.costFee || 0, - parseFloat(stateless.materialCost), - parseFloat(materialQuantity.value) || 0, - ); - statelessDispatch({ type: 'predictPrice', data: parseFloat(price.toFixed(1)) }); - }; - - const fetchMaterialIdOption = async (type: number | string) => { - const response = await fetch('/toy/get/get-detail?materialType=' + type); - const result = await response.json(); - const target: any = []; - result.map((item: any) => { - target.push({ - value: item.id, - text: item['材质'], - costFee: item['锯费'], - materialCost: item['单价'], - length: item['长'], - width: item['宽'], - sellType: item['卖出方式'], - }); - }); - menuOptionDispatch({ type: 'materialIdOption', data: target }); - }; - - const handleChange = ({ item, controllType, key, stateType }: OnChangeProps) => { - const handleWithState = (type: FormControlType) => { - if (stateType === 'stateful') { - if (controllType === 'autoComplete' && stateless.type === 1) { - const materialCostOption = item.materialCost.split(',').map((item: string) => ({ text: item, value: item })); - menuOptionDispatch({ type: 'materialCostOption', data: materialCostOption }); - statelessDispatch({ - type: 'materialCost', - data: materialCostOption.length ? materialCostOption[0].value : '', - }); - } - statefulDispatch({ - type, - key: key as FormStatefulFields, - data: item, - }); - } else if (stateType === 'stateless') { - if (key === 'materialCost') { - const { materialQuantity, weight } = stateful; - const price = calcuteForPredictPrice( - parseFloat(weight.value) || 0, - stateless.costFee || 0, - parseFloat(item.value), - parseFloat(materialQuantity.value) || 0, - ); - // 出库时选择单价后重新计算总价 - statelessDispatch({ type: 'predictPrice', data: parseFloat(price.toFixed(1)) }); - } - statelessDispatch({ type: key as FormStatelessFields, data: item.value }); - } - }; - - switch (controllType) { - case 'input': - handleWithState(controllType); - break; - - case 'select': - if (item.value !== -1 && key === 'materialType') { - fetchMaterialIdOption(item.value); - } - handleWithState(controllType); - break; - - case 'autoComplete': - statelessDispatch({ type: 'costFee', data: item ? item.costFee : 0 }); - handleWithState(controllType); - break; - - default: - break; - } - }; - - const hanldeCloseMessage = () => { - const { materialQuantity, length, width, weight, materialType, sellType, materialId } = stateful; - viewStateDispatch({ type: 'reset' }); - - statelessDispatch({ type: 'description', data: '' }); - statelessDispatch({ type: 'costFee', data: 0 }); - statelessDispatch({ type: 'predictPrice', data: 0 }); - - statefulDispatch({ type: 'input', key: 'materialQuantity', data: materialQuantity }); - statefulDispatch({ type: 'input', key: 'length', data: length }); - statefulDispatch({ type: 'input', key: 'width', data: width }); - statefulDispatch({ type: 'input', key: 'weight', data: weight }); - - statefulDispatch({ type: 'select', key: 'materialType', data: materialType }); - statefulDispatch({ type: 'select', key: 'sellType', data: sellType }); - statefulDispatch({ type: 'autoComplete', key: 'materialId', data: materialId }); - }; - - const commonFormData = { - materialType: stateful.materialType, - materialId: stateful.materialId, - materialCost: stateless.materialCost, - type: stateless.type, - length: stateful.length, - width: stateful.width, - weight: stateful.weight, - predictWeight: stateless.predictWeight, - extraCost: stateless.extraCost, - description: stateless.description, - sellType: stateful.sellType, - materialQuantity: stateful.materialQuantity, - }; - const commonBoundProps = { - loading: viewState.loading, - onSubmit: handleSubmit, - formOptions: { - materialTypeOption: menuOptionState.materialTypeOption, - materialIdOption: menuOptionState.materialIdOption, - sellTypeOption: menuOptionState.sellTypeOption, - materialCostOption: menuOptionState.materialCostOption, - }, - onChange: handleChange, - onSpecificationInputBlur: handleSpecificationInputBlur, - }; - - return ( - <> - - - statelessDispatch({ type: 'type', data: stateless.type === 0 ? 1 : 0 })} - > - - - {stateless.type ? '出库' : '入库'} - - - - {renderMessage({ - type: 'success', - message: '保存成功', - open: viewState.submitSuccess, - onClose: hanldeCloseMessage, - })} - {renderMessage({ - type: 'failed', - message: '保存失败', - open: viewState.submitFailed, - onClose: hanldeCloseMessage, - })} - - {stateless.type ? ( - - ) : ( - - )} - - ); -}; - -export default StockAndShipmentDataController; diff --git a/src/controller/__tests__/StockAndShipmentDataController.test.tsx b/src/controller/__tests__/StockAndShipmentDataController.test.tsx deleted file mode 100644 index f8a605bfb..000000000 --- a/src/controller/__tests__/StockAndShipmentDataController.test.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import React from 'react'; -import { shallow, mount } from 'enzyme'; -import StockAndShipmentDataController from '../StockAndShipmentDataController'; -import fetchMock from 'fetch-mock'; - -describe('StockAndShipmentDataController', () => { - const formData = { - materialType: 1, - materialTypeError: true, - materialTypeMessage: '该项不能为空', - materialCost: '', - materialCostError: true, - materialCostMessage: '该项不能为空', - type: 0, - length: 2, - lengthError: true, - lengthMessage: '该项不能为空', - width: 3, - widthError: true, - widthMessage: '该项不能为空', - height: 4, - heightError: true, - heightMessage: '该项不能为空', - weight: 5, - weightError: true, - weightMessage: '该项不能为空', - predictWeight: 0, - freight: '', - freightError: true, - freightMessage: '该项不能为空', - extraCost: '', - description: '', - calcuteType: 0, - }; - - const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); - const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {}); - - beforeEach(() => { - fetchMock.mock('/toy/good/in', 'success'); - }); - - afterAll(() => { - errorSpy.mockRestore(); - warnSpy.mockRestore(); - }); - - afterEach(() => { - fetchMock.restore(); - }); - - it('onSubmit', async () => { - const wrapper: any = await shallow(); - const result = await wrapper - .find('Inbound') - .props() - .onSubmit(); - expect(result).toBeFalsy(); - }); - - it('AppBar should work', () => { - const wrapper: any = mount(); - expect(wrapper.find('h6').text()).toBe('入库'); - wrapper - .find('ForwardRef(AppBar)') - .find('button') - .props() - .onClick({ text: '', value: '' }, 'type'); - wrapper.setProps({ formData: Object.assign({}, formData, { type: 1 }) }); - expect(wrapper.find('h6').text()).toBe('出库'); - }); -}); diff --git a/src/pages/Inbound.tsx b/src/pages/Inbound.tsx deleted file mode 100644 index 6441766b9..000000000 --- a/src/pages/Inbound.tsx +++ /dev/null @@ -1,65 +0,0 @@ -/* eslint-disable react/prop-types */ -import React from 'react'; -import { FormControl, TextareaAutosize } from '@material-ui/core'; -import { - getInputItem, - CommonBoundFormDataProps, - CommonBoundProps, - useStyles, - renderPickerForMaterialId, - getSubmitButton, -} from '../utils/boundUtil'; - -export type InboundProps = { - formData: CommonBoundFormDataProps; -} & CommonBoundProps; - -const Inbound = ({ onSubmit, formData, onChange, onSpecificationInputBlur, formOptions, loading }: InboundProps) => { - const classes = useStyles(); - - return ( -
- {renderPickerForMaterialId({ - formOptions, - formData, - classes, - onChange, - onSpecificationInputBlur, - })} - - {getInputItem({ - key: 'weight', - error: formData.weight.error, - inputLabel: '实际重量', - inputValue: formData.weight.value, - helperText: formData.weight.message, - xs: 6, - unit: 'kg', - onChange, - onBlur: onSpecificationInputBlur, - classes, - stateType: 'stateful', - })} - - - - onChange({ - item: { text: e.target.value, value: e.target.value }, - controllType: 'input', - key: 'description', - stateType: 'stateless', - }) - } - value={formData.description} - /> - - - {getSubmitButton({ classes, onSubmit, loading })} -
- ); -}; - -export default Inbound; diff --git a/src/pages/MUILoading.tsx b/src/pages/MUILoading.tsx deleted file mode 100644 index 742b4b745..000000000 --- a/src/pages/MUILoading.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react'; -import { makeStyles, Theme, createStyles } from '@material-ui/core/styles'; -import { CircularProgress } from '@material-ui/core'; - -const useStyles = makeStyles((theme: Theme) => - createStyles({ - root: { - display: 'flex', - '& > * + *': { - marginLeft: theme.spacing(2), - }, - height: '100vh', - 'justify-content': 'center', - 'align-items': 'center', - }, - }), -); - -const CircularIndeterminate = () => { - const classes = useStyles(); - - return ( -
- -
- ); -}; - -export default CircularIndeterminate; diff --git a/src/pages/Outbound.tsx b/src/pages/Outbound.tsx deleted file mode 100644 index 1977d749e..000000000 --- a/src/pages/Outbound.tsx +++ /dev/null @@ -1,135 +0,0 @@ -/* eslint-disable react/prop-types */ -import React from 'react'; -import { FormControl, TextareaAutosize } from '@material-ui/core'; -import { - getInputItem, - CommonBoundFormDataProps, - CommonBoundProps, - useStyles, - renderPickerForMaterialId, - getSubmitButton, - InputFormItemProps, - getSelectItem, -} from '../utils/boundUtil'; - -export type OutboundProps = { - formData: { - // 数量。出库用 - materialQuantity: InputFormItemProps; - // 锯费 - costFee: number; - // 预估总价 - predictPrice: number; - } & CommonBoundFormDataProps; -} & CommonBoundProps; - -const Outbound = ({ onSubmit, formData, formOptions, onChange, onSpecificationInputBlur, loading }: OutboundProps) => { - const classes = useStyles(); - - return ( -
- {renderPickerForMaterialId({ - formOptions, - formData, - classes, - onChange, - onSpecificationInputBlur, - })} - - {getInputItem({ - key: 'weight', - error: formData.weight.error, - inputLabel: '实际重量', - inputValue: formData.weight.value, - helperText: formData.weight.message, - xs: 6, - unit: 'kg', - onChange, - onBlur: onSpecificationInputBlur, - classes, - stateType: 'stateful', - })} - - {getInputItem({ - key: 'materialQuantity', - error: formData.materialQuantity.error, - inputLabel: '数量', - inputValue: formData.materialQuantity.value, - helperText: formData.materialQuantity.message, - xs: 6, - unit: '个', - onChange, - onBlur: onSpecificationInputBlur, - classes, - stateType: 'stateful', - })} - - {getSelectItem({ - key: 'materialCost', - error: false, - inputLabel: '单价', - value: formData.materialCost, - options: formOptions.materialCostOption || [], - xs: 6, - // unit: '元/kg', - required: false, - onChange, - classes, - fullWidth: true, - stateType: 'stateless', - })} - - {getInputItem({ - key: 'costFee', - error: false, - inputLabel: '锯费', - inputValue: formData.costFee, - helperText: '', - xs: 6, - unit: '元/个', - readOnly: true, - required: false, - onChange, - onBlur: onSpecificationInputBlur, - classes, - stateType: 'stateless', - })} - - {getInputItem({ - key: 'predictPrice', - error: false, - inputLabel: '预估总价', - inputValue: formData.predictPrice || '', - helperText: '', - xs: 6, - unit: '元', - readOnly: true, - required: false, - onChange, - onBlur: onSpecificationInputBlur, - classes, - stateType: 'stateless', - })} - - - - onChange({ - item: { text: e.target.value, value: e.target.value }, - controllType: 'input', - key: 'description', - stateType: 'stateless', - }) - } - value={formData.description} - /> - - - {getSubmitButton({ classes, onSubmit, loading })} -
- ); -}; - -export default Outbound; diff --git a/src/pages/__tests__/Inbound.test.tsx b/src/pages/__tests__/Inbound.test.tsx deleted file mode 100644 index d9772f704..000000000 --- a/src/pages/__tests__/Inbound.test.tsx +++ /dev/null @@ -1,137 +0,0 @@ -import React from 'react'; -import { mount } from 'enzyme'; -import Inbound from '../Inbound'; - -describe('Inbound', () => { - const formData = { - materialType: { value: 0, error: false, message: 'error' }, - materialId: { value: { value: 0, text: 'text' }, error: false, message: 'error' }, - materialCost: '100', - type: 0, - length: { value: '101', error: false, message: 'error' }, - width: { value: '102', error: false, message: 'error' }, - height: { value: '103', error: false, message: 'error' }, - weight: { value: '104', error: false, message: 'error' }, - predictWeight: 105, - description: '', - round: { value: 0, error: false, message: 'error' }, - sellType: { value: 0, error: false, message: 'error' }, - materialQuantity: { value: '107', error: false, message: 'error' }, - }; - - const formOptions = { - materialTypeOption: [{ text: 'materialTypeText', value: 'materialTypeValue' }], - materialIdOption: [], - sellTypeOption: [], - materialCostOption: [], - }; - - const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); - const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {}); - - afterAll(() => { - errorSpy.mockRestore(); - warnSpy.mockRestore(); - }); - - it('render correctly', () => { - const onChange = jest.fn(); - const onSubmit = jest.fn(); - const onSpecificationInputBlur = jest.fn(); - const wrapper = mount( - , - ); - expect(wrapper).toMatchSnapshot(); - }); - - it('Select of calcuteType', () => { - const onChange = jest.fn(); - const onSubmit = jest.fn(); - const onSpecificationInputBlur = jest.fn(); - const wrapper: any = mount( - , - ); - expect( - wrapper - .find('ForwardRef(Select)') - .first() - .props().value, - ).toBe(0); - wrapper - .find('ForwardRef(Select)') - .first() - .props() - .onChange({ target: { value: 'test1' } }); - expect(onChange).toHaveBeenCalledWith({ - controllType: 'select', - item: { text: 'test1', value: 'test1' }, - key: 'materialType', - stateType: 'stateful', - }); - wrapper.setProps({ formData: Object.assign({}, formData, { calcuteType: 1 }) }); - expect( - wrapper - .find('ForwardRef(Select)') - .first() - .props().value, - ).toBe(0); - }); - - it('renderSpecification', () => { - const onChange = jest.fn(); - const onSubmit = jest.fn(); - const onSpecificationInputBlur = jest.fn(); - const wrapper: any = mount( - , - ); - expect( - wrapper - .find('label') - .at(0) - .text(), - ).toBe('类别 *'); - expect( - wrapper - .find('label') - .at(1) - .text(), - ).toBe('卖出方式 *'); - expect( - wrapper - .find('label') - .at(2) - .text(), - ).toBe('截面直径 *'); - expect( - wrapper - .find('label') - .at(3) - .text(), - ).toBe('材质 *'); - expect(wrapper.find('label')).toHaveLength(5); - - wrapper.setProps({ formData: Object.assign({}, formData, { calcuteType: 2 }) }); - expect(wrapper.find('label')).toHaveLength(5); - }); -}); diff --git a/src/pages/__tests__/MUILoading.test.tsx b/src/pages/__tests__/MUILoading.test.tsx deleted file mode 100644 index 4d45e812a..000000000 --- a/src/pages/__tests__/MUILoading.test.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import React from 'react'; -import { mount } from 'enzyme'; -import MUILoading from '../MUILoading'; - -describe('MUILoading', () => { - it('render correctly', () => { - const wrapper = mount(); - expect(wrapper).toMatchSnapshot(); - }); -}); diff --git a/src/pages/__tests__/__snapshots__/Inbound.test.tsx.snap b/src/pages/__tests__/__snapshots__/Inbound.test.tsx.snap deleted file mode 100644 index 2ea246af1..000000000 --- a/src/pages/__tests__/__snapshots__/Inbound.test.tsx.snap +++ /dev/null @@ -1,3853 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Inbound render correctly 1`] = ` - -
- - -
- - - - - - - - - - - - - materialTypeText - , - ], - "classes": Object { - "disabled": "Mui-disabled", - "filled": "MuiSelect-filled", - "icon": "MuiSelect-icon", - "iconFilled": "MuiSelect-iconFilled", - "iconOpen": "MuiSelect-iconOpen", - "iconOutlined": "MuiSelect-iconOutlined", - "outlined": "MuiSelect-outlined", - "root": "MuiSelect-root", - "select": "MuiSelect-select", - "selectMenu": "MuiSelect-selectMenu", - }, - "displayEmpty": false, - "labelId": undefined, - "multiple": false, - "onClose": undefined, - "onOpen": undefined, - "open": undefined, - "renderValue": undefined, - "type": undefined, - "variant": "standard", - } - } - onChange={[Function]} - value={0} - > - - materialTypeText - , - ], - "classes": Object { - "disabled": "Mui-disabled", - "filled": "MuiSelect-filled", - "icon": "MuiSelect-icon", - "iconFilled": "MuiSelect-iconFilled", - "iconOpen": "MuiSelect-iconOpen", - "iconOutlined": "MuiSelect-iconOutlined", - "outlined": "MuiSelect-outlined", - "root": "MuiSelect-root", - "select": "MuiSelect-select", - "selectMenu": "MuiSelect-selectMenu", - }, - "displayEmpty": false, - "labelId": undefined, - "multiple": false, - "onClose": undefined, - "onOpen": undefined, - "open": undefined, - "renderValue": undefined, - "type": undefined, - "variant": "standard", - } - } - onChange={[Function]} - value={0} - > - - materialTypeText - , - ], - "classes": Object { - "disabled": "Mui-disabled", - "filled": "MuiSelect-filled", - "icon": "MuiSelect-icon", - "iconFilled": "MuiSelect-iconFilled", - "iconOpen": "MuiSelect-iconOpen", - "iconOutlined": "MuiSelect-iconOutlined", - "outlined": "MuiSelect-outlined", - "root": "MuiSelect-root", - "select": "MuiSelect-select", - "selectMenu": "MuiSelect-selectMenu", - }, - "displayEmpty": false, - "labelId": undefined, - "multiple": false, - "onClose": undefined, - "onOpen": undefined, - "open": undefined, - "renderValue": undefined, - "type": undefined, - "variant": "standard", - } - } - multiline={false} - onChange={[Function]} - type="text" - value={0} - > - - materialTypeText - , - ], - "classes": Object { - "disabled": "Mui-disabled", - "filled": "MuiSelect-filled", - "icon": "MuiSelect-icon", - "iconFilled": "MuiSelect-iconFilled", - "iconOpen": "MuiSelect-iconOpen", - "iconOutlined": "MuiSelect-iconOutlined", - "outlined": "MuiSelect-outlined", - "root": "MuiSelect-root", - "select": "MuiSelect-select", - "selectMenu": "MuiSelect-selectMenu", - }, - "displayEmpty": false, - "labelId": undefined, - "multiple": false, - "onClose": undefined, - "onOpen": undefined, - "open": undefined, - "renderValue": undefined, - "type": undefined, - "variant": "standard", - } - } - multiline={false} - onChange={[Function]} - type="text" - value={0} - > -
- -
- -
- - - - - - - - - - - ​ - -
- } - id="menu-" - onClose={[Function]} - open={false} - > - - - ​ - -
- } - classes={ - Object { - "list": "MuiMenu-list", - "paper": "MuiMenu-paper", - } - } - id="menu-" - onClose={[Function]} - open={false} - > - - - ​ - -
- } - anchorOrigin={ - Object { - "horizontal": "left", - "vertical": "top", - } - } - getContentAnchorEl={[Function]} - id="menu-" - onClose={[Function]} - onEntering={[Function]} - open={false} - transformOrigin={ - Object { - "horizontal": "left", - "vertical": "top", - } - } - transitionDuration="auto" - > - - - ​ - - - } - anchorOrigin={ - Object { - "horizontal": "left", - "vertical": "top", - } - } - classes={ - Object { - "paper": "MuiPopover-paper", - "root": "MuiPopover-root", - } - } - getContentAnchorEl={[Function]} - id="menu-" - onClose={[Function]} - onEntering={[Function]} - open={false} - transformOrigin={ - Object { - "horizontal": "left", - "vertical": "top", - } - } - transitionDuration="auto" - > - } - id="menu-" - onClose={[Function]} - open={false} - /> - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - -
- -
- -
- - - - - - - - - - - ​ - -
- } - id="menu-" - onClose={[Function]} - open={false} - > - - - ​ - -
- } - classes={ - Object { - "list": "MuiMenu-list", - "paper": "MuiMenu-paper", - } - } - id="menu-" - onClose={[Function]} - open={false} - > - - - ​ - - - } - anchorOrigin={ - Object { - "horizontal": "left", - "vertical": "top", - } - } - getContentAnchorEl={[Function]} - id="menu-" - onClose={[Function]} - onEntering={[Function]} - open={false} - transformOrigin={ - Object { - "horizontal": "left", - "vertical": "top", - } - } - transitionDuration="auto" - > - - - ​ - - - } - anchorOrigin={ - Object { - "horizontal": "left", - "vertical": "top", - } - } - classes={ - Object { - "paper": "MuiPopover-paper", - "root": "MuiPopover-root", - } - } - getContentAnchorEl={[Function]} - id="menu-" - onClose={[Function]} - onEntering={[Function]} - open={false} - transformOrigin={ - Object { - "horizontal": "left", - "vertical": "top", - } - } - transitionDuration="auto" - > - } - id="menu-" - onClose={[Function]} - open={false} - /> - - - - - - - - - - - - - -
-
- - -
- - -
- - - - - - - - - - - mm - - } - onBlur={[MockFunction]} - onChange={[Function]} - readOnly={false} - type="number" - value="101" - > - - mm - - } - onBlur={[MockFunction]} - onChange={[Function]} - readOnly={false} - type="number" - value="101" - > - - mm - - } - fullWidth={false} - inputComponent="input" - multiline={false} - onBlur={[MockFunction]} - onChange={[Function]} - readOnly={false} - type="number" - value="101" - > - - mm - - } - fullWidth={false} - inputComponent="input" - multiline={false} - onBlur={[MockFunction]} - onChange={[Function]} - readOnly={false} - type="number" - value="101" - > -
- - - -
- - -

- mm -

-
-
-
-
-
-
-
-
-
-
- - -

- error -

-
-
-
-
-
-
-
-
- - -
- - -
- - - - - - - -
, - "ref": [Function], - "startAdornment": undefined, - } - } - disabled={false} - error={false} - fullWidth={true} - id="material-id" - inputProps={ - Object { - "aria-activedescendant": null, - "aria-autocomplete": "list", - "aria-controls": null, - "autoCapitalize": "none", - "autoComplete": "off", - "className": "MuiAutocomplete-input MuiAutocomplete-inputFocused", - "disabled": false, - "id": "material-id", - "onBlur": [Function], - "onChange": [Function], - "onFocus": [Function], - "onMouseDown": [Function], - "ref": Object { - "current": , - }, - "spellCheck": "false", - "value": "text", - } - } - label="材质" - margin="normal" - required={true} - > - - - - - - - -
, - "ref": [Function], - "startAdornment": undefined, - } - } - classes={ - Object { - "root": "MuiTextField-root", - } - } - disabled={false} - error={false} - fullWidth={true} - id="material-id" - inputProps={ - Object { - "aria-activedescendant": null, - "aria-autocomplete": "list", - "aria-controls": null, - "autoCapitalize": "none", - "autoComplete": "off", - "className": "MuiAutocomplete-input MuiAutocomplete-inputFocused", - "disabled": false, - "id": "material-id", - "onBlur": [Function], - "onChange": [Function], - "onFocus": [Function], - "onMouseDown": [Function], - "ref": Object { - "current": , - }, - "spellCheck": "false", - "value": "text", - } - } - label="材质" - margin="normal" - required={true} - > - - -
- - - - - - - - - - - - - - - - -
- } - fullWidth={true} - id="material-id" - inputProps={ - Object { - "aria-activedescendant": null, - "aria-autocomplete": "list", - "aria-controls": null, - "autoCapitalize": "none", - "autoComplete": "off", - "className": "MuiAutocomplete-input MuiAutocomplete-inputFocused", - "disabled": false, - "id": "material-id", - "onBlur": [Function], - "onChange": [Function], - "onFocus": [Function], - "onMouseDown": [Function], - "ref": Object { - "current": , - }, - "spellCheck": "false", - "value": "text", - } - } - multiline={false} - > - - - - - - - - - } - fullWidth={true} - id="material-id" - inputProps={ - Object { - "aria-activedescendant": null, - "aria-autocomplete": "list", - "aria-controls": null, - "autoCapitalize": "none", - "autoComplete": "off", - "className": "MuiAutocomplete-input MuiAutocomplete-inputFocused", - "disabled": false, - "id": "material-id", - "onBlur": [Function], - "onChange": [Function], - "onFocus": [Function], - "onMouseDown": [Function], - "ref": Object { - "current": , - }, - "spellCheck": "false", - "value": "text", - } - } - multiline={false} - > - - - - - - - - - } - fullWidth={true} - id="material-id" - inputComponent="input" - inputProps={ - Object { - "aria-activedescendant": null, - "aria-autocomplete": "list", - "aria-controls": null, - "autoCapitalize": "none", - "autoComplete": "off", - "className": "MuiAutocomplete-input MuiAutocomplete-inputFocused", - "disabled": false, - "id": "material-id", - "onBlur": [Function], - "onChange": [Function], - "onFocus": [Function], - "onMouseDown": [Function], - "ref": Object { - "current": , - }, - "spellCheck": "false", - "value": "text", - } - } - multiline={false} - type="text" - > - - - - - - - - - } - fullWidth={true} - id="material-id" - inputComponent="input" - inputProps={ - Object { - "aria-activedescendant": null, - "aria-autocomplete": "list", - "aria-controls": null, - "autoCapitalize": "none", - "autoComplete": "off", - "className": "MuiAutocomplete-input MuiAutocomplete-inputFocused", - "disabled": false, - "id": "material-id", - "onBlur": [Function], - "onChange": [Function], - "onFocus": [Function], - "onMouseDown": [Function], - "ref": Object { - "current": , - }, - "spellCheck": "false", - "value": "text", - } - } - multiline={false} - type="text" - > -
- -
- - - - - - - - - - - - - - - - - - -
-
-
-
-
- - -
-
- - - - - - - -

- error -

-
-
- -
-
- - -
- - -
- - - - - - - - - - - kg - - } - onBlur={[MockFunction]} - onChange={[Function]} - readOnly={false} - type="number" - value="104" - > - - kg - - } - onBlur={[MockFunction]} - onChange={[Function]} - readOnly={false} - type="number" - value="104" - > - - kg - - } - fullWidth={false} - inputComponent="input" - multiline={false} - onBlur={[MockFunction]} - onChange={[Function]} - readOnly={false} - type="number" - value="104" - > - - kg - - } - fullWidth={false} - inputComponent="input" - multiline={false} - onBlur={[MockFunction]} - onChange={[Function]} - readOnly={false} - type="number" - value="104" - > -
- - - -
- - -

- kg -

-
-
-
-
-
-
-
-
-
-
- - -

- error -

-
-
-
-
-
-
-
-
- - -
- -