Commit 1c0a50268dbe76754e88f9a6d95ff3c7d6bb59ec

Authored by Aaron
1 parent bfe60bf3
Exists in master and in 1 other branch legacy

新增搜索表单

examples/router/routes.js
... ... @@ -25,12 +25,29 @@ const _components = [
25 25 component: () => import('@/views/docs/form.md'),
26 26 },
27 27 {
  28 + path: 'search',
  29 + name: 'search',
  30 + meta: { title: 'Search 搜索' },
  31 + component: () => import('@/views/docs/search.md'),
  32 + },
  33 + {
28 34 path: 'table',
29 35 name: 'table',
30 36 meta: { title: 'Table 表格' },
31 37 component: () => import('@/views/docs/table.md'),
32 38 },
33 39 ]
  40 + },
  41 + {
  42 + group: '业务',
  43 + children: [
  44 + {
  45 + path: 'scheme',
  46 + name: 'scheme',
  47 + meta: { title: 'Scheme 方案' },
  48 + component: () => import('@/views/docs/scheme.md'),
  49 + },
  50 + ]
34 51 }
35 52 ]
36 53  
... ...
examples/views/docs/scheme.md 0 → 100644
... ... @@ -0,0 +1,38 @@
  1 +# Scheme 方案
  2 +
  3 +Scheme是一个数据驱动的解决方案,通过既定的业务配置参数,生成可模块化编辑的`CURD`业务视图
  4 +
  5 +## 基础用法
  6 +
  7 +配置项list中通过type可以配置任意组件,不受框架限制
  8 +
  9 +:::snippet 使用`list`属性设置数据源,列表项中的`type`指定组件类型,每一项都已设置为**el-form-item**的子组件,通过`rules`配置校验规则
  10 +
  11 +```html
  12 +<template>
  13 + <eagle-scheme :list="schemeList"></eagle-scheme>
  14 +</template>
  15 +
  16 +<script>
  17 +export default {
  18 + data() {
  19 + return {
  20 + schemeList: [
  21 + { type: 'el-input', key: 'name', label: '名称', rules: [{ required: true, message: '请输入名称' }] },
  22 + { type: 'eagle-select', key: 'address', label: '住址', props: { dataSource: [{ label: '大街上', value: 'S' }, { label: '小区里', value: 'H' }] } },
  23 + { type: 'el-input', key: 'postcode', label: '邮编', span: 12, tip: { content: '邮政编码', placement: "left" } },
  24 + { type: 'el-input', key: 'number', label: '楼栋号', span: 12, visible: (model) => model.address === 'H' },
  25 + ]
  26 + }
  27 + },
  28 +}
  29 +</script>
  30 +```
  31 +
  32 +:::
  33 +
  34 +## Attribute 属性
  35 +
  36 +参数|说明|类型|可选值|默认值
  37 +-|-|-|-|-
  38 +list | 表单项配置列表 | Array | - | []
