Prechádzať zdrojové kódy

feat: 添加ui组件列表

王家程 3 rokov pred
rodič
commit
9fadda24ce

+ 1 - 49
README.md

@@ -1,49 +1 @@
-# iview 组件替换
-
-## 人事管理-1
-组织架构 薪酬管理 入转调离
-## 资产管理
-车场管理 智能表管理 片区管理
-## 物业服务-1
-服务电话
-服务标准
-流程公约
-收费标准公示
-服务动态管理
-## 任务系统-1
-工单系统
-任务统计
-任务管理
-安保巡逻
-保洁清洁
-执勤记录
-## 收费设置
-账期设置
-押金设置
-预存款设置
-## 财务审核
-流水记录
-作废记录
-减免记录
-补录记录
-退费管理
-账单调账
-## 收费管理
-预存款列表
-退费记录
-押金列表
-## 财务报表
-报表导出
-数据大屏
-## 成本核算-1
-预算计划
-预算统计
-成本代码设置
-## 智能硬件-1
-对讲机
-对讲机绑定管理
-开门记录
-访客记录
-## 设备巡检-1
-设备设置
-设备台账
+# 绘开发

+ 62 - 0
src/components/generator/wisdomUiComp.js

@@ -0,0 +1,62 @@
+/*
+ * @Author: wjc
+ * @Date: 2021-09-15 17:46:28
+ * @LastEditors: wjc
+ * @LastEditTime: 2021-09-16 16:22:50
+ * @Description: wisdom ui 组件
+ */
+
+export const wFormComponents = [
+  {
+    // 组件的自定义配置
+    __config__: {
+      label: '单行文本',
+      labelWidth: null,
+      showLabel: true,
+      changeTag: true,
+      tag: 'el-input',
+      tagIcon: 'input',
+      defaultValue: undefined,
+      required: true,
+      layout: 'colFormItem',
+      span: 24,
+      // 正则校验规则
+      regList: []
+    },
+    // 组件的插槽属性
+    __slot__: {
+      prepend: '',
+      append: ''
+    },
+    // 其余的为可直接写在组件标签上的属性
+    placeholder: '请输入',
+    style: { width: '100%' },
+    clearable: true,
+    'prefix-icon': '',
+    'suffix-icon': '',
+    maxlength: null,
+    'show-word-limit': false,
+    readonly: false,
+    disabled: false
+  }
+]
+
+export const wLayoutComponents = [
+  {
+    // 组件的自定义配置
+    __config__: {
+      label: '页头',
+      tag: 'w-header',
+      tagIcon: 'wheader',
+      layout: 'auto',
+      span: 24
+    },
+    // 组件的插槽属性
+    __slot__: {
+      right: ''
+    },
+    // 其余的为可直接写在组件标签上的属性
+    desc: '', // 描述
+    back: ''
+  }
+]

+ 2 - 2
src/main.js

@@ -1,8 +1,8 @@
 /*
  * @Author: WangJiaCheng
  * @Date: 2021-05-07 11:34:26
- * @LastEditors: WangJiaCheng
- * @LastEditTime: 2021-07-09 15:46:45
+ * @LastEditors: wjc
+ * @LastEditTime: 2021-09-16 15:06:09
  * @Description:  入口
  */
 import Vue from 'vue'

+ 3 - 1
src/styles/variables.less

@@ -1 +1,3 @@
-@base-color: #1890ff;
+@base-color: #1890ff;
+@selectedColor: #f6f7ff;
+@lighterBlue: #409EFF;

+ 38 - 0
src/views/app/components/AttributePane/AttributePane.vue

@@ -0,0 +1,38 @@
+<!--
+ * @Author: WangJiaCheng
+ * @Date: 2021-09-14 16:24:04
+ * @LastEditors: wjc
+ * @LastEditTime: 2021-09-15 09:43:55
+ * @Description: 属性面板
+-->
+<template>
+  <div class="attribute-pane">
+    <el-button
+      type="primary"
+      @click="openPane"
+    >
+      打开
+    </el-button>
+    <div>
+      123
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'AttributePane',
+  props: {
+  },
+  data() {
+    return {
+      visible: false
+    }
+  },
+  methods: {
+    openPane() {
+      this.visible = true
+    }
+  }
+}
+</script>

