Skip to content

自定义输入原子组件

设计思想与原则

简洁

使用简单,只需要<erp-input type="{组件类型}" v-model="value">一行代码,一目了然。组件功能、样式高度内聚,入参简单,出参简单。

统一

对原子化输入组件抽象统一,管理统一,维护统一。

分层

基础组件 -> 应用组件 -> 模板组件 -> 应用程序。

用户树形选择输入

vue
<ErpInput v-model="vm.value" type="user-tree-select" />
<ErpInput v-model="vm.value1" type="user-tree-select" disabled />
代码事例
vue
<template>
	<div class="erp-input-demo">
        <fk-row><fk-button type="primary" @click="handleClick">显示/隐藏</fk-button></fk-row>
        <div v-show="isShow">
            <p>默认模式</p>
            <ErpInput v-model="vm.value" type="user-tree-select" :renderLabel="renderLabel"/>
            <p>默认模式(下拉压平选择)</p>
            <ErpInput v-model="vm.value" planish type="user-tree-select" :renderLabel="renderLabel" />
        </div>
        <p>多选模式(下拉压平选择)</p>
		<ErpInput v-model="vm.value1" planish multiple  type="user-tree-select" />
		<p>默认模式 <code>disabled</code></p>
		<ErpInput v-model="vm.value" type="user-tree-select" disabled>
            <template #tree-slot-extra>123</template>
        </ErpInput>
        <p>多选模式</p>
        <ErpInput 
            v-model="vm.value1" 
            multiple 
            placeholder="请选择客户所属员工" 
            :tree-props="{
                'only-check-leaf': true,
                defaultExpandAll: false,
                virtualListProps: {
                height: 200,
                },
            }" 
            type="user-tree-select" 
            :renderLabel="renderLabel">
            <template #tree-slot-extra>123</template>
        </ErpInput>
	</div>
	<fk-row>
		<JsonViewer :data="vm" />
	</fk-row>
</template>

<script lang="tsx" setup>
import { reactive, ref } from 'vue';
import { Input as ErpInput } from '@erp/biz';

const isShow = ref(true);

const vm = reactive({
	value: '',
	value1: [],
});

const renderLabel = el => {
    return <span>{el.name}(<span style="color: rgb(var(--fkblue-6))">{el.id}</span>)</span>;
}

const handleClick = () => {
    isShow.value = !isShow.value;
}

</script>

<style lang="scss" scoped>
.erp-input-demo {
	width: 240px;
}
</style>

文本输入

vue
<ErpInput type="text" v-model="value" />
代码事例
vue
<template>
	<fk-row class="erp-input-demo">
		<ErpInput ref="input" v-model="vm.text" type="text" :max-length="10" @change="handleChange">
            <template #suffix><i class="erpfont icon-icon-original-order" /></template>
        </ErpInput>
	</fk-row>
    <p>
        <fk-space>
            <fk-button type="primary" @click="handleFocus">聚焦事件</fk-button>
            <fk-button type="primary" @click="handleBlur">失焦事件</fk-button>
            <fk-button type="primary" @click="handleGetInstance">获取实例</fk-button>
        </fk-space>
    </p>
    <fk-row>
		<JsonViewer :data="vm" />
	</fk-row>
</template>

<script lang="ts" setup>
import { reactive, useTemplateRef } from 'vue';
import { Input as ErpInput } from '@erp/biz';

const input = useTemplateRef('input')

const handleChange = (value) => {
  console.log('handleChange >>', value);
}

const handleFocus = () => {
    input.value?.focus();
}

const handleBlur = () => {
    input.value?.blur();
}

const handleGetInstance = () => {
    const instance = input.value.getInstance();
    console.log('instance >>', instance);
}

const vm = reactive({
	text: '',
});
</script>

<style lang="scss" scoped>
.erp-input-demo {
	width: 240px;
}
</style>

文本域输入

vue
<ErpInput type="textarea" v-model="value" />
代码事例
vue
<template>
	<div class="erp-input-demo">
		<ErpInput v-model="vm.text" type="textarea" />
	</div>
	<fk-row>
		<JsonViewer :data="vm" />
	</fk-row>
</template>

<script lang="ts" setup>
import { reactive, ref } from 'vue';
import { Input as ErpInput } from '@erp/biz';

const vm = reactive({
	text: '',
});
</script>

<style lang="scss" scoped>
.erp-input-demo {
	width: 240px;
}
</style>

密码输入

vue
<ErpInput type="text" v-model="value" />
代码事例
vue
<template>
	<div class="erp-input-demo">
		<ErpInput v-model="vm.text" type="password" @change="handleChange" />
	</div>
	<fk-row>
		<JsonViewer :data="vm" />
	</fk-row>
</template>

<script lang="ts" setup>
import { reactive } from 'vue';
import { Input as ErpInput } from '@erp/biz';

const handleChange = value => {
	console.log('handleChange >>', value);
};

const vm = reactive({
	text: '',
});
</script>

<style lang="scss" scoped>
.erp-input-demo {
	width: 240px;
}
</style>

整数输入

仅可输入大于 0 的整数

vue
<ErpInput type="integer" v-model="value" />
代码事例
vue
<template>
	<div class="erp-input-demo">
		<ErpInput v-model="vm.value" type="integer" @change="handleChange" />
	</div>
	<fk-row>
		<JsonViewer :data="vm" />
	</fk-row>
</template>

<script lang="ts" setup>
import { reactive } from 'vue';
import { Input as ErpInput } from '@erp/biz';

