Commit 8002f99d525fa83265105eb39e36037dc2ecfb71

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

更新文档,Scheme支持渲染插槽和表单项渲染插槽

examples/router/routes.js
... ... @@ -76,6 +76,12 @@ const _components = [
76 76 group: '其它',
77 77 children: [
78 78 {
  79 + path: 'specification',
  80 + name: 'specification',
  81 + meta: { title: 'Specification 说明' },
  82 + component: () => import('@/views/docs/component/specification.md'),
  83 + },
  84 + {
79 85 path: 'other',
80 86 name: 'other',
81 87 meta: { title: 'Other 其它' },
... ...
examples/views/docs/component/scheme.md
1 1 # Scheme 方案
2 2  
3   -Scheme是一个数据驱动的解决方案,通过既定的业务配置参数,生成可模块化编辑的`CURD`业务视图
  3 +Scheme是一个数据驱动的解决方案,通过既定的业务配置参数,生成可模块化编辑的`CURD`业务视图。本组件核心是将一个list解析为Search、Table、Form三个组件的配置项,再将这几个组件组合使用。
4 4  
5 5 ## 基础用法
6 6  
7   -配置一个数据项列表快速生成一个增删改查业务视图
  7 +配置一个数据项列表快速生成一个增删改查业务视图,默认为静态数据维护。
8 8  
9   -::: snippet 使用`list`属性设置数据源,列表项中的`type`指定组件类型,其它包括**Form**、**Detail**、**Search**组件的配置参数格式
  9 +::: snippet 使用`list`属性设置数据源,列表项中的`type`指定组件类型,其它参数包括**Form**、**Table**、**Search**组件的配置参数格式。可以使用`include`和`exclude`设置需要包括或者排除在哪个组件中,支持**String**和**Array**,不传则表示默认存在所有组件中。
10 10  
11 11 ```html
12 12 <template>
... ... @@ -28,7 +28,7 @@ export default {
28 28 list: [
29 29 { type: 'el-input', key: 'name', label: '名称', rules: [{ required: true, message: '请输入名称' }] },
30 30 { type: 'el-input', key: 'code', label: '编码', rules: [{ required: true, message: '请输入编码' }], exclude: 'search' },
31   - { type: 'el-input', key: 'type', label: '类型' },
  31 + { type: 'el-input', key: 'type', label: '类型', include: ['table', 'form'] },
32 32 { type: 'el-input-number', key: 'sort', label: '排序', include: 'form', sortable: true },
33 33 { type: 'el-input', key: 'status', label: '状态' },
34 34 ],
... ... @@ -40,16 +40,142 @@ export default {
40 40  
41 41 :::
42 42  
  43 +## 动态列
  44 +
  45 +设置表格列可以动态的控制显示状态
  46 +
  47 +::: snippet `option`中设置`dynamicColumn: true`即可
  48 +
  49 +```html
  50 +<template>
  51 + <eagle-scheme v-model="tableData" :list="list" :option="{ dynamicColumn: true }"></eagle-scheme>
  52 +</template>
  53 +
  54 +<script>
  55 +export default {
  56 + data() {
  57 + return {
  58 + tableData: [
  59 + { name: '产品A', code: 'P0001', type: 'NORMAL', sort: 0, status: '0' },
  60 + { name: '产品B', code: 'P0002', type: 'BROKEN', sort: 1, status: '1' },
  61 + { name: '产品C', code: 'P0003', type: 'NORMAL', sort: 0, status: '0' },
  62 + { name: '产品D', code: 'P0004', type: 'BROKEN', sort: 1, status: '1' },
  63 + ],
  64 + list: [
  65 + { type: 'el-input', key: 'name', label: '名称' },
  66 + { type: 'el-input', key: 'code', label: '编码' },
  67 + { type: 'el-input', key: 'type', label: '类型' },
  68 + { type: 'el-input-number', key: 'sort', label: '排序' },
  69 + { type: 'el-input', key: 'status', label: '状态' },
  70 + ],
  71 + }
  72 + },
  73 +}
  74 +</script>
  75 +```
  76 +
  77 +:::
  78 +
  79 +## 弹出框类型
  80 +
  81 +设置编辑表格时弹出框的类型
  82 +
  83 +::: snippet 设置`dialogComponent`,默认为**el-dialog**,若设置为**el-drawer**,则可在`dialogProps`中可以设置`direction`弹出方向。
  84 +
  85 +```html
  86 +<template>
  87 + <eagle-scheme v-model="tableData" :list="list" dialogComponent="el-drawer" :dialogProps="{ direction: 'rtl' }"></eagle-scheme>
  88 +</template>
  89 +
  90 +<script>
  91 +export default {
  92 + data() {
  93 + return {
  94 + tableData: [
  95 + { name: '产品A', code: 'P0001', type: 'NORMAL', sort: 0, status: '0' },
  96 + { name: '产品B', code: 'P0002', type: 'BROKEN', sort: 1, status: '1' },
  97 + { name: '产品C', code: 'P0003', type: 'NORMAL', sort: 0, status: '0' },
  98 + { name: '产品D', code: 'P0004', type: 'BROKEN', sort: 1, status: '1' },
  99 + ],
  100 + list: [
  101 + { type: 'el-input', key: 'name', label: '名称' },
  102 + { type: 'el-input', key: 'code', label: '编码' },
  103 + { type: 'el-input', key: 'type', label: '类型' },
  104 + { type: 'el-input-number', key: 'sort', label: '排序' },
  105 + { type: 'el-input', key: 'status', label: '状态' },
  106 + ],
  107 + }
  108 + },
  109 +}
  110 +</script>
  111 +```
  112 +
  113 +:::
  114 +
  115 +## 自定义内容
  116 +
  117 +与**Form**、**Table**、**Search**组件相同,可以在Scheme中设置具名插槽替换相关组件。
  118 +
  119 +::: snippet 配置**Form**组件的插槽有:`form-key`表单分组、`form-item-key`表单项、`form-label-key`表单项标题;配置**Table**组件的插槽有:`table-value-key`表格值渲染插槽、`table-key`表格列插槽、`table-append`表格后置列追加、`table-operation`表格操作栏自定义、`table-operation-btn-edit`表格编辑按钮自定义、`table-operation-btn-append`表格操作栏按钮追加;配置**Search**组件的插槽有:`search-key`搜索表单项;配置**Detail**组件的插槽有:`view-key`详情分组、`view-item-key`详情项;其它插槽有:`action-bar`按钮栏自定义、`action-button`按钮追加、`action-btn-new`新增按钮自定义、`render-key`表格和详情表单渲染插槽、`field-key`搜索表单和编辑表单项渲染插槽
  120 +
  121 +```html
  122 +<template>
  123 + <eagle-scheme v-model="tableData" :list="list">
  124 + <template #field-type="{ model }">
  125 + <el-select v-model="model.type">
  126 + <el-option value="NORMAL" label="正常"></el-option>
  127 + <el-option value="BROKEN" label="已损坏"></el-option>
  128 + </el-select>
  129 + </template>
  130 + <template #render-type="{ value, row }">
  131 + <el-tag :type="value === 'BROKEN' ? 'danger' : 'success'">
  132 + {{ value === 'BROKEN' ? '已损坏' : '正常' }}
  133 + </el-tag>
  134 + </template>
  135 + <template #view-item-code="{ value }">
  136 + <el-tag size="small">{{ value }}</el-tag>
  137 + </template>
  138 + <template #form-item-status="{ model }">
  139 + <el-input-number v-model="model.status" :min="0" :max="1" />
  140 + </template>
  141 + </eagle-scheme>
  142 +</template>
  143 +
  144 +<script>
  145 +export default {
  146 + data() {
  147 + return {
  148 + tableData: [
  149 + { name: '产品A', code: 'P0001', type: 'NORMAL', sort: 0, status: '0' },
  150 + { name: '产品B', code: 'P0002', type: 'BROKEN', sort: 1, status: '1' },
  151 + { name: '产品C', code: 'P0003', type: 'NORMAL', sort: 0, status: '0' },
  152 + { name: '产品D', code: 'P0004', type: 'BROKEN', sort: 1, status: '1' },
  153 + ],
  154 + list: [
  155 + { type: 'el-input', key: 'name', label: '名称' },
  156 + { type: 'el-input', key: 'code', label: '编码' },
  157 + { type: 'el-input', key: 'type', label: '类型' },
  158 + { type: 'el-input-number', key: 'sort', label: '排序' },
  159 + { type: 'el-input', key: 'status', label: '状态', formatter: (r, c, v) => v === '1' ? '启用' : '禁用' },
  160 + ],
  161 + }
  162 + },
  163 +}
  164 +</script>
  165 +```
  166 +
  167 +:::
  168 +
43 169 ## API快速配置
44 170  
45 171 传入CURD对应API的Promise方法及URL地址,返回指定格式的结果
46 172  
47   -::: snippet 配置`option`参数设置组件配置项,其中`$http`为配置好拦截器的支持Promise的http框架、`url`基础url地址
  173 +::: snippet 配置`option`参数设置组件配置项,其中`$http`为配置好拦截器的支持Promise的http框架、`url`基础url地址。`currPageAlias`分页当前页别名、`pageSizeAlias`分页每页数据量别名、`totalCountAlias`response返回分页条件中总数据量的别名。API交互逻辑处理见[说明](/component/specification)
48 174  
49 175 ```html
50 176 <template>
51 177 <eagle-scheme :list="list"
52   - :option="{ $http: $axios, url: 'product', currPageAlias: 'page', pageSizeAlias: 'size', totalCountAlias: 'total', dynamicColumn: true }">
  178 + :option="{ $http: $axios, url: 'product', currPageAlias: 'page', pageSizeAlias: 'size', totalCountAlias: 'total' }">
53 179 </eagle-scheme>
54 180 </template>
55 181  
... ... @@ -75,7 +201,7 @@ export default {
75 201  
76 202 :::
77 203  
78   -## API配置
  204 +## 自定义API配置
79 205  
80 206 传入CURD对应API的Promise方法,返回指定格式的结果
81 207  
... ... @@ -147,4 +273,12 @@ setDialog | 打开并设置弹出框模式 | { title, type, model }
147 273 -|-|-
148 274 change | 表单model发生变化时触发 | model对象
149 275 dialog-change | 设置弹出框类型或类型变化时触发 | dialogType
150   -selection | 选中表格内容时触发 | selection
151 276 \ No newline at end of file
  277 +selection | 选中表格内容时触发 | selection
  278 +
  279 +## List 表单项配置列表
  280 +
  281 +参数|说明|类型|可选值|默认值
  282 +-|-|-|-|-
  283 +include | 包含在哪些组件中 | String,Array | - | ['search', 'table', 'form']
  284 +exclude | 不包含在哪些组件中 | String,Array | - | []
  285 +其它参数 | 同时包含Form、Table、Search、Detail配置项的参数 | - | - | -
152 286 \ No newline at end of file
... ...
examples/views/docs/component/specification.md 0 → 100644
... ... @@ -0,0 +1,198 @@
  1 +## 示例axios配置
  2 +
  3 +以下是本演示项目中`main.js`的片段截取
  4 +
  5 +```js
  6 +import axios from 'axios';
  7 +
  8 +const request = axios.create({
  9 + baseURL: 'http://localhost',
  10 + timeout: 1000 * 60,
  11 + withCredentials: true,
  12 +});
  13 +
  14 +// respone 拦截器
  15 +request.interceptors.response.use(
  16 + response => {
  17 + const { data = {}, config } = response;
  18 + const { code = 0 } = data;
  19 + if (config && config.interceptors === false) { // 请求配置不做返回拦截的情况
  20 + return response;
  21 + } else {
  22 + if (`${code}` === '0' || `${code}` === '200') { // 请求成功
  23 + return data;
  24 + } else { // 其它错误,开发环境提示
  25 + return { code };
  26 + }
  27 + }
  28 + },
  29 + error => {
  30 + return { code: 404 };
  31 + });
  32 +
  33 +Vue.prototype.$axios = request;
  34 +```
  35 +
  36 +## Scheme默认逻辑
  37 +
  38 +* 查询列表
  39 +
  40 +传入$http时,如果没有配置searchAPI,则按照以下规则处理:
  41 +
  42 +**默认路径**
  43 +
  44 +`option.searchMethod` 或者默认为 `/page`
  45 +
  46 +**处理规则**
  47 +
  48 +```js
  49 +(response) => {
  50 + const { result = {} } = response || {};
  51 + const { list = [] } = result || {};
  52 + this.tableData = list;
  53 + this.totalCount = result[totalCountAlias] || 0;
  54 +}
  55 +```
  56 +
  57 +* 查询数据
  58 +
  59 +传入$http时,如果没有配置getAPI,则按照以下规则处理:
  60 +
  61 +**默认路径**
  62 +
  63 +`option.getMethod/${id}` 或者默认为 `/id/${id}`
  64 +
  65 +**处理规则**
  66 +
  67 +```js
  68 +(response) => {
  69 + const { result = {} } = response || {};
  70 + this.setFormModel(result);
  71 +}
  72 +```
  73 +
  74 +* 查询详情
  75 +
  76 +传入$http时,如果没有配置detailAPI,则按照以下规则处理:
  77 +
  78 +**默认路径**
  79 +
  80 +`option.detailMethod/${id}` 或者默认为 `/info/${id}`
  81 +
  82 +**处理规则**
  83 +
  84 +```js
  85 +(response) => {
  86 + const { result = {} } = response || {};
  87 + this.setFormModel(result);
  88 +}
  89 +```
  90 +
  91 +* 新增保存
  92 +
  93 +传入$http时,如果没有配置newMethod,则按照以下规则处理:
  94 +
  95 +**默认路径**
  96 +
  97 +`option.newMethod` 或者默认为 `/add`
  98 +
  99 +**处理规则**
  100 +
  101 +```js
  102 +(response) => {
  103 + const { code } = response || {};
  104 + if (`${code}` === '0') {
  105 + // ...
  106 + }
  107 +}
  108 +```
  109 +
  110 +* 编辑保存
  111 +
  112 +传入$http时,如果没有配置editMethod,则按照以下规则处理:
  113 +
  114 +**默认路径**
  115 +
  116 +`option.editMethod` 或者默认为 `/update`
  117 +
  118 +**处理规则**
  119 +
  120 +```js
  121 +(response) => {
  122 + const { code } = response || {};
  123 + if (`${code}` === '0') {
  124 + // ...
  125 + }
  126 +}
  127 +```
  128 +
  129 +* 删除/批量删除
  130 +
  131 +传入$http时,如果没有配置deleteMethod,则按照以下规则处理:
  132 +
  133 +**默认路径**
  134 +
  135 +`option.deleteMethod` 或者默认为 `/delete`
  136 +
  137 +**处理规则**
  138 +
  139 +```js
  140 +(response) => {
  141 + const { code } = response || {};
  142 + if (`${code}` === '0') {
  143 + // ...
  144 + }
  145 +}
  146 +```
  147 +
  148 +## Scheme自定义API
  149 +
  150 +使用方法见[示例](/component/scheme#zi-ding-yiapi-pei-zhi)
  151 +
  152 +* searchAPI 查询列表
  153 +
  154 +```js
  155 +(param) => { // param 包含分页的搜索条件
  156 + return { result, totalCount }; // result 数据源 Object类型; totalCount 总数 Number类型
  157 +}
  158 +```
  159 +
  160 +* detailAPI 查询详情
  161 +
  162 +```js
  163 +(param) => { // param 当前行数据
  164 + return result; // result 查询结果 Object类型
  165 +}
  166 +```
  167 +
  168 +* getAPI 编辑查询数据
  169 +
  170 +```js
  171 +(param) => { // param 当前行数据
  172 + return result; // result 查询结果 Object类型
  173 +}
  174 +```
  175 +
  176 +* deleteAPI 删除
  177 +
  178 +```js
  179 +(selection) => { // selection 选中的数据
  180 + return result; // result 是否执行成功 Boolean类型
  181 +}
  182 +```
  183 +
  184 +* newAPI 新增保存
  185 +
  186 +```js
  187 +(model) => { // model 表单数据
  188 + return result; // result 是否执行成功 Boolean类型
  189 +}
  190 +```
  191 +
  192 +* editAPI 编辑保存
  193 +
  194 +```js
  195 +(model) => { // model 表单数据
  196 + return result; // result 是否执行成功 Boolean类型
  197 +}
  198 +```
... ...
packages/detail/index.vue
... ... @@ -34,7 +34,7 @@
34 34 <slot v-if="$scopedSlots[`item-${item.key}`] || $slots[`item-${item.key}`]" :name="`item-${item.key}`" :model="model" :value="model[item.key]" v-bind="item"></slot>
35 35 <label v-else>
36 36 <template v-if="item.formatter">
37   - {{ item.formatter(item.key, model, item.key) }}
  37 + {{ item.formatter(model, model, model[item.key]) }}
38 38 </template>
39 39 <template v-else>
40 40 {{ model[item.agentKey || item.key] }}
... ...
packages/scheme/index.vue
... ... @@ -85,6 +85,7 @@
85 85 <!-- 搜索表单项具名插槽 -->
86 86 <template v-for="item in _searchList">
87 87 <slot v-if="$scopedSlots[`search-${item.key}`] || $slots[`search-${item.key}`]" :name="`search-${item.key}`" :slot="item.key" :model="searchModel"></slot>
  88 + <slot v-else-if="$scopedSlots[`field-${item.key}`] || $slots[`field-${item.key}`]" :name="`field-${item.key}`" :slot="item.key" :model="searchModel"></slot>
88 89 </template>
89 90 </component>
90 91 </div>
... ... @@ -131,8 +132,14 @@
131 132 >
132 133 <slot></slot>
133 134 <!-- 表格具名插槽 -->
134   - <template v-for="item in _tableList">
  135 + <template v-for="(item, index) in _tableList">
135 136 <slot v-if="$scopedSlots[`table-${item.key}`] || $slots[`table-${item.key}`]" :name="`table-${item.key}`" :slot="item.key" v-bind="slotMethod"></slot>
  137 + <el-table-column v-else-if="$scopedSlots[`table-value-${item.key}`] || $slots[`table-value-${item.key}`]" :slot="item.key" :key="`column-${index}`" v-bind="item" :prop="item.agentKey || item.key" :min-width="item.minWidth || item['min-width'] || '120'">
  138 + <slot slot-scope="{ row, column, $index }" :name="`table-value-${item.key}`" v-bind="{ ...item, ...slotMethod }" :row="row" :value="row[item.key]" :column="column" :index="$index"></slot>
  139 + </el-table-column>
  140 + <el-table-column v-else-if="$scopedSlots[`render-${item.key}`] || $slots[`render-${item.key}`]" :slot="item.key" :key="`render-${index}`" v-bind="item" :prop="item.agentKey || item.key" :min-width="item.minWidth || item['min-width'] || '120'">
  141 + <slot slot-scope="{ row, column, $index }" :name="`render-${item.key}`" v-bind="{ ...item, ...slotMethod }" :row="row" :value="row[item.key]" :column="column" :index="$index"></slot>
  142 + </el-table-column>
136 143 </template>
137 144 <!-- 表格后置插槽 -->
138 145 <template v-if="$scopedSlots['table-append'] || $slots['table-append']">
... ... @@ -180,17 +187,19 @@
180 187 <!-- 表单项具名插槽 -->
181 188 <template v-for="item in _formList">
182 189 <slot v-if="$scopedSlots[`form-item-${item.key}`] || $slots[`form-item-${item.key}`]" :name="`form-item-${item.key}`" :slot="`item-${item.key}`" :model="formModel"></slot>
  190 + <slot v-else-if="$scopedSlots[`field-${item.key}`] || $slots[`field-${item.key}`]" :name="`field-${item.key}`" :slot="`item-${item.key}`" :model="formModel"></slot>
183 191 <slot v-if="$scopedSlots[`form-label-${item.key}`] || $slots[`form-label-${item.key}`]" :name="`form-label-${item.key}`" :slot="`label-${item.key}`" :model="formModel" v-bind="item"></slot>
184 192 </template>
185 193 </component>
186 194 <component :is="_detailComponent" v-else-if="dialogType === 'dialog-view' && !$scopedSlots['dialog-view'] && !$slots['dialog-view']" v-model="formModel" :list="list || detailList || _formList" :span="detailProps.span || dialogComponent === 'el-drawer' ? 12 : 8" :formProps="detailProps">
187   - <!-- 表单分组具名插槽 -->
  195 + <!-- 详情分组具名插槽 -->
188 196 <template v-for="key in formGroupSlotsKeys">
189 197 <slot v-if="$scopedSlots[`view-${key}`] || $slots[`view-${key}`]" :name="`view-${key}`" :slot="key" :model="formModel"></slot>
190 198 </template>
191   - <!-- 表单项具名插槽 -->
  199 + <!-- 详情项具名插槽 -->
192 200 <template v-for="item in _formList">
193   - <slot v-if="$scopedSlots[`view-item-${item.key}`] || $slots[`view-item-${item.key}`]" :name="`view-item-${item.key}`" :slot="`item-${item.key}`" :model="formModel"></slot>
  201 + <slot v-if="$scopedSlots[`view-item-${item.key}`] || $slots[`view-item-${item.key}`]" :name="`view-item-${item.key}`" :slot="`item-${item.key}`" v-bind="{ ...item, ...slotMethod }" :model="formModel" :row="formModel" :value="formModel[item.key]"></slot>
  202 + <slot v-else-if="$scopedSlots[`render-${item.key}`] || $slots[`render-${item.key}`]" :name="`render-${item.key}`" :slot="`item-${item.key}`" v-bind="{ ...item, ...slotMethod }" :model="formModel" :row="formModel" :value="formModel[item.key]"></slot>
194 203 </template>
195 204 </component>
196 205 <!-- 自定义弹出框内容插槽 -->
... ...
packages/table/index.vue
... ... @@ -11,10 +11,10 @@
11 11 <template v-for="(item, index) in list">
12 12 <template v-if="bindItemVisible(item.visible)">
13 13 <slot v-if="$scopedSlots[item.key] || $slots[item.key]" :name="item.key" v-bind="item"></slot>
14   - <el-table-column v-else-if="$scopedSlots[`value-${item.key}`] || $slots[`value-${item.key}`]" v-bind="item" :prop="item.agentKey || item.key" :key="index" :min-width="item.minWidth || '120'">
  14 + <el-table-column v-else-if="$scopedSlots[`value-${item.key}`] || $slots[`value-${item.key}`]" v-bind="item" :prop="item.agentKey || item.key" :key="index" :min-width="item.minWidth || item['min-width'] || '120'">
15 15 <slot slot-scope="{ row, column, $index }" :name="`value-${item.key}`" v-bind="item" :row="row" :value="row[item.key]" :column="column" :index="$index"></slot>
16 16 </el-table-column>
17   - <el-table-column v-else v-bind="item" :prop="item.agentKey || item.key" :key="index" :min-width="item.minWidth || '120'"></el-table-column>
  17 + <el-table-column v-else v-bind="item" :prop="item.agentKey || item.key" :key="index" :min-width="item.minWidth || item['min-width'] || '120'"></el-table-column>
18 18 </template>
19 19 </template>
20 20 </template>
... ...