# 一、json写法工程升级

## （一）下载框架代码，以此为项目目录

## （二）合并资源、样式、自定义组件或工具类代码

### 1、需要移动的资源和配置
* 将原index.html、vendor目录、sso.html、transfer.html、version.txt等静态资源移至本工程public目录下（除checkLowBrowser.js外，其他均可覆盖），具体需要移动的静态资源见原webpack.config.js文件中CopyWebpackPlugin配置了哪些

* 原目录图片资源assets/img调整至src/assets/img
* 原目录assets其他less配置，大部分为框架less引用，业务很少修改，不再需要，若业务在此配置了样式，请配置至src/assets下的app.less（app应用的公共样式）、base.less（全局基础样式）、varible.less（变量）
* 原目录component/assets资源文件参考上两项修改
* 原目录apps下所有目录文件移至src/jsonApps下

### 2、组件
原目录component组件分离为@ttk/component依赖包，不包括以下业务组件
* MoneyCellHeader
* MoneyCell
* QuanAndForeCurrency
* SubjectDisplay
* AccountDisplay
* TableSettingCard
* TableOperate
* TableOperate2
* PrintOption
* PrintOption4
* PrintOption3
* FormDecorator
* GridDecorator
* VirtualTable
* VirtualTable2

业务组件可按以下方式使用：

#### （1）将业务组件代码移至src/components作为业务自定义组件，并在src/components/index.js配置引入（可参考已存在自定义组件）

```
export { default as MoneyCellHeader } from './momeny/moneyCellHeader'
export { default as MoneyCell } from './momeny/moneyCell'
export { default as QuanAndForeCurrency } from './momeny/quanAndForeCurrency'
export { default as SubjectDisplay } from './momeny/subjectDisplay'
export { default as AccountDisplay } from './momeny/accountDisplay'

export { default as TableSettingCard } from './tableSettingCard'
export { default as TableOperate } from './tableOperate'
export { default as TableOperate2 } from './tableOperate2'

export { default as PrintOption } from './printOption'
export { default as PrintOption4 } from './printOption/inventoryPrint'
export { default as PrintOption3 } from './printOption/indexFinance'

export { default as FormDecorator } from './decorator/form'
export { default as GridDecorator } from './decorator/grid'

export { default as VirtualTable } from './virtualTable'
export { default as VirtualTable2 } from './virtualTable-2'
```

#### （2）将组件less文件移至组件目录下，例如原component/assets/style/virtualTable.less移至src/components/virtualTable/style.less，并在组件index.js中引入
例如src/components/virtualTable/index.js文件
```
import React, { Fragment } from 'react'
import VirtualTable from './virtualTable'
import ResizeVirtualTable from './resizeVirtualTable'
import './style.less' // 增加less文件引入
// ...省略代码
```
#### （3）相关import路径修改
* 组件从@ttk/component引入，如下面例子中的Select
* 旧别名尽量修改为依赖包的名称，如edf-utils修改为 @ttk/utils，edf-component 修改为 @ttk/component等
* 删除无用import
例如：
```
import ModalComponent from '../modal/index'
import Select from "../select/index";
import utils from 'edf-utils'
const Modal = ModalComponent
```
修改为
```
import { Modal, Select } from '@ttk/component'
import { number } from '@ttk/utils'
const utils = { number };
```

#### （4）（金财代账release20201026分支）上述业务组件已修改调整（仅涉及路径、引入方式，不涉及功能），并暂时放置于@ttk/component中dz目录中，可供使用，以后会废弃删除

### 3、可能需要移动的代码
* 组件：原目录component组件分离为@ttk/component依赖包，不一致或业务新增的可在src/components自定义组件
* 工具类：目录utils分离为@ttk/utils依赖包，不一致或业务新增的可在src/utils自定义组件
* 常量：原目录constant移至src/constant
* api：原目录api移至src/api

### 4、不需要的代码
* 目录modules、global不再使用，不需要
* 目录app-loader分离为@ttk/app-loader依赖包，一般不修改
* 目录meta-engine分离为@ttk/meta-engine依赖包，一般不修改
* webpack开头相关配置文件不再需要，配置开发代理在config/devServer.js, 其他均在fx.webpack.config.js

## （三）配置修改
### 1、网络请求fetch
src/jsonApps/config.js

```
function configFetch() {
    // 在此配置
    fetch.config(
        // ...省略代码，原配置代码位于工程目录下config.js
    )
}
```

### 2、默认启动app配置
src/constant/index.js，如