const handleChange = value => {
	console.log('handleChange >>', value);
};

const vm = reactive({
	value: '',
});
</script>

<style lang="scss" scoped>
.erp-input-demo {
	width: 240px;
}
</style>

数据输入

vue
<ErpInput type="number" v-model="value" />
代码事例
vue
<template>
	<div class="erp-input-demo">
		<ErpInput v-model="vm.value" type="number" @input="onInput" />
	</div>
	<fk-row>
		<JsonViewer :data="vm" />
	</fk-row>
</template>

<script lang="ts" setup>
import { reactive, ref } from 'vue';
import { Input as ErpInput } from '@erp/biz';

const vm = reactive({
	value: '',
	multiple: [],
});


const onInput = (value) => {
    console.log('onInput >>', value);
}

</script>

<style lang="scss" scoped>
.erp-input-demo {
	width: 240px;
}
</style>

数据范围输入

vue
<ErpInput type="range-number" v-model="value" />
<ErpInput v-model="vm.value" multiple type="number" />
代码事例
vue
<template>
	<div class="erp-input-demo">
		<p>Number multiple 模式</p>
		<ErpInput v-model="vm.multiple" :placeholder="['最小', '最大']" multiple type="number" />
		<p>通用模式</p>
		<ErpInput v-model="vm.multiple1" :placeholder="['min', 'max']" type="range-number" />
	</div>
	<fk-row>
		<JsonViewer :data="vm" />
	</fk-row>
</template>

<script lang="ts" setup>
import { reactive, ref } from 'vue';
import { Input as ErpInput } from '@erp/biz';

const vm = reactive({
	multiple: [],
	multiple1: [1],
});

setTimeout(() => {
	vm.multiple1 = [2, 3];
}, 3000);
</script>

<style lang="scss" scoped>
.erp-input-demo {
	width: 240px;
}
</style>

日期选择输入

日期选择

vue
<ErpInput type="date" v-model="value" />
代码事例
vue
<template>
	<div class="erp-input-demo">
		<h5>单选</h5>
		<ErpInput v-model="vm.value" v-model:shortcutKey="vm.shortcutKey" type="date" />
		<h5>范围选择</h5>
		<ErpInput v-model="vm.values" v-model:shortcutKey="vm.multiShortcutKey" type="date" multiple />
	</div>
	<fk-row>
		<JsonViewer :data="vm" />
	</fk-row>
</template>

<script lang="ts" setup>
import { reactive } from 'vue';
import { Input as ErpInput } from '@erp/biz';

const vm = reactive({
    shortcutKey: 'today',
    multiShortcutKey: '',
	value: '',
	values: [],
});
</script>

<style lang="scss" scoped>
.erp-input-demo {
	width: 240px;
	h5 {
		font-size: 14px;
		margin: 12px 0 6px;
	}
}
</style>

日期时间选择输入

日期时间选择

vue
<ErpInput type="datetime" v-model="value" />
代码事例
vue
<template>
	<div class="erp-input-demo">
		<h5>单选</h5>
		<ErpInput v-model="vm.value" type="datetime" />
		<h5>范围选择</h5>
		<ErpInput v-model="vm.values" type="datetime" multiple />
	</div>
	<fk-row>
		<JsonViewer :data="vm" />
	</fk-row>
</template>

<script lang="ts" setup>
import { reactive } from 'vue';
import { Input as ErpInput } from '@erp/biz';

const vm = reactive({
	value: '',
	values: [],
});
</script>

<style lang="scss" scoped>
.erp-input-demo {
	width: 360px;
	h5 {
		font-size: 14px;
		margin: 12px 0 6px;
	}
}
</style>

时间选择输入

时间选择

vue
<ErpInput type="time" v-model="value" />
代码事例
vue
<template>
	<div class="erp-input-demo">
		<h5>单选</h5>
		<ErpInput v-model="vm.value" type="time" />
		<h5>范围选择</h5>
		<ErpInput v-model="vm.values" type="time" multiple />
	</div>
	<fk-row>
		<JsonViewer :data="vm" />
	</fk-row>
</template>

<script lang="ts" setup>
import { reactive } from 'vue';
import { Input as ErpInput } from '@erp/biz';

const vm = reactive({
	value: '',
	values: [],
});
</script>

<style lang="scss" scoped>
.erp-input-demo {
	width: 240px;
	h5 {
		font-size: 14px;
		margin: 12px 0 6px;
	}
}
</style>

单项选择输入

单项选择

vue
<ErpInput type="radio" v-model="value" :options="options" />
代码事例
vue
<template>
    <h3>基本用法</h3>
	<fk-space>
		<ErpInput v-model="vm.value" type="radio" :options="checkboxOptions" @dblclick="handleDblClick" />
	</fk-space>
    <h3>非严格模式</h3>
	<fk-space>
		<ErpInput v-model="vm.value1" type="radio" :strict="false" :options="checkboxOptions" />
	</fk-space>
	<fk-row>
		<JsonViewer :data="vm" />
	</fk-row>
</template>

<script lang="ts" setup>
import { reactive, ref } from 'vue';
import { Input as ErpInput } from '@erp/biz';

const vm = reactive({
	value: 5,
    value1: 5,
});

const handleDblClick = evnt => {
    console.log('handleDblClick >>', evnt);
}

const checkboxOptions = [
	{
		label: '未选中项',
		value: 1,
	},
	{
		label: '未选悬停项',
		value: 2,
	},
	{
		label: '选中项',
		value: 3,
	},
	{
		label: '未选禁用项',
		value: 4,
	},
	{
		label: '选中禁用项',
		value: 5,
		disabled: true,
	},
];
</script>

