Răsfoiți Sursa

表格快速构建

fangq 4 ani în urmă
părinte
comite
fa5b71cf0f
72 a modificat fișierele cu 5911 adăugiri și 131 ștergeri
  1. 110 0
      packages/FormConfig.vue
  2. 121 0
      packages/WidgetConfig.vue
  3. 138 0
      packages/WidgetForm.vue
  4. 182 0
      packages/WidgetFormGroup.vue
  5. 134 0
      packages/WidgetFormItem.vue
  6. 180 0
      packages/WidgetFormTable.vue
  7. BIN
      packages/assets/widget-empty.png
  8. 62 0
      packages/config/array.vue
  9. 239 0
      packages/config/cascader.vue
  10. 151 0
      packages/config/checkbox.vue
  11. 51 0
      packages/config/color.vue
  12. 78 0
      packages/config/date.vue
  13. 48 0
      packages/config/dynamic.vue
  14. 26 0
      packages/config/group.vue
  15. 54 0
      packages/config/index.js
  16. 82 0
      packages/config/input.vue
  17. 54 0
      packages/config/map.vue
  18. 94 0
      packages/config/number.vue
  19. 147 0
      packages/config/radio.vue
  20. 168 0
      packages/config/rate.vue
  21. 168 0
      packages/config/select.vue
  22. 50 0
      packages/config/slider.vue
  23. 49 0
      packages/config/switch.vue
  24. 85 0
      packages/config/textarea.vue
  25. 237 0
      packages/config/tree.vue
  26. 110 0
      packages/config/ueditor.vue
  27. 203 0
      packages/config/upload.vue
  28. 314 0
      packages/fieldsConfig.js
  29. 9 0
      packages/index.js
  30. 609 0
      packages/index.vue
  31. 568 0
      packages/styles/index.scss
  32. 50 0
      src/api/bank/autodata.js
  33. 50 0
      src/api/bank/autostruct.js
  34. 9 0
      src/api/bank/goodsuse.js
  35. 10 0
      src/api/bank/home.js
  36. 4 0
      src/components/common/cardswallow-comfirm.vue
  37. 4 0
      src/components/common/cardswallow-issue.vue
  38. 61 0
      src/components/common/cy-form-design.vue
  39. 4 0
      src/components/common/goodsuse-sure.vue
  40. 17 5
      src/components/common/returns-approve.vue
  41. 12 1
      src/components/common/returns-comfire.vue
  42. 12 0
      src/components/common/returns-issue.vue
  43. 4 0
      src/components/confirmed/confirmed-cardswallow.vue
  44. 4 0
      src/components/confirmed/confirmed-goodsuse.vue
  45. 8 0
      src/components/confirmed/confirmed-returns.vue
  46. 4 0
      src/components/initiated/init-cardswallow.vue
  47. 4 0
      src/components/initiated/init-goodsuse.vue
  48. 12 0
      src/components/initiated/init-returns.vue
  49. 4 0
      src/components/release/release-cardswallow.vue
  50. 12 0
      src/components/release/release-returns.vue
  51. 4 0
      src/components/tobeconfirm/tobeconfirm-cardswallow.vue
  52. 4 0
      src/components/tobeconfirm/tobeconfirm-goodsuse.vue
  53. 12 0
      src/components/tobeconfirm/tobeconfirm-returns.vue
  54. 4 0
      src/main.js
  55. 287 0
      src/views/bank/autodata.vue
  56. 263 0
      src/views/bank/autostruct.vue
  57. 4 0
      src/views/bank/cardswallow.vue
  58. 9 1
      src/views/bank/checklist.vue
  59. 16 0
      src/views/bank/checkwarehouse.vue
  60. 349 0
      src/views/bank/goodsuse-balance.vue
  61. 18 1
      src/views/bank/goodsuse.vue
  62. 5 3
      src/views/bank/keypwd.vue
  63. 10 1
      src/views/bank/returns.vue
  64. 3 0
      src/views/bank/sealhandover-keep.vue
  65. 8 7
      src/views/bank/sealhandover.vue
  66. 48 6
      src/views/bank/user-log-view.vue
  67. 9 2
      src/views/monitor/log/api.vue
  68. 9 0
      src/views/report/abnormal-reportlist.vue
  69. 34 104
      src/views/report/reportlist.vue
  70. 3 0
      src/views/report/userlog.vue
  71. 3 0
      src/views/resource/oss.vue
  72. 3 0
      src/views/system/dept.vue

+ 110 - 0
packages/FormConfig.vue

@@ -0,0 +1,110 @@
+<template>
+  <div class="form-config-container">
+    <el-form label-position="left"
+             label-suffix=":"
+             label-width="130px"
+             size="small">
+      <el-form-item label="标签对齐方式">
+        <el-select v-model="data.labelPosition"
+                   placeholder="标签对齐方式">
+          <el-option label="左对齐"
+                     value="left"></el-option>
+          <el-option label="右对齐"
+                     value="right"></el-option>
+          <el-option label="顶部对齐"
+                     value="top"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="标签宽度">
+        <el-input-number v-model="data.labelWidth"
+                         :min="80"
+                         :max="200"
+                         :step="10"
+                         controls-position="right"
+                         placeholder="标签宽度"
+                         style="width: 100%"></el-input-number>
+      </el-form-item>
+      <el-form-item label="标签后缀">
+        <el-input v-model="data.labelSuffix"
+                  placeholder="标签后缀"></el-input>
+      </el-form-item>
+      <el-form-item label="项之间的间隔">
+        <el-input-number v-model="data.gutter"
+                         :min="0"
+                         :max="60"
+                         :step="5"
+                         controls-position="right"
+                         placeholder="项之间的间隔"
+                         style="width: 100%"></el-input-number>
+      </el-form-item>
+      <el-form-item label="显示按钮">
+        <el-switch v-model="data.menuBtn"
+                   active-color="#409EFF"></el-switch>
+      </el-form-item>
+      <el-form-item label="按钮位置"
+                    v-if="data.menuBtn">
+        <el-select v-model="data.menuPostion"
+                   placeholder="按钮位置">
+          <el-option label="居左"
+                     value="left"></el-option>
+          <el-option label="居中"
+                     value="center"></el-option>
+          <el-option label="居右"
+                     value="right"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="显示提交按钮"
+                    v-if="data.menuBtn">
+        <el-switch v-model="data.submitBtn"
+                   active-color="#409EFF"></el-switch>
+      </el-form-item>
+      <el-form-item label="提交按钮的大小"
+                    v-if="data.menuBtn && data.submitBtn">
+        <el-select v-model="data.submitSize"
+                   placeholder="提交按钮的大小">
+          <el-option label="正常"
+                     value="medium"></el-option>
+          <el-option label="小"
+                     value="small"></el-option>
+          <el-option label="超小"
+                     value="mini"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="提交按钮的文字"
+                    v-if="data.menuBtn && data.submitBtn">
+        <el-input v-model="data.submitText"
+                  placeholder="提交按钮的文字"></el-input>
+      </el-form-item>
+
+      <el-form-item label="显示清空按钮"
+                    v-if="data.menuBtn">
+        <el-switch v-model="data.emptyBtn"
+                   active-color="#409EFF"></el-switch>
+      </el-form-item>
+      <el-form-item label="清空按钮的大小"
+                    v-if="data.menuBtn && data.emptyBtn">
+        <el-select v-model="data.emptySize"
+                   placeholder="提交按钮的大小">
+          <el-option label="正常"
+                     value="medium"></el-option>
+          <el-option label="小"
+                     value="small"></el-option>
+          <el-option label="超小"
+                     value="mini"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="清空按钮的文字"
+                    v-if="data.menuBtn && data.emptyBtn">
+        <el-input v-model="data.emptyText"
+                  placeholder="提交按钮的文字"></el-input>
+      </el-form-item>
+    </el-form>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'form-config',
+  props: ['data']
+}
+</script>

+ 121 - 0
packages/WidgetConfig.vue

@@ -0,0 +1,121 @@
+<template>
+  <div class="widget-config">
+    <el-form label-suffix=":"
+             v-if="this.data && Object.keys(this.data).length > 0"
+             size="small">
+      <el-form-item label="类型">
+        <el-select v-model="data.type"
+                   placeholder="请选择类型"
+                   @change="handleChangeType">
+          <el-option-group v-for="group in fields"
+                           :key="group.title"
+                           :label="group.title">
+            <el-option v-for="item in group.list"
+                       :key="item.type"
+                       :label="item.label"
+                       :value="item.type">
+            </el-option>
+          </el-option-group>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="属性值">
+        <el-input v-model="data.prop"
+                  placeholder="属性值"></el-input>
+      </el-form-item>
+      <el-form-item label="标题">
+        <el-input v-model="data.label"
+                  placeholder="标题"></el-input>
+      </el-form-item>
+      <el-form-item label="宽度"
+                    v-if="data.subfield">
+        <el-input-number v-model="data.width"
+                         controls-position="right"
+                         placeholder="宽度"
+                         :min="100"></el-input-number>
+      </el-form-item>
+      <el-form-item label="表单栅格"
+                    v-if="!data.subfield && !['group'].includes(data.type)">
+        <el-input-number v-model="data.span"
+                         controls-position="right"
+                         placeholder="表单栅格"
+                         :min="8"
+                         :max="24"></el-input-number>
+      </el-form-item>
+      <el-form-item label="数据类型"
+                    v-if="['cascader','checkbox','upload','img','array'].includes(data.type)">
+        <el-select v-model="data.dataType"
+                   placeholder="数据类型"
+                   clearable>
+          <el-option label="String"
+                     value="string"></el-option>
+          <el-option label="Number"
+                     value="number"></el-option>
+        </el-select>
+        &nbsp;<a href="https://avuejs.com/doc/dataType"
+           target="_blank"
+           style="color: #409EFF;">详情</a><br>
+      </el-form-item>
+      <component :is="getComponent"
+                 :data="data"></component>
+    </el-form>
+    <avue-empty v-else
+                desc="拖拽字段进行配置"
+                style="margin-top: 100%;"></avue-empty>
+  </div>
+</template>
+
+<script>
+import fields from './fieldsConfig.js'
+
+const dateArr = [
+  'year', 'month', 'week', 'date', 'datetime', 'time', 'daterange', 'timerange', 'datetimerange', 'dates'
+]
+
+export default {
+  name: 'widget-config',
+  props: ['data'],
+  computed: {
+    getComponent () {
+      const prefix = 'config-'
+      const { type } = this.data
+      let result = 'input'
+
+      if ([undefined, 'input', 'password', 'url'].includes(type)) result = 'input'
+      else if (dateArr.includes(type)) result = 'date'
+      else if (['array', 'img'].includes(type)) result = 'array'
+      else result = type
+
+      return prefix + result
+    }
+  },
+  data () {
+    return {
+      fields
+    }
+  },
+  methods: {
+    async handleChangeType (type) {
+      if (type) {
+        const config = await this.getConfigByType(type);
+        config.prop = this.data.prop;
+        for (let key in config) {
+          if (config && Object.prototype.hasOwnProperty.call(config, key) && !['icon', 'label', 'span'].includes(key)) {
+            const val = config[key]
+            this.$set(this.data, key, val);
+          }
+        }
+      }
+    },
+    getConfigByType (type) {
+      return new Promise((resolve, reject) => {
+        fields.forEach(field => {
+          field.list.forEach(config => {
+            if (config.type == type) resolve(config)
+          })
+        })
+        reject()
+      })
+    }
+  }
+}
+</script>

+ 138 - 0
packages/WidgetForm.vue

@@ -0,0 +1,138 @@
+<template>
+  <div class="widget-form-container">
+    <el-form :label-position="data.labelPosition || 'left'"
+             :label-width="data.labelWidth ? `${data.labelWidth}px` : '100px' "
+             :label-suffix="data.labelSuffix"
+             :model="form"
+             ref="widgetForm"
+             size="small">
+      <el-row :gutter="data.gutter">
+        <draggable class="widget-form-list"
+                   :list="data.column"
+                   :group="{ name: 'form' }"
+                   ghost-class="ghost"
+                   :animation="300"
+                   @add="handleWidgetAdd">
+          <template v-for="(column, index) in data.column">
+            <div class="widget-form-table"
+                 v-if="column.type == 'dynamic'"
+                 :key="index"
+                 :class="{ active: selectWidget.prop == column.prop }"
+                 @click="handleSelectWidget(index)">
+              <widget-form-table :data="data"
+                                 :column="column"
+                                 :index="index"
+                                 :select.sync="selectWidget"></widget-form-table>
+            </div>
+            <div class="widget-form-group"
+                 v-else-if="column.type == 'group'"
+                 :key="index"
+                 :class="{ active: selectWidget.prop == column.prop }"
+                 @click="handleSelectWidget(index)">
+              <widget-form-group :data="data"
+                                 :column="column"
+                                 :index="index"
+                                 :select.sync="selectWidget">
+              </widget-form-group>
+            </div>
+            <el-col v-else
+                    :key="index"
+                    :md="column.span || 12"
+                    :xs="24"
+                    :offset="column.offset || 0">
+              <el-form-item class="widget-form-item"
+                            :label="column.label"
+                            :prop="column.prop"
+                            :class="{ active: selectWidget.prop == column.prop, 'required': column.required }"
+                            @click.native="handleSelectWidget(index)">
+                <widget-form-item :item="column"></widget-form-item>
+                <el-button title="删除"
+                           @click.stop="handleWidgetDelete(index)"
+                           class="widget-action-delete"
+                           v-if="selectWidget.prop == column.prop"
+                           circle
+                           plain
+                           size="small"
+                           type="danger">
+                  <i class="iconfont icon-delete"></i>
+                </el-button>
+                <el-button title="复制"
+                           @click.stop="handleWidgetClone(index)"
+                           class="widget-action-clone"
+                           v-if="selectWidget.prop == column.prop"
+                           circle
+                           plain
+                           size="small"
+                           type="primary">
+                  <i class="iconfont icon-copy"></i>
+                </el-button>
+              </el-form-item>
+            </el-col>
+          </template>
+        </draggable>
+      </el-row>
+    </el-form>
+  </div>
+</template>
+
+<script>
+import WidgetFormItem from './WidgetFormItem'
+import WidgetFormTable from './WidgetFormTable'
+import WidgetFormGroup from './WidgetFormGroup'
+import Draggable from 'vuedraggable'
+
+export default {
+  name: 'widget-form',
+  components: { Draggable, WidgetFormItem, WidgetFormTable, WidgetFormGroup },
+  props: ['data', 'select'],
+  data () {
+    return {
+      selectWidget: this.select,
+      form: {}
+    }
+  },
+  methods: {
+    handleSelectWidget (index) {
+      this.selectWidget = this.data.column[index]
+    },
+    handleWidgetAdd (evt) {
+      const newIndex = evt.newIndex;
+      const data = this.deepClone(this.data.column[newIndex]);
+      if (!data.prop) data.prop = Date.now() + '_' + Math.ceil(Math.random() * 99999)
+      delete data.icon
+      delete data.subfield
+      this.$set(this.data.column, newIndex, { ...data })
+      this.handleSelectWidget(newIndex)
+    },
+    handleWidgetDelete (index) {
+      if (this.data.column.length - 1 === index) {
+        if (index === 0) this.selectWidget = {}
+        else this.handleSelectWidget(index - 1)
+      } else this.handleSelectWidget(index + 1)
+
+      this.$nextTick(() => {
+        this.data.column.splice(index, 1)
+      })
+    },
+    handleWidgetClone (index) {
+      let cloneData = this.deepClone(this.data.column[index])
+      cloneData.prop = Date.now() + '_' + Math.ceil(Math.random() * 99999)
+      this.data.column.splice(index, 0, cloneData)
+      this.$nextTick(() => {
+        this.handleSelectWidget(index + 1)
+      })
+    },
+  },
+  watch: {
+    select (val) {
+      this.selectWidget = val
+    },
+    selectWidget: {
+      handler (val) {
+        this.$emit('update:select', val)
+      },
+      deep: true
+    }
+  }
+}
+</script>

+ 182 - 0
packages/WidgetFormGroup.vue

@@ -0,0 +1,182 @@
+<template>
+  <div>
+    <h4 class="widget-form-group__head"
+        v-show="column.label"><i :class="column.icon"
+         v-show="column.icon"
+         style="margin-right: 10px;"></i>{{column.label}}</h4>
+    <draggable class="widget-form-group__body"
+               :list="column.children.column"
+               :group="{ name: 'form' }"
+               ghost-class="ghost"
+               :animation="200"
+               @add="handleWidgetGroupAdd($event, column)">
+      <template v-for="(item, groupIndex) in column.children.column">
+        <div class="widget-form-table"
+             v-if="item.type == 'dynamic'"
+             :key="groupIndex"
+             :class="{ active: selectWidget.prop == item.prop }"
+             @click.stop="handleWidgetTableSelect(item)">
+          <widget-form-table :data="column.children"
+                             :column="item"
+                             :index="groupIndex"
+                             :select.sync="selectWidget"></widget-form-table>
+        </div>
+        <el-col v-else
+                :key="groupIndex"
+                :md="item.span || 12"
+                :xs="24"
+                :offset="item.offset || 0">
+          <el-form-item class="widget-form-group__item"
+                        :label="item.label"
+                        :prop="item.prop"
+                        :class="{ active: selectWidget.prop == item.prop, 'required': item.required }"
+                        @click.native.stop="handleWidgetTableSelect(item)">
+            <widget-form-item :item="item"></widget-form-item>
+            <el-button title="删除"
+                       @click.stop="handleWidgetTableDelete(column, groupIndex)"
+                       class="widget-form-group__item--delete"
+                       v-if="selectWidget.prop == item.prop"
+                       circle
+                       plain
+                       type="danger">
+              <i class="iconfont icon-delete"></i>
+            </el-button>
+            <el-button title="复制"
+                       @click.stop="handleWidgetTableClone(column, groupIndex)"
+                       class="widget-form-group__item--clone"
+                       v-if="selectWidget.prop == item.prop"
+                       circle
+                       plain
+                       type="primary">
+              <i class="iconfont icon-copy"></i>
+            </el-button>
+          </el-form-item>
+        </el-col>
+      </template>
+    </draggable>
+    <el-button title="删除"
+               @click.stop="handleWidgetDelete(index)"
+               class="widget-action-delete"
+               v-if="selectWidget.prop == column.prop"
+               circle
+               plain
+               size='small'
+               type="danger">
+      <i class="iconfont icon-delete"></i>
+    </el-button>
+    <el-button title="清空"
+               @click.stop="handleWidgetClear(index)"
+               class="widget-action-clear"
+               v-if="selectWidget.prop == column.prop"
+               circle
+               plain
+               size='small'
+               type="warning">
+      <i class="iconfont icon-clear"></i>
+    </el-button>
+    <el-button title="复制"
+               @click.stop="handleWidgetCloneTable(index)"
+               class="widget-action-clone"
+               v-if="selectWidget.prop == column.prop"
+               circle
+               plain
+               size='small'
+               type="primary">
+      <i class="iconfont icon-copy"></i>
+    </el-button>
+  </div>
+</template>
+<script>
+import WidgetFormItem from './WidgetFormItem'
+import WidgetFormTable from './WidgetFormTable'
+
+export default {
+  name: 'widget-form-table',
+  props: ['data', 'column', 'select', 'index'],
+  components: { WidgetFormItem, WidgetFormTable },
+  data () {
+    return {
+      selectWidget: this.select,
+    }
+  },
+  methods: {
+    handleSelectWidget (index) {
+      this.selectWidget = this.data.column[index]
+    },
+    handleWidgetClear (index) {
+      this.data.column[index].children.column = []
+      this.selectWidget = this.data.column[index]
+    },
+    handleWidgetDelete (index) {
+      if (this.data.column.length - 1 === index) {
+        if (index === 0) this.selectWidget = {}
+        else this.handleSelectWidget(index - 1)
+      } else this.handleSelectWidget(index + 1)
+
+      this.$nextTick(() => {
+        this.data.column.splice(index, 1)
+      })
+    },
+    handleWidgetCloneTable (index) {
+      let cloneData = this.deepClone(this.data.column[index])
+      cloneData.prop = Date.now() + '_' + Math.ceil(Math.random() * 99999)
+      cloneData.children.column.forEach(t => {
+        t.prop = Date.now() + '_' + Math.ceil(Math.random() * 99999)
+      })
+      this.data.column.splice(index, 0, cloneData)
+      this.$nextTick(() => {
+        this.handleSelectWidget(index + 1)
+      })
+    },
+    handleWidgetTableSelect (data) {
+      this.selectWidget = data
+    },
+    handleWidgetTableClone (column, item) {
+      const data = this.deepClone(item);
+      data.prop = Date.now() + '_' + Math.ceil(Math.random() * 99999)
+      this.$set(column.children.column, column.children.column.length, { ...data })
+      this.$nextTick(() => {
+        this.selectWidget = column.children.column[column.children.column.length - 1]
+      })
+    },
+    handleWidgetTableDelete (column, index) {
+      if (column.children.column.length - 1 == index) {
+        if (index == 0) this.selectWidget = column
+        else this.selectWidget = column.children.column[index - 1]
+      } else this.selectWidget = column.children.column[index + 1]
+      this.$nextTick(() => {
+        column.children.column.splice(index, 1)
+      })
+    },
+    handleWidgetGroupAdd (evt, column) {
+      let newIndex = evt.newIndex;
+      const item = evt.item;
+
+      if (newIndex == 1 && newIndex > column.children.column.length - 1) newIndex = 0
+      if (['分组'].includes(item.textContent)) {
+        column.children.column.splice(newIndex, 1)
+        return
+      }
+
+      const data = this.deepClone(column.children.column[newIndex]);
+      if (!data.prop) data.prop = Date.now() + '_' + Math.ceil(Math.random() * 99999)
+      delete data.icon
+      if (data.type == 'dynamic') data.span = 24
+      else data.span = 12
+      this.$set(column.children.column, newIndex, { ...data })
+      this.selectWidget = column.children.column[newIndex]
+    }
+  },
+  watch: {
+    select (val) {
+      this.selectWidget = val
+    },
+    selectWidget: {
+      handler (val) {
+        this.$emit('update:select', val)
+      },
+      deep: true
+    }
+  }
+}
+</script>

+ 134 - 0
packages/WidgetFormItem.vue

