## Antd
### - Form
```
# Faceai內:
components/Face/Filter.js
handleSubmit = e => {
e.preventDefault()
const { form } = this.props
return form.validateFieldsAndScroll(
...)
}
-------
<Form className="app-page__filter" layout="inline" onSubmit={this.handleSubmit}>
<Form.Item label={intl.formatMessage({ id: 'App.form.keyword.label' })}>
{getFieldDecorator('q')(
<Input
maxLength={20}
placeholder={intl.formatMessage({ id: 'App.face.filter.q.msg' })}
/>
)}
</Form.Item>
....
<Form.Item className="buttons-group">
<Button type="primary" htmlType="submit" icon="search">
<FormattedMessage id="App.actions.search" />
</Button>
<Button className="btn-success" icon="reload" onClick={onReset}>
<FormattedMessage id="App.actions.reset" />
</Button>
</Form.Item>
</Form>
export const injectIntl(Form.create()(FaceFilter))
(or)
export default injectIntl(WithForm)
```
> - validateFields / validateFieldsAndScroll 驗證表單後錯誤欄位 (非自動/自動移動至錯誤欄位)
> - {getFieldDecorator(id(value),option{(rules,initialValue...)})(<表格內欄位>)} 利用id對照雙向綁定欄位內容(~=註冊),(內容依照option)
> - (getFieldDecorator)valuePropName: 'checked' 子節點屬性(通常switch,check用)
> - Form.create({option}) 利用Form.create建立表單(~=收集註冊欄位及驗證)
>>*不須額外設定onChange參數,也不需利用state方式控制*
> - mapPropsToFields / createFormField 搭配使用,繼承布局設置預設值
>>*用mapPropsToFields設置預設值時送出表單後輸入格內會是map預設值;
>>用initialValue設置預設值時送出表單後輸入格內會是輸入的值;
>>同時設置mapPropsToFields及initialValue時以map為主;都沒設置則會是輸入的值
>>```
>># Faceai內map方式是將value指定到輸入的值,則送出後表格仍會顯示輸入值*
>>
>>const WithForm = Form.create({
>> mapPropsToFields({ filter: { typeId = '', q, company, qHost } = {} }) {
>> const { createFormField } = Form
>> return {
>> typeId: createFormField({
>> value: typeId
>> }),
>> q: createFormField({
>> value: q
>> }),
>> company: createFormField({
>> value: company
>> }),
>> qHost: createFormField({
>> value: qHost
>> })
>> }
>> }
>>})(FaceFilter)
>>```
> - onSubmit 送出 (利用表單onSubmit送出開始驗證表單)
> - label 表格前方顯示之名稱
> - rules 規則
> - required 是否為必填
> - message 提示字串
> - initialValue 預設值
>> **v3 到 v4**
>> - onSubmit 替換成 **onFinish**
>> - 去除 Form.create ( **getFieldDecorator** 已不再需要 )
>> [相關文件](https://ant.design/components/form/v3-cn)
### - Button
```
# Faceai內:
## Filter.js :
日誌/設備/人員/抓拍(搜尋 取消 匯出)
<Button type="primary" htmlType="submit" icon="search">
<FormattedMessage id="App.actions.search" />
</Button>
<Button className="btn-success" icon="reload" onClick={onReset}>
<FormattedMessage id="App.actions.reset" />
</Button>
<Button type="primary" icon="export">
<FormattedMessage id="App.actions.export" />
</Button>
## Form.js :
加入/編輯(彈跳出新表單的) 設備/人員/設備類別/臉庫(儲存 取消)
<Button type="primary" htmlType="submit">
{intl.formatMessage({ id: 'App.actions.save' })}
</Button>
<Button onClick={onCancelClick}>
{intl.formatMessage({ id: 'App.actions.cancel' })}
</Button>
## Index.js :
返回至Link的頁面
<Button icon="rollback" onClick={this.handleGoBack}>
<FormattedMessage id="App.actions.back" />
</Button>
<Link to=<Path>>
<Button type="primary">
<FormattedMessage id="App.capture.ations.allAlertRecords" />
</Button>
</Link>
比對
<Button
size="large"
type="primary"
disabled={!leftPhoto || !rightPhoto}
onClick={this.handleCompare}
>
<FormattedMessage id="App.actions.compare" />
</Button>
新增/編輯/刪除 icon按鈕
<Button
shape="circle"
icon="plus"
size="small"
title={intl.formatMessage({ id: 'App.category.add' })}
onClick={() => this.showFormModal('new')}
/>
```
> - type 按鈕類型 primary主按鈕(藍底白字) ghost透明 dashed虛線框 link鍊結 text(純文字) default次按鈕(白底黑字)
> - htmlType 原html的類型 button submit
> - disabled 失效
### - Checkbox
```
# Faceai內:
人員設定通行設備類別/臉庫管理員設定臉庫
<Checkbox.Group value={selectedValues} onChange={handleCheckEvent}>
{[...categories.values()].map(category => (
<Checkbox key={category.id} value={category.id}>
{category.name}
</Checkbox>
))}
</Checkbox.Group>
與臉庫對比
<Checkbox.Group
onChange={this.handleFaceTypeIdsChange}
className={styles.faceTypeGroup}
>
<Row gutter={10}>
<Col span={24}>
<Checkbox value={CHECK_ALL_SYMBOL}>All</Checkbox>
</Col>
{[...faceTypes.values()].map(faceType => (
<Col span={8} key={faceType.id}>
<Checkbox value={faceType.id}>{faceType.name}</Checkbox>
</Col>
))}
</Row>
</Checkbox.Group>
```
### - Input
```
# Faceai內:
輸入格內空白時顯示字元
<Input placeholder={intl.formatMessage({ id: 'App.form.name.msg' })} />
輸入數字
<InputNumber
style={{ width: 200 }} /*格子長度
min={0} /*數字下限值
max={100} /*數字上限值
formatter={v => `${v}%`} /*顯示格式number->string
parser={v => v.replace('%', '')} /*搭配formatter使用 string->number
precision={1} /*小數點後n位數
/>
密碼格 (可隱藏/顯示)
<Input.Password
autoComplete="new-password" /*取消自動填充密碼功能,因無法設定為off,則給一字串替代
placeholder={intl.formatMessage({
id: 'App.form.password.msg.required'
})}
/>
大區塊輸入框
<Input.TextArea
rows={6}
placeholder={intl.formatMessage({ id: 'App.setting.form.val.msg' })}
/>
```
> - (InputNumber)min 數字下限值
> - (InputNumber)max 數字上限值
> - (InputNumber)formatter 顯示格式number->string
> - (InputNumber)parser 搭配formatter使用 string->number
> - (InputNumber)precision 小數點後n位數
> - (Input.Password)autoComplete 自動填充密碼功能
> - (Input.TextArea)rows 高度(字數超過高度則顯示滾軸)
### - Radio
```
# Faceai內:
設備選擇類別/設備選擇繼電器類別/臉庫選擇動態靜態/通行規則選擇黑白名單->皆為單選之Radio
<Radio.Group>
<Radio value="camera">
{intl.formatMessage({ id: 'App.device.form.deviceType.options.camera' })}
</Radio>
<Radio value="fc20">
{intl.formatMessage({ id: 'App.device.form.deviceType.options.fc20' })}
</Radio>
<Radio value="pad">
{intl.formatMessage({ id: 'App.device.form.deviceType.options.pad' })}
</Radio>
</Radio.Group>
```
### - Select
```
# Faceai內:
基本搜尋或選擇(ex:設備管理中設備類型搜尋/系統參數選擇布林值時為0 1 等...)
<Select>
<Select.Option value="">
{intl.formatMessage({ id: 'App.form.options.all' })}
</Select.Option>
<Select.Option value="camera">
{intl.formatMessage({ id: 'App.device.form.deviceType.options.camera' })}
</Select.Option>
<Select.Option value="fc20">
{intl.formatMessage({ id: 'App.device.form.deviceType.options.fc20' })}
</Select.Option>
</Select>
<Select placeholder={intl.formatMessage({ id: 'App.setting.form.val.msg' })}>
<Select.Option value="1">TRUE</Select.Option>
<Select.Option value="0">FALSE</Select.Option>
</Select>
在臉庫頁面搜尋
{getFieldDecorator('typeId')(
lockFaceType ? (
<Select>
<Select.Option value={typeIdSelected}>{typeNameSelected</Select.Option>
</Select>
) : (<EntitySelector /*shared/components/EntitySelector/indexjs
showAllOption
entityName="faceTypes"
placeholder={intl.formatMessage({ id: 'App.form.library.msg' })}
/>
)
)}
```
### - Switch
```
# Faceai內:
人員/設備等等切換啟用/停用
<Switch
checkedChildren={<FormattedMessage id="App.table.status.options.1" />} /*啟用
unCheckedChildren={<FormattedMessage id="App.table.status.options.2" />} /*停用
/>
<Switch
disabled={!actionAuth} /*預設取消=不顯示
checkedChildren={intl.formatMessage({
id: 'App.table.status.options.1'
})} /*啟用
unCheckedChildren={intl.formatMessage({
id: 'App.table.status.options.2'
})} /*停用
checked={status} /*預設狀態啟用或停用(不設定則為停用)
/>
頁面切換(switch + route)
<Switch>
<AuthenticatedRoute
exact
path={match.path}
component={() => <Redirect to={ROUTES.alertMonitor} />}
/>
{/* AlertMonitor */}
<AuthenticatedRoute path={ROUTES.alertMonitor} component={AlertMonitor} />
{/* AlertSetting */}
<AuthenticatedRoute path={ROUTES.alertSetting} component={AlertSetting} />
{/* PassRule */}
<AuthenticatedRoute path={ROUTES.passRule} component={PassRule} />
</Switch>
```
> - checkedChildren 啟用
> - unCheckedChildren 停用
> - disabled 失效
### - Table
```
# Faceai內:
臉辨設定左方臉庫table
<Table columns={columns} dataSource={dataSource} pagination={false} />
權限管理/抓拍紀錄/與抓拍紀錄對比result/與臉庫對比result/設備管理/臉庫人臉/日誌管理/通行規則/人員管理/系統管理
<Table
className="app-table"
columns={columns}
dataSource={dataSource}
pagination={{
...meta,
showSizeChanger: true,
showTotal: total => intl.formatMessage({ id: 'App.pagination.total' }, { total }),
onShowSizeChange: onPageShowSizeChange,
onChange: onPageChange
}}
/>
```
> - columns 表格第一列分類命名
> - dataSource 表格內容物
> - pagination 是否顯示分頁
> - showSizeChanger 是否可更改pageSize (10條/頁,20條/頁..)
> - showTotal 顯示總比數(可自訂格式)
> - onShowSizeChange pageSize更改後的回調
> - onChange page更改後的回調
### - List
```
# Faceai內:
臉庫頁面
<List
itemLayout="horizontal"
className={styles.list}
grid={{ gutter: 16, column: 4 }}
dataSource={dataSource}
header={
<>
<FormattedMessage id="App.library.allFaceNums" />:<b>{stats.faceCnt}</b>
<FormattedMessage id="App.library.allPicNums" />:<b>{stats.photoCnt}</b>
<Link to={`/library/face?typeName=${intl.formatMessage({ id: 'App.library.all' })}`}>
<FormattedMessage id="App.actions.more" />
</Link>
</>
}
renderItem={item => {
const { id, faceCnt, photoCnt } = item
return (
<List.Item>
...
</List.Item>
)
}}
/>
首頁右側即時監控
<List
className={styles.alertList}
grid={{ gutter: 3, column: 2 }}
dataSource={identifiedCaptureList}
renderItem={capture => {
const { id, photo, face = {}, capturedAt } = capture
return (
<List.Item key={id} onClick={() => this.handleCaptureClick(capture)}>
<List.Item.Meta
description={
<p className={styles.alertName}>
{privacyMasking ? this.maskName(face.person) : face.person}
</p>
<Avatar
...
/>
<b>{moment(capturedAt).format('MM-DD HH:mm')}</b>
}
/>
</List.Item>
)
}}
/>
首頁下方抓拍紀錄
<List
className={styles.captureList}
grid={{ gutter: 16, column: 8 }}
dataSource={captureList}
renderItem={capture => (
<List.Item key={capture.id} onClick={() => this.handleCaptureClick(capture)}>
<Badge count={capture.face && <Icon type="alert" />}>
<Avatar
...
/>
</Badge>
</List.Item>
)}
/>
```
> - itemLayout 排版(vertical直/horizontal橫)
> - grid 列表欄位配置
> - gutter 每一格的間隔
> - column 列數
> - dataSource 內容物
> - header 列表頭部
> - (List.Item.Meta)description 內容
> - (List.Item.Meta)avatar 圖標
### - LocaleProvider
```
# Faceai內:
<LocaleProvider locale={antd}>
<IntlProvider locale={locale} messages={messages}>
{children}
</IntlProvider>
</LocaleProvider>
<LocaleProvider
key={forceRerender /* HACK: just force render when locale change */}
appLocale={appLocale}
>
{children}
</LocaleProvider>
<LocaleProvider>
...
</LocaleProvider>
```
> - locale 語言包
>> **v3 到 v4**
>> - LovaleProvider 替換成 **ConfigProvider**
>> [相關文件](https://ant.design/docs/react/migration-v4-cn)
### - Menu
```
# Faceai內:
臉辨監控/抓拍紀錄內左側設備類別Menu(DeviceMenu)(CategoryMenu) nvr/語言/signout選單
<Menu>
<Menu.Item key="all">
<FormattedMessage id="App.form.options.all" />
</Menu.Item>
....
return (
<Menu.SubMenu key={categoryId} title={cat.name}>
...
return (
<Menu.Item key={id} disabled={disableInactiveDevice && !device.enabled}>
</Menu.Item>
)
) : (
<Menu.ItemGroup/>
</Menu.SubMenu>
</Menu>
```
> - Menu 選單
> - Menu.SubMenu 子選單
> - Menu.Item 選單內選項
### - Alert
```
# Faceai內:
首頁影像warning提示/臉庫/抓拍紀錄/通行規則等等info提示
<Alert
message={<FormattedMessage id="App.messages.info" />}
description={<FormattedMessage id="App.library.addInfo" />}
type="info"
style={{ marginBottom: '2em' }}
showIcon
/>
```
> - message 標題
> - description 內文
> - type 類別 success、info、warning、error
### - Tooltip
```
# Faceai內:
與抓拍紀錄比對頁面中 抓拍設備之result顯示tooltip於上方
<Tooltip title={text}>
<span className={styles.deviceNames}>{text}</span>
</Tooltip>
```
> - title 內容
> - placement 箭頭對應位置 (12種位置可選)
### - Tree
```
# Faceai內:
DeviceTree 用於 臉辨設定/與抓拍紀錄對比頁面
<TreeNode title={item.name} key={item.key} selectable={false}>
{this.renderTreeNodes(item.children)}
</TreeNode>
<TreeNode
selectable={false}
title={
<span>
{item.name}
{item.symbol === 'DEVICE' && !item.enabled && (
<Tag size="small" color="rgba(0,0,0,0.35)">
<FormattedMessage id="App.deviceMenu.status.disabled" />
</Tag>
)}
</span>
}
key={item.key}
/>
<Tree defaultExpandAll checkedKeys={value} onCheck={this.handleCheck} checkable {...rest}>
{this.renderTreeNodes(treeData)}
</Tree>
```
> - selectable 是否能被勾選
> - defaultExpandAll 預設全展開
> - checkedKeys 勾選(未設定參數則全未勾選)
> - checkable 開啟複選框
### - Spin
```
# Faceai內:
<Spin tip="Loading..." /> /*加載...
```
> - tip 加載圖案下方顯示字串
### - Progress
```
# Faceai內:
與圖片對比頁面內顯示圓形數值表
<Progress type="circle" percent={percent} format={p => `${p}%`} />
臉庫頁面中分成動態及靜態臉庫的數線
<Progress
strokeWidth={15}
percent={Number(((stats.dynamicPhotoCnt / totalDaynamicMax) * 100).toFixed(2))}
/>
```
> - type 圖形(預設為橫條)
> - percent 數值
> - format 顯示格式
> - strokeWidth 圖形線條粗度