<style lang="scss" scoped>
.erp-input-demo {
	// width: 240px;
}
</style>

复选选择输入

复选选择

vue
<ErpInput type="checkbox" v-model="value" :options="options" />
<ErpInput v-model="vm.value2" :multiple="false" type="checkbox" :options="checkboxOptions" />
代码事例
vue
<template>
	<div class="erp-input-demo">
        <p>多选复选框</p>
		<ErpInput v-model="vm.value" multiple type="checkbox" :options="checkboxOptions" />
		<p>单选复选框</p>
		<ErpInput v-model="vm.value2" :multiple="false" type="checkbox" :options="checkboxOptions" />
	</div>
	<fk-row>
		<JsonViewer :data="vm" />
	</fk-row>
</template>

<script lang="ts" setup>
import { reactive, ref } from 'vue';
import { Input as ErpInput } from '@erp/biz';

const vm = reactive({
	value: [3, 5],
	value2: 1,
});

const checkboxOptions = [
	{
		label: '未选中项',
		value: 1,
	},
	{
		label: '未选悬停项',
		value: 2,
	},
	{
		label: '选中项',
		value: 3,
	},
	{
		label: '未选禁用项',
		value: 4,
	},
	{
		label: '选中禁用项',
		value: 5,
		disabled: true,
	},
];
</script>

<style lang="scss" scoped>
.erp-input-demo {
	// width: 240px;
}
</style>

选择器输入

基础用法

最简单的选择器用法:

vue
<ErpInput type="select" v-model="value" :options="options" />

完整示例

代码事例
vue
<template>
  <div class="select-demo">
    <!-- 单选 -->
    <div class="demo-section">
      <h5>单选</h5>
      <ErpInput 
        ref="inputRef"
        v-model="formData.value" 
        v-model:viewOption="formData.viewSingleOption" 
        :loading="formData.loading"
        type="select" 
        :options="options" 
        placeholder="请选择"
        @search="handleSearch" 
        @blur="handleBlur" 
        @focus="handleFocus"
      />
    </div>

    <!-- 多选 -->
    <div class="demo-section">
      <h5>多选</h5>
      <ErpInput 
        v-model="formData.values" 
        v-model:viewOption="formData.viewOption" 
        allow-create 
        type="select" 
        :options="options" 
        multiple
        placeholder="请选择多个选项"
        @blur="handleBlur" 
        @focus="handleFocus" 
      />
    </div>

    <!-- 多选(无默认值) -->
    <div class="demo-section">
      <h5>多选(无默认值)</h5>
      <ErpInput 
        v-model="formData.undefinedValue" 
        type="select" 
        :options="options" 
        multiple
        placeholder="请选择"
      />
    </div>

    <!-- 多选(全选) -->
    <div class="demo-section">
      <h5>多选(全选) <code>check-all</code> 属性</h5>
      <ErpInput 
        v-model="formData.values1" 
        check-all 
        type="select" 
        :options="options" 
        multiple
        placeholder="支持全选"
      />
    </div>

    <!-- 超大数据量 -->
    <div class="demo-section">
      <h5>超大数据量</h5>
      <ErpInput 
        v-model="formData.largeValues" 
        allow-create 
        type="select" 
        :options="largeOptions" 
        multiple
        placeholder="支持大量数据"
      />
    </div>

    <!-- 操作按钮 -->
    <div class="demo-actions">
      <fk-space>
        <fk-button type="primary" @click="focusInput">聚焦</fk-button>
        <fk-button type="primary" @click="blurInput">失焦</fk-button>
        <fk-button @click="resetData">重置数据</fk-button>
      </fk-space>
    </div>

    <!-- 数据展示 -->
    <div class="demo-data">
      <h5>表单数据</h5>
      <JsonViewer :data="formData" />
    </div>
  </div>
</template>

<script lang="ts" setup>
import { reactive, ref, useTemplateRef } from 'vue';
import { cloneDeep } from 'lodash-es';
import { Input as ErpInput } from '@erp/biz';

// 输入框引用
const inputRef = useTemplateRef('inputRef');

// 表单数据
const formData = reactive({
  value: 1,                    // 单选值
  values: ['1', 2, 5],        // 多选值
  undefinedValue: undefined,   // 无默认值的多选
  values1: [],                 // 全选多选
  largeValues: [],            // 大数据量多选
  viewOption: null,           // 多选视图选项
  viewSingleOption: null,     // 单选视图选项
  loading: false,             // 加载状态
});

// 基础选项数据
const options = ref([
  { label: '未选中项', value: 1 },
  { label: '未选悬停项', value: '2' },
  { label: '选中项', value: 3 },
  { label: '未选禁用项', value: 4 },
  { label: '选中禁用项', value: 5, disabled: true },
]);

// 大数据量选项(用于性能测试)
const largeOptions = Array.from({ length: 1000 }, (_, i) => ({
  label: `选项 ${i + 1}`,
  value: i,
}));

// 搜索处理
const handleSearch = (searchValue: string) => {
  if (!searchValue) {
    options.value = [];
    return;
  }

  // 显示加载状态
  formData.loading = true;
  // formData.fallbackOption = cloneDeep(formData.viewSingleOption);

  // 模拟异步搜索
  setTimeout(() => {
    // 随机决定是否返回结果
    if (Math.random() > 0.5) {
      options.value = [
        { label: `${searchValue}-选项1`, value: `${searchValue}-1` },
        { label: `${searchValue}-选项2`, value: `${searchValue}-2` },
        { label: `${searchValue}-选项3`, value: `${searchValue}-3` },
      ];
    } else {
      options.value = [];
    }
    formData.loading = false;
  }, 500);
};