```
const EDFX_APP_ROOT = 'edfx-app-root';
const TTK_EDF_APP_ROOT = 'ttk-edf-app-root';
const APP_ROOT_NAME = 'app-root';
/**
 * 启动app名，需要根据实际情况配置，默认使用hook的路由，启动app名为app-root。
 * 如果需要使用json原路由方式，请修改为'ttk-edf-app-root'或'edfx-app-root'
 */
const startAppName = EDFX_APP_ROOT;
```

### 3、开发模式服务代理
config/devServer.js

### 4、其他webpack配置——默认不需要修改
fx.webpack.config详细见改文件注释说明


## （四）业务代码涉及调整内容修改
### 1、删除无用app模块配置

* 框架将自动扫描jsonApps目录中的app和相关style.less文件并引入，模块不需要theme目录、index.js、index.less
文件，可以使用npm run delModulesConfig自动删除

### 2、删除未使用mock.js
* 框架将自动扫描jsonApps目录中的mock.js文件并引入，因此需要删除业务apps中无用mock.js，部分mock.js存在语法错误，编译时会报错

### 3、api引用路径修改，如果还有使用api

src/api/index.js，全部替换'../api'为'../jsonApps', 例如：
```
import { person } from '../api/ba/app-card-person/webapi'
修改为
import { person } from '../jsonApps/ba/app-card-person/webapi'
```

### 3、修改不规范引用或语法,可根据编译报错提示修改

* 依赖包不要使用相对路径
```
import { Checkbox } from '../../../../../node_modules/antd'; // 直接修改为依赖包，'@ttk/component'或'antd'
import {fromJS} from "../../../node_modules/immutable/dist/immutable"; // 直接修改为依赖包，'immutable'
```
* import或者url()引入vendor目录中的图片资源文件，编译打包会生成1个文件、copy插件又复制1个文件，重复了。请移至src/assets/img，使用@/assets/img(@为src别名)引入，或者在fx.webpack.config.js配置别名。当然也可移至业务app内其他合适位置
```
import img from '../../../../vendor/img/gl/blank.png'
// 移至src/assets/img后, 修改引入路径
import img from '@/assets/img/gl/blank.png'

.bg-login-bg-3{
    background-image: url("../../../vendor/img/login/login-bg-3.png");
}
// 移至src/assets/img后, 修改引入路径
.bg-login-bg-3{
    background-image: url("@/assets/img/login/login-bg-3.png");
}
```
若修改位置较多，也可以移动图片后，在fx.webpack.config.js配置别名，不用修改引入的代码
```
fxAlias: {
    '../../../vendor/img': path.resolve(__dirname, 'src/assets/img'),
    '../../../../vendor/img': path.resolve(__dirname, 'src/assets/img'),
},
```

* 对于其他非import或者url()引入的图片资源，是不会经过webpack编译，应规范使用正确src路径，例如
```
{
    name: 'audited',
    component: '::img',
    className: 'app-proof-of-charge-title-right-tag',
    src: '../../../vendor/img/gl/audited_charge.png',
    _visible: '{{$getAudited()}}'
}
// data.js中直接配置src的，该路径将直接成为html中img元素的src属性
<img src="../../../vendor/img/gl/audited_charge.png">
// 因此，src相对路径应该是基于index.html,而非data.js, 即正确规范的路径应为'./vendor/img/gl/audited_charge.png'
```

* 组件独立为@ttk/component依赖包后，引用路径修改

```
import FormDecorator from '../../../component/decorator/form'
// 修改为
import { FormDecorator } from '@ttk/component'

import GridDecorator from '../../../component/decorator/grid'
// 修改为
import { GridDecorator } from '@ttk/component'
```

* utils独立为npm包后，引用路径修改
```
import {
	isAcrobatInstalledInIE
} from '../../../../../utils/fetch/pdfplugin'
//修改为
import { fetch } from '@ttk/utils'
const {
	isAcrobatInstalledInIE
} = fetch;

import { trimLeft, trimRight, trim } from '../../../utils/string/index'
// 修改为
import {  math, string } from 'edf-utils'
const { trimLeft, trimRight, trim } = string
```

* 不要使用core-js相关引用，直接使用es6等新语法，编译会兼容的。
```
import { isArray } from "core-js/fn/array"; // 删除，直接使用Array.isArray
import { Number } from 'core-js' // 删除，直接使用Number
```

* js文件中不要使用typescript语法, 编译会报错, 例如

```
// invoices/components/print/createContainer.js
export const createContainer = () => {
    const element: HTMLDivElement = document.createElement("div"); 
    element.className = "print-wrapper";
    const container = document.body.appendChild(element);
    return container;
};
// 删除: HTMLDivElement
```