@@ -0,0 +1,134 @@
+<template>
+  <component :is="getComponent(item.type, item.component)"
+             v-model="form[item.prop]"
+             :item="item"
+             :action="item.action"
+             :append="item.append"
+             :accordion="item.accordion"
+             :typeslot="item.typeslot"
+             :appendClick="item.appendClick"
+             :border="item.border"
+             :change="item.change"
+             :checked="item.checked"
+             :clearable="item.clearable"
+             :changeOnSelect="item.changeOnSelect"
+             :click="item.click"
+             :onRemove="item.onRemove"
+             :showWordLimit="item.showWordLimit"
+             :colors="item.colors"
+             :canvasOption="item.canvasOption"
+             :controls-position="item.controlsPosition"
+             :dataType="item.dataType"
+             :defaultExpandAll="item.defaultExpandAll"
+             :defaultTime="item.defaultTime"
+             :dic="item.dicData"
+             :dicUrl="item.dicUrl"
+             :dicMethod="item.dicMethod"
+             :dicQuery="item.dicQuery"
+             :disabled="item.disabled"
+             :drag="item.drag"
+             :endPlaceholder="item.endPlaceholder"
+             :expand-trigger="item.expandTrigger"
+             :filter="item.filter"
+             :blur="item.blur"
+             :focus="item.focus"
+             :tpyeformat="item.tpyeformat"
+             :filesize="item.filesize"
+             :filterable="item.filterable"
+             :format="item.format"
+             :formatTooltip="item.formatTooltip"
+             :iconClasses="item.iconClasses"
+             :label="item.label"
+             :limit="item.limit"
+             :listType="item.listType"
+             :loadText="item.loadText"
+             :min="item.min"
+             :max="item.max"
+             :minlength="item.minlength"
+             :maxlength="item.maxlength"
+             :minRows="item.minRows"
+             :maxRows="item.maxRows"
+             :multiple="item.multiple"
+             :nodeClick="item.nodeClick"
+             :options="item.options"
+             :oss="item.oss"
+             :parent="item.parent"
+             :pickerOptions="item.pickerOptions"
+             :placeholder="item.placeholder || getPlaceholder(item)"
+             :precision="item.precision"
+             :prefixIcon="item.prefixIcon"
+             :prepend="item.prepend"
+             :prependClick="item.prependClick"
+             :prop="item.prop"
+             :props="item.props"
+             :propsHttp="item.propsHttp"
+             :range="item.range"
+             :iconList="item.iconList"
+             :readonly="item.readonly"
+             :checkStrictly="item.checkStrictly"
+             :separator="item.separator"
+             :showFileList="item.showFileList"
+             :showInput="item.showInput"
+             :showStops="item.showStops"
+             :showAllLevels="item.showAllLevels"
+             :showText="item.showText"
+             :size="item.size || 'small'"
+             :startPlaceholder="item.startPlaceholder"
+             :step="item.step"
+             :suffixIcon="item.suffixIcon"
+             :texts="item.texts"
+             :tip="item.tip"
+             :type="item.type"
+             :accept="item.accept"
+             :tags="item.tags"
+             :value-format="item.valueFormat"
+             :voidIconClass="item.voidIconClass"
+             :remote="item.remote"
+             :autocomplete="item.autocomplete"
+             :allow-create="item.allowCreate"
+             :default-first-option="item.defaultFirstOption"
+             :is-img="item.isImg"></component>
+</template>
+<script>
+export default {
+  name: 'widget-form-item',
+  props: ['item'],
+  data () {
+    return {
+      form: {}
+    }
+  },
+  methods: {
+    getComponent (type, component) {
+      let KEY_COMPONENT_NAME = 'avue-';
+      let result = 'input';
+      if (!this.validatenull(component)) result = component;
+      else if (type === 'array') result = 'array';
+      else if (type === 'select') result = 'select';
+      else if (type === 'radio') result = 'radio';
+      else if (type === 'checkbox') result = 'checkbox';
+      else if (['time', 'timerange'].includes(type)) result = 'time';
+      else if (['dates', 'date', 'datetime', 'datetimerange', 'daterange', 'week', 'month', 'year'].includes(type))
+        result = 'date';
+      else if (type === 'cascader') result = 'cascader';
+      else if (type === 'number') result = 'input-number';
+      else if (type === 'password') result = 'input';
+      else if (type === 'switch') result = 'switch';
+      else if (type === 'rate') result = 'rate';
+      else if (type === 'upload') result = 'upload';
+      else if (type === 'slider') result = 'slider';
+      else if (type === 'dynamic') result = 'dynamic';
+      else if (type === 'icon-select') result = 'icon-select';
+      else if (type === 'color') result = 'color';
+      return KEY_COMPONENT_NAME + result;
+    },
+
+    getPlaceholder (item) {
+      const label = item.label;
+      if (['select', 'checkbox', 'radio', 'tree', 'color', 'dates', 'date', 'datetime', 'datetimerange', 'daterange', 'week', 'month', 'year'].includes(item.type))
+        return `请选择${label}`;
+      else return `请输入${label}`;
+    },
+  }
+}
+</script>

+ 180 - 0
packages/WidgetFormTable.vue

@@ -0,0 +1,180 @@
+<template>
+  <div>
+    <h3 style="margin: 10px"
+        v-show="column.label">{{column.label}}</h3>
+    <draggable class="widget-form-table__content"
+               :list="column.children.column"
+               :group="{ name: 'form' }"
+               ghost-class="ghost"
+               :animation="200"
+               handle=".widget-form-table__item"
+               @add="handleWidgetTableAdd($event, column)">
+      <template v-if="column.children.column.length > 0">
+        <div v-for="(item, tableIndex) in column.children.column"
+             :key="tableIndex"
+             class="widget-form-table__item"
+             :class="{ active: selectWidget.prop == item.prop, required: item.required }"
+             :style="{minWidth: item.width ? `${item.width}px`: '33.3%', width: item.width ? `${item.width}px`: '33.3%'}"
+             @click.stop="handleWidgetTableSelect(item)">
+          <el-table :data="[item]"
+                    border>
+            <el-table-column :prop="item.prop"
+                             :label="item.label"
+                             :align="column.children.align"
+                             :header-align="column.children.headerAlign">
+              <widget-form-item :item="item"></widget-form-item>
+              <el-button title="删除"
+                         @click.stop="handleWidgetTableDelete(column, tableIndex)"
+                         class="widget-table-action-delete"
+                         v-if="selectWidget.prop == item.prop"
+                         circle
+                         plain
+                         size='small'
+                         type="danger">
+                <i class="iconfont icon-delete"></i>
+              </el-button>
+              <el-button title="复制"
+                         @click.stop="handleWidgetTableClone(column, item)"
+                         class="widget-table-action-clone"
+                         v-if="selectWidget.prop == item.prop"
+                         circle
+                         plain
+                         size='small'
+                         type="primary">
+                <i class="iconfont icon-copy"></i>
+              </el-button>
+            </el-table-column>
+          </el-table>
+        </div>
+      </template>
+      <template v-else>
+        <avue-empty size="50"
+                    style="width: 100%;"
+                    desc="拖拽字段至此"></avue-empty>
+      </template>
+    </draggable>
+    <el-button title="删除"
+               @click.stop="handleWidgetDelete(index)"
+               class="widget-action-delete"
+               v-if="selectWidget.prop == column.prop"
+               circle
+               plain
+               size='small'
+               type="danger">
+      <i class="iconfont icon-delete"></i>
+    </el-button>
+    <el-button title="清空"
+               @click.stop="handleWidgetClear(index)"
+               class="widget-action-clear"
+               v-if="selectWidget.prop == column.prop"
+               circle
+               plain
+               size='small'
+               type="warning">
+      <i class="iconfont icon-clear"></i>
+    </el-button>
+    <el-button title="复制"
+               @click.stop="handleWidgetCloneTable(index)"
+               class="widget-action-clone"
+               v-if="selectWidget.prop == column.prop"
+               circle
+               plain
+               size='small'
+               type="primary">
+      <i class="iconfont icon-copy"></i>
+    </el-button>
+  </div>
+</template>
+<script>
+import WidgetFormItem from './WidgetFormItem'
+import draggable from 'vuedraggable'
+
+export default {
+  name: 'widget-form-table',
+  props: ['data', 'column', 'select', 'index'],
+  components: { WidgetFormItem, draggable },
+  data () {
+    return {
+      selectWidget: this.select,
+    }
+  },
+  methods: {
+    handleSelectWidget (index) {
+      this.selectWidget = this.data.column[index]
+    },
+    handleWidgetClear (index) {
+      this.data.column[index].children.column = []
+      this.selectWidget = this.data.column[index]
+    },
+    handleWidgetDelete (index) {
+      if (this.data.column.length - 1 === index) {
+        if (index === 0) this.selectWidget = {}
+        else this.handleSelectWidget(index - 1)
+      } else this.handleSelectWidget(index + 1)
+
+      this.$nextTick(() => {
+        this.data.column.splice(index, 1)
+      })
+    },
+    handleWidgetCloneTable (index) {
+      let cloneData = this.deepClone(this.data.column[index])
+      cloneData.prop = Date.now() + '_' + Math.ceil(Math.random() * 99999)
+      cloneData.children.column.forEach(t => {
+        t.prop = Date.now() + '_' + Math.ceil(Math.random() * 99999)
+      })
+      this.data.column.splice(index, 0, cloneData)
+      this.$nextTick(() => {
+        this.handleSelectWidget(index + 1)
+      })
+    },
+    handleWidgetTableAdd (evt, column) {
+      let newIndex = evt.newIndex;
+      const item = evt.item;
+
+      if (newIndex == 1 && newIndex > column.children.column.length - 1) newIndex = 0
+      if (['子表单', '富文本', '坐标拾取器', '分组'].includes(item.textContent)) {
+        column.children.column.splice(newIndex, 1)
+        return
+      }
+
+      const data = this.deepClone(column.children.column[newIndex]);
+      if (!data.prop) data.prop = Date.now() + '_' + Math.ceil(Math.random() * 99999)
+      data.subfield = true
+      delete data.icon
+      this.$set(column.children.column, newIndex, { ...data })
+      this.selectWidget = column.children.column[newIndex]
+    },
+    handleWidgetTableSelect (data) {
+      this.selectWidget = data
+    },
+    handleWidgetTableClone (column, item) {
+      const data = this.deepClone(item);
+      data.prop = Date.now() + '_' + Math.ceil(Math.random() * 99999)
+      this.$set(column.children.column, column.children.column.length, { ...data })
+      this.$nextTick(() => {
+        this.selectWidget = column.children.column[column.children.column.length - 1]
+      })
+    },
+    handleWidgetTableDelete (column, index) {
+      if (column.children.column.length - 1 == index) {
+        if (index == 0) this.selectWidget = column
+        else this.selectWidget = column.children.column[index - 1]
+      } else this.selectWidget = column.children.column[index + 1]
+      this.$nextTick(() => {
+        column.children.column.splice(index, 1)
+      })
+    },
+  },
+  watch: {
+    select (val) {
+      this.selectWidget = val
+    },
+    selectWidget: {
+      handler (val) {
+        this.$emit('update:select', val)
+      },
+      deep: true
+    }
+  }
+}
+</script>

BIN
packages/assets/widget-empty.png


+ 62 - 0
packages/config/array.vue

@@ -0,0 +1,62 @@
+<template>
+  <div>
+    <el-form-item label="占位内容">
+      <el-input v-model="data.placeholder"
+                placeholder="占位内容"></el-input>
+    </el-form-item>
+    <el-form-item label="默认值">
+      <el-input v-model="data.valueDefault"
+                placeholder="默认值"></el-input>
+    </el-form-item>
+    <el-form-item label="尺寸">
+      <el-radio-group v-model="data.size"
+                      size="mini">
+        <el-radio-button label="medium">正常</el-radio-button>
+        <el-radio-button label="small">小</el-radio-button>
+        <el-radio-button label="mini">超小</el-radio-button>
+      </el-radio-group>
+    </el-form-item>
+    <el-form-item label="是否禁用">
+      <el-switch v-model="data.disabled"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否可见">
+      <el-switch v-model="data.display"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否必填">
+      <el-switch v-model="data.required"></el-switch>
+    </el-form-item>
+  </div>
+</template>
+<script>
+export default {
+  name: 'config-array',
+  props: ['data'],
+  data () {
+    return {
+      validator: {
+        type: null,
+        required: null,
+        pattern: null,
+        length: null
+      }
+    }
+  },
+  methods: {
+    generateRule () {
+      const rules = [];
+      Object.keys(this.validator).forEach(key => {
+        if (this.validator[key]) rules.push(this.validator[key])
+      })
+      this.data.rules = rules
+    },
+  },
+  watch: {
+    'data.required': function (val) {
+      if (val) this.validator.required = { required: true, message: `请输入${this.data.label}` }
+      else this.validator.required = null
+
+      this.generateRule()
+    }
+  }
+}
+</script>

+ 239 - 0
packages/config/cascader.vue

@@ -0,0 +1,239 @@
+<template>
+  <div>
+    <el-form-item label="占位内容">
+      <el-input v-model="data.placeholder"
+                placeholder="占位内容"></el-input>
+    </el-form-item>
+    <el-form-item label="默认值">
+      <el-input v-model="data.valueDefault"
+                placeholder="默认值"></el-input>
+    </el-form-item>
+    <el-form-item label="字典配置"><br>
+      <el-tabs v-model="data.dicOption"
+               stretch
+               @tab-click="handleTabClick">
+        <el-tab-pane label="静态数据"
+                     name="static">
+          <el-tree ref="tree"
+                   :data="data.dicData"
+                   default-expand-all
+                   draggable
+                   node-key="value"
+                   :expand-on-click-node="false">
+            <span class="custom-tree-node"
+                  slot-scope="{ node, data }">
+              <span>{{ node.label }}</span>
+              <span>
+                <el-button type="text"
+                           size="mini"
+                           icon="el-icon-plus"
+                           @click="handleNodeAdd(data)"></el-button>
+                <!--                <el-button class="warning" type="text" size="mini" icon="el-icon-edit"-->
+                <!--                           @click="handleNodeEdit(data)"></el-button>-->
+                <el-button class="danger"
+                           type="text"
+                           size="mini"
+                           icon="el-icon-delete"
+                           @click="handleNodeRemove(node, data)"></el-button>
+              </span>
+            </span>
+          </el-tree>
+          <div style="margin-left: 22px;">
+            <el-button type="text"
+                       @click="handleParentNodeAdd">添加父级
+            </el-button>
+          </div>
+        </el-tab-pane>
+        <el-tab-pane label="远端数据"
+                     name="remote">
+          网址
+          <el-input v-model="data.dicUrl"
+                    placeholder="远端数据字典网址"></el-input>
+          请求方法
+          <el-select v-model="data.dicMethod"
+                     placeholder="请求方法"
+                     style="width: 100%;">
+            <el-option label="POST"
+                       value="post"></el-option>
+            <el-option label="GET"
+                       value="get"></el-option>
+          </el-select>
+          <p v-if="data.dicMethod == 'post'">
+            请求参数
+            <avue-dynamic v-model="data.dicQuery"
+                          :children="option"></avue-dynamic>
+          </p>
+        </el-tab-pane>
+      </el-tabs>
+    </el-form-item>
+    <el-form-item label="选项分隔符">
+      <el-input v-model="data.separator"
+                placeholder="选项分隔符"></el-input>
+    </el-form-item>
+    <el-form-item label="是否显示选中值的完整路径">
+      <el-switch v-model="data.showAllLevels"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否可清空">
+      <el-switch v-model="data.clearable"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否可搜索">
+      <el-switch v-model="data.filterable"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否禁用">
+      <el-switch v-model="data.disabled"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否可见">
+      <el-switch v-model="data.display"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否必填">
+      <el-switch v-model="data.required"></el-switch>
+    </el-form-item>
+
+    <el-dialog :visible.sync="dialogVisible"
+               :rules="dialogRules"
+               :before-close="beforeClose">
+      <el-form ref="dialogForm"
+               :model="dialogForm"
+               label-width="80px">
+        <el-form-item label="label">
+          <el-input v-model="dialogForm.label"
+                    placeholder="label"></el-input>
+        </el-form-item>
+        <el-form-item label="value">
+          <el-input v-model="dialogForm.value"
+                    placeholder="value"
+                    :type="this.dialogInputType">
+            <el-select v-model="dialogInputType"
+                       slot="append"
+                       placeholder="数据类型"
+                       style="width: 100px">
+              <el-option label="String"
+                         value="text"></el-option>
+              <el-option label="Number"
+                         value="number"></el-option>
+            </el-select>
+          </el-input>
+        </el-form-item>
+      </el-form>
+      <span slot="footer"
+            class="dialog-footer">
+        <el-button @click="dialogVisible = false">取 消</el-button>
+        <el-button type="primary"
+                   @click="handleDialogAdd"
+                   v-if="dialogStatus == 'add'">确 定</el-button>
+        <!--        <el-button type="primary" @click="handleDialogUpdate" v-else>确 定</el-button>-->
+      </span>
+    </el-dialog>
+  </div>
+</template>
+<script>
+
+export default {
+  name: "config-cascader",
+  props: ['data'],
+  data () {
+    return {
+      validator: {
+        type: null,
+        required: null,
+        pattern: null,
+        length: null
+      },
+      dialogForm: {},
+      dialogVisible: false,
+      dialogRules: {
+        label: { required: true, message: '请输入label' },
+        value: { required: true, message: '请输入value' },
+      },
+      dialogStatus: 'add',
+      selectData: undefined,
+      dialogInputType: 'text',
+      option: {
+        column: [{
+          type: 'input',
+          prop: 'key',
+          label: 'key'
+        }, {
+          type: 'input',
+          prop: 'value',
+          label: 'value'
+        }]
+      },
+    }
+  },
+  methods: {
+    generateRule () {
+      const rules = [];
+      Object.keys(this.validator).forEach(key => {
+        if (this.validator[key]) rules.push(this.validator[key])
+      })
+      this.data.rules = rules
+    },
+    handleTabClick ({ name }) {
+      if (name == 'remote' && !this.data.dicQuery) this.data.dicQuery = []
+    },
+    handleParentNodeAdd () {
+      this.selectData = undefined
+      this.dialogStatus = 'add';
+      this.dialogVisible = true;
+    },
+    handleNodeAdd (data) {
+      this.selectData = data;
+      this.dialogStatus = 'add';
+      this.dialogVisible = true;
+    },
+    handleNodeRemove (node, data) {
+      const parent = node.parent;
+      const children = parent.data.children || parent.data;
+      const index = children.findIndex(d => d.id === data.id);
+      children.splice(index, 1);
+    },
+    handleDialogAdd () {
+      this.$refs.dialogForm.validate((valid) => {
+        if (valid) {
+          const { label, value } = this.dialogForm;
+          const node = this.$refs.tree.getNode(value)
+          if (node) this.$message.error("value重复")
+          else {
+            const data = this.selectData
+            const newNode = {
+              label,
+              value: this.dialogInputType == 'number' ? Number(value) : value,
+            }
+            if (data) {
+              if (!data.children) this.$set(data, 'children', [])
+              data.children.push(newNode)
+            } else {
+              this.$set(this.data.dicData, this.data.dicData.length, newNode)
+            }
+            this.beforeClose()
+          }
+        }
+      })
+    },
+    beforeClose () {
+      this.$refs.dialogForm.clearValidate()
+      this.dialogForm = {}
+      this.dialogVisible = false
+    }
+  },
+  watch: {
+    'data.required': function (val) {
+      if (val) this.validator.required = { required: true, message: `请选择${this.data.label}` }
+      else this.validator.required = null
+
+      this.generateRule()
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.custom-tree-node {
+  flex: 1;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  font-size: 14px;
+  padding-right: 8px;
+}
+</style>

+ 151 - 0
packages/config/checkbox.vue

@@ -0,0 +1,151 @@
+<template>
+  <div>
+    <el-form-item label="默认值">
+      <el-input v-model="data.valueDefault"
+                placeholder="默认值"></el-input>
+    </el-form-item>
+    <el-form-item label="字典配置"><br>
+      <el-tabs v-model="data.dicOption"
+               stretch
+               @tab-click="handleTabClick">
+        <el-tab-pane label="静态数据"
+                     name="static">
+          <draggable tag="ul"
+                     :list="data.dicData"
+                     :group="{ name: 'dic' }"
+                     ghost-class="ghost"
+                     handle=".drag-item">
+            <li v-for="(item, index) in data.dicData"
+                :key="index">
+              <i class="drag-item el-icon-s-operation"
+                 style="font-size: 16px; margin: 0 5px; cursor: move;"></i>
+              <el-input style="margin-right: 5px;"
+                        size="mini"
+                        v-model="item.label"
+                        placeholder="label"></el-input>
+              <el-input size="mini"
+                        v-model="item.value"
+                        placeholder="value"></el-input>
+              <el-button @click="handleRemoveFields(index)"
+                         circle
+                         plain
+                         type="danger"
+                         size="mini"
+                         icon="el-icon-minus"
+                         style="padding: 4px;margin-left: 5px;"></el-button>
+            </li>
+          </draggable>
+          <div style="margin-left: 22px;">
+            <el-button type="text"
+                       @click="handleAddFields">添加列
+            </el-button>
+          </div>
+        </el-tab-pane>
+        <el-tab-pane label="远端数据"
+                     name="remote">
+          网址
+          <el-input v-model="data.dicUrl"
+                    placeholder="远端数据字典网址"></el-input>
+          请求方法
+          <el-select v-model="data.dicMethod"
+                     placeholder="请求方法"
+                     style="width: 100%;">
+            <el-option label="POST"
+                       value="post"></el-option>
+            <el-option label="GET"
+                       value="get"></el-option>
+          </el-select>
+          <p v-if="data.dicMethod == 'post'">
+            请求参数
+            <avue-dynamic v-model="data.dicQuery"
+                          :children="option"></avue-dynamic>
+          </p>
+        </el-tab-pane>
+      </el-tabs>
+    </el-form-item>
+    <el-form-item label="边框"
+                  v-if="!data.button">
+      <el-switch v-model="data.border"></el-switch>
+    </el-form-item>
+    <el-form-item label="按钮"
+                  v-if="!data.border">
+      <el-switch v-model="data.button"></el-switch>
+    </el-form-item>
+    <el-form-item label="尺寸"
+                  v-if="data.border || data.button">
+      <el-radio-group v-model="data.size"
+                      size="mini">
+        <el-radio-button label="medium">正常</el-radio-button>
+        <el-radio-button label="small">小</el-radio-button>
+        <el-radio-button label="mini">超小</el-radio-button>
+      </el-radio-group>
+    </el-form-item>
+    <el-form-item label="是否禁用">
+      <el-switch v-model="data.disabled"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否可见">
+      <el-switch v-model="data.display"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否必填">
+      <el-switch v-model="data.required"></el-switch>
+    </el-form-item>
+  </div>
+</template>
+
+<script>
+import Draggable from 'vuedraggable'
+
+export default {
+  name: "config-checkbox",
+  props: ['data'],
+  components: { Draggable },
+  data () {
+    return {
+      validator: {
+        type: null,
+        required: null,
+        pattern: null,
+        length: null
+      },
+      option: {
+        column: [{
+          type: 'input',
+          prop: 'key',
+          label: 'key'
+        }, {
+          type: 'input',
+          prop: 'value',
+          label: 'value'
+        }]
+      },
+    }
+  },
+  methods: {
+    generateRule () {
+      const rules = [];
+      Object.keys(this.validator).forEach(key => {
+        if (this.validator[key]) rules.push(this.validator[key])
+      })
+      this.data.rules = rules
+    },
+    handleRemoveFields (index) {
+      this.data.dicData.splice(index, 1)
+    },
+    handleAddFields () {
+      const i = Math.ceil(Math.random() * 99999)
+      this.data.dicData.push({ label: `字段${i}`, value: `col_${i}` })
+    },
+    handleTabClick ({ name }) {
+      if (name == 'remote' && !this.data.dicQuery) this.data.dicQuery = []
+    }
+  },
+  watch: {
+    'data.required': function (val) {
+      if (val) this.validator.required = { required: true, message: `请选择${this.data.label}` }
+      else this.validator.required = null
+
+      this.generateRule()
+    }
+  }
+}
+</script>

+ 51 - 0
packages/config/color.vue

@@ -0,0 +1,51 @@
+<template>
+  <div>
+    <el-form-item label="占位内容">
+      <el-input v-model="data.placeholder"
+                placeholder="占位内容"></el-input>
+    </el-form-item>
+    <el-form-item label="是否禁用">
+      <el-switch v-model="data.disabled"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否可见">
+      <el-switch v-model="data.display"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否必填">
+      <el-switch v-model="data.required"></el-switch>
+    </el-form-item>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "config-color",
+  props: ['data'],
+  data () {
+    return {
+      validator: {
+        type: null,
+        required: null,
+        pattern: null,
+        length: null
+      }
+    }
+  },
+  methods: {
+    generateRule () {
+      const rules = [];
+      Object.keys(this.validator).forEach(key => {
+        if (this.validator[key]) rules.push(this.validator[key])
+      })
+      this.data.rules = rules
+    },
+  },
+  watch: {
+    'data.required': function (val) {
+      if (val) this.validator.required = { required: true, message: `${this.data.label}必须填写` }
+      else this.validator.required = null
+
+      this.generateRule()
+    }
+  }
+}
+</script>

+ 78 - 0
packages/config/date.vue

@@ -0,0 +1,78 @@
+<template>
+  <div>
+    <template v-if="data.type.indexOf('range') != -1">
+      <el-form-item label="开始占位内容">
+        <el-input v-model="data.startPlaceholder"
+                  placeholder="开始占位内容"></el-input>
+      </el-form-item>
+      <el-form-item label="结束占位内容">
+        <el-input v-model="data.endPlaceholder"
+                  placeholder="结束占位内容"></el-input>
+      </el-form-item>
+    </template>
+    <el-form-item label="占位内容"
+                  v-else>
+      <el-input v-model="data.placeholder"
+                placeholder="占位内容"></el-input>
+    </el-form-item>
+    <el-form-item label="默认值">
+      <el-input v-model="data.valueDefault"
+                placeholder="默认值"></el-input>
+    </el-form-item>
+    <el-form-item label="显示格式化">
+      <el-input v-model="data.format"
+                placeholder="显示格式化"></el-input>
+    </el-form-item>
+    <el-form-item label="值格式化">
+      <el-input v-model="data.valueFormat"
+                placeholder="值格式化"></el-input>
+    </el-form-item>
+    <el-form-item label="取消范围联动"
+                  v-if="['timerange', 'daterange', 'datetimerange'].includes(data.type)">
+      <el-switch v-model="data.unlinkPanels"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否禁用">
+      <el-switch v-model="data.disabled"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否可见">
+      <el-switch v-model="data.display"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否必填">
+      <el-switch v-model="data.required"></el-switch>
+    </el-form-item>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "config-date",
+  props: ['data'],
+  data () {
+    return {
+      validator: {
+        type: null,
+        required: null,
+        pattern: null,
+        length: null
+      }
+    }
+  },
+  methods: {
+    generateRule () {
+      const rules = [];
+      Object.keys(this.validator).forEach(key => {
+        if (this.validator[key]) rules.push(this.validator[key])
+      })
+      this.data.rules = rules
+    },
+  },
+  watch: {
+    'data.required': function (val) {
+      if (val) this.validator.required = { required: true, message: `${this.data.label}必须填写` }
+      else this.validator.required = null
+
+      this.generateRule()
+    }
+  }
+}
+</script>

+ 48 - 0
packages/config/dynamic.vue

@@ -0,0 +1,48 @@
+<template>
+  <div>
+    <el-form-item label="对齐方式">
+      <el-select v-model="data.children.align"
+                 placeholder="对齐方式">
+        <el-option label="居左"
+                   value="left"></el-option>
+        <el-option label="居中"
+                   value="center"></el-option>
+        <el-option label="居右"
+                   value="right"></el-option>
+      </el-select>
+    </el-form-item>
+    <el-form-item label="头部对齐方式">
+      <el-select v-model="data.children.headerAlign"
+                 placeholder="对齐方式">
+        <el-option label="居左"
+                   value="left"></el-option>
+        <el-option label="居中"
+                   value="center"></el-option>
+        <el-option label="居右"
+                   value="right"></el-option>
+      </el-select>
+    </el-form-item>
+    <el-form-item label="添加按钮">
+      <el-switch v-model="data.children.addBtn"></el-switch>
+    </el-form-item>
+    <el-form-item label="删除按钮">
+      <el-switch v-model="data.children.delBtn"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否只读">
+      <el-switch v-model="data.children.viewBtn"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否禁用">
+      <el-switch v-model="data.disabled"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否可见">
+      <el-switch v-model="data.display"></el-switch>
+    </el-form-item>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "config-dynamic",
+  props: ['data']
+}
+</script>