// 事件处理
const handleFocus = (event: FocusEvent) => {
  console.log('输入框聚焦:', event);
};

const handleBlur = (event: FocusEvent) => {
  console.log('输入框失焦:', event);
};

// 操作方法
const focusInput = () => {
  inputRef.value?.focus();
};

const blurInput = () => {
  inputRef.value?.blur();
};

const resetData = () => {
  Object.assign(formData, {
    value: 1,
    values: ['1', 2, 5],
    undefinedValue: undefined,
    values1: [],
    largeValues: [],
    viewOption: null,
    viewSingleOption: null,
    loading: false,
    fallbackOption: null,
  });
};
</script>

<style lang="scss" scoped>
.select-demo {
  width: 300px;
  
  .demo-section {
    margin-bottom: 24px;
    
    h5 {
      font-size: 14px;
      font-weight: 500;
      margin: 0 0 8px 0;
      color: var(--fk-color-text-primary);
    }
  }
  
  .demo-actions {
    margin: 20px 0;
    padding: 16px;
    background-color: var(--fk-color-bg-secondary);
    border-radius: 6px;
  }
  
  .demo-data {
    margin-top: 24px;
    padding: 16px;
    background-color: var(--fk-color-bg-secondary);
    border-radius: 6px;
    
    h5 {
      font-size: 14px;
      font-weight: 500;
      margin: 0 0 12px 0;
      color: var(--fk-color-text-primary);
    }
  }
}
</style>

开关输入

开关选择

vue
<ErpInput type="switch" v-model="value" :options="options" />
代码事例
vue
<template>
	<div class="erp-input-demo">
		<ErpInput v-model="vm.value" type="switch" :options="options" />
	</div>
	<fk-row>
		<JsonViewer :data="vm" />
	</fk-row>
</template>

<script lang="ts" setup>
import { reactive, ref } from 'vue';
import { Input as ErpInput } from '@erp/biz';

const vm = reactive({
	value: 1,
});

const options = [
	{
		label: '开',
		value: 1,
	},
	{
		label: '关',
		value: 2,
	},
];
</script>

<style lang="scss" scoped>
.erp-input-demo {
	// width: 240px;
}
</style>

级联选择输入

级联选择

vue
<ErpInput type="cascader" v-model="value" :options="options" path-mode/>
代码事例
vue
<template>
	<div class="erp-input-demo">
		<h5>单选</h5>
		<ErpInput v-model="vm.value" v-model:viewOption="vm.viewOption" type="cascader" :triggerProps="{composite: true}" :options="options" path-mode />
		<h5>多选</h5>
		<ErpInput v-model="vm.values" v-model:viewOption="vm.viewOption" type="cascader" :options="options" multiple />
        <ErpInput v-model="vm.values" v-model:viewOption="vm.viewOption" type="cascader" :triggerProps="{composite: true}" :options="options" multiple />
	</div>
	<fk-row>
        <JsonViewer :data="vm" />
    </fk-row>
</template>

<script lang="ts" setup>
import { reactive } from 'vue';
import { Input as ErpInput } from '@erp/biz';

const vm = reactive({
	value: '',
	values: [],
	viewOption: undefined,
});

const options = [
	{
		value: 'beijing',
		label: 'Beijing',
		children: [
			{
				value: 'chaoyang',
				label: 'ChaoYang',
				children: [
					{
						value: 'datunli',
						label: 'Datunli',
					},
				],
			},
			{
				value: 'haidian',
				label: 'Haidian',
			},
			{
				value: 'dongcheng',
				label: 'Dongcheng',
			},
			{
				value: 'xicheng',
				label: 'Xicheng',
				children: [
					{
						value: 'jinrongjie',
						label: 'Jinrongjie',
					},
					{
						value: 'tianqiao',
						label: 'Tianqiao',
					},
				],
			},
		],
	},
	{
		value: 'shanghai',
		label: 'Shanghai',
		children: [
			{
				value: 'huangpu',
				label: 'Huangpu',
			},
		],
	},
];
</script>

<style lang="scss" scoped>
.erp-input-demo {
	// width: 240px;
    :deep(ul) {
        padding: 0;
        margin: 0;
    }
	h5 {
		font-size: 14px;
		margin: 12px 0 6px;
	}
}
</style>

树形选择输入

树形选择

vue
<ErpInput type="tree" v-model="value" :options="options" />
代码事例
vue
<template>
	<div class="erp-input-demo">
		<h5>单选</h5>
		<ErpInput ref="input" v-model="vm.value" v-model:viewOption="vm.viewOption" type="tree" :options="options" @blur="onBlur"/>
		<h5>多选</h5>
		<ErpInput v-model="vm.values" v-model:viewOption="vm.viewOption" type="tree" :options="options" multiple @blur="onBlur"/>
	</div>
    <fk-row style="margin-top: 12px">
		<fk-space>
			<fk-button type="primary" @click="handleFocus">聚焦事件</fk-button>
			<fk-button type="primary" @click="handleBlur">失焦事件</fk-button>
		</fk-space>
	</fk-row>
	<fk-row>
		<JsonViewer :data="vm" />
	</fk-row>