* 删除无使用的引用, 例如
```
import table from '../../../component/components/table/table'
import error from "../../../component/components/modal/error"
import webapi from '../../../../api'
```

### 4、样式使用不规范导致不生效

* 框架升级后app样式也是按需加载的，app使用其他app定义的样式, 将不在正常显示，应在src/assets/app.less配置app公共样式

例如：App申报缴款ttk-edf-app-electronic-tax中的data.js使用了App通用Iframe嵌套页ttk-edf-app-iframe在style.less定义的className，ttk-edf-app-iframe-iframe
```
{
    name: 'ttkIframe',
    id: 'ttkIframe',
    key: '{{data.random}}',
    className: 'ttk-edf-app-iframe-iframe',
    onload: '{{$changeFrameHeight}}',
    _visible: '{{!!data.src}}',
    component: '::iframe',
    height: '600',
    scrolling: 'auto',
    src: '{{data.src}}',
}
```

例如：App申报缴款ttk-edf-app-electronic-tax中的data.js使用了App通用Iframe嵌套页ttk-edf-app-iframe在style.less定义的className，ttk-edf-app-iframe-iframe
```
{
    name: 'ttkIframe',
    id: 'ttkIframe',
    key: '{{data.random}}',
    className: 'ttk-edf-app-iframe-iframe',
    onload: '{{$changeFrameHeight}}',
    _visible: '{{!!data.src}}',
    component: '::iframe',
    height: '600',
    scrolling: 'auto',
    src: '{{data.src}}',
}
```

### 5、样式使用不规范导致样式覆盖
* app的style.less文件定义的css类选择器，不包括在当前app名称的css类选择器下，则当app加载时，会覆盖其他app的样式

例如：operation/ttk-edf-app-simple-portal/style.less
```
// 不包括在当前app名称的css类选择器下, 成为全局css类选择器，会覆盖其他app的样式
.ant-menu.mk-menu.ant-menu-root {
    max-height: 300px;
    overflow-y: auto;
}
// 当前app名称的css类选择器
.ttk-edf-app-simple-portal{
    // ...省略
}

.left-menu-itemgroup {
    // ...省略
}
// ...省略
```

### 6、app名称的css类选择器下的样式在modal不生效，不应该采取定义全局css类选择器的方式，因为modal是全局的，会影响其他app的modal，应该把app名称的css类选择器名称（或者自定义唯一的类选择器名称）传给modal

* app的style.less文件定义的css类，不包括在当前app名称的css类下，则当app加载时，会覆盖其他app的样式

例如：operation/ttk-edf-app-simple-portal/style.less，定义了
```
const ret = await this.metaAction.modal('confirm', {
    title: '',
    // 传给modal的className
    className: 'ttk-scm-app-inventory-automaticcalculationxb-confirm',
    width: 400,
    content: <p>{title}</p>
})
```


### 7、不能直接修改React创建的element的props

例如：edfba/ttk-app-inventory-list/util/DataGrid.js

```
getColumns() {
    // ...省略代码

    // renderDataGridCol返回React创建的element
    columns = columns.map(m => renderDataGridCol({ ...colOption, ...m }))

    // let tableSettingData =
    //     (this.props.metaAction.gf("data.other.columns") &&
    //         this.props.metaAction.gf("data.other.columns").toJS()) ||
    //     []
    const tableSettingData = this.metaAction.gf('data.tableData.tableSettingData').toJS();
    if (Array.isArray(tableSettingData) && tableSettingData.length > 0) {
        let cols = []
        columns.forEach(item => {
            let cell =
                item.key === "id" || item.key === "option"
                    ? item
                    : tableSettingData.find(
                        f => f.fieldName === item.key && f.isVisible
                    )
            if (cell) {
                // 此次直接修改了react element 的props
                item.props.width = cell.width || item.props.width
                cols.push(item)
            }
        })
        return cols
    }
    return columns
}
```

两种解决方法: 1、在React创建element前修改props，比如上例的renderDataGridCol前
2、使用React.cloneElement复制element
```
item.props.width = cell.width || item.props.width
cols.push(item)
// 修改为
let ele = React.cloneElement(item, {width: cell.width || item.props.width})
cols.push(ele)
```

### 8、data.js中使用div、a、span等原生html元素，请在前面带::，例如::div、::a、::span

### 9、其他警告问题修改
* URL使用javascript:;

Warning: A future version of React will block javascript: URLs as a security precaution. Use event handlers instead if you can. If you need to generate unsafe HTML try using dangerouslySetInnerHTML instead. React was passed "javascript:;".
    in a (created by TableCell)

```
<a href='javascript:;' onClick={(value) => { handleRangeSetting('inventoryTypeList') }}>设置</a>
```