+ 26 - 0
packages/config/group.vue

@@ -0,0 +1,26 @@
+<template>
+  <div>
+    <el-form-item label="图标">
+      <avue-icon-select v-model="data.icon"
+                        :icon-list="iconList"
+                        placeholder="图标"></avue-icon-select>
+    </el-form-item>
+  </div>
+</template>
+<script>
+
+export default {
+  name: "config-group",
+  props: ['data'],
+  data () {
+    return {
+      iconList: [{
+        label: 'element-ui',
+        list: ['el-icon-info', 'el-icon-error', 'el-icon-success', 'el-icon-warning', 'el-icon-question']
+      }]
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+</style>

+ 54 - 0
packages/config/index.js

@@ -0,0 +1,54 @@
+import Input from './input.vue'
+import Textarea from './textarea.vue'
+import Number from './number.vue'
+import Dynamic from './dynamic.vue'
+import Switch from './switch.vue'
+import Rate from './rate.vue'
+import Slider from './slider.vue'
+import Color from './color.vue'
+import Radio from './radio.vue'
+import Checkbox from './checkbox.vue'
+import Select from './select.vue'
+import Cascader from './cascader.vue'
+import Tree from './tree.vue'
+import Date from './date.vue'
+import Upload from './upload.vue'
+import UEditor from './ueditor.vue'
+import Map from './map.vue'
+import Group from './group.vue'
+import Array from './array.vue'
+
+const components = [
+  Input,
+  Textarea,
+  Number,
+  Dynamic,
+  Switch,
+  Rate,
+  Slider,
+  Color,
+  Radio,
+  Checkbox,
+  Select,
+  Cascader,
+  Tree,
+  Date,
+  UEditor,
+  Upload,
+  Map,
+  Group,
+  Array
+]
+
+const Config = {
+  install (Vue) {
+    if (this.installed) return
+    this.installed = true
+
+    components.map(component => {
+      Vue.component(component.name, component);
+    })
+  }
+}
+
+export default Config

+ 82 - 0
packages/config/input.vue

@@ -0,0 +1,82 @@
+<template>
+  <div>
+    <el-form-item label="占位内容">
+      <el-input v-model="data.placeholder"
+                placeholder="占位内容"></el-input>
+    </el-form-item>
+    <el-form-item label="默认值">
+      <el-input v-model="data.valueDefault"
+                placeholder="默认值"></el-input>
+    </el-form-item>
+    <el-form-item label="前缀">
+      <el-input v-model="data.prepend"
+                placeholder="前缀"></el-input>
+    </el-form-item>
+    <el-form-item label="后缀">
+      <el-input v-model="data.append"
+                placeholder="后缀"></el-input>
+    </el-form-item>
+    <el-form-item label="最大长度">
+      <el-input-number v-model="data.maxlength"
+                       controls-position="right"
+                       placeholder="最大长度"></el-input-number>
+    </el-form-item>
+    <el-form-item label="显示计数"
+                  v-if="data.type != 'password'">
+      <el-switch v-model="data.showWordLimit"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否只读">
+      <el-switch v-model="data.readonly"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否可见">
+      <el-switch v-model="data.display"></el-switch>
+    </el-form-item>
+    <el-form-item label="校验"><br>
+      是否必填:
+      <el-switch v-model="data.required"></el-switch>
+      <el-input v-model.lazy="data.pattern"
+                placeholder="正则表达式"></el-input>
+    </el-form-item>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "config-input",
+  props: ['data'],
+  data () {
+    return {
+      validator: {
+        type: null,
+        required: null,
+        pattern: null,
+        length: null
+      }
+    }
+  },
+  methods: {
+    generateRule () {
+      const rules = [];
+      Object.keys(this.validator).forEach(key => {
+        if (this.validator[key]) rules.push(this.validator[key])
+      })
+      this.data.rules = rules
+    },
+  },
+  watch: {
+    'data.required': function (val) {
+      if (val) this.validator.required = { required: true, message: `${this.data.label}必须填写` }
+      else this.validator.required = null
+
+      this.generateRule()
+    },
+    'data.pattern': function (val) {
+      if (val) this.validator.pattern = { pattern: new RegExp(val), message: `${this.data.label}格式不匹配` }
+      else this.validator.pattern = null
+
+      // delete this.data.pattern
+      this.generateRule()
+    }
+  }
+}
+</script>

+ 54 - 0
packages/config/map.vue

@@ -0,0 +1,54 @@
+<template>
+  <div>
+    <el-form-item label="默认值">
+      <a href="https://avuejs.com/doc/plugins/map-plugins"
+         target="_blank"
+         style="color: #409EFF;">详细文档</a><br>
+      <el-input v-model="data.valueDefault"
+                placeholder="默认值"></el-input>
+    </el-form-item>
+    <el-form-item label="是否禁用">
+      <el-switch v-model="data.disabled"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否可见">
+      <el-switch v-model="data.display"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否必填">
+      <el-switch v-model="data.required"></el-switch>
+    </el-form-item>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "config-map",
+  props: ['data'],
+  data () {
+    return {
+      validator: {
+        type: null,
+        required: null,
+        pattern: null,
+        length: null
+      }
+    }
+  },
+  methods: {
+    generateRule () {
+      const rules = [];
+      Object.keys(this.validator).forEach(key => {
+        if (this.validator[key]) rules.push(this.validator[key])
+      })
+      this.data.rules = rules
+    },
+  },
+  watch: {
+    'data.required': function (val) {
+      if (val) this.validator.required = { required: true, message: `${this.data.label}必须填写` }
+      else this.validator.required = null
+
+      this.generateRule()
+    }
+  }
+}
+</script>

+ 94 - 0
packages/config/number.vue

@@ -0,0 +1,94 @@
+<template>
+  <div>
+    <el-form-item label="占位内容">
+      <el-input v-model="data.placeholder"
+                placeholder="占位内容"></el-input>
+    </el-form-item>
+    <el-form-item label="默认值">
+      <el-input v-model="data.valueDefault"
+                placeholder="默认值"></el-input>
+    </el-form-item>
+    <el-form-item label="最小值">
+      <el-input-number v-model="data.minRows"
+                       controls-position="right"
+                       placeholder="最小值"></el-input-number>
+    </el-form-item>
+    <el-form-item label="最大值">
+      <el-input-number v-model="data.maxRows"
+                       controls-position="right"
+                       placeholder="最大值"></el-input-number>
+    </el-form-item>
+    <el-form-item label="步长">
+      <el-input-number v-model="data.step"
+                       controls-position="right"
+                       placeholder="步长"></el-input-number>
+    </el-form-item>
+    <el-form-item label="数值精度">
+      <el-input-number v-model="data.precision"
+                       controls-position="right"
+                       placeholder="数值精度"
+                       :min="0"
+                       :max="10"></el-input-number>
+    </el-form-item>
+    <el-form-item label="控制器位置">
+      <el-radio v-model="data.controlsPosition"
+                label="">默认
+      </el-radio>
+      <el-radio v-model="data.controlsPosition"
+                label="right">右
+      </el-radio>
+    </el-form-item>
+    <el-form-item label="是否只读">
+      <el-switch v-model="data.readonly"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否可见">
+      <el-switch v-model="data.display"></el-switch>
+    </el-form-item>
+    <el-form-item label="校验"><br>
+      是否必填:
+      <el-switch v-model="data.required"></el-switch>
+      <el-input v-model.lazy="data.pattern"
+                placeholder="正则表达式"></el-input>
+    </el-form-item>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "config-number",
+  props: ['data'],
+  data () {
+    return {
+      validator: {
+        type: null,
+        required: null,
+        pattern: null,
+        length: null
+      }
+    }
+  },
+  methods: {
+    generateRule () {
+      this.data.rules.clear()
+      Object.keys(this.validator).forEach(key => {
+        if (this.validator[key]) this.data.rules.push(this.validator[key])
+      })
+    },
+  },
+  watch: {
+    'data.required': function (val) {
+      if (val) this.validator.required = { required: true, message: `${this.data.label}必须填写` }
+      else this.validator.required = null
+
+      this.generateRule()
+    },
+    'data.pattern': function (val) {
+      if (val) this.validator.pattern = { pattern: new RegExp(val), message: `${this.data.label}格式不匹配` }
+      else this.validator.pattern = null
+
+      // delete this.data.pattern
+      this.generateRule()
+    }
+  }
+}
+</script>

+ 147 - 0
packages/config/radio.vue

@@ -0,0 +1,147 @@
+<template>
+  <div>
+    <el-form-item label="默认值">
+      <el-input v-model="data.valueDefault"
+                placeholder="默认值"></el-input>
+    </el-form-item>
+    <el-form-item label="字典配置"><br>
+      <el-tabs v-model="data.dicOption"
+               stretch
+               @tab-click="handleTabClick">
+        <el-tab-pane label="静态数据"
+                     name="static">
+          <draggable tag="ul"
+                     :list="data.dicData"
+                     :group="{ name: 'dic' }"
+                     ghost-class="ghost"
+                     handle=".drag-item">
+            <li v-for="(item, index) in data.dicData"
+                :key="index">
+              <i class="drag-item el-icon-s-operation"
+                 style="font-size: 16px; margin: 0 5px; cursor: move;"></i>
+              <el-input style="margin-right: 5px;"
+                        size="mini"
+                        v-model="item.label"
+                        placeholder="label"></el-input>
+              <el-input size="mini"
+                        v-model="item.value"
+                        placeholder="value"></el-input>
+              <el-button @click="handleRemoveFields(index)"
+                         circle
+                         plain
+                         type="danger"
+                         size="mini"
+                         icon="el-icon-minus"
+                         style="padding: 4px;margin-left: 5px;"></el-button>
+            </li>
+          </draggable>
+          <div style="margin-left: 22px;">
+            <el-button type="text"
+                       @click="handleAddFields">添加列
+            </el-button>
+          </div>
+        </el-tab-pane>
+        <el-tab-pane label="远端数据"
+                     name="remote">
+          网址
+          <el-input v-model="data.dicUrl"
+                    placeholder="远端数据字典网址"></el-input>
+          请求方法
+          <el-select v-model="data.dicMethod"
+                     placeholder="请求方法"
+                     style="width: 100%;">
+            <el-option label="POST"
+                       value="post"></el-option>
+            <el-option label="GET"
+                       value="get"></el-option>
+          </el-select>
+          <p v-if="data.dicMethod == 'post'">
+            请求参数
+            <avue-dynamic v-model="data.dicQuery"
+                          :children="option"></avue-dynamic>
+          </p>
+        </el-tab-pane>
+      </el-tabs>
+    </el-form-item>
+    <el-form-item label="边框">
+      <el-switch v-model="data.border"></el-switch>
+    </el-form-item>
+    <el-form-item label="尺寸"
+                  v-if="data.border">
+      <el-radio-group v-model="data.size"
+                      size="mini">
+        <el-radio-button label="medium">正常</el-radio-button>
+        <el-radio-button label="small">小</el-radio-button>
+        <el-radio-button label="mini">超小</el-radio-button>
+      </el-radio-group>
+    </el-form-item>
+    <el-form-item label="是否禁用">
+      <el-switch v-model="data.disabled"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否可见">
+      <el-switch v-model="data.display"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否必填">
+      <el-switch v-model="data.required"></el-switch>
+    </el-form-item>
+  </div>
+</template>
+
+<script>
+import Draggable from 'vuedraggable'
+
+
+export default {
+  name: "config-radio",
+  props: ['data'],
+  components: { Draggable },
+  data () {
+    return {
+      validator: {
+        type: null,
+        required: null,
+        pattern: null,
+        length: null
+      },
+      option: {
+        column: [{
+          type: 'input',
+          prop: 'key',
+          label: 'key'
+        }, {
+          type: 'input',
+          prop: 'value',
+          label: 'value'
+        }]
+      },
+    }
+  },
+  methods: {
+    generateRule () {
+      const rules = [];
+      Object.keys(this.validator).forEach(key => {
+        if (this.validator[key]) rules.push(this.validator[key])
+      })
+      this.data.rules = rules
+    },
+    handleRemoveFields (index) {
+      this.data.dicData.splice(index, 1)
+    },
+    handleAddFields () {
+      const i = Math.ceil(Math.random() * 99999)
+      this.data.dicData.push({ label: `字段${i}`, value: `col_${i}` })
+    },
+    handleTabClick ({ name }) {
+      if (name == 'remote' && !this.data.dicQuery) this.data.dicQuery = []
+    }
+  },
+  watch: {
+    'data.required': function (val) {
+      if (val) this.validator.required = { required: true, message: `请选择${this.data.label}` }
+      else this.validator.required = null
+
+      this.generateRule()
+    }
+  }
+}
+</script>

+ 168 - 0
packages/config/rate.vue

@@ -0,0 +1,168 @@
+<template>
+  <div>
+    <el-form-item label="默认值">
+      <el-input v-model="data.valueDefault"
+                placeholder="默认值"></el-input>
+    </el-form-item>
+    <el-form-item label="最大星数">
+      <el-input-number v-model="data.max"
+                       controls-position="right"
+                       placeholder="最大星数"></el-input-number>
+    </el-form-item>
+    <el-form-item label="是否显示文本">
+      <el-switch v-model="data.showText"></el-switch>
+    </el-form-item>
+    <el-form-item label="自定义文本"
+                  v-if="data.showText">
+      <el-tag :key="index"
+              v-for="(tag,index) in data.texts"
+              closable
+              @close="handleTextClose(tag)">{{tag}}
+      </el-tag>
+      <el-input class="input-new-tag"
+                v-if="textVisible"
+                v-model="textValue"
+                size="mini"
+                ref="textTag"
+                @keyup.enter.native="handleTextConfirm"
+                @blur="handleTextConfirm">
+      </el-input>
+      <el-button v-else
+                 @click="showTextInput"
+                 size="mini"
+                 icon="el-icon-plus"
+                 circle
+                 style="margin-left: 5px;"></el-button>
+    </el-form-item>
+    <el-form-item label="自定义颜色">
+      <el-tag :key="index"
+              v-for="(tag,index) in data.colors"
+              closable
+              @close="handleColorClose(tag)"
+              :style="{color: tag}">{{tag}}
+      </el-tag>
+      <el-color-picker v-model="colorValue"
+                       size="mini"
+                       @change="handleColorConfirm"
+                       class="color-picker"></el-color-picker>
+    </el-form-item>
+    <!--    <el-form-item label="自定义图标">-->
+    <!--      <el-tag :key="index" v-for="(tag,index) in data.iconClasses" closable @close="handleIconClose(tag)">{{tag}}-->
+    <!--      </el-tag>-->
+    <!--      <el-input class="input-new-tag"-->
+    <!--                v-if="iconVisible"-->
+    <!--                v-model="iconValue"-->
+    <!--                size="mini"-->
+    <!--                ref="iconTag"-->
+    <!--                @keyup.enter.native="handleIconConfirm"-->
+    <!--                @blur="handleIconConfirm">-->
+    <!--      </el-input>-->
+    <!--      <el-button v-else @click="showIconInput" size="mini" icon="el-icon-plus" circle-->
+    <!--                 style="margin-left: 5px;"></el-button>-->
+    <!--    </el-form-item>-->
+    <el-form-item label="是否禁用">
+      <el-switch v-model="data.disabled"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否可见">
+      <el-switch v-model="data.display"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否必填">
+      <el-switch v-model="data.required"></el-switch>
+    </el-form-item>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "config-rate",
+  props: ['data'],
+  data () {
+    return {
+      validator: {
+        type: null,
+        required: null,
+        pattern: null,
+        length: null
+      },
+      textVisible: false,
+      textValue: '',
+      colorVisible: false,
+      colorValue: '',
+      iconVisible: false,
+      iconValue: ''
+    }
+  },
+  methods: {
+    generateRule () {
+      const rules = [];
+      Object.keys(this.validator).forEach(key => {
+        if (this.validator[key]) rules.push(this.validator[key])
+      })
+      this.data.rules = rules
+    },
+    handleTextClose (tag) {
+      this.data.texts.splice(this.data.texts.indexOf(tag), 1);
+    },
+    showTextInput () {
+      this.textVisible = true;
+      this.$nextTick(() => {
+        this.$refs.textTag.$refs.input.focus();
+      });
+    },
+    handleTextConfirm () {
+      if (this.textValue) this.data.texts.push(this.textValue);
+      this.textVisible = false;
+      this.textValue = '';
+    },
+    handleColorClose (tag) {
+      this.data.colors.splice(this.data.colors.indexOf(tag), 1);
+    },
+    handleColorConfirm () {
+      if (this.colorValue) this.data.colors.push(this.colorValue);
+      this.colorValue = '';
+    },
+    // handleIconClose(tag) {
+    //   this.data.iconClasses.splice(this.data.iconClasses.indexOf(tag), 1);
+    // },
+    // showIconInput() {
+    //   this.iconVisible = true;
+    //   this.$nextTick(() => {
+    //     this.$refs.iconTag.$refs.input.focus();
+    //   });
+    // },
+    // handleIconConfirm() {
+    //   if (this.iconValue) this.data.iconClasses.push(this.iconValue);
+    //   this.iconVisible = false;
+    //   this.iconValue = '';
+    // }
+  },
+  watch: {
+    'data.required': function (val) {
+      if (val) this.validator.required = { required: true, message: `${this.data.label}必须填写` }
+      else this.validator.required = null
+
+      this.generateRule()
+    },
+  }
+}
+</script>
+<style lang="scss" scoped>
+.el-tag {
+  vertical-align: top;
+}
+
+.el-tag + .el-tag {
+  margin-left: 5px;
+}
+
+.input-new-tag {
+  width: 90px;
+  margin-left: 5px;
+  vertical-align: bottom;
+}
+
+.color-picker {
+  left: 10px;
+  vertical-align: top;
+}
+</style>

+ 168 - 0
packages/config/select.vue