+ 10 - 0
src/views/app/components/AttributePane/index.js

@@ -0,0 +1,10 @@
+/*
+ * @Author: WangJiaCheng
+ * @Date: 2021-09-14 16:24:09
+ * @LastEditors: WangJiaCheng
+ * @LastEditTime: 2021-09-14 16:25:10
+ * @Description:
+ */
+import AttributePane from './AttributePane.vue'
+
+export default AttributePane

+ 120 - 0
src/views/app/components/DraggableItem/DraggableItem.vue

@@ -0,0 +1,120 @@
+<script>
+import draggable from 'vuedraggable'
+import render from '@/components/render/render'
+
+const components = {
+  itemBtns(h, currentItem, index, list) {
+    const { copyItem, deleteItem } = this.$listeners
+    return [
+      <span class="drawing-item-copy" title="复制" onClick={event => {
+        copyItem(currentItem, list); event.stopPropagation()
+      }}>
+        <i class="el-icon-copy-document" />
+      </span>,
+      <span class="drawing-item-delete" title="删除" onClick={event => {
+        deleteItem(index, list); event.stopPropagation()
+      }}>
+        <i class="el-icon-delete" />
+      </span>
+    ]
+  }
+}
+const layouts = {
+  colFormItem(h, currentItem, index, list) {
+    const { activeItem } = this.$listeners
+    const config = currentItem.__config__
+    const child = renderChildren.apply(this, arguments)
+    let className = this.activeId === config.formId ? 'drawing-item active-from-item' : 'drawing-item'
+    if (this.formConf.unFocusedComponentBorder) className += ' unfocus-bordered'
+    let labelWidth = config.labelWidth ? `${config.labelWidth}px` : null
+    if (config.showLabel === false) labelWidth = '0'
+    return (
+      <el-col span={config.span} class={className}
+        nativeOnClick={event => { activeItem(currentItem); event.stopPropagation() }}>
+        <el-form-item label-width={labelWidth}
+          label={config.showLabel ? config.label : ''} required={config.required}>
+          <render key={config.renderKey} conf={currentItem} onInput={ event => {
+            this.$set(config, 'defaultValue', event)
+          }}>
+            {child}
+          </render>
+        </el-form-item>
+        {components.itemBtns.apply(this, arguments)}
+      </el-col>
+    )
+  },
+  rowFormItem(h, currentItem, index, list) {
+    const { activeItem } = this.$listeners
+    const config = currentItem.__config__
+    const className = this.activeId === config.formId
+      ? 'drawing-row-item active-from-item'
+      : 'drawing-row-item'
+    let child = renderChildren.apply(this, arguments)
+    if (currentItem.type === 'flex') {
+      child = <el-row type={currentItem.type} justify={currentItem.justify} align={currentItem.align}>
+              {child}
+            </el-row>
+    }
+    return (
+      <el-col span={config.span}>
+        <el-row gutter={config.gutter} class={className}
+          nativeOnClick={event => { activeItem(currentItem); event.stopPropagation() }}>
+          <span class="component-name">{config.componentName}</span>
+          <draggable list={config.children || []} animation={340}
+            group="componentsGroup" class="drag-wrapper">
+            {child}
+          </draggable>
+          {components.itemBtns.apply(this, arguments)}
+        </el-row>
+      </el-col>
+    )
+  },
+  raw(h, currentItem, index, list) {
+    const config = currentItem.__config__
+    const child = renderChildren.apply(this, arguments)
+    return <render key={config.renderKey} conf={currentItem} onInput={ event => {
+      this.$set(config, 'defaultValue', event)
+    }}>
+      {child}
+    </render>
+  }
+}
+
+function renderChildren(h, currentItem, index, list) {
+  const config = currentItem.__config__
+  if (!Array.isArray(config.children)) return null
+  return config.children.map((el, i) => {
+    const layout = layouts[el.__config__.layout]
+    if (layout) {
+      return layout.call(this, h, el, i, config.children)
+    }
+    return layoutIsNotFound.call(this)
+  })
+}
+
+function layoutIsNotFound() {
+  throw new Error(`没有与${this.currentItem.__config__.layout}匹配的layout`)
+}
+
+export default {
+  components: {
+    render,
+    draggable
+  },
+  props: [
+    'currentItem',
+    'index',
+    'drawingList',
+    'activeId',
+    'formConf'
+  ],
+  render(h) {
+    const layout = layouts[this.currentItem.__config__.layout]
+
+    if (layout) {
+      return layout.call(this, h, this.currentItem, this.index, this.drawingList)
+    }
+    return layoutIsNotFound.call(this)
+  }
+}
+</script>