0 39 \ No newline at end of file
... ...
examples/views/docs/search.md 0 → 100644
... ... @@ -0,0 +1,130 @@
  1 +# Search 搜索
  2 +
  3 +Search 搜索组件是一个使用`list`来配置生成的搜索表单
  4 +
  5 +## 基础用法
  6 +
  7 +配置项list中通过type可以配置任意组件,不受框架限制
  8 +
  9 +:::snippet 使用`list`属性设置数据源,列表项中的`type`指定组件类型,支持通过`rules`配置校验规则
  10 +
  11 +```html
  12 +<template>
  13 + <eagle-search :list="searchList" @search="handleSearch" @reset="handleReset" :span="8" :searching="searching"></eagle-search>
  14 +</template>
  15 +
  16 +<script>
  17 +export default {
  18 + data() {
  19 + return {
  20 + searching: false,
  21 + searchList: [
  22 + { type: 'el-input', key: 'name', label: '名称', rules: [{ required: true, message: '请输入名称' }] },
  23 + { type: 'eagle-select', key: 'type', label: '类型', props: { dataSource: [{ label: '呆萌', value: '1' }, { label: '二货', value: '2' }] } },
  24 + { type: 'el-input', key: 'postcode', label: '邮编', tip: { content: '邮政编码', placement: "left" } },
  25 + { type: 'el-input', key: 'number', label: '楼栋号' },
  26 + { type: 'el-input', key: 'not', label: '我不是', visible: (model) => model.type === '2' },
  27 + { type: 'el-input', key: 'no', label: '我没有', visible: (model) => model.type === '2' },
  28 + { type: 'el-input', key: 'never', label: '别瞎说啊', visible: (model) => model.type === '2' },
  29 + ]
  30 + }
  31 + },
  32 + mounted() {
  33 + this.searching = true;
  34 + setTimeout(() => {
  35 + this.searching = false;
  36 + }, 3000);
  37 + },
  38 + methods: {
  39 + handleSearch(value) {
  40 + console.log(value);
  41 + },
  42 + handleReset() {
  43 + console.log('reset');
  44 + }
  45 + }
  46 +}
  47 +</script>
  48 +```
  49 +
  50 +:::
  51 +
  52 +## 自定义组件
  53 +
  54 +在使用`list`的同时,也支持通过`slot`传入组件,以满足不同的业务需求
  55 +
  56 +:::snippet 使用`list`属性设置数据源,列表项中的`type`指定组件类型,支持通过`rules`配置校验规则
  57 +
  58 +```html
  59 +<template>
  60 + <eagle-search :list="searchList">
  61 + <template #type="{ model }">
  62 + <eagle-select v-model="model.type" :dataSource="dataSource"></eagle-select>
  63 + </template>
  64 + <template #button-group="{ model, collapse, doSearch, doReset, doCollapse }">
  65 + <el-button size="mini" type="primary" round @click="handleQuery(model, doSearch)">搜索</el-button>
  66 + <el-button size="mini" type="success" round @click="doReset">恢复</el-button>
  67 + <el-button size="mini" type="info" round @click="doCollapse">{{ collapse ? '打开' : '关闭' }}</el-button>
  68 + </template>
  69 + </eagle-search>
  70 +</template>
  71 +
  72 +<script>
  73 +export default {
  74 + data() {
  75 + return {
  76 + searchList: [
  77 + { type: 'el-input', key: 'name', label: '名称' },
  78 + { key: 'type', label: '类型' },
  79 + { type: 'el-input', key: 'yes', label: '是的' },
  80 + { type: 'el-input', key: 'yeah', label: '没错' },
  81 + { type: 'el-input', key: 'absolutely', label: '就这样' },
  82 + ],
  83 + dataSource: [
  84 + { label: '选项A', value: 'A' },
  85 + { label: '选项B', value: 'B' },
  86 + ]
  87 + }
  88 + },
  89 + methods: {
  90 + handleQuery(model, action) {
  91 + if (action) {
  92 + action();
  93 + console.log(model);
  94 + }
  95 + },
  96 + }
  97 +}
  98 +</script>
  99 +```
  100 +
  101 +:::
  102 +
  103 +## Attribute 属性
  104 +
  105 +参数|说明|类型|可选值|默认值
  106 +-|-|-|-|-
  107 +value / v-model | 绑定值 | Object | - | -
  108 +list | 表单项配置列表 | Array | - | []
  109 +
  110 +## Events 事件
  111 +
  112 +事件名称|说明|回调参数
  113 +-|-|-
  114 +change | 表单model发生变化时触发 | model对象
  115 +search | 点击查询按钮时触发 | model对象
  116 +reset | 点击重置按钮时触发 | -
  117 +
  118 +## List 表单项配置列表
  119 +
  120 +参数|说明|类型|可选值|默认值
  121 +-|-|-|-|-
  122 +type | 组件类型 | String | - | el-input
  123 +key | 参数名 | String | - | -
  124 +label | 参数标签 | String | - | -
  125 +props | 组件参数 | Object,Function(model: object)) | - | {}
  126 +style | 组件样式 | Object | - | { width: "100%" }
  127 +on | 组件事件 | Object,Function(model: object) | - | {}
  128 +visible | 组件v-if状态 | Boolean,Function(model: object) | - | true
  129 +rules | 组件校验规则 | Object,Array | - | -
  130 +tip | 组件提示框 | Object,String | - | {}