@@ -0,0 +1,168 @@
+<template>
+  <div>
+    <el-form-item label="占位内容">
+      <el-input v-model="data.placeholder"
+                placeholder="占位内容"></el-input>
+    </el-form-item>
+    <el-form-item label="默认值">
+      <el-input v-model="data.valueDefault"
+                placeholder="默认值"></el-input>
+    </el-form-item>
+    <el-form-item label="是否多选">
+      <el-switch v-model="data.multiple"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否可拖拽(需引入sortable.js)"
+                  v-if="data.multiple">
+      <el-switch v-model="data.drag"></el-switch>
+    </el-form-item>
+    <el-form-item label="多选数量限制"
+                  v-if="data.multiple">
+      <el-input-number v-model="data.limit"
+                       controls-position="right"
+                       placeholder="多选限制"
+                       :min="0"
+                       :max="data.dicData.length"></el-input-number>
+    </el-form-item>
+    <el-form-item label="字典配置"><br>
+      <el-tabs v-model="data.dicOption"
+               stretch
+               @tab-click="handleTabClick">
+        <el-tab-pane label="静态数据"
+                     name="static">
+          <draggable tag="ul"
+                     :list="data.dicData"
+                     :group="{ name: 'dic' }"
+                     ghost-class="ghost"
+                     handle=".drag-item">
+            <li v-for="(item, index) in data.dicData"
+                :key="index">
+              <i class="drag-item el-icon-s-operation"
+                 style="font-size: 16px; margin: 0 5px; cursor: move;"></i>
+              <el-input style="margin-right: 5px;"
+                        size="mini"
+                        v-model="item.label"
+                        placeholder="label"></el-input>
+              <el-input size="mini"
+                        v-model="item.value"
+                        placeholder="value"></el-input>
+              <el-button @click="handleRemoveFields(index)"
+                         circle
+                         plain
+                         type="danger"
+                         size="mini"
+                         icon="el-icon-minus"
+                         style="padding: 4px;margin-left: 5px;"></el-button>
+            </li>
+          </draggable>
+          <div style="margin-left: 22px;">
+            <el-button type="text"
+                       @click="handleAddFields">添加列
+            </el-button>
+          </div>
+        </el-tab-pane>
+        <el-tab-pane label="远端数据"
+                     name="remote">
+          网址
+          <el-input v-model="data.dicUrl"
+                    placeholder="远端数据字典网址"></el-input>
+          请求方法
+          <el-select v-model="data.dicMethod"
+                     placeholder="请求方法"
+                     style="width: 100%;">
+            <el-option label="POST"
+                       value="post"></el-option>
+            <el-option label="GET"
+                       value="get"></el-option>
+          </el-select>
+          <p v-if="data.dicMethod == 'post'">
+            请求参数
+            <avue-dynamic v-model="data.dicQuery"
+                          :children="option"></avue-dynamic>
+          </p>
+
+        </el-tab-pane>
+      </el-tabs>
+    </el-form-item>
+    <el-form-item label="尺寸">
+      <el-radio-group v-model="data.size"
+                      size="mini">
+        <el-radio-button label="medium">正常</el-radio-button>
+        <el-radio-button label="small">小</el-radio-button>
+        <el-radio-button label="mini">超小</el-radio-button>
+      </el-radio-group>
+    </el-form-item>
+    <el-form-item label="是否可清空">
+      <el-switch v-model="data.clearable"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否可搜索">
+      <el-switch v-model="data.filterable"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否禁用">
+      <el-switch v-model="data.disabled"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否可见">
+      <el-switch v-model="data.display"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否必填">
+      <el-switch v-model="data.required"></el-switch>
+    </el-form-item>
+  </div>
+</template>
+
+<script>
+import Draggable from 'vuedraggable'
+
+export default {
+  name: "config-select",
+  props: ['data'],
+  components: { Draggable },
+  data () {
+    return {
+      validator: {
+        type: null,
+        required: null,
+        pattern: null,
+        length: null
+      },
+      option: {
+        column: [{
+          type: 'input',
+          prop: 'key',
+          label: 'key'
+        }, {
+          type: 'input',
+          prop: 'value',
+          label: 'value'
+        }]
+      },
+    }
+  },
+  methods: {
+    generateRule () {
+      const rules = [];
+      Object.keys(this.validator).forEach(key => {
+        if (this.validator[key]) rules.push(this.validator[key])
+      })
+      this.data.rules = rules
+    },
+    handleRemoveFields (index) {
+      this.data.dicData.splice(index, 1)
+    },
+    handleAddFields () {
+      const i = Math.ceil(Math.random() * 99999)
+      this.data.dicData.push({ label: `字段${i}`, value: `col_${i}` })
+    },
+    handleTabClick ({ name }) {
+      if (name == 'remote' && !this.data.dicQuery) this.data.dicQuery = []
+    }
+  },
+  watch: {
+    'data.required': function (val) {
+      if (val) this.validator.required = { required: true, message: `请选择${this.data.label}` }
+      else this.validator.required = null
+
+      this.generateRule()
+    }
+  }
+}
+</script>

+ 50 - 0
packages/config/slider.vue

@@ -0,0 +1,50 @@
+<template>
+  <div>
+    <el-form-item label="默认值">
+      <el-input v-model="data.valueDefault"
+                placeholder="默认值"></el-input>
+    </el-form-item>
+    <el-form-item label="最小值">
+      <el-input-number v-model="data.min"
+                       controls-position="right"
+                       placeholder="最小值"
+                       :max="data.max - 1"
+                       :min="0"></el-input-number>
+    </el-form-item>
+    <el-form-item label="最大值">
+      <el-input-number v-model="data.max"
+                       controls-position="right"
+                       placeholder="最大值"
+                       :min="data.min + 1"></el-input-number>
+    </el-form-item>
+    <el-form-item label="步长">
+      <el-input-number v-model="data.step"
+                       controls-position="right"
+                       placeholder="步长"
+                       :min="1"
+                       :max="data.max - data.min"></el-input-number>
+    </el-form-item>
+    <el-form-item label="显示间隔点">
+      <el-switch v-model="data.showStops"></el-switch>
+    </el-form-item>
+    <el-form-item label="显示输入框">
+      <el-switch v-model="data.showInput"></el-switch>
+    </el-form-item>
+    <!--    <el-form-item label="范围滑块">-->
+    <!--      <el-switch v-model="data.range"></el-switch>-->
+    <!--    </el-form-item>-->
+    <el-form-item label="是否禁用">
+      <el-switch v-model="data.disabled"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否可见">
+      <el-switch v-model="data.display"></el-switch>
+    </el-form-item>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "config-slider",
+  props: ['data']
+}
+</script>

+ 49 - 0
packages/config/switch.vue

@@ -0,0 +1,49 @@
+<template>
+  <div>
+    <el-form-item label="默认值">
+      <el-input v-model="data.valueDefault"
+                placeholder="默认值"></el-input>
+    </el-form-item>
+    <el-form-item label="自定义">
+      <el-button type="text"
+                 @click="handleDicClear"
+                 class="danger">清空
+      </el-button>
+      <div class="dic"
+           v-for="(item, index) in data.dicData"
+           :key="index">
+        <el-input size="mini"
+                  v-model="item.label"
+                  placeholder="自定义文字"
+                  style="margin-right: 5px"></el-input>
+        <el-input size="mini"
+                  v-model="item.value"
+                  placeholder="自定义值"></el-input>
+      </div>
+    </el-form-item>
+    <el-form-item label="是否禁用">
+      <el-switch v-model="data.disabled"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否可见">
+      <el-switch v-model="data.display"></el-switch>
+    </el-form-item>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "config-switch",
+  props: ['data'],
+  methods: {
+    handleDicClear () {
+      this.data.dicData = [{ label: '', value: '0' }, { label: '', value: '1' }]
+    }
+  },
+}
+</script>
+<style lang="scss" scoped>
+.dic {
+  display: flex;
+  margin-bottom: 5px;
+}
+</style>

+ 85 - 0
packages/config/textarea.vue

@@ -0,0 +1,85 @@
+<template>
+  <div>
+    <el-form-item label="占位内容">
+      <el-input v-model="data.placeholder"
+                placeholder="占位内容"></el-input>
+    </el-form-item>
+    <el-form-item label="默认值">
+      <el-input v-model="data.valueDefault"
+                placeholder="默认值"></el-input>
+    </el-form-item>
+    <el-form-item label="最大长度">
+      <el-input-number v-model="data.maxlength"
+                       controls-position="right"
+                       placeholder="最大长度"></el-input-number>
+    </el-form-item>
+    <el-form-item label="显示计数">
+      <el-switch v-model="data.showWordLimit"></el-switch>
+    </el-form-item>
+    <el-form-item label="最小行">
+      <el-input-number v-model="data.minRows"
+                       controls-position="right"
+                       placeholder="最小行"
+                       :min="1"></el-input-number>
+    </el-form-item>
+    <el-form-item label="最大行">
+      <el-input-number v-model="data.maxRows"
+                       controls-position="right"
+                       placeholder="最大行"
+                       :min="2"></el-input-number>
+    </el-form-item>
+    <el-form-item label="是否只读">
+      <el-switch v-model="data.readonly"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否可见">
+      <el-switch v-model="data.display"></el-switch>
+    </el-form-item>
+    <el-form-item label="校验"><br>
+      是否必填:
+      <el-switch v-model="data.required"></el-switch>
+      <el-input v-model.lazy="data.pattern"
+                placeholder="正则表达式"></el-input>
+    </el-form-item>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "config-textarea",
+  props: ['data'],
+  data () {
+    return {
+      validator: {
+        type: null,
+        required: null,
+        pattern: null,
+        length: null
+      }
+    }
+  },
+  methods: {
+    generateRule () {
+      const rules = [];
+      Object.keys(this.validator).forEach(key => {
+        if (this.validator[key]) rules.push(this.validator[key])
+      })
+      this.data.rules = rules
+    },
+  },
+  watch: {
+    'data.required': function (val) {
+      if (val) this.validator.required = { required: true, message: `${this.data.label}必须填写` }
+      else this.validator.required = null
+
+      this.generateRule()
+    },
+    'data.pattern': function (val) {
+      if (val) this.validator.pattern = { pattern: new RegExp(val), message: `${this.data.label}格式不匹配` }
+      else this.validator.pattern = null
+
+      // delete this.data.pattern
+      this.generateRule()
+    }
+  }
+}
+</script>

+ 237 - 0
packages/config/tree.vue