+ 10 - 0
src/views/app/components/DraggableItem/index.js

@@ -0,0 +1,10 @@
+/*
+ * @Author: wjc
+ * @Date: 2021-09-16 17:06:12
+ * @LastEditors: wjc
+ * @LastEditTime: 2021-09-16 17:06:13
+ * @Description:
+ */
+import DraggableItem from './DraggableItem.vue'
+
+export default DraggableItem

+ 150 - 0
src/views/app/components/ElementUiPane/ElementUiPane.vue

@@ -0,0 +1,150 @@
+<!--
+ * @Author: wjc
+ * @Date: 2021-09-15 16:03:17
+ * @LastEditors: wjc
+ * @LastEditTime: 2021-09-16 11:23:18
+ * @Description:
+-->
+<template>
+  <div class="element-ui-pane">
+    <el-scrollbar>
+      <div class="components-list">
+        <div v-for="(item, listIndex) in elementComponents" :key="listIndex">
+          <div class="components-title">
+            <svg-icon icon-class="component" />
+            {{ item.title }}
+          </div>
+          <draggable
+            class="components-draggable"
+            :list="item.list"
+            :group="{ name: 'componentsGroup', pull: 'clone', put: false }"
+            :clone="cloneComponent"
+            draggable=".components-item"
+            :sort="false"
+            @end="onEnd"
+          >
+            <div
+              v-for="(element, index) in item.list"
+              :key="index"
+              class="components-item"
+              @click="addComponent(element)"
+            >
+              <div class="components-body">
+                <svg-icon :icon-class="element.__config__.tagIcon" />
+                {{ element.__config__.label }}
+              </div>
+            </div>
+          </draggable>
+        </div>
+      </div>
+    </el-scrollbar>
+  </div>
+</template>
+
+<script>
+import draggable from 'vuedraggable'
+
+import {
+  inputComponents, selectComponents, layoutComponents, formConf
+} from '@/components/generator/config'
+
+export default {
+  name: 'ElementUiPane',
+  components: {
+    draggable
+  },
+  props: {
+  },
+  data() {
+    return {
+      elementComponents: [
+        {
+          title: '输入型组件',
+          list: inputComponents
+        },
+        {
+          title: '选择型组件',
+          list: selectComponents
+        },
+        {
+          title: '布局型组件',
+          list: layoutComponents
+        }
+      ]
+    }
+  },
+  methods: {
+    addComponent(item) {
+      // const clone = this.cloneComponent(item)
+      // this.fetchData(clone)
+      // this.drawingList.push(clone)
+      // this.activeFormItem(clone)
+    },
+    cloneComponent(origin) {
+      // const clone = deepClone(origin)
+      // const config = clone.__config__
+      // config.span = this.formConf.span // 生成代码时,会根据span做精简判断
+      // this.createIdAndKey(clone)
+      // clone.placeholder !== undefined && (clone.placeholder += config.label)
+      // tempActiveData = clone
+      // return tempActiveData
+    },
+    onEnd(obj) {
+      // if (obj.from !== obj.to) {
+      //   this.fetchData(tempActiveData)
+      //   this.activeData = tempActiveData
+      //   this.activeId = this.idGlobal
+      // }
+    }
+  }
+}
+</script>
+
+<style lang="less">
+  .element-ui-pane {
+    height: calc(100vh - 60px);
+    overflow: hidden;
+    .components-list {
+      padding: 8px;
+      box-sizing: border-box;
+      height: 100%;
+      .components-draggable {
+        padding-bottom: 20px;
+        .components-item {
+          display: inline-block;
+          width: 48%;
+          margin: 1%;
+          transition: transform 0ms !important;
+          .components-body {
+            padding: 8px 10px;
+            background: @selectedColor;
+            font-size: 12px;
+            cursor: move;
+            border: 1px dashed @selectedColor;
+            border-radius: 3px;
+            .svg-icon{
+              color: #777;
+              font-size: 15px;
+            }
+            &:hover {
+              border: 1px dashed #787be8;
+              color: #787be8;
+              .svg-icon {
+                color: #787be8;
+              }
+            }
+          }
+        }
+      }
+      .components-title{
+        font-size: 14px;
+        color: #222;
+        margin: 6px 2px;
+        .svg-icon{
+          color: #666;
+          font-size: 18px;
+        }
+      }
+    }
+  }
+</style>