</template>

<script lang="tsx" setup>
import { reactive, useTemplateRef } from 'vue';
import { Input as ErpInput } from '@erp/biz';

const input = useTemplateRef('input');

const handleFocus = () => {
	input.value?.focus();
};

const handleBlur = () => {
	input.value?.blur();
};

const onBlur = (e) => {
    console.log('blur', vm.value, e);
}

const vm = reactive({
	value: '',
	values: [],
	viewOption: [],
});

const options = [
	{
		value: 'node1',
		label: '一级树',
		children: [
			{
				value: 'node2',
				label: '二级树',
				disabled: true,
			},
		],
	},
	{
		value: 'node3',
		label: '三级树',
        render() {
            return <span>三级树三级树三级树三级树</span>;
        },
		children: [
			{
				value: 'node4',
				label: '四级树',
			},
			{
				value: 'node5',
				label: '五级树',
			},
			{
				value: 'node6',
				label: '六级树',
			},
			{
				value: 'node7',
				label: '七级树',
			},
		],
	},
];
</script>

<style lang="scss" scoped>
.erp-input-demo {
	width: 240px;
	h5 {
		font-size: 14px;
		margin: 12px 0 6px;
	}
}
</style>

上传文件输入

上传文件

vue
<ErpInput type="upload" v-model="value" />
代码事例
vue
<template>
	<div class="erp-input-demo">
		<h5>单选</h5>
		<ErpInput v-model="vm.value" type="upload" :max-size="1"/>
		<h5>多选</h5>
		<ErpInput v-model="vm.values" accept="图片" type="upload" multiple />
		<h5>视频</h5>
		<ErpInput v-model="vm.video" accept="视频" drag-text="也可拖拽视频文件到此处" button-text="点击选择视频" type="upload" :pasted="false" />
        <h5>图片 card</h5>
        <ErpInput v-model="vm.video" accept="图片" drag-text="也可拖拽视频文件到此处 drag-text" list-type="picture-card" type="upload" placeholder="此处是 placeholder 配置,对应的是upload tip 配置" :pasted="false" :draggable="false" />
		<h5>图片</h5>
		<ErpInput v-model="vm.value" class="picture-48" :show-picture-name="false" type="upload" />
	</div>
	<fk-row>
		<JsonViewer :data="vm" />
	</fk-row>
</template>

<script lang="ts" setup>
import { reactive } from 'vue';
import { Input as ErpInput } from '@erp/biz';

const vm = reactive({
	video: null,
	value: {
		uid: '-2',
		name: '103937.png',
        url: '//test.img.fukerp.com/default/FLIrNHVfnvjvOXN40Rm1l5dugEwsjUDsxEDW3kIP.jpg',
	},
	values: [
		{
			uid: '-2',
			name: '103937.png',
			url: '//test.img.fukerp.com/default/FLIrNHVfnvjvOXN40Rm1l5dugEwsjUDsxEDW3kIP.jpg',
		},
		{
			uid: '-1',
			name: 'hahhahahahaha.png',
			url: '//test.img.fukerp.com/default/j44G9LTLBxBkNlLu84HOSGF6qgzQLjg7kK3WuuVg.jpg',
		},
		{
			uid: '1',
			name: '103937.png',
			url: '//test.img.fukerp.com/default/FLIrNHVfnvjvOXN40Rm1l5dugEwsjUDsxEDW3kIP.jpg',
		},
	],
});
</script>

<style lang="scss" scoped>
.erp-input-demo {
	h5 {
		font-size: 14px;
		margin: 12px 0 6px;
	}
	:deep(.fk-upload-drag-wrapper) {
		width: 400px;
	}
	:deep(.picture-48) {
		.fk-upload-list-picture {
			--picture-width: 48px;
		}
	}
}
pre {
	overflow: auto;
}
</style>

店铺选择输入

vue
<ErpInput type="select-shop" v-model="value" />
代码事例
vue
<template>
	<div class="erp-input-demo">
        <p>多选</p>
		<ErpInput v-model="vm.select" placeholder="店铺选择" :apiParams="{ids: [1,2,3]}" :multiple="true" type="select-shop" />
	</div>
    <div class="erp-input-demo">
        <p>单选</p>
		<ErpInput v-model="vm.single" placeholder="店铺选择" :multiple="false" type="select-shop" />
	</div>
	<fk-row>
		<JsonViewer :data="vm" />
	</fk-row>
</template>

<script lang="ts" setup>
import { reactive, ref } from 'vue';
import { Input as ErpInput } from '@erp/biz';

const vm = reactive({
	select: [208],
    single: null,
});

setTimeout(() => {
    vm.single = 208;
}, 3000)

</script>

<style lang="scss" scoped>
.erp-input-demo {
	width: 240px;
}
</style>

选择弹窗输入

vue
<ErpInput type="select-input" v-model="value" />
代码事例
vue
<template>
	<div class="erp-input-demo">
        <p>多选</p>
		<ErpInput v-model="vm.select" placeholder="店铺选择" :echo-label-api="echoLabelApi" :data-source-api="options" :multiple="true" type="select-input" />
	</div>
    <div class="erp-input-demo">
        <p>单选</p>
		<ErpInput v-model="vm.single" placeholder="店铺选择" :options="options" :multiple="false" type="select-input" />
	</div>
	<fk-row>
		<JsonViewer :data="vm" />
	</fk-row>
</template>

