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