---
# System prepended metadata

title: Untitled

---

## 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 圖形線條粗度