<script lang="ts" setup>
import { reactive } from 'vue';
import { Input as ErpInput, getStoreApi } from '@erp/biz';
import { cloneDeep } from 'lodash-es';
import data from '/biz/shop.json';

const vm = reactive({
	select: [208],
    single: 208,
});

const options = () => {
    return cloneDeep(data.data)
};

const echoLabelApi = (values: any) => {
    return getStoreApi().then(res => {
        const options = [];
        (res || []).forEach(el => {
            el.children.forEach(c => {
                options.push({
                    value: c.id,
                    label: c.name
                })
            });
        });
        return options;
    });
}

</script>

<style lang="scss" scoped>
.erp-input-demo {
	width: 240px;
}
</style>

字典选择输入

代码事例
vue
<template>
	<p>单选</p>
	<ErpInput v-model="model.single" code="sex_code" type="dic" placeholder="请选择" />
	<p>多选</p>
	<ErpInput v-model="model.multiple" code="unit" type="dic" multiple placeholder="请选择" />
	<p>数据模型</p>
	<fk-row>
		<JsonViewer :data="model" />
	</fk-row>
</template>

<script lang="ts" setup>
import { ref } from 'vue';
import { Input as ErpInput } from '@erp/biz';

const model = ref({
	single: '',
	multiple: [],
});
</script>

富文本输入

代码事例
vue
<template>
	<h3>编辑状态</h3>
	<ErpInput v-model="model.single" type="rich-text" />
	<h3>查看状态</h3>
	<ErpInput v-model="model.single" type="rich-text" disabled />
	<fk-row>
		<JsonViewer :data="model" />
	</fk-row>
</template>

<script lang="ts" setup>
import { ref } from 'vue';
import { Input as ErpInput } from '@erp/biz';