+ 10 - 0
src/views/app/components/ElementUiPane/index.js

@@ -0,0 +1,10 @@
+/*
+ * @Author: wjc
+ * @Date: 2021-09-15 16:02:17
+ * @LastEditors: wjc
+ * @LastEditTime: 2021-09-15 16:08:48
+ * @Description:
+ */
+import ElementUiPane from './ElementUiPane.vue'
+
+export default ElementUiPane

+ 152 - 0
src/views/app/components/WisdomUiPane/WisdomUiPane.vue

@@ -0,0 +1,152 @@
+<!--
+ * @Author: wjc
+ * @Date: 2021-09-15 16:03:17
+ * @LastEditors: wjc
+ * @LastEditTime: 2021-09-16 17:46:09
+ * @Description:
+-->
+<template>
+  <div class="wisdom-ui-pane">
+    <el-scrollbar>
+      <div class="components-list">
+        <div v-for="(item, listIndex) in elementComponents" :key="listIndex">
+          <div class="components-title">
+            <svg-icon icon-class="component" />
+            {{ item.title }}
+          </div>
+          <draggable
+            class="components-draggable"
+            :list="item.list"
+            :group="{ name: 'componentsGroup', pull: 'clone', put: false }"
+            :clone="cloneComponent"
+            draggable=".components-item"
+            :sort="false"
+            @end="onEnd"
+          >
+            <div
+              v-for="(element, index) in item.list"
+              :key="index"
+              class="components-item"
+              @click="addComponent(element)"
+            >
+              <div class="components-body">
+                <svg-icon :icon-class="element.__config__.tagIcon" />
+                {{ element.__config__.label }}
+              </div>
+            </div>
+          </draggable>
+        </div>
+      </div>
+    </el-scrollbar>
+  </div>
+</template>
+
+<script>
+import draggable from 'vuedraggable'
+
+import {
+  exportDefault, beautifierConf, isNumberStr, titleCase, deepClone, isObjectObject
+} from '@/utils/index'
+import {
+  wFormComponents, wLayoutComponents
+} from '@/components/generator/wisdomUiComp'
+
+let tempActiveData
+
+export default {
+  name: 'WisdomUiPane',
+  components: {
+    draggable
+  },
+  props: {
+  },
+  data() {
+    return {
+      elementComponents: [
+        {
+          title: '表单型组件',
+          list: wFormComponents
+        },
+        {
+          title: '布局型组件',
+          list: wLayoutComponents
+        }
+      ]
+    }
+  },
+  methods: {
+    addComponent(item) {
+      // const clone = this.cloneComponent(item)
+      // this.fetchData(clone)
+      // this.drawingList.push(clone)
+      // this.activeFormItem(clone)
+    },
+    cloneComponent(origin) {
+      const clone = deepClone(origin)
+      const config = clone.__config__
+      // config.span = this.formConf.span // 生成代码时,会根据span做精简判断
+      // this.createIdAndKey(clone)
+      clone.placeholder !== undefined && (clone.placeholder += config.label)
+      tempActiveData = clone
+      console.log('clone', tempActiveData)
+      return tempActiveData
+    },
+    onEnd(obj) {
+      // if (obj.from !== obj.to) {
+      //   this.fetchData(tempActiveData)
+      //   this.activeData = tempActiveData
+      //   this.activeId = this.idGlobal
+      // }
+    }
+  }
+}
+</script>
+
+<style lang="less">
+  .wisdom-ui-pane {
+    height: calc(100vh - 60px);
+    overflow: hidden;
+    .components-list {
+      padding: 8px;
+      box-sizing: border-box;
+      height: 100%;
+      .components-draggable {
+        padding-bottom: 20px;
+        .components-item {
+          display: inline-block;
+          width: 48%;
+          margin: 1%;
+          transition: transform 0ms !important;
+          .components-body {
+            padding: 8px 10px;
+            background: @selectedColor;
+            font-size: 12px;
+            cursor: move;
+            border: 1px dashed @selectedColor;
+            border-radius: 3px;
+            .svg-icon{
+              color: #777;
+              font-size: 15px;
+            }
+            &:hover {
+              border: 1px dashed #787be8;
+              color: #787be8;
+              .svg-icon {
+                color: #787be8;
+              }
+            }
+          }
+        }
+      }
+      .components-title{
+        font-size: 14px;
+        color: #222;
+        margin: 6px 2px;
+        .svg-icon{
+          color: #666;
+          font-size: 18px;
+        }
+      }
+    }
+  }
+</style>