@@ -0,0 +1,237 @@
+<template>
+  <div>
+    <el-form-item label="占位内容">
+      <el-input v-model="data.placeholder"
+                placeholder="占位内容"></el-input>
+    </el-form-item>
+    <el-form-item label="默认值">
+      <el-input v-model="data.valueDefault"
+                placeholder="默认值"></el-input>
+    </el-form-item>
+    <el-form-item label="字典配置"><br>
+      <el-tabs v-model="data.dicOption"
+               stretch
+               @tab-click="handleTabClick">
+        <el-tab-pane label="静态数据"
+                     name="static">
+          <el-tree ref="tree"
+                   :data="data.dicData"
+                   default-expand-all
+                   draggable
+                   node-key="value"
+                   :expand-on-click-node="false">
+            <span class="custom-tree-node"
+                  slot-scope="{ node, data }">
+              <span>{{ node.label }}</span>
+              <span>
+                <el-button type="text"
+                           size="mini"
+                           icon="el-icon-plus"
+                           @click="handleNodeAdd(data)"></el-button>
+                <!--                <el-button class="warning" type="text" size="mini" icon="el-icon-edit"-->
+                <!--                           @click="handleNodeEdit(data)"></el-button>-->
+                <el-button class="danger"
+                           type="text"
+                           size="mini"
+                           icon="el-icon-delete"
+                           @click="handleNodeRemove(node, data)"></el-button>
+              </span>
+            </span>
+          </el-tree>
+          <div style="margin-left: 22px;">
+            <el-button type="text"
+                       @click="handleParentNodeAdd">添加父级
+            </el-button>
+          </div>
+        </el-tab-pane>
+        <el-tab-pane label="远端数据"
+                     name="remote">
+          网址
+          <el-input v-model="data.dicUrl"
+                    placeholder="远端数据字典网址"></el-input>
+          请求方法
+          <el-select v-model="data.dicMethod"
+                     placeholder="请求方法"
+                     style="width: 100%;">
+            <el-option label="POST"
+                       value="post"></el-option>
+            <el-option label="GET"
+                       value="get"></el-option>
+          </el-select>
+          <p v-if="data.dicMethod == 'post'">
+            请求参数
+            <avue-dynamic v-model="data.dicQuery"
+                          :children="option"></avue-dynamic>
+          </p>
+        </el-tab-pane>
+      </el-tabs>
+    </el-form-item>
+    <el-form-item label="当有子级时,是否可选择父级">
+      <el-switch v-model="data.parent"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否多选">
+      <el-switch v-model="data.multiple"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否禁用">
+      <el-switch v-model="data.disabled"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否可见">
+      <el-switch v-model="data.display"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否必填">
+      <el-switch v-model="data.required"></el-switch>
+    </el-form-item>
+
+    <el-dialog :visible.sync="dialogVisible"
+               :rules="dialogRules"
+               :before-close="beforeClose">
+      <el-form ref="dialogForm"
+               :model="dialogForm"
+               label-width="80px">
+        <el-form-item label="label">
+          <el-input v-model="dialogForm.label"
+                    placeholder="label"></el-input>
+        </el-form-item>
+        <el-form-item label="value">
+          <el-input v-model="dialogForm.value"
+                    placeholder="value"
+                    :type="this.dialogInputType">
+            <el-select v-model="dialogInputType"
+                       slot="append"
+                       placeholder="数据类型"
+                       style="width: 100px">
+              <el-option label="String"
+                         value="text"></el-option>
+              <el-option label="Number"
+                         value="number"></el-option>
+            </el-select>
+          </el-input>
+        </el-form-item>
+      </el-form>
+      <span slot="footer"
+            class="dialog-footer">
+        <el-button @click="dialogVisible = false">取 消</el-button>
+        <el-button type="primary"
+                   @click="handleDialogAdd"
+                   v-if="dialogStatus == 'add'">确 定</el-button>
+        <!--        <el-button type="primary" @click="handleDialogUpdate" v-else>确 定</el-button>-->
+      </span>
+    </el-dialog>
+  </div>
+</template>
+<script>
+
+
+export default {
+  name: "config-tree",
+  props: ['data'],
+  data () {
+    return {
+      validator: {
+        type: null,
+        required: null,
+        pattern: null,
+        length: null
+      },
+      dialogForm: {},
+      dialogVisible: false,
+      dialogRules: {
+        label: { required: true, message: '请输入label' },
+        value: { required: true, message: '请输入value' },
+      },
+      dialogStatus: 'add',
+      selectData: undefined,
+      dialogInputType: 'text',
+      option: {
+        column: [{
+          type: 'input',
+          prop: 'key',
+          label: 'key'
+        }, {
+          type: 'input',
+          prop: 'value',
+          label: 'value'
+        }]
+      },
+    }
+  },
+  methods: {
+    generateRule () {
+      const rules = [];
+      Object.keys(this.validator).forEach(key => {
+        if (this.validator[key]) rules.push(this.validator[key])
+      })
+      this.data.rules = rules
+    },
+    handleTabClick ({ name }) {
+      if (name == 'remote' && !this.data.dicQuery) this.data.dicQuery = []
+    },
+    handleParentNodeAdd () {
+      this.selectData = undefined
+      this.dialogStatus = 'add';
+      this.dialogVisible = true;
+    },
+    handleNodeAdd (data) {
+      this.selectData = data;
+      this.dialogStatus = 'add';
+      this.dialogVisible = true;
+    },
+    handleNodeRemove (node, data) {
+      const parent = node.parent;
+      const children = parent.data.children || parent.data;
+      const index = children.findIndex(d => d.id === data.id);
+      children.splice(index, 1);
+    },
+    handleDialogAdd () {
+      this.$refs.dialogForm.validate((valid) => {
+        if (valid) {
+          const { label, value } = this.dialogForm;
+          const node = this.$refs.tree.getNode(value)
+          if (node) this.$message.error("value重复")
+          else {
+            const data = this.selectData
+            const newNode = {
+              label,
+              value: this.dialogInputType == 'number' ? new Number(value) : value,
+            }
+            if (data) {
+              if (!data.children) this.$set(data, 'children', [])
+              data.children.push(newNode)
+            } else {
+              this.$set(this.data.dicData, this.data.dicData.length, newNode)
+            }
+            this.beforeClose()
+          }
+        }
+      })
+    },
+    beforeClose () {
+      this.$refs.dialogForm.clearValidate()
+      this.dialogForm = {}
+      this.dialogVisible = false
+    }
+  },
+  watch: {
+    'data.required': function (val) {
+      if (val) this.validator.required = { required: true, message: `请选择${this.data.label}` }
+      else this.validator.required = null
+
+      this.generateRule()
+    },
+    'data.multiple': function (val) {
+      if (val) this.data.defaultValue = []
+      else delete this.data.defaultValue
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.custom-tree-node {
+  flex: 1;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  font-size: 14px;
+  padding-right: 8px;
+}
+</style>

+ 110 - 0
packages/config/ueditor.vue

@@ -0,0 +1,110 @@
+<template>
+  <div>
+    <el-form-item label="图片上传地址">
+      <el-input v-model="data.upload.action"
+                placeholder="图片上传地址"></el-input>
+    </el-form-item>
+    <el-form-item label="配置参数">
+      <a href="https://avuejs.com/doc/plugins/ueditor-plugins"
+         target="_blank"
+         style="color: #409EFF;">详细文档</a><br>
+      返回的数据结构层次
+      <el-input v-model="data.upload.props.res"
+                placeholder="返回的数据结构层次"></el-input>
+      返回结构体图片地址字段
+      <el-input v-model="data.upload.props.url"
+                placeholder="返回结构体图片地址字段"></el-input>
+    </el-form-item>
+    <el-form-item label="oss">
+      <el-select v-model="data.upload.oss"
+                 placeholder="oss不写则为普通上传"
+                 clearable>
+        <el-option label="阿里"
+                   value="ali"></el-option>
+        <el-option label="七牛"
+                   value="qiniu"></el-option>
+      </el-select>
+    </el-form-item>
+    <template v-if="data.upload.oss == 'qiniu'">
+      <el-form-item label="七牛oss配置"><br>
+        AK
+        <el-input v-model="data.upload.qiniu.AK"
+                  placeholder="七牛云的密钥(AK)"></el-input>
+        SK
+        <el-input v-model="data.upload.qiniu.SK"
+                  placeholder="七牛云的密钥(SK)"></el-input>
+        scope
+        <el-input v-model="data.upload.qiniu.scope"
+                  placeholder="七牛云存储的空间名"></el-input>
+        url
+        <el-input v-model="data.upload.qiniu.url"
+                  placeholder="空间的自定义域名"></el-input>
+        deadline
+        <el-input v-model="data.upload.qiniu.deadline"
+                  placeholder="token的过期时间"></el-input>
+      </el-form-item>
+    </template>
+    <template v-if="data.upload.oss == 'ali'">
+      <el-form-item label="阿里oss配置"><br>
+        region
+        <el-input v-model="data.upload.ali.region"
+                  placeholder="region"></el-input>
+        endpoint
+        <el-input v-model="data.upload.ali.endpoint"
+                  placeholder="endpoint"></el-input>
+        accessKeyId
+        <el-input v-model="data.upload.ali.accessKeyId"
+                  placeholder="accessKeyId"></el-input>
+        accessKeySecret
+        <el-input v-model="data.upload.ali.accessKeySecret"
+                  placeholder="accessKeySecret"></el-input>
+        bucket
+        <el-input v-model="data.upload.ali.bucket"
+                  placeholder="bucket	"></el-input>
+      </el-form-item>
+    </template>
+    <el-form-item label="是否可见">
+      <el-switch v-model="data.display"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否必填">
+      <el-switch v-model="data.required"></el-switch>
+    </el-form-item>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "config-ueditor",
+  props: ['data'],
+  data () {
+    return {
+      validator: {
+        type: null,
+        required: null,
+        pattern: null,
+        length: null
+      }
+    }
+  },
+  methods: {
+    generateRule () {
+      const rules = [];
+      Object.keys(this.validator).forEach(key => {
+        if (this.validator[key]) rules.push(this.validator[key])
+      })
+      this.data.rules = rules
+    },
+  },
+  watch: {
+    'data.required': function (val) {
+      if (val) this.validator.required = { required: true, message: `${this.data.label}必须填写` }
+      else this.validator.required = null
+      this.generateRule()
+    },
+    'data.upload.oss': function (val) {
+      if (val == 'ali') this.data.upload.qiniu = {}
+      else if (val == 'qiniu') this.data.upload.ali = {}
+    }
+  }
+}
+</script>

+ 203 - 0
packages/config/upload.vue

@@ -0,0 +1,203 @@
+<template>
+  <div>
+    <el-form-item label="上传地址"
+                  v-if="!data.oss">
+      <el-input v-model="data.action"
+                placeholder="上传地址"></el-input>
+    </el-form-item>
+    <el-form-item label="接受文件类型"
+                  v-if="!data.oss">
+      <el-input v-model="data.accept"
+                placeholder="接受文件类型"></el-input>
+    </el-form-item>
+    <el-form-item label="oss">
+      <a href="https://avuejs.com/doc/form/form-upload-qiniu"
+         target="_blank"
+         style="color: #409EFF;">请先按照相关文档配置avue七牛/阿里配置</a><br>
+      <el-select v-model="data.oss"
+                 placeholder="oss不写则为普通上传"
+                 clearable
+                 style="width: 100%">
+        <el-option label="阿里"
+                   value="ali"></el-option>
+        <el-option label="七牛"
+                   value="qiniu"></el-option>
+      </el-select>
+    </el-form-item>
+    <el-form-item label="是否拖拽上传">
+      <el-switch v-model="data.drag"></el-switch>
+    </el-form-item>
+    <el-form-item label="文件列表类型"
+                  v-if="!data.drag">
+      <el-select v-model="data.listType"
+                 placeholder="文件列表类型"
+                 clearable>
+        <el-option label="附件"
+                   value="text"></el-option>
+        <el-option label="照片墙"
+                   value="picture-card"></el-option>
+        <el-option label="头像"
+                   value="picture-img"></el-option>
+        <el-option label="缩略图"
+                   value="picture"></el-option>
+      </el-select>
+    </el-form-item>
+    <el-form-item label="参数设置">
+      <a href="https://avuejs.com/doc/form/form-upload"
+         target="_blank"
+         style="color: #409EFF;">详细文档</a><br>
+      数据对象的图片地址
+      <el-input v-model="data.props.label"
+                placeholder="数据对象的图片地址"></el-input>
+      数据对象的图片名称
+      <el-input v-model="data.props.value"
+                placeholder="数据对象的图片名称"></el-input>
+      请求头
+      <avue-dynamic v-model="data.headers"
+                    :children="option"></avue-dynamic>
+      请求体
+      <avue-dynamic v-model="data.data"
+                    :children="option"></avue-dynamic>
+    </el-form-item>
+    <el-form-item label="服务器返回参数设置"><br>
+      上传成功返回结构体的图片地址
+      <el-input v-model="data.propsHttp.url"
+                placeholder="上传成功返回结构体的图片地址"></el-input>
+      上传成功返回结构体的图片的姓名
+      <el-input v-model="data.propsHttp.name"
+                placeholder="上传成功返回结构体的图片的姓名"></el-input>
+      返回结构体的层次
+      <el-input v-model="data.propsHttp.res"
+                placeholder="返回结构体的层次"></el-input>
+      上传文件流时的名称
+      <el-input v-model="data.propsHttp.fileName"
+                placeholder="fileName"></el-input>
+    </el-form-item>
+    <el-form-item label="是否显示已上传文件列表">
+      <el-switch v-model="data.showFileList"></el-switch>
+    </el-form-item>
+    <el-form-item label="文件大小限制(字节)">
+      <el-input-number v-model="data.filesize"
+                       controls-position="right"
+                       placeholder="文件大小限制(字节)"
+                       :min="0"
+                       style="width: 100%;"></el-input-number>
+    </el-form-item>
+    <el-form-item label="上传限制提示">
+      <el-input v-model="data.tip"
+                placeholder="上传限制提示"></el-input>
+    </el-form-item>
+    <el-form-item label="上传中提示">
+      <el-input v-model="data.loadText"
+                placeholder="上传中提示"></el-input>
+    </el-form-item>
+    <el-form-item label="是否多文件上传">
+      <el-switch v-model="data.multiple"></el-switch>
+    </el-form-item>
+    <el-form-item label="多文件上传数量限制">
+      <el-input-number v-model="data.limit"
+                       controls-position="right"
+                       placeholder="多文件上传数量限制"
+                       :min="1"
+                       style="width: 100%;"></el-input-number>
+    </el-form-item>
+    <el-form-item label="图片水印设置"><br>
+      水印文字
+      <el-input v-model="data.canvasOption.text"
+                placeholder="水印文字"></el-input>
+      字体类型
+      <el-input v-model="data.canvasOption.fontFamily"
+                placeholder="字体类型"></el-input>
+      字体颜色
+      <avue-color placeholder="字体颜色"></avue-color>
+      字体大小
+      <el-input-number v-model="data.canvasOption.fontSize"
+                       controls-position="right"
+                       placeholder="字体大小"
+                       style="width: 100%;"></el-input-number>
+      文字的透明度
+      <el-input-number v-model="data.canvasOption.opacity"
+                       controls-position="right"
+                       placeholder="文字的透明度"
+                       :step="10"
+                       :min="10"
+                       :max="100"
+                       style="width: 100%;"></el-input-number>
+      文字距离图片底部的距离<br>
+      <el-input-number v-model="data.canvasOption.bottom"
+                       controls-position="right"
+                       placeholder="文字距离图片底部的距离"
+                       style="width: 100%;"></el-input-number>
+      文字距离图片右边的距离<br>
+      <el-input-number v-model="data.canvasOption.right"
+                       controls-position="right"
+                       placeholder="文字距离图片右边的距离"
+                       style="width: 100%;"></el-input-number>
+      压缩图片比率<br>
+      <el-input-number v-model="data.canvasOption.ratio"
+                       controls-position="right"
+                       placeholder="压缩图片比率"
+                       :step="0.1"
+                       :min="0"
+                       :max="1"
+                       style="width: 100%;"></el-input-number>
+    </el-form-item>
+    <el-form-item label="是否禁用">
+      <el-switch v-model="data.disabled"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否可见">
+      <el-switch v-model="data.display"></el-switch>
+    </el-form-item>
+    <el-form-item label="是否必填">
+      <el-switch v-model="data.required"></el-switch>
+    </el-form-item>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "config-upload",
+  props: ['data'],
+  data () {
+    return {
+      validator: {
+        type: null,
+        required: null,
+        pattern: null,
+        length: null
+      },
+      option: {
+        column: [{
+          type: 'input',
+          prop: 'key',
+          label: 'key'
+        }, {
+          type: 'input',
+          prop: 'value',
+          label: 'value'
+        }]
+      },
+    }
+  },
+  methods: {
+    generateRule () {
+      const rules = [];
+      Object.keys(this.validator).forEach(key => {
+        if (this.validator[key]) rules.push(this.validator[key])
+      })
+      this.data.rules = rules
+    },
+  },
+  watch: {
+    'data.required': function (val) {
+      if (val) this.validator.required = { required: true, message: `${this.data.label}必须填写` }
+      else this.validator.required = null
+
+      this.generateRule()
+    },
+    'data.drag': function (val) {
+      if (val) delete this.data.listType
+    }
+  }
+}
+</script>

+ 314 - 0
packages/fieldsConfig.js

@@ -0,0 +1,314 @@
+export default [
+  {
+    title: '布局字段',
+    list: [{
+      type: 'group',
+      label: '分组',
+      icon: 'icon-group',
+      display: true,
+      children: {
+        column: []
+      }
+    }, {
+      type: 'dynamic',
+      label: '子表单',
+      icon: 'icon-table',
+      span: 24,
+      display: true,
+      children: {
+        align: 'center',
+        headerAlign: 'center',
+        addBtn: true,
+        delBtn: true,
+        column: []
+      }
+    }]
+  },
+  {
+    title: '输入字段',
+    list: [{
+      type: 'input',
+      label: '单行文本',
+      icon: 'icon-input',
+      span: 24,
+      display: true
+    }, {
+      type: 'password',
+      label: '密码',
+      icon: 'icon-password',
+      span: 24,
+      display: true
+    }, {
+      type: 'textarea',
+      label: '多行文本',
+      icon: 'icon-textarea',
+      span: 24,
+      display: true
+    }, {
+      type: 'number',
+      label: '计数器',
+      icon: 'icon-number',
+      span: 24,
+      display: true
+    }, {
+      type: 'url',
+      label: '超链接',
+      icon: 'icon-url',
+      span: 24,
+      display: true
+    }, {
+      type: 'array',
+      label: '数组',
+      icon: 'icon-array',
+      span: 24,
+      display: true,
+    }, {
+      type: 'img',
+      label: '图片',
+      icon: 'icon-img',
+      span: 24,
+      display: true,
+    }]
+  },
+  {
+    title: '选择字段',
+    list: [{
+      type: 'radio',
+      label: '单选框组',
+      icon: 'icon-radio',
+      dicData: [
+        { label: '选项一', value: 0 },
+        { label: '选项二', value: 1 },
+        { label: '选项三', value: 2 },
+      ],
+      span: 24,
+      display: true,
+      dicOption: 'static'
+    }, {
+      type: 'checkbox',
+      label: '多选框组',
+      icon: 'icon-checkbox',
+      dicData: [
+        { label: '选项一', value: 0 },
+        { label: '选项二', value: 1 },
+        { label: '选项三', value: 2 },
+      ],
+      span: 24,
+      display: true,
+      dicOption: 'static'
+    }, {
+      type: 'select',
+      label: '下拉选择器',
+      icon: 'icon-select',
+      dicData: [
+        { label: '选项一', value: 0 },
+        { label: '选项二', value: 1 },
+        { label: '选项三', value: 2 },
+      ],
+      span: 24,
+      display: true,
+      dicOption: 'static'
+    }, {
+      type: 'cascader',
+      label: '级联选择器',
+      icon: 'icon-link',
+      span: 24,
+      display: true,
+      dicData: [
+        {
+          label: '选项一',
+          value: 0,
+          children: [{
+            label: '选项1-1',
+            value: 11,
+          }, {
+            label: '选项1-2',
+            value: 12,
+          }]
+        },
+        { label: '选项二', value: 1 },
+        { label: '选项三', value: 2 },
+      ],
+      showAllLevels: true,
+      dicOption: 'static',
+      separator: "/"
+    }, {
+      type: 'tree',
+      label: '树形选择器',
+      icon: 'icon-tree',
+      span: 24,
+      display: true,
+      dicOption: 'static',
+      dicData: [
+        {
+          label: '选项一',
+          value: 0,
+          children: [{
+            label: '选项1-1',
+            value: 11,
+          }, {
+            label: '选项1-2',
+            value: 12,
+          }]
+        },
+        { label: '选项二', value: 1 },
+        { label: '选项三', value: 2 },
+      ],
+      parent: true
+    }]
+  },
+  {
+    title: '上传字段',
+    list: [{
+      type: 'upload',
+      label: '上传',
+      icon: 'icon-upload',
+      span: 24,
+      display: true,
+      showFileList: true,
+      multiple: true,
+      limit: 10,
+      props: {},
+      propsHttp: {},
+      canvasOption: {},
+      headers: [],
+      data: []
+    }],
+  },
+  {
+    title: '日期时间字段',
+    list: [{
+      type: 'year',
+      label: '年',
+      icon: 'icon-year',
+      span: 24,
+      display: true,
+      format: 'yyyy',
+      valueFormat: 'yyyy'
+    }, {
+      type: 'month',
+      label: '月',
+      icon: 'icon-month',
+      span: 24,
+      display: true,
+      format: 'MM',
+      valueFormat: 'MM'
+    }, {
+      type: 'week',
+      label: '周',
+      icon: 'icon-week',
+      span: 24,
+      display: true,
+      format: 'yyyy 第 WW 周',
+    }, {
+      type: 'date',
+      label: '日期',
+      icon: 'icon-date',
+      span: 24,
+      display: true,
+      format: 'yyyy-MM-dd',
+      valueFormat: 'yyyy-MM-dd'
+    }, {
+      type: 'time',
+      label: '时间',
+      icon: 'icon-time',
+      span: 24,
+      display: true,
+      format: 'HH:mm:ss',
+      valueFormat: 'HH:mm:ss'
+    }, {
+      type: 'datetime',
+      label: '日期时间',
+      icon: 'icon-datetime',
+      span: 24,
+      display: true,
+      format: 'yyyy-MM-dd HH:mm:ss',
+      valueFormat: 'yyyy-MM-dd HH:mm:ss'
+    }, {
+      type: 'daterange',
+      label: '日期范围',
+      icon: 'icon-date-range',
+      span: 24,
+      display: true,
+      format: 'yyyy-MM-dd',
+      valueFormat: 'yyyy-MM-dd'
+    }, {
+      type: 'timerange',
+      label: '时间范围',
+      icon: 'icon-time-range',
+      span: 24,
+      display: true,
+      format: 'HH:mm:ss',
+      valueFormat: 'HH:mm:ss'
+    }, {
+      type: 'datetimerange',
+      label: '日期时间范围',
+      icon: 'icon-datetime-range',
+      span: 24,
+      display: true,
+      format: 'yyyy-MM-dd HH:mm:ss',
+      valueFormat: 'yyyy-MM-dd HH:mm:ss'
+    }],
+  },
+  {
+    title: '插件字段(请自行引入avue插件)',
+    list: [{
+      type: 'ueditor',
+      component: 'ueditor',
+      label: '富文本',
+      icon: 'icon-richtext',
+      span: 24,
+      display: true,
+      options: {
+        action: '',
+        oss: '',
+        props: {},
+        ali: {},
+        qiniu: {}
+      }
+    }, {
+      type: 'map',
+      component: 'map',
+      label: '坐标拾取器',
+      icon: 'icon-map',
+      span: 24,
+      display: true,
+    }],
+  },
+  {
+    title: '其他字段',
+    list: [{
+      type: 'switch',
+      label: '开关',
+      icon: 'icon-switch',
+      span: 24,
+      display: true,
+      valueDefault: 0,
+      dicData: [{ label: '', value: '0' }, { label: '', value: '1' }]
+    }, {
+      type: 'rate',
+      label: '评价',
+      icon: 'icon-star',
+      span: 24,
+      display: true,
+      max: 5,
+      valueDefault: 0,
+      texts: ['极差', '失望', '一般', '满意', '惊喜'],
+      colors: ['#99A9BF', '#F7BA2A', '#FF9900'],
+    }, {
+      type: 'slider',
+      label: '滑块',
+      icon: 'icon-slider',
+      span: 24,
+      display: true,
+      min: 0,
+      max: 10
+    }, {
+      type: 'color',
+      label: '颜色选择器',
+      icon: 'icon-color',
+      span: 24,
+      display: true
+    }]
+  }
+]

+ 9 - 0
packages/index.js

@@ -0,0 +1,9 @@
+import Config from './config'
+import FormDesign from './index.vue'
+
+export default {
+  install (Vue) {
+    Vue.use(Config)
+    Vue.component('Avue' + FormDesign.name, FormDesign);
+  }
+}

+ 609 - 0
packages/index.vue

@@ -0,0 +1,609 @@
+<template>
+  <div class="form-designer">
+    <el-container>
+      <!-- 左侧字段 -->
+      <el-aside :width="leftWidth">
+        <div class="fields-list">
+          <div v-for="(field, index) in fields"
+               :key="index">
+            <div v-if="!field.disabled">
+              <div class="field-title">{{field.title}}</div>
+              <draggable tag="ul"
+                         :list="field.list"
+                         :group="{ name: 'form', pull: 'clone', put: false }"
+                         ghost-class="ghost"
+                         :sort="false">
+                <li class="field-label"
+                    v-for="(item, index) in field.list"
+                    :key="index">
+                  <a>
+                    <i class="icon iconfont"
+                       :class="item.icon"></i>
+                    <span>{{item.label}}</span>
+                  </a>
+                </li>
+              </draggable>
+            </div>
+            <div v-else>
+              <div class="field-title">{{field.title}}
+                <span class="danger">(开发中)</span>
+              </div>
+              <ul>
+                <li class="field-label-disabled"
+                    v-for="(item, index) in field.list"
+                    :key="index">
+                  <a>
+                    <i class="icon iconfont"
+                       :class="item.icon"></i>
+                    <span>{{item.label}}</span>
+                  </a>
+                </li>
+              </ul>
+            </div>
+          </div>
+        </div>
+      </el-aside>
+      <!-- 中间主布局 -->
+      <el-container class="widget-container"
+                    direction="vertical">
+        <el-header class="widget-container-header">
+          <el-button type="text"
+                     size="medium"
+                     icon="el-icon-document"
+                     @click="handleAvueDoc">Avue文档</el-button>
+          <el-button type="text"
+                     size="medium"
+                     icon="el-icon-upload2"
+                     @click="importJsonVisible = true">导入JSON</el-button>
+          <el-button type="text"
+                     size="medium"
+                     icon="el-icon-download"
+                     @click="handleGenerateJson">生成JSON</el-button>
+          <el-button type="text"
+                     size="medium"
+                     icon="el-icon-view"
+                     @click="handlePreview">预览</el-button>
+          <el-button class="danger"
+                     type="text"
+                     size="medium"
+                     icon="el-icon-delete"
+                     @click="handleClear">清空</el-button>
+        </el-header>
+        <el-main :style="{background: widgetForm.column.length == 0 ? `url(${widgetEmpty}) no-repeat 50%`: ''}">
+          <widget-form ref="widgetForm"
+                       :data="widgetForm"
+                       :select.sync="widgetFormSelect"></widget-form>
+        </el-main>
+      </el-container>
+      <!-- 右侧配置 -->
+      <el-aside class="widget-config-container"
+                :width="asideRightWidth">
+        <el-tabs v-model="configTab"
+                 stretch>
+          <el-tab-pane label="字段属性"
+                       name="widget"
+                       style="padding: 0 10px;">
+            <widget-config :data="widgetFormSelect"></widget-config>
+          </el-tab-pane>
+          <el-tab-pane label="表单属性"
+                       name="form"
+                       lazy
+                       style="padding: 0 10px;">
+            <form-config :data="widgetForm"></form-config>
+          </el-tab-pane>
+        </el-tabs>
+      </el-aside>
+      <!-- 弹窗 -->
+      <!-- 导入JSON -->
+      <el-drawer title="导入JSON"
+                 :visible.sync="importJsonVisible"
+                 size="50%"
+                 destroy-on-close>
+        <v-json-editor v-model="importJson"
+                       height="82vh"></v-json-editor>
+        <div class="drawer-foot">
+          <el-button size="medium"
+                     type="primary"
+                     @click="handleImportJsonSubmit">确定</el-button>
+          <el-button size="medium"
+                     type="danger"
+                     @click="importJsonVisible = false">取消</el-button>
+        </div>
+      </el-drawer>
+      <!-- 生成JSON -->
+      <el-drawer title="生成JSON"
+                 :visible.sync="generateJsonVisible"
+                 size="50%"
+                 destroy-on-close>
+        <v-json-editor v-model="widgetFormPreview"
+                       height="82vh"></v-json-editor>
+        <div class="drawer-foot">
+          <el-button size="medium"
+                     type="primary"
+                     @click="handleGenerate">生成</el-button>
+          <el-popover placement="top"
+                      trigger="hover"
+                      popper-class="popper-bo"
+                      width="250px">
+            <el-button size="medium"
+                       type="primary"
+                       slot="reference"
+                       @click="handleCopy"
+                       style="margin-left: 10px;">复制</el-button>
+            <div>
+              <el-form label-width="180px"
+                       label-position="left">
+                <el-alert :closable="false">
+                  在没有开启美化的情况下,当前编辑器内可见的文本,就是复制得到的内容。<br>
+                  如有需要,您可以开启美化,然后选取适合自己的美化配置。
+                  <a href="https://www.npmjs.com/package/csvjson-json_beautifier"
+                     target="_blank">参考资料</a>
+                </el-alert>
+                <el-form-item label="是否开启美化">
+                  <el-switch v-model="beautifierOptions.enabled" />
+                </el-form-item>
+                <el-form-item label="缩进长度-空格数量">
+                  <el-slider v-model="beautifierOptions.space"
+                             show-stops
+                             :marks="{ 1: '1', 2: '2', 3: '3', 4: '4' }"
+                             :min="1"
+                             :max="4"
+                             :step="1"></el-slider>
+                </el-form-item>
+                <el-form-item label="引号类型">
+                  <el-switch v-model="beautifierOptions.quoteType"
+                             active-value="single"
+                             inactive-value="double"
+                             active-text="单引号"
+                             inactive-text="双引号"></el-switch>
+                </el-form-item>
+                <el-form-item label="移除key的引号">
+                  <el-switch v-model="beautifierOptions.dropQuotesOnKeys"></el-switch>
+                </el-form-item>
+                <el-form-item label="移除数字字符串的引号">
+                  <el-switch v-model="beautifierOptions.dropQuotesOnNumbers"></el-switch>
+                </el-form-item>
+              </el-form>
+            </div>
+          </el-popover>
+        </div>
+      </el-drawer>
+      <!-- 预览 -->
+      <el-drawer title="预览"
+                 :visible.sync="previewVisible"
+                 size="60%"
+                 :before-close="handleBeforeClose">
+        <avue-form v-if="previewVisible"
+                   ref="form"
+                   class="preview-form"
+                   :option="widgetFormPreview"
+                   v-model="widgetModels"></avue-form>
+        <div class="drawer-foot">
+          <el-button size="medium"
+                     type="primary"
+                     @click="handlePreviewSubmit">确定</el-button>
+          <el-button size="medium"
+                     type="danger"
+                     @click="handleBeforeClose">取消</el-button>
+        </div>
+      </el-drawer>
+    </el-container>
+  </div>
+</template>
+
+<script>
+import Draggable from 'vuedraggable'
+import VJsonEditor from 'v-jsoneditor'
+import fields from './fieldsConfig.js'
+import WidgetForm from './WidgetForm'
+import FormConfig from './FormConfig'
+import WidgetConfig from './WidgetConfig'
+import widgetEmpty from './assets/widget-empty.png'
+import beautifier from 'csvjson-json_beautifier'
+
+export default {
+  name: "FormDesign",
+  components: { Draggable, VJsonEditor, WidgetForm, FormConfig, WidgetConfig },
+  props: {
+    options: {
+      type: Object,
+      default: () => {
+        return {
+          column: []
+        }
+      }
+    },
+    storage: {
+      type: Boolean,
+      default: false
+    },
+    asideLeftWidth: {
+      type: [String, Number],
+      default: '270px'
+    },
+    asideRightWidth: {
+      type: [String, Number],
+      default: '380px'
+    }
+  },
+  watch: {
+    widgetForm: {
+      handler (val) {
+        if (this.storage) {
+          if (val.column && val.column.length > 0) localStorage.setItem('avue-form', JSON.stringify(val))
+          else localStorage.removeItem('avue-form')
+        }
+      },
+      deep: true
+    },
+    beautifierOptions: {
+      handler (val) {
+        if (this.storage) {
+          localStorage.setItem('avue-form-beautifier-options', JSON.stringify(val))
+        }
+      },
+      deep: true
+    },
+    options: {
+      handler (val) {
+        this.transAvueOptionsToFormDesigner(val).then(res => {
+          this.widgetForm = { ...this.widgetForm, ...res }
+        })
+      },
+      deep: true
+    }
+  },
+  computed: {
+    leftWidth () {
+      if (typeof this.asideLeftWidth == 'string') {
+        return this.asideLeftWidth
+      } else {
+        return `${this.asideLeftWidth}px`
+      }
+    },
+    rightWidth () {
+      if (typeof this.asideRightWidth == 'string') {
+        return this.asideRightWidth
+      } else {
+        return `${this.asideRightWidth}px`
+      }
+    }
+  },
+  data () {
+    return {
+      widgetEmpty,
+      fields,
+      widgetForm: {
+        column: [],
+        labelPosition: 'left',
+        labelSuffix: ':',
+        labelWidth: 120,
+        gutter: 0,
+        menuBtn: true,
+        submitBtn: true,
+        submitSize: 'medium',
+        submitText: '提交',
+        emptyBtn: true,
+        emptySize: 'medium',
+        emptyText: '清空',
+        menuPosition: 'center'
+      },
+      widgetFormPreview: {},
+      configTab: 'widget',
+      widgetFormSelect: {},
+      previewVisible: false,
+      generateJsonVisible: false,
+      importJsonVisible: false,
+      importJson: {},
+      widgetModels: {},
+      configOption: {},
+      beautifierOptions: {
+        enabled: false,
+        space: 2,
+        quoteType: 'single',
+        dropQuotesOnKeys: true,
+        dropQuotesOnNumbers: false
+      }
+    }
+  },
+  mounted () {
+    this.handleLoadCss();
+    this.handleLoadStorage();
+    this.loadBeautifierOptions();
+  },
+  methods: {
+    // 组件初始化时加载本地存储中的options(需开启storage),若不存在则读取用户配置的options
+    handleLoadStorage () {
+      if (this.storage) {
+        const form = localStorage.getItem('avue-form')
+        if (form) this.transAvueOptionsToFormDesigner(JSON.parse(form)).then(data => this.widgetForm = data)
+      } else this.transAvueOptionsToFormDesigner({ ...this.widgetForm, ...this.options }).then(data => this.widgetForm = data)
+    },
+    // 获取JSON格式化属性
+    loadBeautifierOptions () {
+      const bo = localStorage.getItem('avue-form-beautifier-options')
+      if (bo) this.beautifierOptions = JSON.parse(bo)
+    },
+    // 加载阿里iconfront
+    handleLoadCss () {
+      const url = '//at.alicdn.com/t/font_1254447_rwaizg76pz.css'
+      const link = document.createElement('link');
+      link.rel = 'stylesheet';
+      link.href = url;
+      window.document.head.appendChild(link)
+    },
+    // Avue文档链接
+    handleAvueDoc () {
+      window.open('https://avuejs.com/doc/form/form-doc', '_blank')
+    },
+    // 预览 - 弹窗
+    handlePreview () {
+      if (!this.widgetForm.column || this.widgetForm.column.length == 0) this.$message.error("没有需要展示的内容")
+      else {
+        this.transformToAvueOptions(this.widgetForm).then(data => {
+          this.widgetFormPreview = data
+          this.previewVisible = true
+        })
+      }
+    },
+    // 导入JSON - 弹窗 - 确定
+    handleImportJsonSubmit () {
+      try {
+        this.transAvueOptionsToFormDesigner(this.importJson).then(res => {
+          this.widgetForm = res
+          this.importJsonVisible = false
+        })
+      } catch (e) {
+        this.$message.error(e.message)
+      }
+    },
+    // 生成JSON - 弹窗
+    handleGenerateJson () {
+      this.transformToAvueOptions(this.widgetForm).then(data => {
+        this.widgetFormPreview = data
+        this.generateJsonVisible = true
+      })
+    },
+    // 生成JSON - 弹窗 - 确定
+    handleGenerate () {
+      this.transformToAvueOptions(this.widgetForm).then(data => {
+        this.$emit('submit', data)
+      })
+    },
+    // 生成JSON - 弹窗 - 拷贝
+    handleCopy () {
+      this.$Clipboard({
+        text: this.getCopyContent()
+      }).then(() => {
+        this.$message.success('复制成功')
+      }).catch(() => {
+        this.$message.error('复制失败')
+      });
+    },
+    // 预览 - 弹窗 - 确定
+    handlePreviewSubmit () {
+      this.$refs.form.validate((valid) => {
+        if (valid) this.$alert(this.widgetModels).catch(() => {
+        })
+      })
+    },
+    // 预览 - 弹窗 - 关闭前
+    handleBeforeClose () {
+      this.$refs.form.resetForm();
+      this.previewVisible = false
+    },
+    // 清空
+    handleClear () {
+      if (this.widgetForm && this.widgetForm.column && this.widgetForm.column.length > 0) {
+        this.$confirm('确定要清空吗?', '警告', {
+          type: 'warning'
+        }).then(() => {
+          this.widgetForm = { column: [] }
+          this.widgetFormSelect = {}
+        }).catch(() => {
+        })
+      } else this.$message.error("没有需要清空的内容")
+    },
+    /**
+     * 获取需要复制的内容
+     * @return {String}
+     */
+    getCopyContent () {
+      if (this.beautifierOptions.enabled) return beautifier(this.widgetFormPreview, this.beautifierOptions)
+      else return JSON.stringify(this.widgetFormPreview, null, 2)
+    },
+    // 表单设计器配置项 转化为 Avue配置项
+    transformToAvueOptions (obj) {
+      return new Promise((resolve, reject) => {
+        try {
+          const data = this.deepClone(obj)
+          for (let i = 0; i < data.column.length; i++) {
+            const col = data.column[i]
+            if (col.type == 'dynamic' && col.children && col.children.column && col.children.column.length > 0) {
+              const c = col.children.column;
+              c.forEach(item => {
+                delete item.subfield
+              })
+              this.transformToAvueOptions(col.children).then(res => {
+                col.children = res
+              })
+            } else if (col.type == 'group') {
+              if (!data.group) data.group = []
+
+              const group = {
+                label: col.label,
+                icon: col.icon,
+                prop: col.prop,
+              }
+              this.transformToAvueOptions(col.children).then(res => {
+                group.column = res.column
+                data.group.push(group)
+              })
+              data.column.splice(i, 1)
+              i--
+            } else if (['checkbox', 'radio', 'tree', 'cascader', 'select'].includes(col.type)) {
+              if (col.dicOption == 'static') {
+                delete col.dicUrl
+                delete col.dicMethod
+                delete col.dicQuery
+              } else if (col.dicOption == 'remote') {
+                delete col.dicData
+                if (col.dicQuery && col.dicQuery.length > 0) {
+                  const query = {}
+                  col.dicQuery.forEach(q => {
+                    if (q.key && q.value) query[q.key] = q.value
+                  })
+                  col.dicQuery = query
+                } else delete col.dicQuery
+              }
+              delete col.dicOption
+            } else if (['upload'].includes(col.type)) {
+              if (col.headers && col.headers.length > 0) {
+                const headers = {}
+                col.headers.forEach(h => {
+                  if (h.key && h.value) headers[h.key] = h.value
+                })
+                col.headers = headers
+              }
+
+              if (col.data && col.data.length > 0) {
+                const data = {}
+                col.data.forEach(h => {
+                  if (h.key && h.value) data[h.key] = h.value
+                })
+                col.data = data
+              }
+            }
+          }
+          resolve(data)
+        } catch (e) {
+          reject(e)
+        }
+      })
+    },
+    // Avue配置项 转化为 表单设计器配置项
+    transAvueOptionsToFormDesigner (obj) {
+      const data = this.deepClone(obj)
+      return new Promise((resolve, reject) => {
+        try {
+          if (data.column && data.column.length > 0) {
+            data.column.forEach(col => {
+              if (col.type == 'dynamic' && col.children && col.children.column && col.children.column.length > 0) {
+                const c = col.children.column;
+                c.forEach(item => {
+                  item.subfield = true
+                })
+                this.transAvueOptionsToFormDesigner(col.children).then(res => {
+                  col.children = res
+                })
+              } else if (['checkbox', 'radio', 'tree', 'cascader', 'select'].includes(col.type)) {
+                if (!col.dicData && col.dicQuery && typeof col.dicQuery == 'object') {
+                  const arr = []
+                  for (let key in col.dicQuery) {
+                    arr.push({
+                      key,
+                      value: col.dicQuery[key],
+                      $cellEdit: true
+                    })
+                  }
+                  col.dicQuery = arr
+                }
+                if (col.dicUrl) col.dicOption = 'remote'
+                else col.dicOption = 'static'
+                if (!col.dicData) col.dicData = []
+              } else if (['upload'].includes(col.type)) {
+                if (col.headers && typeof col.headers == 'object') {
+                  const arr = []
+                  for (let key in col.headers) {
+                    arr.push({
+                      key,
+                      value: col.headers[key],
+                      $cellEdit: true
+                    })
+                  }
+                  col.headers = arr
+                }
+
+                if (col.data && typeof col.data == 'object') {
+                  const arr = []
+                  for (let key in col.data) {
+                    arr.push({
+                      key,
+                      value: col.data[key],
+                      $cellEdit: true
+                    })
+                  }
+                  col.data = arr
+                }
+              }
+            })
+          }
+          if (data.group && data.group.length > 0) {
+            for (let i = 0; i < data.group.length; i++) {
+              if (!data.column) data.column = []
+              const col = data.group[i]
+
+              const group = {
+                type: 'group',
+                label: col.label,
+                icon: col.icon,
+                prop: col.prop,
+              }
+              this.transAvueOptionsToFormDesigner(col).then(res => {
+                group.children = res
+                data.column.push(group)
+              })
+            }
+            delete data.group
+          }
+          resolve(data)
+        } catch (e) {
+          reject(e)
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss">
+@import "./styles/index.scss";
+
+.drawer-foot {
+  position: absolute;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  padding: 20px;
+  display: flex;
+
+  button {
+    width: 50%;
+  }
+}
+
+.drawer-foot > span {
+  display: inline-block;
+  width: 50%;
+  button {
+    width: 100%;
+  }
+}
+
+.popper-bo {
+  .el-alert {
+    margin-bottom: 10px;
+  }
+}
+
+.preview-form {
+  overflow-y: scroll;
+  height: 83vh;
+}
+
+.widget-config-container {
+  .avue-group__item {
+    padding: 0;
+  }
+}
+</style>

+ 568 - 0
packages/styles/index.scss

@@ -0,0 +1,568 @@
+$primary-color: #409eff;
+$primary-active-color: #ecf5ff;
+$primary-background-color: #ecf8ff;
+
+*,
+:after,
+:before {
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+}
+
+body {
+  margin: 0 !important;
+}
+
+#app {
+  font-family: 'Avenir', Helvetica, Arial, sans-serif;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  color: #2c3e50;
+  min-height: 100%;
+  height: 100%;
+}
+
+.form-designer {
+  height: 100%;
+
+  .fields-list {
+    padding: 10px 0;
+    width: 100%;
+    height: 100%;
+
+    .field-title {
+      padding: 8px 12px;
+      font-size: 13px;
+    }
+
+    ul {
+      position: relative;
+      overflow: hidden;
+      padding: 0 10px 10px;
+      margin: 0;
+    }
+
+    .field-label {
+      font-size: 12px;
+      display: block;
+      width: 48%;
+      line-height: 26px;
+      position: relative;
+      float: left;
+      left: 0;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+      margin: 1%;
+      color: #333;
+      border: 1px solid #f4f6fc;
+
+      &:hover {
+        color: $primary-color;
+        border: 1px dashed $primary-color;
+      }
+
+      & > a {
+        display: block;
+        cursor: move;
+        background: #f4f6fc;
+        border: 1px solid #f4f6fc;
+
+        .icon {
+          margin-right: 6px;
+          margin-left: 8px;
+          font-size: 14px;
+          display: inline-block;
+          vertical-align: middle;
+        }
+
+        span {
+          display: inline-block;
+          vertical-align: middle;
+        }
+      }
+    }
+
+    .field-label-disabled {
+      font-size: 12px;
+      display: block;
+      width: 48%;
+      line-height: 26px;
+      position: relative;
+      float: left;
+      left: 0;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+      margin: 1%;
+      color: #333;
+      border: 1px solid #f4f6fc;
+
+      &:hover {
+        color: gray;
+        border: 1px dashed gray;
+      }
+
+      & > a {
+        display: block;
+        cursor: not-allowed;
+        background: #f4f6fc;
+        border: 1px solid #f4f6fc;
+
+        .icon {
+          margin-right: 6px;
+          margin-left: 8px;
+          font-size: 14px;
+          display: inline-block;
+          vertical-align: middle;
+        }
+
+        span {
+          display: inline-block;
+          vertical-align: middle;
+        }
+      }
+    }
+  }
+
+  .widget-container {
+    border-left: 1px solid #e0e0e0;
+    border-right: 1px solid #e0e0e0;
+
+    .widget-container-header {
+      height: 45px !important;
+      line-height: 45px;
+      font-size: 18px;
+      border-bottom: solid 2px #e4e7ed;
+      text-align: right;
+    }
+
+    .el-main {
+      padding: 0;
+      position: relative;
+    }
+  }
+
+  .widget-form-container {
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+
+    .widget-form-list {
+      height: 100%;
+      min-height: calc(100vh - 45px);
+      padding-bottom: 20px;
+
+      .widget-form-item {
+        padding: 5px 10px 18px;
+        margin: 0;
+        position: relative;
+        border-left: 5px solid transparent;
+
+        &.required {
+          .el-form-item__label::before {
+            content: '*';
+            color: #f56c6c;
+            margin-right: 4px;
+          }
+        }
+
+        &:after {
+          position: absolute;
+          left: 0;
+          right: 0;
+          bottom: 0;
+          top: 0;
+          display: block;
+          z-index: 1001;
+        }
+
+        &:hover {
+          background: $primary-background-color;
+          cursor: move;
+        }
+
+        &.active {
+          border-left: 3px solid $primary-color;
+          background: $primary-active-color;
+        }
+
+        .widget-action-delete {
+          position: absolute;
+          right: 10px;
+          bottom: -32px;
+          z-index: 1002;
+        }
+
+        .widget-action-clone {
+          position: absolute;
+          right: 50px;
+          bottom: -32px;
+          z-index: 1002;
+        }
+      }
+
+      .widget-form-table {
+        position: relative;
+        padding: 2px;
+        float: left;
+        width: 100%;
+
+        &__content {
+          display: flex;
+          padding: 10px 5px;
+          width: 100%;
+          height: 100%;
+          overflow-y: hidden;
+          outline: 1px dashed #ccc;
+          outline-offset: -1px;
+          min-height: 103px;
+
+          .ghost {
+            background: white;
+            border-left: 5px solid $primary-color;
+            box-sizing: border-box;
+            font-size: 0;
+            content: '';
+            overflow: hidden;
+            padding: 0 !important;
+            position: relative;
+            outline: none 0;
+            height: 100%;
+            min-height: 90px;
+            width: 0 !important;
+            min-width: 0 !important;
+            margin: 1px 2px 0 2px;
+          }
+        }
+
+        &__item {
+          position: relative;
+          min-width: 33.3%;
+          width: 33.3%;
+          padding: 1px;
+          height: 100%;
+
+          &.required {
+            .el-table__header .cell::before {
+              content: '*';
+              color: #f56c6c;
+              margin-right: 4px;
+            }
+          }
+
+          &.active {
+            outline: 1px solid $primary-color;
+            outline-offset: -1px;
+          }
+
+          &:hover {
+            outline: 1px solid $primary-color;
+            outline-offset: -1px;
+            cursor: move;
+          }
+
+          &:after {
+            position: absolute;
+            left: 0;
+            right: 0;
+            bottom: 0;
+            top: 0;
+            display: block;
+            content: '';
+            z-index: 1001;
+          }
+
+          .widget-table-action-delete {
+            position: absolute;
+            right: 0;
+            bottom: 0;
+            z-index: 1002;
+          }
+
+          .widget-table-action-clone {
+            position: absolute;
+            right: 30px;
+            bottom: 0;
+            z-index: 1002;
+
+            i {
+              font-size: 10px;
+            }
+          }
+
+          .el-button--small.is-circle {
+            padding: 5px;
+          }
+        }
+
+        &.active {
+          border-left: 3px solid $primary-color;
+          background: $primary-active-color;
+        }
+
+        &:hover {
+          background: $primary-background-color;
+          cursor: move;
+        }
+
+        .widget-action-delete {
+          position: absolute;
+          right: 10px;
+          bottom: -12px;
+          z-index: 1001;
+        }
+
+        .widget-action-clear {
+          position: absolute;
+          right: 50px;
+          bottom: -12px;
+          z-index: 1001;
+        }
+
+        .widget-action-clone {
+          position: absolute;
+          right: 90px;
+          bottom: -12px;
+          z-index: 1001;
+        }
+      }
+
+      .widget-form-group {
+        position: relative;
+        width: 100%;
+        float: left;
+        padding: 2px;
+
+        &__head {
+          margin: 10px;
+        }
+
+        &__body {
+          min-height: 150px;
+          height: 100%;
+          outline: 1px dashed #ccc;
+          outline-offset: -1px;
+          overflow: hidden;
+          padding-bottom: 15px;
+
+          .ghost {
+            background: white;
+            border-left: 5px solid $primary-color;
+            box-sizing: border-box;
+            font-size: 0;
+            content: '';
+            overflow: hidden;
+            padding: 0 !important;
+            position: relative;
+            outline: none 0;
+            height: 100%;
+            min-height: 57px;
+            width: 0 !important;
+            min-width: 0 !important;
+            margin: 1px 2px 0 2px;
+          }
+        }
+
+        &__item {
+          padding: 10px;
+          margin: 3px;
+          position: relative;
+          border-left: 5px solid transparent;
+          background: white;
+
+          &.required {
+            .el-form-item__label::before {
+              content: '*';
+              color: #f56c6c;
+              margin-right: 4px;
+            }
+          }
+
+          &.active {
+            outline: 1px solid $primary-color;
+            outline-offset: -1px;
+          }
+
+          &:hover {
+            outline: 1px solid $primary-color;
+            outline-offset: -1px;
+            cursor: move;
+          }
+
+          &:after {
+            position: absolute;
+            left: 0;
+            right: 0;
+            bottom: 0;
+            top: 0;
+            display: block;
+            content: '';
+            z-index: 1001;
+          }
+
+          &--delete {
+            position: absolute;
+            right: 0;
+            bottom: -24px;
+            z-index: 1002;
+          }
+
+          &--clone {
+            position: absolute;
+            right: 34px;
+            bottom: -24px;
+            z-index: 1002;
+          }
+        }
+
+        &.active {
+          border-left: 3px solid $primary-color;
+          background: $primary-active-color;
+        }
+
+        &:hover {
+          background: $primary-background-color;
+          cursor: move;
+        }
+
+        .widget-action-delete {
+          position: absolute;
+          right: 10px;
+          bottom: -12px;
+          z-index: 1001;
+        }
+
+        .widget-action-clear {
+          position: absolute;
+          right: 50px;
+          bottom: -12px;
+          z-index: 1001;
+        }
+
+        .widget-action-clone {
+          position: absolute;
+          right: 90px;
+          bottom: -12px;
+          z-index: 1001;
+        }
+      }
+
+      .iconfont {
+        font-size: 13px;
+      }
+
+      .el-button--small.is-circle {
+        padding: 7px;
+      }
+    }
+
+    .ghost {
+      background: white;
+      border-top: 5px solid $primary-color;
+      box-sizing: border-box;
+      font-size: 0;
+      content: '';
+      overflow: hidden;
+      padding: 0 !important;
+      position: relative;
+      outline: none 0;
+      height: 0 !important;
+      width: 100%;
+      margin: 2px 0;
+    }
+  }
+
+  .widget-config-container {
+    margin-top: 5px;
+    //position: relative;
+
+    .el-tabs__header {
+      position: fixed;
+      top: 5px;
+      width: 380px;
+      height: 45px;
+      background: white;
+      z-index: 1000;
+    }
+
+    .el-tabs__content {
+      margin-top: 50px;
+    }
+
+    .widget-config {
+      .el-tabs__header {
+        position: relative;
+        display: block;
+        top: 0;
+        margin: 0;
+      }
+
+      .el-tabs__content {
+        margin-top: 0;
+      }
+
+      .ghost {
+        background: #fff;
+        border: 1px dashed $primary-color;
+      }
+
+      ul {
+        margin: 0;
+        padding: 0;
+
+        li {
+          display: flex;
+          align-items: center;
+          width: 100%;
+
+          .ghost {
+            list-style: none;
+            font-size: 0;
+            height: 35px;
+          }
+        }
+      }
+    }
+    .avue-group__item {
+      padding: 0;
+    }
+  }
+
+  .el-container {
+    height: 100vh;
+
+    .el-main {
+      height: calc(100% - 45px);
+    }
+  }
+
+  .danger {
+    color: #f56c6c;
+  }
+
+  .warning {
+    color: #e6a23c;
+  }
+}
+
+.drawer-foot {
+  position: absolute;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  padding: 20px;
+  display: flex;
+
+  button {
+    width: 50%;
+  }
+}
+
+.preview-form {
+  overflow-y: scroll;
+  height: 83vh;
+}

+ 50 - 0
src/api/bank/autodata.js

@@ -0,0 +1,50 @@
+import request from '@/router/axios';
+
+export const getList = (current, size, params) => {
+  return request({
+    url: '/api/bank/autodata/list',
+    method: 'get',
+    params: {
+      ...params,
+      current,
+      size,
+    }
+  })
+}
+
+export const getDetail = (id) => {
+  return request({
+    url: '/api/bank/autodata/detail',
+    method: 'get',
+    params: {
+      id
+    }
+  })
+}
+
+export const remove = (ids) => {
+  return request({
+    url: '/api/bank/autodata/remove',
+    method: 'post',
+    params: {
+      ids,
+    }
+  })
+}
+
+export const add = (row) => {
+  return request({
+    url: '/api/bank/autodata/submit',
+    method: 'post',
+    data: row
+  })
+}
+
+export const update = (row) => {
+  return request({
+    url: '/api/bank/autodata/submit',
+    method: 'post',
+    data: row
+  })
+}
+

+ 50 - 0
src/api/bank/autostruct.js

@@ -0,0 +1,50 @@
+import request from '@/router/axios';
+
+export const getList = (current, size, params) => {
+  return request({
+    url: '/api/bank/autostruct/list',
+    method: 'get',
+    params: {
+      ...params,
+      current,
+      size,
+    }
+  })
+}
+
+export const getDetail = (id) => {
+  return request({
+    url: '/api/bank/autostruct/detail',
+    method: 'get',
+    params: {
+      id
+    }
+  })
+}
+
+export const remove = (ids) => {
+  return request({
+    url: '/api/bank/autostruct/remove',
+    method: 'post',
+    params: {
+      ids,
+    }
+  })
+}
+
+export const add = (row) => {
+  return request({
+    url: '/api/bank/autostruct/submit',
+    method: 'post',
+    data: row
+  })
+}
+
+export const update = (row) => {
+  return request({
+    url: '/api/bank/autostruct/submit',
+    method: 'post',
+    data: row
+  })
+}
+

+ 9 - 0
src/api/bank/goodsuse.js

@@ -95,4 +95,13 @@ export const getLastByType = (type) => {
   })
 }
 
+export const getBalanceList = () => {
+  return request({
+    url: '/api/bank/goodsuse/getBalanceList',
+    method: 'get',
+    params: {
+    }
+  })
+}
+
 

+ 10 - 0
src/api/bank/home.js

@@ -45,3 +45,13 @@ export const getHomeCount = () => {
   })
 }
 
+export const getReport = (params) => {
+  return request({
+    url: '/api/bank/checklist/getReport',
+    method: 'get',
+    params: {
+      ...params
+    }
+  })
+}
+

+ 4 - 0
src/components/common/cardswallow-comfirm.vue

@@ -164,6 +164,10 @@
                 label: "dictValue",
                 value: "dictKey"
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               rules: [{
                 required: true,
                 message: "请输入發送狀態",

+ 4 - 0
src/components/common/cardswallow-issue.vue

@@ -87,6 +87,10 @@
                 label: "dictValue",
                 value: "dictKey"
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               disabled: true,
             },
             {

+ 61 - 0
src/components/common/cy-form-design.vue

@@ -0,0 +1,61 @@
+<template>
+  <basic-container>
+    <avue-form-design :options="options"
+                      :aside-left-width="270"
+                      :aside-right-width="380"
+                      storage
+                      @submit="handleSubmit">
+    </avue-form-design>
+  </basic-container>
+</template>
+
+<script>
+    export default {
+      name: "cy-form-design",
+      props: {
+        callback: {
+          type: Function
+        }
+      },
+      data(){
+        return {
+          options: {
+            detail: true,
+            column: [
+              {
+                type: 'url',
+                prop: 'url',
+                label: '超链接',
+                icon: 'icon-url',
+                valueDefault: 'http://www.baidu.com',
+                span: 24,
+                display: true
+              },
+              {
+                prop: 'img',
+                type: 'img',
+                label: '图片',
+                span: '24',
+                display: true
+              }
+            ]
+          },
+        }
+      },
+      methods: {
+        handleSubmit(value){
+          let jsonStr = JSON.stringify(value, (k,v) => {
+            if(typeof v === "function"){
+              return v.toString();
+            }
+            return v;
+          })
+          this.callback(jsonStr);
+        },
+      }
+    }
+</script>
+
+<style scoped>
+
+</style>

+ 4 - 0
src/components/common/goodsuse-sure.vue

@@ -57,6 +57,10 @@
                 label: "dictValue",
                 value: "dictKey"
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               disabled: true,
               rules: [{
                 required: true,

+ 17 - 5
src/components/common/returns-approve.vue

@@ -35,6 +35,10 @@
                 label: "dictValue",
                 value: "dictKey"
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               rules: [{
                 required: true,
                 message: "请输入業務類型",
@@ -96,6 +100,10 @@
                 label: "dictValue",
                 value: "dictKey"
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               rules: [{
                 required: true,
                 message: "请输入狀態",
@@ -115,7 +123,7 @@
               label: "備註",
               prop: "remark",
               rules: [{
-                required: true,
+                required: false,
                 message: "请输入備註",
                 trigger: "blur"
               }]
@@ -124,7 +132,7 @@
               label: "條碼",
               prop: "barCode",
               rules: [{
-                required: true,
+                required: false,
                 message: "请输入條碼",
                 trigger: "blur"
               }]
@@ -142,7 +150,7 @@
               label: "接辦行覆核",
               prop: "handlingBankReview",
               rules: [{
-                required: true,
+                required: false,
                 message: "请输入接辦行覆核",
                 trigger: "blur"
               }]
@@ -166,7 +174,7 @@
               }]
             },
             {
-              label: "處理狀態",
+              label: "跟進情況",
               prop: "handlingStatus",
               type: "select",
               dataType: "string",
@@ -175,8 +183,12 @@
                 label: "dictValue",
                 value: "dictKey"
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               rules: [{
-                required: true,
+                required: false,
                 message: "请输入處理狀態",
                 trigger: "blur"
               }]

+ 12 - 1
src/components/common/returns-comfire.vue

@@ -48,6 +48,10 @@
                 label: "dictValue",
                 value: "dictKey"
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               rules: [{
                 required: true,
                 message: "请输入業務類型",
@@ -108,6 +112,9 @@
               props: {
                 label: "dictValue",
                 value: "dictKey"
+              },dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
               },
               rules: [{
                 required: true,
@@ -179,7 +186,7 @@
               }]
             },
             {
-              label: "處理狀態",
+              label: "跟進情況",
               prop: "handlingStatus",
               type: "select",
               dataType: "string",
@@ -188,6 +195,10 @@
                 label: "dictValue",
                 value: "dictKey"
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               rules: [{
                 required: false,
                 message: "请输入處理狀態",

+ 12 - 0
src/components/common/returns-issue.vue

@@ -36,6 +36,10 @@
                 label: "dictValue",
                 value: "dictKey"
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               rules: [{
                 required: true,
                 message: "请输入業務類型",
@@ -103,6 +107,10 @@
                 label: "dictValue",
                 value: "dictKey"
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               rules: [{
                 required: true,
                 message: "请输入狀態",
@@ -190,6 +198,10 @@
                 label: "dictValue",
                 value: "dictKey"
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               rules: [{
                 required: true,
                 message: "请输入處理狀態",

+ 4 - 0
src/components/confirmed/confirmed-cardswallow.vue

@@ -199,6 +199,10 @@
                 label: "dictValue",
                 value: "dictKey"
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               rules: [{
                 required: true,
                 message: "请输入發送狀態",

+ 4 - 0
src/components/confirmed/confirmed-goodsuse.vue

@@ -119,6 +119,10 @@
                 label: "dictValue",
                 value: "dictKey"
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               rules: [{
                 required: true,
                 message: "请输入憑證/實物種類",

+ 8 - 0
src/components/confirmed/confirmed-returns.vue

@@ -93,6 +93,10 @@
                 label: "dictValue",
                 value: "dictKey"
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               rules: [{
                 required: true,
                 message: "请输入業務類型",
@@ -154,6 +158,10 @@
                 label: "dictValue",
                 value: "dictKey"
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               rules: [{
                 required: true,
                 message: "请输入狀態",

+ 4 - 0
src/components/initiated/init-cardswallow.vue

@@ -187,6 +187,10 @@
                 label: "dictValue",
                 value: "dictKey"
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               rules: [{
                 required: true,
                 message: "请输入發送狀態",

+ 4 - 0
src/components/initiated/init-goodsuse.vue

@@ -120,6 +120,10 @@
                 label: "dictValue",
                 value: "dictKey"
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               rules: [{
                 required: true,
                 message: "请输入憑證/實物種類",

+ 12 - 0
src/components/initiated/init-returns.vue

@@ -88,6 +88,10 @@
                 label: "dictValue",
                 value: "dictKey"
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               rules: [{
                 required: true,
                 message: "请输入業務類型",
@@ -149,6 +153,10 @@
                 label: "dictValue",
                 value: "dictKey"
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               rules: [{
                 required: true,
                 message: "请输入狀態",
@@ -231,6 +239,10 @@
                 label: "dictValue",
                 value: "dictKey"
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               rules: [{
                 required: true,
                 message: "请输入處理狀態",

+ 4 - 0
src/components/release/release-cardswallow.vue

@@ -181,6 +181,10 @@
                 label: "dictValue",
                 value: "dictKey"
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               rules: [{
                 required: true,
                 message: "请输入發送狀態",

+ 12 - 0
src/components/release/release-returns.vue

@@ -89,6 +89,10 @@
                 label: "dictValue",
                 value: "dictKey"
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               rules: [{
                 required: true,
                 message: "请输入業務類型",
@@ -150,6 +154,10 @@
                 label: "dictValue",
                 value: "dictKey"
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               rules: [{
                 required: true,
                 message: "请输入狀態",
@@ -232,6 +240,10 @@
                 label: "dictValue",
                 value: "dictKey"
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               rules: [{
                 required: true,
                 message: "请输入處理狀態",

+ 4 - 0
src/components/tobeconfirm/tobeconfirm-cardswallow.vue

@@ -180,6 +180,10 @@
                 label: "dictValue",
                 value: "dictKey"
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               rules: [{
                 required: true,
                 message: "请输入發送狀態",

+ 4 - 0
src/components/tobeconfirm/tobeconfirm-goodsuse.vue

@@ -118,6 +118,10 @@
                 label: "dictValue",
                 value: "dictKey"
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               rules: [{
                 required: true,
                 message: "请输入憑證/實物種類",

+ 12 - 0
src/components/tobeconfirm/tobeconfirm-returns.vue

@@ -93,6 +93,10 @@
                 label: "dictValue",
                 value: "dictKey"
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               rules: [{
                 required: true,
                 message: "请输入業務類型",
@@ -154,6 +158,10 @@
                 label: "dictValue",
                 value: "dictKey"
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               rules: [{
                 required: true,
                 message: "请输入狀態",
@@ -236,6 +244,10 @@
                 label: "dictValue",
                 value: "dictKey"
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               rules: [{
                 required: true,
                 message: "请输入處理狀態",

+ 4 - 0
src/main.js

@@ -22,9 +22,13 @@ import thirdRegister from './components/third-register/main';
 import avueUeditor from 'avue-plugin-ueditor';
 import website from '@/config/website';
 import crudCommon from '@/mixins/crud';
+import AvueFormDesign from 'avue-form-design';
+// import AvueFormDesign from '../packages/';
+Vue.use(AvueFormDesign)
 // 注册全局crud驱动
 window.$crudCommon = crudCommon;
 // 加载Vue拓展
+Vue.use(AvueFormDesign);
 Vue.use(router);
 Vue.use(VueAxios, axios);
 Vue.use(Element, {

+ 287 - 0
src/views/bank/autodata.vue

@@ -0,0 +1,287 @@
+<template>
+  <basic-container>
+    <el-select v-model="value" filterable placeholder="请选择" @change="selectTable">
+      <el-option
+        v-for="(item, idx) in tableList"
+        :key="idx"
+        :label="item.name"
+        :value="item.id">
+      </el-option>
+    </el-select>
+    <div v-if="value">
+      <avue-crud :option="option"
+                 :table-loading="loading"
+                 :data="data"
+                 :page.sync="page"
+                 :permission="permissionList"
+                 :before-open="beforeOpen"
+                 v-model="form"
+                 ref="crud"
+                 @row-update="rowUpdate"
+                 @row-save="rowSave"
+                 @row-del="rowDel"
+                 @search-change="searchChange"
+                 @search-reset="searchReset"
+                 @selection-change="selectionChange"
+                 @current-change="currentChange"
+                 @size-change="sizeChange"
+                 @refresh-change="refreshChange"
+                 @on-load="onLoad">
+        <template slot="menuLeft">
+          <el-button type="danger"
+                     size="small"
+                     icon="el-icon-delete"
+                     plain
+                     v-if="permission.autodata_delete"
+                     @click="handleDelete">删 除
+          </el-button>
+        </template>
+      </avue-crud>
+    </div>
+  </basic-container>
+</template>
+
+<script>
+  import {getList, getDetail, add, update, remove} from "@/api/bank/autodata";
+  import {mapGetters} from "vuex";
+  import {getList as getTables} from "@/api/bank/autostruct";
+
+  export default {
+    data() {
+      return {
+        value: '',
+        tableList: [],
+
+        form: {},
+        query: {},
+        loading: true,
+        page: {
+          pageSize: 10,
+          currentPage: 1,
+          total: 0
+        },
+        selectionList: [],
+        option: {
+          height:'auto',
+          calcHeight: 30,
+          tip: false,
+          searchShow: true,
+          searchMenuSpan: 6,
+          border: true,
+          index: true,
+          viewBtn: true,
+          selection: true,
+          dialogClickModal: false,
+          column: [
+          ]
+        },
+        data: []
+      };
+    },
+    computed: {
+      ...mapGetters(["permission"]),
+      permissionList() {
+        return {
+          addBtn: this.vaildData(this.permission.autodata_add, false),
+          viewBtn: this.vaildData(this.permission.autodata_view, false),
+          delBtn: this.vaildData(this.permission.autodata_delete, false),
+          editBtn: this.vaildData(this.permission.autodata_edit, false)
+        };
+      },
+      ids() {
+        let ids = [];
+        this.selectionList.forEach(ele => {
+          ids.push(ele.id);
+        });
+        return ids.join(",");
+      }
+    },
+    created() {
+      // let data = {column:[{type:'input',label:'姓名',span:12,display:true,prop:'name',required:true,rules:[{required:true,message:'姓名必须填写'}]},{type:'input',label:'年齡',span:12,display:true,prop:'age'},{type:'input',label:'手機號',span:12,display:true,prop:'phone',maxlength:11},{type:'input',label:'住址',span:12,display:true,prop:'address'}],labelPosition:'right',labelSuffix:':',labelWidth:120,gutter:0,menuBtn:true,submitBtn:true,submitText:'提交',emptyBtn:true,emptyText:'清空',menuPosition:'center'};
+      // this.option = data;
+      this.initTableList();
+    },
+    methods: {
+      initTableList(){
+        getTables(1, 500, {}).then(res => {
+          const data = res.data.data;
+          this.tableList = data.records;
+
+        });
+      },
+      selectTable(value){
+        let table = this.getItemById(value);
+        let optionStr = table.columns.replace(/(s*?{s*?|s*?,s*?)(['"])?([a-zA-Z0-9]+)(['"])?:/g, '$1"$3":').replaceAll('\'', '\"');
+        optionStr = optionStr.replace('&gt;', '>')
+        optionStr = optionStr.replace(/\s*/g, '')
+        // str.replace(/\s*/g,"")
+        this.option = JSON.parse(optionStr, (k,v)=>{
+          if(k == 'change'){
+            return eval('"' + v + '"')
+          }
+          return v
+        })
+        this.onLoad(this.page)
+      },
+      getItemById(id){
+        for (let i = 0; i < this.tableList.length; i++) {
+          let item = this.tableList[i];
+          console.log(i)
+          if (item.id == id){
+            return item;
+          }
+        }
+      },
+      beforeSave(row){
+        let  keys = Object.keys(row);
+        let form = {}
+        for(let i = 0; i < keys.length; i++){
+          let item = {};
+          item['' + keys[i]] = row[''+keys[i]];
+          form['params'+(i+1)] = JSON.stringify(item);
+        }
+        form.tableId = this.value;
+        return form;
+      },
+      rowSave(row, done, loading) {
+        let form = this.beforeSave(row)
+        add(form).then(() => {
+          this.onLoad(this.page);
+          this.$message({
+            type: "success",
+            message: "操作成功!"
+          });
+          done();
+        }, error => {
+          loading();
+          window.console.log(error);
+        });
+      },
+      rowUpdate(row, index, done, loading) {
+        let formTem = this.deepClone(row);
+        delete formTem.$index,delete formTem.createDept,delete formTem.createTime,delete formTem.createUser,delete formTem.id;
+        let form = this.beforeSave(formTem);
+        form.id = row.id;
+        update(form).then(() => {
+          this.onLoad(this.page);
+          this.$message({
+            type: "success",
+            message: "操作成功!"
+          });
+          done();
+        }, error => {
+          loading();
+          console.log(error);
+        });
+      },
+      rowDel(row) {
+        this.$confirm("确定将选择数据删除?", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        })
+          .then(() => {
+            return remove(row.id);
+          })
+          .then(() => {
+            this.onLoad(this.page);
+            this.$message({
+              type: "success",
+              message: "操作成功!"
+            });
+          });
+      },
+      handleDelete() {
+        if (this.selectionList.length === 0) {
+          this.$message.warning("请选择至少一条数据");
+          return;
+        }
+        this.$confirm("确定将选择数据删除?", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        })
+          .then(() => {
+            return remove(this.ids);
+          })
+          .then(() => {
+            this.onLoad(this.page);
+            this.$message({
+              type: "success",
+              message: "操作成功!"
+            });
+            this.$refs.crud.toggleSelection();
+          });
+      },
+      beforeOpen(done, type) {
+        if (["edit", "view"].includes(type)) {
+          /*getDetail(this.form.id).then(res => {
+            this.form = res.data.data;
+          });*/
+        }
+        done();
+      },
+      searchReset() {
+        this.query = {};
+        this.onLoad(this.page);
+      },
+      searchChange(params, done) {
+        this.query = params;
+        this.page.currentPage = 1;
+        this.onLoad(this.page, params);
+        done();
+      },
+      selectionChange(list) {
+        this.selectionList = list;
+      },
+      selectionClear() {
+        this.selectionList = [];
+        this.$refs.crud.toggleSelection();
+      },
+      currentChange(currentPage){
+        this.page.currentPage = currentPage;
+      },
+      sizeChange(pageSize){
+        this.page.pageSize = pageSize;
+      },
+      refreshChange() {
+        this.onLoad(this.page, this.query);
+      },
+      initData(data){
+        let newData = [];
+        for (let i = 0; i < data.length; i++) {
+          let row = data[i];
+          let form = {};
+          form.id = row.id, form.createUser = row.createUser, form.createTime = row.createTime, form.createDept = row.createDept;
+          let keys = Object.keys(row);
+          for (let j = 0; j < keys.length; j++) {
+            let key = keys[j];
+            if (key.indexOf("params") != -1){
+              let value = row['' + key];
+              if (value != ''){
+                let item = JSON.parse(value);
+                Object.assign(form, item);
+              }
+            }
+          }
+          newData.push(form)
+        }
+        return newData;
+      },
+      onLoad(page, params = {}) {
+        this.loading = true;
+        params.tableId = this.value;
+        getList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => {
+          const data = res.data.data;
+          this.page.total = data.total;
+          this.data = this.initData(data.records);
+          this.loading = false;
+          this.selectionClear();
+        });
+      }
+    }
+  };
+</script>
+
+<style>
+</style>

+ 263 - 0
src/views/bank/autostruct.vue

@@ -0,0 +1,263 @@
+<template>
+  <basic-container>
+    <avue-crud :option="option"
+               :table-loading="loading"
+               :data="data"
+               :page.sync="page"
+               :permission="permissionList"
+               :before-open="beforeOpen"
+               v-model="form"
+               ref="crud"
+               @row-update="rowUpdate"
+               @row-save="rowSave"
+               @row-del="rowDel"
+               @search-change="searchChange"
+               @search-reset="searchReset"
+               @selection-change="selectionChange"
+               @current-change="currentChange"
+               @size-change="sizeChange"
+               @refresh-change="refreshChange"
+               @on-load="onLoad">
+      <template slot="menuLeft">
+        <el-button type="danger"
+                   size="small"
+                   icon="el-icon-delete"
+                   plain
+                   v-if="permission.autostruct_delete"
+                   @click="handleDelete">删 除
+        </el-button>
+      </template>
+
+      <template slot="designForm" slot-scope="{row}">
+        <el-button type="primary"
+                   size="small"
+                   icon="el-icon-design"
+                   plain
+                   @click="designVisible = true">設計
+        </el-button>
+      </template>
+    </avue-crud>
+
+    <el-dialog :append-to-body="true" :modal-append-to-body="false" :destroy-on-close="true" :fullscreen="true" :visible.sync="designVisible" title="表單設計">
+      <cy-form-design :callback="testCallback"></cy-form-design>
+    </el-dialog>
+
+  </basic-container>
+</template>
+
+<script>
+  import {getList, getDetail, add, update, remove} from "@/api/bank/autostruct";
+  import {mapGetters} from "vuex";
+  import CyFormDesign from "../../components/common/cy-form-design";
+
+  export default {
+    components: {CyFormDesign},
+    data() {
+      return {
+        designVisible: false,
+
+        form: {},
+        query: {},
+        loading: true,
+        page: {
+          pageSize: 10,
+          currentPage: 1,
+          total: 0
+        },
+        selectionList: [],
+        option: {
+          height:'auto',
+          calcHeight: 30,
+          tip: false,
+          searchShow: true,
+          searchMenuSpan: 6,
+          border: true,
+          index: true,
+          viewBtn: true,
+          selection: true,
+          dialogClickModal: false,
+          column: [
+            {
+              label: "表名",
+              prop: "name",
+              span: 24,
+              rules: [{
+                required: true,
+                message: "请输入表名",
+                trigger: "blur"
+              }]
+            },
+            {
+              label: "表單設計",
+              prop: "design",
+              span: 24,
+              hide: true,
+              viewDisplay: false,
+              formslot: true,
+            },
+            {
+              label: "列结构",
+              prop: "columns",
+              type: "textarea",
+              span: 24,
+              rules: [{
+                required: true,
+                message: "请输入列结构",
+                trigger: "blur"
+              }]
+            },
+            {
+              label: "創建時間",
+              prop: "createTime",
+              type: "datetime",
+              display: false,
+              rules: [{
+                required: true,
+                message: "请输入列结构",
+                trigger: "blur"
+              }]
+            },
+          ]
+        },
+        data: []
+      };
+    },
+    computed: {
+      ...mapGetters(["permission"]),
+      permissionList() {
+        return {
+          addBtn: this.vaildData(this.permission.autostruct_add, false),
+          viewBtn: this.vaildData(this.permission.autostruct_view, false),
+          delBtn: this.vaildData(this.permission.autostruct_delete, false),
+          editBtn: this.vaildData(this.permission.autostruct_edit, false)
+        };
+      },
+      ids() {
+        let ids = [];
+        this.selectionList.forEach(ele => {
+          ids.push(ele.id);
+        });
+        return ids.join(",");
+      }
+    },
+    methods: {
+      testCallback(value){
+        this.designVisible = false;
+        this.form.columns = value;
+      },
+      rowSave(row, done, loading) {
+        add(row).then(() => {
+          this.onLoad(this.page);
+          this.$message({
+            type: "success",
+            message: "操作成功!"
+          });
+          done();
+        }, error => {
+          loading();
+          window.console.log(error);
+        });
+      },
+      rowUpdate(row, index, done, loading) {
+        debugger
+        update(row).then(() => {
+          this.onLoad(this.page);
+          this.$message({
+            type: "success",
+            message: "操作成功!"
+          });
+          done();
+        }, error => {
+          loading();
+          console.log(error);
+        });
+      },
+      rowDel(row) {
+        this.$confirm("确定将选择数据删除?", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        })
+          .then(() => {
+            return remove(row.id);
+          })
+          .then(() => {
+            this.onLoad(this.page);
+            this.$message({
+              type: "success",
+              message: "操作成功!"
+            });
+          });
+      },
+      handleDelete() {
+        if (this.selectionList.length === 0) {
+          this.$message.warning("请选择至少一条数据");
+          return;
+        }
+        this.$confirm("确定将选择数据删除?", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        })
+          .then(() => {
+            return remove(this.ids);
+          })
+          .then(() => {
+            this.onLoad(this.page);
+            this.$message({
+              type: "success",
+              message: "操作成功!"
+            });
+            this.$refs.crud.toggleSelection();
+          });
+      },
+      beforeOpen(done, type) {
+        if (["edit", "view"].includes(type)) {
+          getDetail(this.form.id).then(res => {
+            this.form = res.data.data;
+          });
+        }
+        done();
+      },
+      searchReset() {
+        this.query = {};
+        this.onLoad(this.page);
+      },
+      searchChange(params, done) {
+        this.query = params;
+        this.page.currentPage = 1;
+        this.onLoad(this.page, params);
+        done();
+      },
+      selectionChange(list) {
+        this.selectionList = list;
+      },
+      selectionClear() {
+        this.selectionList = [];
+        this.$refs.crud.toggleSelection();
+      },
+      currentChange(currentPage){
+        this.page.currentPage = currentPage;
+      },
+      sizeChange(pageSize){
+        this.page.pageSize = pageSize;
+      },
+      refreshChange() {
+        this.onLoad(this.page, this.query);
+      },
+      onLoad(page, params = {}) {
+        this.loading = true;
+        getList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => {
+          const data = res.data.data;
+          this.page.total = data.total;
+          this.data = data.records;
+          this.loading = false;
+          this.selectionClear();
+        });
+      }
+    }
+  };
+</script>
+
+<style>
+</style>

+ 4 - 0
src/views/bank/cardswallow.vue

@@ -318,6 +318,10 @@
                 label: "dictValue",
                 value: "dictKey"
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               rules: [{
                 required: true,
                 message: "请输入發送狀態",

+ 9 - 1
src/views/bank/checklist.vue

@@ -45,6 +45,12 @@
         </el-button>
       </template>
 
+      <template slot="menu" slot-scope="{row, index}">
+<!--        <el-button size="small" class="el-button&#45;&#45;text" v-if="permission.checklist_delete " @click="$refs.crud.rowDel(row, index)"><i class="el-icon-delete"></i> 刪 除</el-button>-->
+        <el-button size="small" class="el-button--text" v-if="permission.checklist_view" @click="$refs.crud.rowView(row, index)"><i class="el-icon-view"></i> 查 看</el-button>
+        <el-button size="small" class="el-button--text" v-if="permission.checklist_edit && !row.isChecked" @click="$refs.crud.rowEdit(row, index)"><i class="el-icon-edit"></i> 编 辑</el-button>
+      </template>
+
       <template slot="isChecked" slot-scope="{row, index}">
 <!--        <el-tag size="small " type="primary" plain v-if="row.isChecked == 1">√</el-tag>-->
         <el-tag size="small " type="success" plain v-if="row.isChecked">已核對</el-tag>
@@ -108,7 +114,9 @@
           searchMenuSpan: 6,
           border: true,
           index: true,
-          viewBtn: true,
+          editBtn: false,
+          delBtn: false,
+          viewBtn: false,
           selection: true,
           dialogClickModal: false,
           column: [

+ 16 - 0
src/views/bank/checkwarehouse.vue

@@ -225,6 +225,10 @@
                 label: "dictValue",
                 value: "dictKey",
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               change: ({value, column}) => {
                 if (!value) return;
                 let $nameOut = this.findObject(this.option.column, 'checkPersonNameOut');
@@ -259,6 +263,10 @@
                 label: "dictValue",
                 value: "dictKey",
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               rules: [{
                 required: true,
                 message: "请输入檢查目的",
@@ -277,6 +285,10 @@
                 label: "dictValue",
                 value: "dictKey",
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               rules: [{
                 required: true,
                 message: "请输入檢查內容",
@@ -292,6 +304,10 @@
                 label: "dictValue",
                 value: "dictKey",
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               tip: "不能為空值;如選擇〝賬實不符〞需要在備註欄解釋原因",
               change: ({value, column}) => {
                 if (!this.form.checkUnit || !value) return;

+ 349 - 0
src/views/bank/goodsuse-balance.vue

@@ -0,0 +1,349 @@
+<template>
+  <basic-container>
+    <avue-crud :option="option"
+               :table-loading="loading"
+               :data="data"
+               :permission="permissionList"
+               :before-open="beforeOpen"
+               v-model="form"
+               ref="crud"
+               @search-change="searchChange"
+               @search-reset="searchReset"
+               @selection-change="selectionChange"
+               @current-change="currentChange"
+               @size-change="sizeChange"
+               @refresh-change="refreshChange"
+               @on-load="onLoad">
+      <template slot="menuLeft">
+        <el-button type="primary"
+                   size="small"
+                   icon="el-icon-download"
+                   plain
+                   v-if="permission.goodsuse_download"
+                   @click="handleDownload">下載
+        </el-button>
+      </template>
+
+      <template slot="process" slot-scope="{row, index}">
+        <el-tag size="small " type="warning" plain v-if="row.process == 2">待確認</el-tag>
+        <el-tag size="small " type="success" plain v-if="row.process == 3">已確認</el-tag>
+      </template>
+    </avue-crud>
+
+  </basic-container>
+</template>
+
+<script>
+  import {getBalanceList, getDetail} from "@/api/bank/goodsuse";
+  import {mapGetters} from "vuex";
+  import {dateFormat} from "../../util/date";
+  import { getCurrentDept } from "@/api/system/dept";
+  import {getDeptTree, getTree} from "@/api/system/dept";
+
+  export default {
+    name: 'goodsuse-balance',
+    data() {
+      return {
+        type: '',
+        form: {},
+        query: {},
+        loading: true,
+        page: {
+          pageSize: 10,
+          currentPage: 1,
+          total: 0
+        },
+        selectionList: [],
+        option: {
+          height:'auto',
+          calcHeight: 30,
+          tip: false,
+          searchShow: true,
+          searchMenuSpan: 6,
+          border: true,
+          index: true,
+          viewBtn: true,
+          addBtn: false,
+          editBtn: false,
+          delBtn: false,
+          selection: true,
+          menu: false,
+          // header: false,
+
+          dialogClickModal: false,
+          column: [
+            {
+              label: "銀行號",
+              prop: "bankNo",
+              disabled: true,
+              // search: true,
+              searchSpan: 4,
+              rules: [{
+                required: true,
+                message: "请输入銀行號",
+                trigger: "blur"
+              }]
+            },
+            {
+              label: "機構號",
+              prop: "orgNo",
+              disabled: true,
+              rules: [{
+                required: true,
+                message: "请输入機構號",
+                trigger: "blur"
+              }]
+            },
+            {
+              label: "日期",
+              prop: "date",
+              type: "datetime",
+              format: "yyyy-MM-dd",
+              valueFormat: "yyyy-MM-dd",
+              rules: [{
+                required: true,
+                message: "请输入日期",
+                trigger: "blur"
+              }]
+            },
+            {
+              label: "日期",
+              prop: "dateRange",
+              type: "date",
+              format: "yyyy-MM-dd",
+              valueFormat: "yyyy-MM-dd",
+              searchRange:true,
+              hide: true,
+              addDisplay: false,
+              editDisplay: false,
+              viewDisplay: false,
+              // search: true,
+              rules: [{
+                required: true,
+                message: "请输入交接日期",
+                trigger: "blur"
+              }]
+            },
+            {
+              label: "区域/支行",
+              prop: "orgNos",
+              hide: true,
+              display: false,
+              searchMultiple: true,
+              // search: true,
+              type: "tree",
+              dicData: [],
+              props: {
+                label: "title",
+                value: "key"
+              },
+              checkStrictly: true,
+
+            },
+            {
+              label: "憑證/實物種類",
+              prop: "type",
+              type: "select",
+              // search: true,
+              searchSpan: 4,
+              searchMultiple: true,
+              dicUrl: "/api/blade-system/dict/dictionary?code=voucher_type",
+              props: {
+                label: "dictValue",
+                value: "dictKey"
+              },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
+            },
+            {
+              label: "餘額",
+              prop: "balance",
+              type: "number",
+              disabled: true,
+            },
+
+            {
+              label: "填報時間",
+              prop: "fillingDate",
+              addDisplay: false,
+              editDisplay: false,
+            },
+            {
+              label: "填報人",
+              prop: "fillingName",
+              addDisplay: false,
+              editDisplay: false,
+            },
+            {
+              label: "進度",
+              prop: "process",
+              display: false,
+              rules: [{
+                required: true,
+                message: "请输入節點",
+                trigger: "blur"
+              }]
+            },
+            {
+              label: "審批時間",
+              prop: "approveTime",
+              hide: true,
+              addDisplay: false,
+              editDisplay: false,
+
+            },
+          ]
+        },
+        data: []
+      };
+    },
+    computed: {
+      ...mapGetters(["permission"]),
+      ...mapGetters(["userInfo"]),
+      permissionList() {
+        return {
+          addBtn: this.vaildData(this.permission.goodsuse_add, false),
+          viewBtn: this.vaildData(this.permission.goodsuse_view, false),
+          delBtn: this.vaildData(this.permission.goodsuse_delete, false),
+          editBtn: this.vaildData(this.permission.goodsuse_edit, false)
+        };
+      },
+      ids() {
+        let ids = [];
+        this.selectionList.forEach(ele => {
+          ids.push(ele.id);
+        });
+        return ids.join(",");
+      }
+    },
+    watch: {
+      'form.useNumber': {
+        handler: function(value) {
+          this.calcBalance();
+        }
+      },
+      'form.receiptNumber': {
+        handler: function(value) {
+          this.calcBalance();
+        }
+      },
+      'form.writeOffNumber': {
+        handler: function(value) {
+          this.calcBalance();
+        }
+      },
+      'form.type': {
+        handler: function(value) {
+          this.calcBalance();
+        }
+      },
+
+    },
+    mounted() {
+      getDeptTree().then(res => {
+        const column = this.findObject(this.option.column, "orgNos");
+        let treeData = getTree(res.data.data, this.userInfo.dept_id);
+        column.dicData = treeData;
+      });
+    },
+    methods: {
+      handleDownload(){
+        if (this.selectionList.length === 0) {
+          this.$message.warning("请选择至少一条数据");
+          return;
+        }
+        let columns = this.deepClone(this.option.column);
+        for (let i = 0; i < columns.length; i++) {
+          let item = columns[i];
+          if (item.hide || item.prop == 'process'){
+            columns.splice(i, 1);
+            i--;
+          }
+          if (item.type == 'select' || item.type == 'tree'){
+            item.prop = '$' + item.prop;
+          }
+        }
+        this.$Export.excel({
+          title: "使用及出入庫登記表" || new Date().getTime(),
+          columns: columns,
+          data: this.selectionList
+        });
+      },
+      beforeOpen(done, type) {
+        this.type = type;
+        if (type === 'add'){
+          this.form.writeOffNumber = 0;
+          this.form.receiptNumber = 0;
+          this.form.handoverDate = dateFormat(new Date(), "yyyy-MM-dd hh:mm");
+
+          this.calcBalance();
+
+          getCurrentDept().then(res => {
+            const data =  res.data.data;
+            this.form.bankNo = data.bankNo;
+            this.form.orgNo = data.orgNo;
+          });
+        }
+        if (["edit", "view"].includes(type)) {
+          getDetail(this.form.id).then(res => {
+            this.form = res.data.data;
+          });
+        }
+        done();
+      },
+      searchReset() {
+        this.query = {};
+        this.onLoad(this.page);
+      },
+      searchChange(params, done) {
+        if (params.dateRange){
+          params.date_begin = params.dateRange[0], params.date_end = params.dateRange[1];
+          params.dateRange = null;
+        }
+        if (params.orgNos){
+          params.orgNostr = params.orgNos.join();
+          params.orgNos = '';
+        }
+        if (params.type){
+          params.type = params.type.join();
+        }
+
+        this.query = params;
+        this.page.currentPage = 1;
+        this.onLoad(this.page, params);
+        done();
+      },
+      selectionChange(list) {
+        this.selectionList = list;
+      },
+      selectionClear() {
+        this.selectionList = [];
+        this.$refs.crud.toggleSelection();
+      },
+      currentChange(currentPage){
+        this.page.currentPage = currentPage;
+      },
+      sizeChange(pageSize){
+        this.page.pageSize = pageSize;
+      },
+      refreshChange() {
+        this.onLoad(this.page, this.query);
+      },
+      onLoad(page, params = {}) {
+        this.loading = true;
+        getBalanceList().then(res => {
+          const data = res.data.data;
+          debugger
+          this.data = data;
+          this.loading = false;
+          this.selectionClear();
+        });
+      }
+    }
+  };
+</script>
+
+<style>
+</style>

+ 18 - 1
src/views/bank/goodsuse.vue

@@ -47,6 +47,12 @@
                    v-if="permission.goodsuse_download"
                    @click="handleDownload">下載
         </el-button>
+        <el-button type="success"
+                   size="small"
+                   icon="el-icon-search"
+                   plain
+                   @click="balanceVisible = true">餘額查詢
+        </el-button>
       </template>
 
       <template slot="personNameForm">
@@ -77,6 +83,10 @@
       <select-dialog-user :callback="transferCallback"></select-dialog-user>
     </el-dialog>
 
+    <el-dialog :append-to-body="true" :modal-append-to-body="false" :destroy-on-close="true" :fullscreen="true" :visible.sync="balanceVisible" title="餘額查詢">
+      <goodsuse-balance></goodsuse-balance>
+    </el-dialog>
+
   </basic-container>
 </template>
 
@@ -91,11 +101,13 @@
   import {getDeptTree, getTree} from "@/api/system/dept";
   import {getStandardByCode} from "@/api/bank/handoverstandard";
   import {validatenumplus} from "../../util/validate";
+  import GoodsuseBalance from "./goodsuse-balance";
 
   export default {
-    components: {GoodsuseSure, SelectDialogUser, FlowSettings},
+    components: {GoodsuseBalance, GoodsuseSure, SelectDialogUser, FlowSettings},
     data() {
       return {
+        balanceVisible: false,
         transferVisible: false,
 
         personId: null,
@@ -216,6 +228,10 @@
                 label: "dictValue",
                 value: "dictKey"
               },
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
               rules: [{
                 required: true,
                 message: "请输入憑證/實物種類",
@@ -284,6 +300,7 @@
               prop: "lastBalance",
               type: "number",
               disabled: true,
+              hide: true,
               viewDisplay: false,
               rules: [{
                 required: true,

+ 5 - 3
src/views/bank/keypwd.vue

@@ -56,7 +56,7 @@
       </template>
 
       <template slot-scope="{disabled,size}" slot="categorySearch">
-        <avue-input-tree :check-strictly="true" multiple v-model="search.category" placeholder="请选择内容" type="tree" :dic="typeList" :props="props"></avue-input-tree>
+        <avue-input-tree :check-strictly="false" multiple v-model="search.category" placeholder="请选择内容" type="tree" :dic="typeList" :props="props"></avue-input-tree>
       </template>
 
       <template slot="titleForm" slot-scope="{row, index}">
@@ -401,6 +401,7 @@
       getDeptTree().then(res => {
         const column = this.findObject(this.option.column, "orgNos");
         let treeData = getTree(res.data.data, this.userInfo.dept_id);
+        debugger
         column.dicData = treeData;
       });
       getStandardByCode("keypwd").then(res => {
@@ -461,12 +462,13 @@
                 it.dictValue = item.dictValue + '-' + it.dictValue;
                 item.children.push(it)
                 item.hasChildren = true;
-                item.disabled = true;
               }
             })
           })
           this.typeList = arr;
-          this.findObject(this.option.column, 'category').dicData = arr;
+          let formDicData = this.deepClone(arr);
+          formDicData.forEach(item => {item.disabled = true;});
+          this.findObject(this.option.column, 'category').dicData = formDicData;
           return arr;
         })
       },

+ 10 - 1
src/views/bank/returns.vue

@@ -161,6 +161,9 @@
               props: {
                 label: "dictValue",
                 value: "dictKey"
+              },dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
               },
               rules: [{
                 required: true,
@@ -244,6 +247,9 @@
               props: {
                 label: "dictValue",
                 value: "dictKey"
+              },dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
               },
               rules: [{
                 required: true,
@@ -340,7 +346,7 @@
               }]
             },
             {
-              label: "處理狀態",
+              label: "跟進情況",
               prop: "handlingStatus",
               type: "select",
               dataType: "string",
@@ -348,6 +354,9 @@
               props: {
                 label: "dictValue",
                 value: "dictKey"
+              },dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
               },
               rules: [{
                 required: false,

+ 3 - 0
src/views/bank/sealhandover-keep.vue

@@ -107,6 +107,9 @@
               props:{
                 label: "dictValue",
                 value: "dictKey",
+              },dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
               },
               search: true,
               searchMultiple: true,

+ 8 - 7
src/views/bank/sealhandover.vue

@@ -167,6 +167,9 @@
               props:{
                 label: "dictValue",
                 value: "dictKey",
+              },dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
               },
               search: true,
               hide: true,
@@ -181,15 +184,13 @@
               props:{
                 label: "dictValue",
                 value: "dictKey",
+              },dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
               },
               dicFormatter: (res) => {
-                let data = res.data;
-                // data[0].disabled = true;
-                for (let i = 0; i < data.length; i++) {
-                  let item = data[i];
-                  item.disabled = item.isSealed == 1;
-                }
-                return data;
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
               },
               rules: [{
                 required: true,

+ 48 - 6
src/views/bank/user-log-view.vue

@@ -148,6 +148,9 @@
               props:{
                 label: "dictValue",
                 value: "dictKey",
+              },dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
               },
             },
             {
@@ -205,6 +208,9 @@
               props:{
                 label: "dictValue",
                 value: "dictKey",
+              },dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
               },
               search: true,
               searchMultiple: true,
@@ -281,7 +287,10 @@
                 label: "dictValue",
                 value: "dictKey",
               },
-
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
             },
             {
               label: "檢查目的",
@@ -291,6 +300,9 @@
               props:{
                 label: "dictValue",
                 value: "dictKey",
+              },dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
               },
             },
             {
@@ -302,7 +314,10 @@
                 label: "dictValue",
                 value: "dictKey",
               },
-
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
             },
             {
               label: "核對結果",
@@ -312,6 +327,9 @@
               props:{
                 label: "dictValue",
                 value: "dictKey",
+              },dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
               },
             },
             {
@@ -352,6 +370,9 @@
               props:{
                 label: "dictValue",
                 value: "dictKey",
+              },dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
               },
             },
             {
@@ -378,6 +399,9 @@
               props:{
                 label: "dictValue",
                 value: "dictKey",
+              },dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
               },
 
             },
@@ -401,6 +425,9 @@
               props:{
                 label: "dictValue",
                 value: "dictKey",
+              },dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
               },
             },
             {
@@ -412,7 +439,10 @@
                 label: "dictValue",
                 value: "dictKey",
               },
-
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
             },
 
             {
@@ -475,6 +505,9 @@
               props:{
                 label: "dictValue",
                 value: "dictKey",
+              },dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
               },
             },
             {
@@ -486,7 +519,10 @@
                 label: "dictValue",
                 value: "dictKey",
               },
-
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
             },
             {
               label: "核對內容/標準",
@@ -497,7 +533,10 @@
                 label: "dictValue",
                 value: "dictKey",
               },
-
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
             },
             {
               label: "已核對",
@@ -550,7 +589,10 @@
                 label: "dictValue",
                 value: "dictKey"
               },
-
+              dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
+              },
             },
             {
               label: "使用數量",

+ 9 - 2
src/views/monitor/log/api.vue

@@ -171,11 +171,18 @@
       },
       onLoad(page, params = {}) {
         this.loading = true;
-        console.log(page)
-        debugger
         getApiList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => {
           const data = res.data.data;
           this.page.total = data.total;
+          data.records.forEach(item => {
+            if (!item.createBy){
+            //  tenantId=000000&username=mo153842&password=a5cfe98d240800a4e84eaa425abed1dd&grant_type=password&scope=all&type=account
+              let arr = item.params.split('username=');
+              if(arr.length > 1){
+                item.createBy = arr[1].split('&')[0]
+              }
+            }
+          })
           this.data = data.records;
           this.loading = false;
         });

+ 9 - 0
src/views/report/abnormal-reportlist.vue

@@ -173,6 +173,9 @@ export default {
             props:{
               label: "dictValue",
               value: "dictKey",
+            },dicFormatter: (res) => {
+              res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+              return res.data;
             },
             rules: [{
               required: true,
@@ -191,6 +194,9 @@ export default {
             props:{
               label: "dictValue",
               value: "dictKey",
+            },dicFormatter: (res) => {
+              res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+              return res.data;
             },
             rules: [{
               required: true,
@@ -206,6 +212,9 @@ export default {
             props:{
               label: "dictValue",
               value: "dictKey",
+            },dicFormatter: (res) => {
+              res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+              return res.data;
             },
             rules: [{
               required: true,

+ 34 - 104
src/views/report/reportlist.vue

@@ -24,7 +24,7 @@
                @refresh-change="refreshChange"
                @on-load="onLoad">
       <template slot="menuLeft">
-        <el-button type="primary"
+        <!--<el-button type="primary"
                    size="small"
                    icon="el-icon-s-data"
                    plain
@@ -37,7 +37,7 @@
                    plain
                    v-if="permission.message_delete"
                    @click="handleInitAll">生成圖表(全部)
-        </el-button>
+        </el-button>-->
       </template>
     </avue-crud>
 
@@ -51,11 +51,10 @@
 </template>
 
 <script>
-  import {getList, getDetail} from "@/api/bank/checklist";
   import {mapGetters} from "vuex";
   import {getDeptTree, getTree} from "@/api/system/dept";
   import CheckChart from "../../components/chart/check-chart";
-  import {getHomeCount} from "../../api/bank/home";
+  import {getReport} from "../../api/bank/home";
 
 export default {
   components: {CheckChart},
@@ -87,10 +86,11 @@ export default {
         addBtn: false,
         editBtn: false,
         delBtn: false,
+        menu: false,
         selection: true,
         dialogClickModal: false,
         column: [
-          {
+          /*{
             label: "銀行號",
             prop: "bankNo",
             disabled: true,
@@ -101,7 +101,7 @@ export default {
               message: "请输入銀行號",
               trigger: "blur"
             }]
-          },
+          },*/
           {
             label: "機構號",
             prop: "orgNo",
@@ -112,7 +112,7 @@ export default {
               trigger: "blur"
             }]
           },
-          {
+          /*{
             label: "区域/支行",
             prop: "orgNos",
             hide: true,
@@ -131,10 +131,10 @@ export default {
               message: "请输入機構號",
               trigger: "blur"
             }]
-          },
-          {
+          },*/
+         /* {
             label: "核對日期",
-            prop: "checkDate",
+            prop: "date",
             type: "datetime",
             format: "yyyy-MM-dd",
             valueFormat: "yyyy-MM-dd",
@@ -143,10 +143,10 @@ export default {
               message: "请输入核對日期",
               trigger: "blur"
             }]
-          },
+          },*/
           {
-            label: "核對日期",
-            prop: "checkDateRange",
+            label: "日期",
+            prop: "dateRange",
             type: "date",
             format: "yyyy-MM-dd",
             valueFormat: "yyyy-MM-dd",
@@ -166,13 +166,16 @@ export default {
             label: "分類",
             prop: "type",
             type: "select",
-            search: true,
+            // search: true,
             // searchSpan: 4,
             searchMultiple: true,
             dicUrl: "/api/blade-system/dict/dictionary?code=check_category",
             props:{
               label: "dictValue",
               value: "dictKey",
+            },dicFormatter: (res) => {
+              res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+              return res.data;
             },
             rules: [{
               required: true,
@@ -184,13 +187,16 @@ export default {
             label: "核對項目",
             prop: "item",
             type: "select",
-            search: true,
+            // search: true,
             // searchSpan: 4,
             searchMultiple: true,
             dicUrl: "/api/blade-system/dict/dictionary?code=check_item",
             props:{
               label: "dictValue",
               value: "dictKey",
+            },dicFormatter: (res) => {
+              res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+              return res.data;
             },
             rules: [{
               required: true,
@@ -198,7 +204,7 @@ export default {
               trigger: "blur"
             }]
           },
-          {
+          /*{
             label: "核對內容/標準",
             prop: "content",
             type: "select",
@@ -212,59 +218,18 @@ export default {
               message: "请输入核對內容/標準",
               trigger: "blur"
             }]
-          },
+          },*/
           {
             label: "已核對",
             prop: "checked",
-            type: "checkbox",
-            dicData: [{
-              value: 1
-            }],
-            rules: [{
-              required: true,
-              message: "請勾選已核對",
-              trigger: "blur"
-            }]
           },
           {
-            label: "核對人",
-            prop: "checkName",
-            disabled: true,
-            rules: [{
-              required: true,
-              message: "请输入核對人姓名",
-              trigger: "blur"
-            }]
+            label: "未核對",
+            prop: "nocheck",
           },
           {
-            label: "核對人員工號",
-            prop: "checkNo",
-            disabled: true,
-            rules: [{
-              required: true,
-              message: "请输入核對人員工號",
-              trigger: "blur"
-            }]
-          },
-          {
-            label: "備註",
-            prop: "remark",
-            rules: [{
-              required: false,
-              message: "请输入備註",
-              trigger: "blur"
-            }]
-          },
-          {
-            label: "填報時間",
-            prop: "fillingDate",
-            addDisplay: false,
-            editDisplay: false,
-            rules: [{
-              required: true,
-              message: "请输入填報時間",
-              trigger: "blur"
-            }]
+            label: "後補核對",
+            prop: "over",
           },
         ]
       },
@@ -317,33 +282,9 @@ export default {
 
     },
     handleInitAll(){
-      getHomeCount().then(res => {
-        const data = res.data.data;
-        if (this.cycle == 'day'){
-          this.chartData = {checkedCount: data.dayCheckedCount, noCheckCount: data.dayNocheckCount};
-
-        }else if (this.cycle == 'week'){
-          this.chartData = {checkedCount: data.weekCheckedCount, noCheckCount: data.weekNocheckCount};
-        }else{
-          this.chartData = {checkedCount: data.monthCheckedCount, noCheckCount: data.monthNocheckCount};
-        }
-        if (this.chartData.checkedCount == 0 && this.chartData.noCheckCount == 0){
-          this.$message.success("暫無數據!");
-        }else{
-          this.chartVisible = true;
-        }
 
-      })
     },
     handleClick(tab, event) {
-      // console.log(tab, event);
-      /*if (tab.name == 'day'){
-        this.dataType = 1;
-      }else if(tab.name == 'week'){
-        this.dataType = 2;
-      }else if (tab.name == 'month'){
-        this.dataType = 3;
-      }*/
       this.cycle = tab.name;
       this.onLoad(this.page);
     },
@@ -352,7 +293,7 @@ export default {
       arr.push(this.form.isChecked)
       this.form.checked = arr;
       if (["edit", "view"].includes(type)) {
-        if (type == "view"){
+        /*if (type == "view"){
           this.findObject(this.option.column, "content").tip = this.form.$content;
           console.log(this.form)
         }
@@ -362,7 +303,7 @@ export default {
             this.findObject(this.option.column, "content").tip = "this.form.$content";
             console.log(this.form)
           }
-        });
+        });*/
 
       }
       done();
@@ -372,19 +313,9 @@ export default {
       this.onLoad(this.page);
     },
     searchChange(params, done) {
-      if (params.checkDateRange){
-        params.checkDate_begin = params.checkDateRange[0], params.checkDate_end = params.checkDateRange[1];
-        params.checkDateRange = null;
-      }
-      if (params.orgNos){
-        params.orgNostr = params.orgNos.join();
-        params.orgNos = '';
-      }
-      if (params.type){
-        params.type = params.type.join();
-      }
-      if (params.item){
-        params.item = params.item.join();
+      if (params.dateRange){
+        params.date_begin = params.dateRange[0], params.date_end = params.dateRange[1];
+        params.dateRange = null;
       }
 
       this.query = params;
@@ -411,10 +342,9 @@ export default {
     onLoad(page, params = {}) {
       this.loading = true;
       params.cycle = this.cycle;
-      getList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => {
+      getReport(Object.assign(params, this.query)).then(res => {
         const data = res.data.data;
-        this.page.total = data.total;
-        this.data = data.records;
+        this.data = data;
         this.loading = false;
         this.selectionClear();
       });

+ 3 - 0
src/views/report/userlog.vue

@@ -284,6 +284,9 @@
               props:{
                 label: "dictValue",
                 value: "dictKey",
+              },dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
               },
               search: true,
               searchMultiple: true,

+ 3 - 0
src/views/resource/oss.vue

@@ -104,6 +104,9 @@
               props: {
                 label: "dictValue",
                 value: "dictKey"
+              },dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
               },
               dataType: "number",
               slot: true,

+ 3 - 0
src/views/system/dept.vue

@@ -171,6 +171,9 @@
               props: {
                 label: "dictValue",
                 value: "dictKey"
+              },dicFormatter: (res) => {
+                res.data.forEach(item => {item.disabled = item.isSealed == 1;})
+                return res.data;
               },
               dataType: "number",
               width: 120,