const model = ref({
	single: `<div dir="auto" data-component="RootComponent" style="padding-bottom:40px" class="xnote-root">
    <div data-placeholder="" class="xnote-content">
        <div data-component="ParagraphComponent" data-placeholder="" class="xnote-paragraph">
            <div><strong>定制款式</strong></div>
        </div>
        <div data-component="ParagraphComponent" data-placeholder="输入此案例包含的具体款式 <br />示例:T恤:CYJD-1006重磅紧密赛络纺落肩袖橙色T恤;围裙:LS-22S102红色围裙" class="xnote-paragraph">
            <div><br></div>
        </div>
        <div data-component="ParagraphComponent" data-placeholder="" class="xnote-paragraph">
            <div><br></div>
        </div>
        <div data-component="ParagraphComponent" data-placeholder="" class="xnote-paragraph">
            <div><strong>定制款式</strong></div>
        </div>
        <div data-component="ParagraphComponent" data-placeholder="输入此案例包含的具体款式 示例:T恤:CYJD-1006重磅紧密赛络纺落肩袖橙色T恤;围裙:LS-22S102红色围裙" class="xnote-paragraph">
            <div><br></div>
        </div>
        <div data-component="ParagraphComponent" data-placeholder="" class="xnote-paragraph">
            <div><br></div>
        </div>
        <div data-component="ParagraphComponent" data-placeholder="" class="xnote-paragraph">
            <div><strong>定制款式</strong></div>
        </div>
        <div data-component="ParagraphComponent" data-placeholder="输入此案例包含的具体款式 示例:T恤:CYJD-1006重磅紧密赛络纺落肩袖橙色T恤;围裙:LS-22S102红色围裙" class="xnote-paragraph">
            <div><br></div>
        </div>
        <div data-component="ParagraphComponent" data-placeholder="" class="xnote-paragraph">
            <div><br></div>
        </div>
    </div>
</div><div dir="auto" data-component="RootComponent" class="xnote-root"><div data-placeholder="" class="xnote-content"><div data-component="ParagraphComponent" class="xnote-paragraph"><div>adasd</div></div><div data-component="ParagraphComponent" class="xnote-paragraph"><div class="xnote-h1">H1 121312</div></div><div data-component="ParagraphComponent" class="xnote-paragraph"><div class="xnote-h2">H2 12312312</div></div><div data-component="ParagraphComponent" class="xnote-paragraph"><div class="xnote-h4">H3 123123213</div></div><div data-component="ParagraphComponent" class="xnote-paragraph"><div class="xnote-h5">H4 123123123</div></div><div data-component="ParagraphComponent" class="xnote-paragraph"><div class="xnote-h5">H5 55555</div></div><div data-component="ParagraphComponent" class="xnote-paragraph"><div class="xnote-h6">H6</div></div><div data-component="ParagraphComponent" class="xnote-paragraph"><div>有数字序列</div></div><ol data-component="ListComponent" data-reorder="true" style="margin-left:0px" class="xnote-list"><li><div class="xnote-list-type"><span class="xnote-order-btn">1.</span></div><div class="xnote-list-content">代办事项</div></li></ol><ol data-component="ListComponent" data-reorder="false" style="margin-left:0px" class="xnote-list"><li><div class="xnote-list-type"><span class="xnote-order-btn">2.</span></div><div class="xnote-list-content">23243</div></li></ol><ol data-component="ListComponent" data-reorder="false" style="margin-left:0px" class="xnote-list"><li><div class="xnote-list-type"><span class="xnote-order-btn">3.</span></div><div class="xnote-list-content">3</div></li></ol><div data-component="ParagraphComponent" class="xnote-paragraph"><div>无序序列</div></div><ul data-component="ListComponent" data-reorder="true" style="margin-left:0px" class="xnote-list"><li><div class="xnote-list-type"><span class="xnote-order-btn">•</span></div><div class="xnote-list-content">1</div></li></ul><ul data-component="ListComponent" data-reorder="true" style="margin-left:0px" class="xnote-list"><li><div class="xnote-list-type"><span class="xnote-order-btn">•</span></div><div class="xnote-list-content">2</div></li></ul><ul data-component="ListComponent" data-reorder="true" style="margin-left:0px" class="xnote-list"><li><div class="xnote-list-type"><span class="xnote-order-btn">•</span></div><div class="xnote-list-content">3</div></li></ul><ul data-component="ListComponent" data-reorder="true" style="margin-left:0px" class="xnote-list"><li><div class="xnote-list-type"><span class="xnote-order-btn">•</span></div><div class="xnote-list-content">4</div></li></ul><div data-component="ParagraphComponent" class="xnote-paragraph"><div><br></div></div><div data-component="ParagraphComponent" class="xnote-paragraph"><div>代办事项</div></div><div data-component="TodoListComponent" style="margin-left:0px" class="xnote-todolist"><div class="xnote-todolist-icon"><span class="xnote-icon-checkbox-unchecked"></span></div><div class="xnote-todolist-content">1</div></div><div data-component="TodoListComponent" style="margin-left:0px" class="xnote-todolist"><div class="xnote-todolist-icon"><span class="xnote-icon-checkbox-unchecked"></span></div><div class="xnote-todolist-content">2</div></div><div data-component="TodoListComponent" style="margin-left:0px" class="xnote-todolist"><div class="xnote-todolist-icon"><span class="xnote-icon-checkbox-unchecked"></span></div><div class="xnote-todolist-content">3</div></div><div data-component="TodoListComponent" style="margin-left:0px" class="xnote-todolist"><div class="xnote-todolist-icon"><span class="xnote-icon-checkbox-unchecked"></span></div><div class="xnote-todolist-content">4</div></div><div data-component="TodoListComponent" style="margin-left:0px" class="xnote-todolist"><div class="xnote-todolist-icon"><span class="xnote-icon-checkbox-unchecked"></span></div><div class="xnote-todolist-content">5</div></div><div data-component="ParagraphComponent" class="xnote-paragraph"><div>高亮块</div></div><div data-component="HighlightBoxComponent" data-icon="" class="xnote-highlight-box"><div class="xnote-highlight-box-left"><div class="xnote-highlight-box-icon"><button type="button">❤️</button></div></div><div class="xnote-highlight-box-content"><div data-component="ParagraphComponent" class="xnote-paragraph"><div>是打发斯蒂芬水电费水电费地方</div></div><div data-component="ParagraphComponent" class="xnote-paragraph"><div>水电费萨芬的</div></div></div></div><div data-component="ParagraphComponent" class="xnote-paragraph"><div><span data-component="KatexComponent" data-katex="%25%20%5Cf%20is%20defined%20as%20%231f(%232)%20using%20the%20macro%0A%5Cf%5Crelax%7Bx%7D%20%3D%20%5Cint_%7B-%5Cinfty%7D%5E%5Cinfty%0A%5Cf%5Chat%5Cxi%5C%2Ce%5E%7B2%20%5Cpi%20i%20%5Cxi%20x%7D%0A%5C%2Cd%5Cxi" class="xnote-katex"><span class="katex-display"><span class="katex"><span aria-hidden="true" class="katex-html"><span class="base"><span style="height:1em;vertical-align:-0.25em" class="strut"></span><span style="margin-right:0.10764em" class="mord mathnormal">f</span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span><span style="margin-right:0.2778em" class="mspace"></span><span class="mrel">=</span><span style="margin-right:0.2778em" class="mspace"></span></span><span class="base"><span style="height:2.3846em;vertical-align:-0.9703em" class="strut"></span><span class="mop"><span style="margin-right:0.44445em;position:relative;top:-0.0011em" class="mop op-symbol large-op">∫</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span style="height:1.4143em" class="vlist"><span style="top:-1.7881em;margin-left:-0.4445em;margin-right:0.05em"><span style="height:2.7em" class="pstrut"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">−</span><span class="mord mtight">∞</span></span></span></span><span style="top:-3.8129em;margin-right:0.05em"><span style="height:2.7em" class="pstrut"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">∞</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span style="height:0.9703em" class="vlist"><span></span></span></span></span></span></span><span style="margin-right:0.1667em" class="mspace"></span><span class="mord accent"><span class="vlist-t vlist-t2"><span class="vlist-r"><span style="height:0.9579em" class="vlist"><span style="top:-3em"><span style="height:3em" class="pstrut"></span><span style="margin-right:0.10764em" class="mord mathnormal">f</span></span><span style="top:-3.2634em"><span style="height:3em" class="pstrut"></span><span style="left:-0.0833em" class="accent-body"><span class="mord">^</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span style="height:0.1944em" class="vlist"><span></span></span></span></span></span><span class="mopen">(</span><span style="margin-right:0.04601em" class="mord mathnormal">ξ</span><span class="mclose">)</span><span style="margin-right:0.1667em" class="mspace"></span><span class="mord"><span class="mord mathnormal">e</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span style="height:0.8991em" class="vlist"><span style="top:-3.113em;margin-right:0.05em"><span style="height:2.7em" class="pstrut"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span><span class="mord mathnormal mtight">πi</span><span style="margin-right:0.04601em" class="mord mathnormal mtight">ξ</span><span class="mord mathnormal mtight">x</span></span></span></span></span></span></span></span></span><span style="margin-right:0.1667em" class="mspace"></span><span class="mord mathnormal">d</span><span style="margin-right:0.04601em" class="mord mathnormal">ξ</span></span></span></span></span></span></div></div><div data-step="0" data-component="StepComponent" class="xnote-step"><div class="xnote-step-item xnote-current"><div class="xnote-step-item-header"><div class="xnote-step-item-line"></div><div class="xnote-step-item-icon">1</div></div><div class="xnote-step-item-content"><div data-component="ParagraphComponent" class="xnote-paragraph"><div><strong style="font-size:18px">标题</strong></div></div><div data-component="ParagraphComponent" class="xnote-paragraph"><div>描述信息...</div></div></div></div></div><div data-component="ParagraphComponent" class="xnote-paragraph"><div>图片</div></div><div data-component="ParagraphComponent" class="xnote-paragraph"><div style="text-align:center"><div data-component="ImageComponent" class="xnote-image"><img alt="" src="https://test.img.fukerp.com/default/xI6kPcjlQpYU72aV3u7jsnQ3EhDVhir6PmZ5Dzct.png" style="width:298.703125px;height:342.796875px"></div></div></div><div data-component="ParagraphComponent" class="xnote-paragraph"><div>视频</div></div><div data-component="ParagraphComponent" class="xnote-paragraph"><div style="text-align:center"><div data-component="VideoComponent" class="xnote-video"><video src="https://test.img.fukerp.com/default/T9Gr83BmzO9KHTC43m28If1xjSYwLGvF6gnwdc6G.mp4" style="width:644px;height:362.25px"></video></div></div></div></div></div>`,
	multiple: [],
});
</script>