+ 10 - 0
src/views/app/components/WisdomUiPane/index.js

@@ -0,0 +1,10 @@
+/*
+ * @Author: wjc
+ * @Date: 2021-09-15 17:30:23
+ * @LastEditors: wjc
+ * @LastEditTime: 2021-09-15 17:30:23
+ * @Description:
+ */
+import WisdomUiPane from './WisdomUiPane.vue'
+
+export default WisdomUiPane

+ 101 - 0
src/views/app/editor/EditorArea/EditorArea.vue

@@ -0,0 +1,101 @@
+<!--
+ * @Author: wjc
+ * @Date: 2021-09-16 10:55:40
+ * @LastEditors: wjc
+ * @LastEditTime: 2021-09-16 18:03:27
+ * @Description:
+-->
+<template>
+  <div class="editor-area">
+    <draggable
+      :list="editorList"
+      :animation="340"
+      class="drag-board"
+      group="componentsGroup"
+    >
+      <draggable-item
+        v-for="(item, index) in editorList"
+        :key="item.renderKey"
+        :drawing-list="editorList"
+        :current-item="item"
+        :index="index"
+        :active-id="activeId"
+        :form-conf="formConf"
+        @activeItem="activeFormItem"
+        @deleteItem="drawingItemDelete"
+      />
+    </draggable>
+    <div class="header-area">
+      header
+    </div>
+    <div class="form-area">
+      form
+    </div>
+    <div class="table-area">
+      table
+    </div>
+  </div>
+</template>
+
+<script>
+import draggable from 'vuedraggable'
+
+import DraggableItem from '../../components/DraggableItem'
+
+export default {
+  name: 'EditorArea',
+  components: {
+    draggable,
+    DraggableItem
+  },
+  data() {
+    return {
+      formConf: {
+        formRef: 'elForm',
+        inline: false,
+        formModel: 'formData',
+        size: 'medium',
+        labelPosition: 'right',
+        labelWidth: 100,
+        formRules: 'rules',
+        gutter: 15,
+        disabled: false,
+        span: 24,
+        formBtns: true
+      },
+      activeId: 1,
+      activeData: [],
+      editorList: []
+    }
+  },
+  methods: {
+    // 当前选中的组件
+    activeFormItem(currentItem) {
+      this.activeData = currentItem
+      this.activeId = currentItem.__config__.formId
+    },
+    drawingItemDelete(index, list) {
+      list.splice(index, 1)
+      this.$nextTick(() => {
+        const len = this.editorList.length
+        if (len) {
+          this.activeFormItem(this.editorList[len - 1])
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style lang='less'>
+  .editor-area {
+    background: #fff;
+    width: 100%;
+    height: 100%;
+    .drag-board {
+      height: 500px;
+    }
+    // .header-area {
+    // }
+  }
+</style>

+ 10 - 0
src/views/app/editor/EditorArea/index.js

@@ -0,0 +1,10 @@
+/*
+ * @Author: WangJiaCheng
+ * @Date: 2021-09-14 16:24:09
+ * @LastEditors: wjc
+ * @LastEditTime: 2021-09-16 10:56:25
+ * @Description:
+ */
+import EditorArea from './EditorArea.vue'
+
+export default EditorArea

+ 37 - 16
src/views/app/editor/index.vue

@@ -1,8 +1,8 @@
 <!--
  * @Author: WangJiaCheng
  * @Date: 2021-08-20 09:10:36
- * @LastEditors: WangJiaCheng
- * @LastEditTime: 2021-08-20 18:12:06
+ * @LastEditors: wjc
+ * @LastEditTime: 2021-09-16 15:24:45
  * @Description: 编辑器
 -->
 <template>
@@ -10,45 +10,55 @@
     <div class="editor-menu">
       <el-tabs
         tab-position="left"
-        style="width: 400px;height: 100%;"
+        style="height: 100%;"
       >
         <el-tab-pane>
-          <span slot="label">
-            <img :src="wcIconImg" alt="wc" style="width: 24px;">
+          <span slot="label" style="text-align: center">
+            <img :src="wcIconImg" alt="wc" style="width: 16px; vertical-align: middle">
           </span>
-          WisdomUI
+          <wisdom-ui-pane />
         </el-tab-pane>
         <el-tab-pane>
-          <span slot="label">
-            <svg-icon icon-class="element-icon" style="font-size: 24px;" />
+          <span slot="label" style="text-align: center">
+            <svg-icon icon-class="element-icon" style="font-size: 24px; vertical-align: middle" />
           </span>
-          ElemenUI
+          <element-ui-pane />
         </el-tab-pane>
         <el-tab-pane>
-          <span slot="label">
-            <svg-icon icon-class="component" style="font-size: 24px;" />
+          <span slot="label" style="text-align: center">
+            <svg-icon icon-class="component" style="font-size: 24px; vertical-align: middle" />
           </span>
-          自定义
+          自定义组件
         </el-tab-pane>
       </el-tabs>
     </div>
     <div class="editor-main">
-      编辑区
+      <editor-area />
     </div>
     <div class="editor-prop">
       属性
+      <attribute-pane />
     </div>
   </div>
 </template>
 
 <script>
-import {
-  inputComponents, selectComponents, layoutComponents, formConf
-} from '@/components/generator/config'
 import wcIcon from '@/assets/wc.png'
 
+import AttributePane from '../components/AttributePane'
+import WisdomUiPane from '../components/WisdomUiPane'
+import ElementUiPane from '../components/ElementUiPane'
+
+import EditorArea from './EditorArea'
+
 export default {
   name: 'Editor',
+  components: {
+    AttributePane,
+    WisdomUiPane,
+    ElementUiPane,
+    EditorArea
+  },
   data() {
     return {}
   },
@@ -66,7 +76,18 @@ export default {
     height: 100%;
     display: flex;
     .editor-menu {
+      width: 20%;
       height: 100%;
+      .el-tabs__nav {
+        .el-tabs__item {
+          text-align: center;
+        }
+      }
+    }
+    .editor-main {
+      padding: 20px;
+      background: #f5f5f5;
+      width: 60%;
     }
   }
 </style>