0 131 \ No newline at end of file
... ...
packages/index.js
... ... @@ -8,6 +8,8 @@ import ImageUpload from &#39;./Image-upload&#39;
8 8 import ImageUploadMultiple from './Image-upload/multiple'
9 9 import ImageView from './image-view'
10 10 import RadioGroup from './radio-group'
  11 +import Scheme from './scheme'
  12 +import Search from './search'
11 13 import Select from './select'
12 14 import StatusIndicator from './status-indicator'
13 15 import SwitchButton from './switch-button'
... ... @@ -25,6 +27,8 @@ const components = {
25 27 ImageUploadMultiple,
26 28 ImageView,
27 29 RadioGroup,
  30 + Scheme,
  31 + Search,
28 32 Select,
29 33 StatusIndicator,
30 34 SwitchButton,
... ...
packages/scheme/index.vue 0 → 100644
... ... @@ -0,0 +1,30 @@
  1 +<style>
  2 +.eagle-scheme {
  3 + padding: 0px;
  4 +}
  5 +</style>
  6 +
  7 +<template>
  8 + <div class="eagle-scheme">
  9 + Scheme
  10 + </div>
  11 +</template>
  12 +
  13 +<script>
  14 +export default {
  15 + name: 'Scheme',
  16 + props: {
  17 + // 配置列表
  18 + list: {
  19 + type: Array,
  20 + required: true
  21 + },
  22 + },
  23 + data() {
  24 + return {
  25 + // 编辑器表单模型
  26 + model: {}
  27 + };
  28 + },
  29 +};
  30 +</script>
0 31 \ No newline at end of file
... ...
packages/search/index.vue 0 → 100644
... ... @@ -0,0 +1,189 @@
  1 +<style>
  2 +.eagle-search {
  3 + padding: 0px;
  4 +}
  5 +.eagle-search__btn-col {
  6 + text-align: right;
  7 +}
  8 +</style>
  9 +
  10 +<template>
  11 + <el-form class="eagle-search" ref="search" :model="model" v-bind="formProps">
  12 + <el-row :gutter="15">
  13 + <template v-for="(item, index) in list">
  14 + <el-col v-if="bindItemVisible(item.visible)" v-show="!(collapse && index > visibleColNum - 2)" :key="index + 'data'" :span="!item.span ? span : item.span">
  15 + <el-form-item :label="item.label" :label-width="item.label ? undefined : item.labelWidth || '0px'" :prop="item.key" :rules="item.rules">
  16 + <el-tooltip :disabled="!item.tip" v-bind="bindItemTip(item.tip)">
  17 + <slot v-if="$scopedSlots[item.key] || $slots[item.key]" :name="item.key" :model="model" v-bind="item"></slot>
  18 + <component v-else :is="item.type || 'el-input'" v-model="model[item.key]" v-bind="bindItemProps(item)" v-on="bindItemEvent(item)" :style="bindItemStyle(item.style)"></component>
  19 + </el-tooltip>
  20 + </el-form-item>
  21 + </el-col>
  22 + </template>
  23 + <el-col :span="list.length > visibleColNum ? collapse ? span : 24 : span" class="eagle-search__btn-col">
  24 + <slot v-if="$scopedSlots['button-group'] || $slots['button-group']" name="button-group"
  25 + :model="model" :collapse="collapse" :doSearch="handleSearch" :doReset="handleReset" :doCollapse="handleCollapse"
  26 + ></slot>
  27 + <el-button-group v-else>
  28 + <el-button size="small" type="primary" :loading="searching" @click="handleSearch" icon="el-icon-search">查询</el-button>
  29 + <el-button size="small" @click="handleReset">重置</el-button>
  30 + <el-button size="small" v-if="list.length > visibleColNum" :icon="collapse ? 'ios-arrow-down' : 'ios-arrow-up'" @click="handleCollapse">
  31 + {{ collapse ? '展开' : '收起' }}
  32 + </el-button>
  33 + </el-button-group>
  34 + </el-col>
  35 + </el-row>
  36 + </el-form>
  37 +</template>
  38 +
  39 +<script>
  40 +export default {
  41 + name: 'Search',
  42 + props: {
  43 + // 用于实例化本组件绑定v-model的值
  44 + value: {
  45 + type: Object,
  46 + default: () => {
  47 + return {};
  48 + }
  49 + },
  50 + // 配置列表
  51 + list: {
  52 + type: Array,
  53 + required: true
  54 + },
  55 + // 提交加载状态
  56 + searching: Boolean,
  57 + // 表单参数
  58 + formProps: {
  59 + type: Object,
  60 + default() {
  61 + return {
  62 + size: 'small',
  63 + 'label-width': '70px'
  64 + }
  65 + }
  66 + },
  67 + // 表单项占位
  68 + span: {
  69 + type: Number,
  70 + default: 6
  71 + }
  72 + },
  73 + data() {
  74 + return {
  75 + // 编辑器表单模型
  76 + model: {},
  77 + // 表单折叠状态
  78 + collapse: false,
  79 + };
  80 + },
  81 + computed: {
  82 + visibleColNum() {
  83 + return 24 / this.span;
  84 + }
  85 + },
  86 + watch: {
  87 + // 组件外部v-model值更新后同步刷新model
  88 + value(val) {
  89 + Object.keys(this.model).forEach(key => {
  90 + this.model[key] = val ? val[key] : undefined;
  91 + });
  92 + },
  93 + // 配置列表有改动时初始化表单模型
  94 + list(value) {
  95 + this.initModel(value);
  96 + },
  97 + model: {
  98 + handler(val) {
  99 + this.$emit("input", val);
  100 + this.$emit("change", val);
  101 + },
  102 + deep: true
  103 + }
  104 + },
  105 + created() {
  106 + // 初始化表单模型
  107 + this.initModel(this.list);
  108 + },
  109 + methods: {
  110 + // 绑定提示组件参数
  111 + bindItemTip(tip) {
  112 + if (typeof tip === 'string') {
  113 + return { content: tip, effect: 'light' };
  114 + } else if (typeof tip === 'object') {
  115 + return tip;
  116 + } else {
  117 + return {};
  118 + }
  119 + },
  120 + // 绑定组件事件
  121 + bindItemEvent(item) {
  122 + if (item.on) {
  123 + if (typeof item.on === 'function') {
  124 + return item.on(this.model);
  125 + } else {
  126 + return item.on
  127 + }
  128 + } else {
  129 + return undefined
  130 + }
  131 + },
  132 + // 初始化表单模型
  133 + initModel(list) {
  134 + list.forEach(item => {
  135 + this.$set(this.model, item.key, item.default || undefined)
  136 + });
  137 + },
  138 + // 绑定组件v-if状态
  139 + bindItemVisible(visible = true) {
  140 + let result = visible;
  141 + if (typeof visible === 'function') {
  142 + result = visible(this.model);
  143 + }
  144 + return result;
  145 + },
  146 + // 绑定组件参数
  147 + bindItemProps(item) {
  148 + const { props = {} } = item;
  149 + let result = { ...props };
  150 + Object.keys(result).forEach(key => {
  151 + if (typeof result[key] === 'function') {
  152 + result[key] = result[key](this.model);
  153 + }
  154 + });
  155 + return result;
  156 + },
  157 + // 绑定组件样式
  158 + bindItemStyle(style = {}) {
  159 + return {
  160 + width: "100%",
  161 + ...style
  162 + };
  163 + },
  164 + // 点击确定提交表单的操作
  165 + handleSearch() {
  166 + this.$refs.search.validate(valid => {
  167 + if (valid) {
  168 + const result = JSON.parse(JSON.stringify(this.model));
  169 + this.$emit("search", result);
  170 + }
  171 + });
  172 + },
  173 + // 重置表单
  174 + handleReset() {
  175 + Object.keys(this.model).forEach(key => {
  176 + this.model[key] = this.list[key] ? this.list[key].default : undefined;
  177 + });
  178 + this.$nextTick(() => {
  179 + this.$refs.search.clearValidate();
  180 + });
  181 + this.$emit('reset');
  182 + },
  183 + // 折叠表单
  184 + handleCollapse() {
  185 + this.collapse = !this.collapse;
  186 + }
  187 + }
  188 +};
  189 +</script>
0 190 \ No newline at end of file
... ...