搜索框输入

vue
<ErpInput v-model="vm.value" type="search-input" />
<ErpInput v-model="vm.value1" type="search-input" search-button />
代码事例
vue
<template>
	<div class="erp-input-demo">
		<p>搜索图标</p>
		<ErpInput v-model="vm.value" type="search-input" @search="onSearch" />
		<p>搜索button</p>
		<ErpInput v-model="vm.value1" type="search-input" search-button loading @search="onSearch"/>
	</div>
	<fk-row>
		<JsonViewer :data="vm" />
	</fk-row>
</template>

<script lang="ts" setup>
import { reactive } from 'vue';
import { Input as ErpInput } from '@erp/biz';

const vm = reactive({
	value: '',
	value1: '',
});

/**
 * 单击搜索按钮时触发
 */
const onSearch = () => {
    console.log('onSearch')
}

</script>

<style lang="scss" scoped>
.erp-input-demo {
	width: 240px;
}
</style>

批量输入

vue
<ErpInput v-model="vm.value" type="batch-input" />
<ErpInput v-model="vm.value1" type="batch-input" disabled />
代码事例
vue
<template>
	<div class="erp-input-demo">
		<p>默认模式</p>
		<ErpInput v-model="vm.value" placeholder="回车或双击进行批量输入" :limit="0" name="商品编号" type="batch-input"  @confirm="handleConfirm" />
		<p>默认模式 <code>disabled</code></p>
		<ErpInput v-model="vm.value" placeholder="批量输入" type="batch-input" disabled/>
	</div>
	<fk-row>
		<JsonViewer :data="vm" />
	</fk-row>
</template>

<script lang="ts" setup>
import { reactive } from 'vue';
import { Input as ErpInput } from '@erp/biz';

const vm = reactive({
	value: '',
	value1: '',
});

/**
 * 单击搜索按钮时触发
 */
const onSearch = () => {
    console.log('onSearch')
}

const handleConfirm = (value: string) => {
    console.log('handleConfirm', value);
}

</script>

<style lang="scss" scoped>
.erp-input-demo {
	width: 240px;
}
</style>

HTML富文本输入

代码事例
vue
<template>
	<h3>编辑状态</h3>
	<ErpInput v-model="model.single" type="html-input" />
	<h3>查看状态</h3>
	<ErpInput v-model="model.multiple" type="html-input" />
	<fk-row>
		<JsonViewer :data="model" />
	</fk-row>
</template>

<script lang="ts" setup>
import { reactive } from 'vue';
import { Input as ErpInput } from '@erp/biz';

const model = reactive({
	single: '',
	multiple: 'aaadf',
});

setTimeout(() => {
    // 清空
    model.multiple = '<br>';
}, 3000)
</script>

API

<input> Props

参数名描述类型默认值
model-value (v-model)绑定值ModelValueType''
type (必填)输入类型InputType'text'
allow-clear是否允许清空输入框booleantrue
disabled是否禁用booleanfalse
multiple是否多选booleanfalse
placeholder提示文字string | string[]-
options配置(string | number | OptionData)[] | Promise<(string | number | OptionData)[]>[]
accept上传文件限制
图片, Excel, Word, PPT, PDF, 视频, 音频
string[] | string-

<input> Events

事件名描述参数
change仅在输入框失焦或按下回车时触发value: ModelValueType
ev: Event

OptionData

参数名描述类型默认值
value选项值string | number | boolean | Record<string, any>-
label选项内容string-
disabled是否禁用booleanfalse
children树形结构OptionData[]-

BaseInputProps

参数名描述类型默认值
modelValue (v-model)绑定值string | number | boolean | Record<string, any> | (string | number | Record<string, any>)[]-
allowClear是否允许清空输入框booleanfalse
disabled是否禁用booleanfalse
multiple是否多选booleanfalse
placeholder提示文字string-

基于 MIT 许可发布