# SecretSelect 密级组件

- 来源：[E10 UI 组件库](https://www.e-cology.com.cn/ui/secret-select/freepass)
- 平台：PC
- 维护者：许平源
- Issue：http://gitlab.ecology10.cn/FRONTEND/weapp-ui/-/issues?state=all&search=[SecretSelect]

## 代码演示

### 基础用法

直接引入组件进行使用

```jsx
import React, { Component } from 'react';
import { SecretSelect, SecretSelectValueType, SecretSelectOptionType, Dialog, utils, Button } from '@weapp/ui';

const { isValueEmpty } = utils;

const options = [{
  "needValidity": false,
  "canceled": false,
  "isDefault": false,
  "defaultSecretLevelValidity": "",
  "id": "4",
  "secretLevelValidityShowType": "hidden",
  "content": "公开"
},
{
  "needValidity": false,
  "canceled": false,
  "isDefault": false,
  "defaultSecretLevelValidity": "",
  "id": "3",
  "secretLevelValidityShowType": "hidden",
  "content": "内部"
},
{
  "needValidity": true,
  "canceled": false,
  "isDefault": false,
  "defaultSecretLevelValidity": "10年",
  "id": "2",
  "secretLevelValidityShowType": "required",
  "content": "秘密"
},
{
  "needValidity": true,
  "canceled": false,
  "isDefault": false,
  "defaultSecretLevelValidity": "10年",
  "id": "1",
  "secretLevelValidityShowType": "required",
  "content": "机密"
}
];

class SecretSelectDemo extends Component<any, any> {
  instance?: any;
  instance2?: any;

  state = {
    value: {
      // secretLevel: '2',
      // secretLevelValidity: '20年'
    },
    value2: {
    }
  }

  getInstance = (el: any) => {
    this.instance = el;
  }
  getInstance2 = (el: any) => {
    this.instance2 = el;
  }

  handleSubmit = () => {
    // 提交前手动触发校验
    this.instance.validate()
      .then((res: any) => {
        console.log(res);
        if (isValueEmpty(res.errors)) {
          Dialog.message({ type: 'success', content: '校验通过' })
        } else {
          // 校验失败
          Dialog.message({ type: 'error', content: '校验失败' })
        }
      })
  }
  handleSubmit2 = () => {
    // 提交前手动触发校验
    this.instance2.validate()
      .then((res: any) => {
        console.log(res);
        if (isValueEmpty(res.errors)) {
          Dialog.message({ type: 'success', content: '校验通过' })
        } else {
          // 校验失败
          Dialog.message({ type: 'error', content: '校验失败' })
        }
      })
  }

  onChange = (value: SecretSelectValueType, option?: SecretSelectOptionType) => {
    console.error('onChange', value, option)
    this.setState({ value });
  }
  onChange2 = (value: SecretSelectValueType, option?: SecretSelectOptionType) => {
    console.error('onChange', value, option)
    this.setState({ value2: value });
  }
  onBlur = (value: SecretSelectValueType, option?: SecretSelectOptionType) => {
    console.error('onBlur', value, option)
  }
  render() {
    const { value, value2 } = this.state;
    return (
      <div>
        <h3>直接使用</h3>
        <SecretSelect
          value={value}
          required
          onChange={this.onChange}
          onBlur={this.onBlur}
          getInstance={this.getInstance}
        />
        <br />
        <Button onClick={this.handleSubmit} style={{ marginTop: 20 }}>主动校验</Button>
        <h3>只读</h3>
        <SecretSelect
          value={value}
          readOnly
        />
        <h3>禁用</h3>
        <SecretSelect
          value={value}
          disabled
        />
        <h3>设置保密等级必填</h3>
        <SecretSelect
          value={value2}
          required
          onChange={this.onChange2}
          getInstance={this.getInstance2}
        />
        <br />
        <Button onClick={this.handleSubmit2} style={{ marginTop: 20 }}>主动校验</Button>
      </div>
    );
  }
}

export default SecretSelectDemo;
```

### 换行模式，展示 label，弹框模式

```jsx
import { PureComponent } from 'react';
import { Button, SecretSelect, SecretSelectValueType, SecretSelectOptionType, Dialog, utils } from '@weapp/ui';

const { isValueEmpty } = utils;

const { SecretSelectDialog } = SecretSelect;

const options = [{
  "needValidity": false,
  "canceled": false,
  "isDefault": false,
  "defaultSecretLevelValidity": "",
  "id": "4",
  "secretLevelValidityShowType": "hidden",
  "content": "公开"
},
{
  "needValidity": false,
  "canceled": false,
  "isDefault": false,
  "defaultSecretLevelValidity": "",
  "id": "3",
  "secretLevelValidityShowType": "hidden",
  "content": "内部"
},
{
  "needValidity": true,
  "canceled": false,
  "isDefault": false,
  "defaultSecretLevelValidity": "10年",
  "id": "2",
  "secretLevelValidityShowType": "required",
  "content": "秘密"
},
{
  "needValidity": true,
  "canceled": false,
  "isDefault": false,
  "defaultSecretLevelValidity": "10年",
  "id": "1",
  "secretLevelValidityShowType": "required",
  "content": "机密"
}
];

class Demo extends PureComponent<any, any> {

  instance?: any;
  instance2?: any;

  state = {
    value: {
    },
    value2: {
      secretLevel: '1',
      secretLevelValidity: '10年'
    },
    value3: {
    },
    visible: false,
  }

  getInstance = (el: any) => {
    this.instance = el;
  }
  getInstance2 = (el: any) => {
    this.instance2 = el;
  }

  handleSubmit = () => {
    // 提交前手动触发校验
    this.instance.validate()
      .then((res: any) => {
        console.log(res);
        if (isValueEmpty(res.errors)) {
          Dialog.message({ type: 'success', content: '校验通过' })
        } else {
          // 校验失败
          Dialog.message({ type: 'error', content: '校验失败' })
        }
      })
  }
  handleSubmit2 = () => {
    // 提交前手动触发校验
    this.instance2.validate()
      .then((res: any) => {
        console.log(res);
        if (isValueEmpty(res.errors)) {
          Dialog.message({ type: 'success', content: '校验通过' })
        } else {
          // 校验失败
          Dialog.message({ type: 'error', content: '校验失败' })
        }
      })
  }

  openSecretSelectDialog = () => {
    this.setState({ visible: true })
  }

  onClose = () => {
    this.setState({ visible: false })
  }

  onSure = (value: SecretSelectValueType, option?: SecretSelectOptionType) => {
    console.error('onSure', value, option)
    this.setState({ visible: false })
  }

  onChange = (value: SecretSelectValueType, option?: SecretSelectOptionType) => {
    console.error('onChange', value, option)
    this.setState({ value });
  }
  onChange2 = (value: SecretSelectValueType, option?: SecretSelectOptionType) => {
    console.error('onChange2', value, option)
    this.setState({ value2: value });
  }
  onChange3 = (value: SecretSelectValueType, option?: SecretSelectOptionType) => {
    console.error('onChange3', value, option)
    this.setState({ value3: value });
  }

  render() {
    const { value, value2, value3, visible } = this.state;
    return (
      <div>
        <h3>换行展示</h3>
        <SecretSelect
          wrapDisplay
          required
          value={value}
          onChange={this.onChange}
          getInstance={this.getInstance}
        />
        <br />
        <Button onClick={this.handleSubmit} >主动校验</Button>
        <h3>展示 label</h3>
        <div style={{ width: '400px' }}>
          <SecretSelect
            withLabel
            required
            value={value2}
            onChange={this.onChange2}
            getInstance={this.getInstance2}
          />
        </div>
        <br />
        <Button onClick={this.handleSubmit2} >主动校验</Button>
        <h3>展示 label - 只读</h3>
        <div style={{ width: '400px' }}>
          <SecretSelect
            value={value2}
            withLabel
            readOnly
          />
        </div>
        <br />
        <h3>弹框模式</h3>
        <SecretSelectDialog
          visible={visible}
          required
          onChange={this.onChange3}
          onClose={this.onClose}
          onSure={this.onSure}
        />
        <Button
          onClick={this.openSecretSelectDialog}
        >打开密级弹框</Button>
      </div>
    );
  }
}

export default Demo;
```

### 支持自定义 options

```jsx
import React, { Component } from 'react';
import { Button, Dialog, SecretSelect, utils } from '@weapp/ui';

const { isValueEmpty } = utils;
const options = [
  {
    "id": "4",  // 保密等级
    "content": "公开",  // 密级名称
    "needValidity": false,  // true: 密级和保密期限，false：仅密级
    "defaultSecretLevelValidity": "",  // 默认保密期限
    "canceled": false,  // 是否封存 false未封存（启用）,true封存（未启用）
    "secretLevelValidityShowType": "hidden",  // required：必填，edit：可编辑，readOnly：显示，hidden：隐藏
  },
  {
    "needValidity": false,
    "canceled": false,
    "isDefault": false,
    "defaultSecretLevelValidity": "10年",
    "id": "3",
    "secretLevelValidityShowType": "required",
    "content": "内部"
  }
];

class SecretSelectDemo extends Component<any, any> {
  instance?: any;
  getInstance = (el: any) => {
    this.instance = el;
  }

  handleSubmit = () => {
    // 提交前手动触发校验
    this.instance.validate()
      .then((res: any) => {
        console.log(res);
        if (isValueEmpty(res.errors)) {
          Dialog.message({ type: 'success', content: '校验通过' })
        } else {
          // 校验失败
          Dialog.message({ type: 'error', content: '校验失败' })
        }
      })
  }
  render() {
    return (
      <div>
        <SecretSelect 
          data={options}
          required
          getInstance={this.getInstance}
        />
        <br />
        <Button onClick={this.handleSubmit} style={{ marginTop: 20 }}>主动校验</Button>
      </div>
    );
  }
}

export default SecretSelectDemo;
```

### 动态过滤密级配置

支持动态过滤密级配置

```jsx
import React, { Component } from 'react';
import { SecretSelect, SecretSelectValueType, SecretSelectOptionType, Dialog, utils, Button, Input, Select, SelectValueType } from '@weapp/ui';

const { isValueEmpty } = utils;

const { getSecretLevelInfo } = SecretSelect;

class SecretSelectDemo extends Component<any, any> {
  instance?: any;
  instance2?: any;

  state = {
    filterLevel: '',
    value: {
    },
    resourceOptionInfo: []
  }

  componentDidMount(): void {
    getSecretLevelInfo().then(res => {
      console.log('res', res)
      this.setState({ resourceOptionInfo: res.resourceOptionInfo })
    })
  }

  getInstance = (el: any) => {
    this.instance = el;
  }
  getInstance2 = (el: any) => {
    this.instance2 = el;
  }

  handleSubmit = () => {
    // 提交前手动触发校验
    this.instance.validate()
      .then((res: any) => {
        console.log(res);
        if (isValueEmpty(res.errors)) {
          Dialog.message({ type: 'success', content: '校验通过' })
        } else {
          // 校验失败
          Dialog.message({ type: 'error', content: '校验失败' })
        }
      })
  }
  handleSubmit2 = () => {
    // 提交前手动触发校验
    this.instance2.validate()
      .then((res: any) => {
        console.log(res);
        if (isValueEmpty(res.errors)) {
          Dialog.message({ type: 'success', content: '校验通过' })
        } else {
          // 校验失败
          Dialog.message({ type: 'error', content: '校验失败' })
        }
      })
  }

  onChange = (value: SecretSelectValueType, option?: SecretSelectOptionType) => {
    console.error('onChange', value, option)
    this.setState({ value });
  }
  onInputChange = (value: React.ReactText) => {
    this.setState({ filterLevel: value });
  }
  onSelectChange = (value: SelectValueType) => {
    this.setState({ filterLevel: value });
  }
  render() {
    const { value, filterLevel, resourceOptionInfo } = this.state;
    console.log('getSecretLevelInfo', getSecretLevelInfo())
    return (
      <div>
        <span>设置过滤等级：</span>
        <Select data={resourceOptionInfo} value={filterLevel} onChange={this.onSelectChange} />
        <br />
        <h3>自动过滤比当前配置的密级等级更高的密级（默认）</h3>
        <SecretSelect
          filterLevel={filterLevel}
          required
          getInstance={this.getInstance}
        />
        <br />
        <Button onClick={this.handleSubmit} style={{ marginTop: 20 }}>主动校验</Button>
        <br />
        <h3>自动过滤比当前配置的密级等级更低的密级</h3>
        <SecretSelect
          filterLevel={filterLevel}
          filterLevelType={'down'}
          required
          getInstance={this.getInstance2}
        />
        <br />
        <Button onClick={this.handleSubmit2} style={{ marginTop: 20 }}>主动校验</Button>
      </div>
    );
  }
}

export default SecretSelectDemo;
```

### form 表单中使用

```jsx
import { toJS } from 'mobx';
import { Component } from 'react';
import {
  FormRenderProps, constants, Dialog, Button, FormItemProps,
  Form, FormDatas, MDialogButtonType, FormHelpTipPostion,
} from '@weapp/ui';
import FormDemoStore from './store';
import { options } from '../mock';

const { uiPcClsPrefix } = constants;
const prefixCls = `${uiPcClsPrefix}-demo-form-m`;
interface FormRenderState {
  data: FormDatas,
}
interface FormRenderDemoProps extends FormRenderProps {
  data: FormDatas,
}

const helpTipPostion: FormHelpTipPostion = 'afterLabel';

const items: FormItemProps = {
  'input': {
    itemType: "INPUT",
    value: '',
    rules: 'required',
    placeholder: '请输入',
    showVoiceToTextBtn: true, // 是否显示语音按钮（仅 em 生效）
    required: true
  },
  'secret-select': {
    itemType: "PLUGIN",
    required: true,
    pluginParams: {
      packageName: '@weapp/ui',
      compName: 'SecretSelect',
    }
  },
  'secret-select2': {
    itemType: "PLUGIN",
    required: true,
    pluginParams: {
      packageName: '@weapp/ui',
      compName: 'SecretSelect',
      wrapDisplay: true
    }
  },
  'secret-select3': {
    itemType: "PLUGIN",
    required: true,
    pluginParams: {
      packageName: '@weapp/ui',
      compName: 'SecretSelect',
      data: options,
    },
    readOnly: true,
    value: {
      secretLevel: '1',
      secretLevelValidity: '30年'
    }
  },
  'select': {
    required: true,
    itemType: "SELECT",
    placeholder: '请选择',
    readOnly: true,
    data: [
      { id: 'op1', content: '选项一' },
      { id: 'op2', content: '选项二' },
    ],
  },
  'date': {
    itemType: 'DATETIMEPICKER',
    required: true,
  },
  'scope': {
    itemType: 'SCOPE',
    placeholder: '请输入',
  },
  'browser': {
    itemType: 'BROWSER',
    browserBean: {
      type: "resource",
      module: "hrm",
      showVoiceToTextBtn: true
    }
  },
  'money': {
    itemType: 'INPUT',
    placeholder: '请输入金额',
    otherParams: {
      type: 'money',
      moneyKeyboardAlign: "left",
      suffix: '人民币',
    }
  },
}
const initLayout = [
  [
    { id: '1', label: '文本输入框', items: ['input'], labelSpan: 8, hide: false, classNames: "", helpfulTip: '提示信息', helpTipPostion },
  ],
  [
    { id: '2', label: '下拉选择框', items: ['select'], labelSpan: 8, hide: false, },
  ],
  [
    { id: '3', label: '密级', items: ['secret-select'], labelSpan: 8, hide: false, },
  ],
  [
    { id: '4', label: '密级2', items: ['secret-select2'], labelSpan: 8, hide: false, },
  ],
  [
    { id: '5', label: '密级3', items: ['secret-select3'], labelSpan: 8, hide: false, },
  ],
  [
    { id: '10', label: '请假时间', items: ['date'], labelSpan: 8, hide: false, helpfulTip: '提示信息', },
  ],
  [
    { id: '11', label: '金额', items: ['money'], labelSpan: 8, hide: false, },
  ],
  [
    { id: '15', label: '区间', items: ['scope'], labelSpan: 8, hide: false, },
  ],
  [
    { id: '16', label: '浏览框', items: ['browser'], labelSpan: 8, hide: false, },
  ],
]

const formDemoStore = new FormDemoStore();
class FormDemo extends Component<FormRenderDemoProps, FormRenderState> {

  constructor(props: FormRenderDemoProps) {
    super(props);
    this.state = {
      data: { //字段默认值，可通过data处理，或者在items里面配置，如两边有冲突，则以data为准
        'select': ['op1'],
        'input_readonly': '内容',
      },
    }
  }
  //  基本用法：初始化表单
  componentDidMount() {
    const { data } = this.state;
    const apiTimeout = setTimeout(() => { // 延时模拟接口数据
      formDemoStore.formCustom.initForm({
        data, items, layout: initLayout, groups: [], // groups为空，则不分组显示
      })
      if (apiTimeout) clearTimeout(apiTimeout);
    }, 50)
  }

  //  基本用法：获取表单数据
  getFormValue = () => {
    console.log(toJS(formDemoStore.formCustom.getFormDatas()));
  }

  //  基本用法：重置表单数据
  resetForm = () => {
    formDemoStore.formCustom.resetForm(); // 清空form表单数据
  }

  /* -------------------------------------------------------------------------------------- */
  onChange = (value?: FormDatas, otherParams?: any) => {
    console.log('onChange', value);
    console.log('otherParams', otherParams); // otherParams 字段非value的所有参数
  }
  onBeforeChange = (datas?: FormDatas) => console.log('onBeforeChange', datas);

  onBlur = (value?: FormDatas, otherParams?: any) => {
    console.log('onBlur', value, otherParams);
  }
  onFocus = (value?: FormDatas, otherParams?: any) => {
    console.log('onFocus', value, otherParams);
  }
  validateForm = () => formDemoStore.formCustom.validate().then((errors) => {
    console.log(errors);
  });
  render() {
    return (
      <div className={prefixCls}>
        <Form
          store={formDemoStore.formCustom}
          onChange={this.onChange}
          onBlur={this.onBlur}
          onFocus={this.onFocus}
          isMobile={false}
          onBeforeChange={this.onBeforeChange}
        />
        <div className={`${prefixCls}-footer`}>
          <Button type="primary" className={`${prefixCls}-btn`} onClick={this.getFormValue}>获取form数据</Button>
          <Button type="primary" className={`${prefixCls}-btn`} onClick={this.validateForm}>校验</Button>
          <Button className={`${prefixCls}-btn`} onClick={this.resetForm}>重置</Button>
        </div>
      </div>
    );
  }
}

export default FormDemo
```

### formSwitch 中使用

```jsx
import { toJS } from 'mobx';
import { Component, PureComponent, ReactNode } from 'react';
import {
  FormRenderProps, constants, Dialog,
  Form, FormDatas, FormItemProps, FormItem, utils, FormValue, TypesBrowserOption, MDialogButtonType, FormItemRenderProps, FormHelpTipPostion, ShareBrowserOption, FormSwitch, Button
} from '@weapp/ui';

const { uiPcClsPrefix } = constants;
const { isValueEmpty } = utils;

const prefixCls = `${uiPcClsPrefix}-demo-form-m`;
interface FormRenderState {
  data: FormDatas,
}
interface FormRenderDemoProps extends FormRenderProps {
  data: FormDatas,
}

class FormDemo extends Component<FormRenderDemoProps, FormRenderState> {
  instance?: any;
  instance2?: any;

  constructor(props: FormRenderDemoProps) {
    super(props);
    this.state = {
      data: { //字段默认值，可通过data处理，或者在items里面配置，如两边有冲突，则以data为准
        'select': ['op1'],
        'input_readonly': '内容',
      },
    }
  }
  getInstance = (el: any) => {
    this.instance = el;
  }
  getInstance2 = (el: any) => {
    this.instance2 = el;
  }
  onChange1 = (data?: FormDatas | undefined, otherParams?: any) => {
    console.log('formItem', data, otherParams);
  }
  onChange2 = (value?: FormValue | undefined, otherParams?: any) => {
    console.log('formSwitch', value, otherParams);
  }
  handleSubmit = () => {
    // 提交前手动触发校验
    this.instance.validate()
      .then((res: any) => {
        console.log(res);
        if (isValueEmpty(res.errors)) {
          Dialog.message({ type: 'success', content: '校验通过' })
        } else {
          // 校验失败
          Dialog.message({ type: 'error', content: '校验失败' })
        }
      })
  }
  handleSubmit2 = () => {
    // 提交前手动触发校验
    this.instance2.validate()
      .then((res: any) => {
        console.log(res);
        if (isValueEmpty(res.errors)) {
          Dialog.message({ type: 'success', content: '校验通过' })
        } else {
          // 校验失败
          Dialog.message({ type: 'error', content: '校验失败' })
        }
      })
  }
  render() {
    const items: FormItemProps = {
      'secretSelect': {
        itemType: "PLUGIN",
        pluginParams: {
          packageName: '@weapp/ui',
          compName: 'SecretSelect',
          getInstance: this.getInstance,
        },
        required: true,
      },
    }
    const initLayout = ["secretSelect"]
    return (
      <div className={prefixCls}>
        <h2>FormItem 中使用</h2>
        <FormItem
          item={items}
          com={initLayout}
          label="密级"
          onChange={this.onChange1}
        />
        <br />
        <Button onClick={this.handleSubmit} style={{ marginTop: 20 }}>主动校验</Button>
        <h2>FormSwitch 中使用</h2>
        <FormSwitch
          itemType='PLUGIN'
          onChange={this.onChange2}
          required
          pluginParams={{
            packageName: '@weapp/ui',
            compName: 'SecretSelect',
            getInstance: this.getInstance2,
          }}
        />
        <Button onClick={this.handleSubmit2} style={{ marginTop: 20 }}>主动校验</Button>
      </div>
    );
  }
}

export default FormDemo
```

## API

### 参数说明如下：

| 参数 | 说明 | 类型 | 是否必填 | 默认值 |
| --- | --- | --- | --- | --- |
| value | 当前密级(受控值) | SecretSelectValueType |  |  |
| defaultValue | 默认密级 | SecretSelectValueType | F | - |
| data | 密级配置（如果不配置，默认使用系统配置的密级信息） | SecretSelectOptionType[] | F | - |
| checkValidity | 校验规则(一个正则字符串，组件内通过 new RegExp(checkValidity) 进行校验) | string | F | ((永久)\|(^(\d)+(天\|个月\|年)))$ |
| secretLevelValidityInfo | 保密期限配置（如果不配置，默认使用系统配置的保密期限提示） | string | F | - |
| onChange | 密级变化回调 | (value: SecretSelectValueType, option?: SecretSelectOptionType) => void | F | - |
| getInstance | 获取组件实例(参考 demo 可以通过实例主动调用校验方法) | (secretSelect: any) => void | F | - |
| autoValidate | 密级期限 input 框失焦时是否自动触发密级期限校验 | boolean | F | true |
| filterLevel | 设置密级过滤（仅有低于该密级的等级可用） | string | F | - |
| filterLevelType | 设置密级过滤方向（up：自动过滤比当前密级更高的密级，仅有低于等于该密级的等级可用；down：自动过滤比当前密级更低的密级，仅有高于等于该密级的等级可用） | `up` \| `down` | F | - |
### SecretSelectOptionType 说明：

```
{
  /** 保密等级 */
  id: string,
  /** 密级名称 */
  content: string,
  /** 保密期限显示状态：require：必填，edit：可编辑，readOnly：显示，hidden：隐藏 */
  secretLevelValidityShowType: 'require' | 'edit' | 'readOnly' | 'hidden',
  /** 默认保密期限 */
  defaultSecretLevelValidity?: string,
  /** 是否封存 false未封存（启用）,true封存（未启用） */
  canceled?: boolean,
}
```

## 组件使用说明

组件支持通过 `` 传递密级配置信息，如果没有传递 data，将默认取系统配置的密级配置。

当 `` 为 true 时，编辑时下拉框不会显示该密级，只读时会展示。

当 `` 为 `` 时，对应密级不会显示保密期限输入框。

需要注意配置的密级信息中，id 数字越大，密级越低。

## 组件提供的方法

### 密级校验方法：doValidate

使用方法:

```
doValidate({
  secretLevel: string,  // 保密等级 id
  secretLevelValidity: string, // 保密期限
  }, {
  required?: boolean,  // 是否校验保密等级必填
  options?: secretLevelOptions,  // 主动传递密级配置信息
  checkValidity?: string,  // 主动设置保密期限校验规则
}).then((res: any) => {
  if (!isValueEmpty(res.errors)) {
  // 校验不通过
  } else {
  // 校验通过
  }
});
```

### 获取密级配置方法：getSecretLevelInfo

返回内容：

```
{
    resourceOptionInfo: SecretSelectOptionType[];  // 保密等级配置
    secretLevelValidityInfo: string;  // 保密期限提示
    isOpenClassification: boolean;  // 是否开启密级
}
```
