ymy 6 månader sedan
förälder
incheckning
05cf979263

+ 140 - 0
src/api/flowable/definition.js

@@ -0,0 +1,140 @@
+import request from '@/benyun/utils/request'
+
+// 查询流程定义列表
+export function listDefinition(query) {
+  return request({
+    url: '/system/flowable/definition/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 部署流程实例
+export function definitionStart(procDefId, data) {
+  return request({
+    url: '/system/flowable/definition/start/' + procDefId,
+    method: 'post',
+    data: data
+  })
+}
+
+// 获取流程变量
+export function getProcessVariables(taskId) {
+  return request({
+    url: '/system/flowable/task/processVariables/' + taskId,
+    method: 'get'
+  })
+}
+
+// 激活/挂起流程
+export function updateState(params) {
+  return request({
+    url: '/system/flowable/definition/updateState',
+    method: 'put',
+    params: params
+  })
+}
+
+// 指定流程办理人员列表
+export function userList(query) {
+  return request({
+    url: '/system/flowable/definition/userList',
+    method: 'get',
+    params: query
+  })
+}
+
+// 指定流程办理组列表
+export function roleList(query) {
+  return request({
+    url: '/system/flowable/definition/roleList',
+    method: 'get',
+    params: query
+  })
+}
+
+// 指定流程表达式
+export function expList(query) {
+  return request({
+    url: '/system/flowable/definition/expList',
+    method: 'get',
+    params: query
+  })
+}
+
+// 读取xml文件
+export function readXml(deployId) {
+  return request({
+    url: '/system/flowable/definition/readXml/' + deployId,
+    method: 'get'
+  })
+}
+
+// 读取image文件
+export function readImage(deployId) {
+  return request({
+    url: '/system/flowable/definition/readImage/' + deployId,
+    method: 'get'
+  })
+}
+
+// 获取流程执行节点
+export function getFlowViewer(procInsId, executionId) {
+  return request({
+    url: '/system/flowable/task/flowViewer/' + procInsId + '/' + executionId,
+    method: 'get'
+  })
+}
+
+// 流程节点数据
+export function flowXmlAndNode(query) {
+  return request({
+    url: '/system/flowable/task/flowXmlAndNode',
+    method: 'get',
+    params: query
+  })
+}
+
+// 读取xml文件
+export function saveXml(data) {
+  return request({
+    url: '/system/flowable/definition/save',
+    method: 'post',
+    data: data
+  })
+}
+
+// 新增流程定义
+export function addDeployment(data) {
+  return request({
+    url: '/system/system/deployment',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改流程定义
+export function updateDeployment(data) {
+  return request({
+    url: '/system/system/deployment',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除流程定义
+export function delDeployment(deployId) {
+  return request({
+    url: '/system/flowable/definition/' + deployId,
+    method: 'delete',
+  })
+}
+
+// 导出流程定义
+export function exportDeployment(query) {
+  return request({
+    url: '/system/system/deployment/export',
+    method: 'get',
+    params: query
+  })
+}

+ 80 - 0
src/api/flowable/finished.js

@@ -0,0 +1,80 @@
+import request from '@/benyun/utils/request'
+import da from "element-ui/src/locale/lang/da";
+
+// 查询已办任务列表
+export function finishedList(query) {
+  return request({
+    url: '/system/flowable/task/finishedList',
+    method: 'get',
+    params: query
+  })
+}
+
+// 任务流转记录
+export function flowRecord(query) {
+  return request({
+    url: '/system/flowable/task/flowRecord',
+    method: 'get',
+    params: query
+  })
+}
+
+// 撤回任务
+export function revokeProcess(data) {
+  return request({
+    url: '/system/flowable/task/revokeProcess',
+    method: 'post',
+    data: data
+  })
+}
+
+// 部署流程实例
+export function deployStart(deployId) {
+  return request({
+    url: '/system/flowable/process/startFlow/' + deployId,
+    method: 'get',
+  })
+}
+
+// 查询流程定义详细
+export function getDeployment(id) {
+  return request({
+    url: '/system/system/deployment/' + id,
+    method: 'get'
+  })
+}
+
+// 新增流程定义
+export function addDeployment(data) {
+  return request({
+    url: '/system/system/deployment',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改流程定义
+export function updateDeployment(data) {
+  return request({
+    url: '/system/system/deployment',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除流程定义
+export function delDeployment(id) {
+  return request({
+    url: '/system/flowable/instance/delete/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出流程定义
+export function exportDeployment(query) {
+  return request({
+    url: '/system/system/deployment/export',
+    method: 'get',
+    params: query
+  })
+}

+ 68 - 0
src/api/flowable/form.js

@@ -0,0 +1,68 @@
+import request from '@/benyun/utils/request'
+
+// 查询流程表单列表
+export function listForm(query) {
+  return request({
+    url: '/system/flowable/form/list',
+    method: 'get',
+    params: query
+  })
+}
+export function listAllForm(query) {
+  return request({
+    url: '/system/flowable/form/formList',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询流程表单详细
+export function getForm(formId) {
+  return request({
+    url: '/system/flowable/form/' + formId,
+    method: 'get'
+  })
+}
+
+// 新增流程表单
+export function addForm(data) {
+  return request({
+    url: '/system/flowable/form',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改流程表单
+export function updateForm(data) {
+  return request({
+    url: '/system/flowable/form',
+    method: 'put',
+    data: data
+  })
+}
+// 挂载表单
+export function addDeployForm(data) {
+  return request({
+    url: '/system/flowable/form/addDeployForm',
+    method: 'post',
+    data: data
+  })
+}
+
+// 删除流程表单
+export function delForm(formId) {
+  return request({
+    url: '/system/flowable/form/' + formId,
+    method: 'delete'
+  })
+}
+
+// 导出流程表单
+export function exportForm(query) {
+  return request({
+    url: '/system/flowable/form/export',
+    method: 'get',
+    params: query
+  })
+}

+ 106 - 0
src/api/flowable/process.js

@@ -0,0 +1,106 @@
+import request from '@/benyun/utils/request'
+import da from "element-ui/src/locale/lang/da";
+
+// 我的发起的流程
+export function myProcessList(query) {
+  return request({
+    url: '/system/flowable/task/myProcess',
+    method: 'get',
+    params: query
+  })
+}
+
+export function flowFormData(query) {
+  return request({
+    url: '/system/flowable/task/flowFormData',
+    method: 'get',
+    params: query
+  })
+}
+
+// 完成任务
+export function complete(data) {
+  return request({
+    url: '/system/flowable/task/complete',
+    method: 'post',
+    data: data
+  })
+}
+
+// 取消申请
+export function stopProcess(data) {
+  return request({
+    url: '/system/flowable/task/stopProcess',
+    method: 'post',
+    data: data
+  })
+}
+
+// 驳回任务
+export function rejectTask(data) {
+  return request({
+    url: '/system/flowable/task/reject',
+    method: 'post',
+    data: data
+  })
+}
+
+// 可退回任务列表
+export function returnList(data) {
+  return request({
+    url: '/system/flowable/task/returnList',
+    method: 'post',
+    data: data
+  })
+}
+
+// 部署流程实例
+export function deployStart(deployId) {
+  return request({
+    url: '/system/flowable/process/startFlow/' + deployId,
+    method: 'get',
+  })
+}
+
+// 查询流程定义详细
+export function getDeployment(id) {
+  return request({
+    url: '/system/system/deployment/' + id,
+    method: 'get'
+  })
+}
+
+// 新增流程定义
+export function addDeployment(data) {
+  return request({
+    url: '/system/system/deployment',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改流程定义
+export function updateDeployment(data) {
+  return request({
+    url: '/system/system/deployment',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除流程定义
+export function delDeployment(id) {
+  return request({
+    url: '/system/system/deployment/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出流程定义
+export function exportDeployment(query) {
+  return request({
+    url: '/system/system/deployment/export',
+    method: 'get',
+    params: query
+  })
+}

+ 133 - 0
src/api/flowable/todo.js

@@ -0,0 +1,133 @@
+import request from '@/benyun/utils/request'
+import da from "element-ui/src/locale/lang/da";
+
+// 查询待办任务列表
+export function todoList(query) {
+  return request({
+    url: '/system/flowable/task/todoList',
+    method: 'get',
+    params: query
+  })
+}
+
+// 完成任务
+export function complete(data) {
+  return request({
+    url: '/system/flowable/task/complete',
+    method: 'post',
+    data: data
+  })
+}
+
+// 委派任务
+export function delegate(data) {
+  return request({
+    url: '/system/flowable/task/delegate',
+    method: 'post',
+    data: data
+  })
+}
+
+// 退回任务
+export function returnTask(data) {
+  return request({
+    url: '/system/flowable/task/return',
+    method: 'post',
+    data: data
+  })
+}
+
+// 驳回任务
+export function rejectTask(data) {
+  return request({
+    url: '/system/flowable/task/reject',
+    method: 'post',
+    data: data
+  })
+}
+
+// 可退回任务列表
+export function returnList(data) {
+  return request({
+    url: '/system/flowable/task/returnList',
+    method: 'post',
+    data: data
+  })
+}
+
+// 下一节点
+export function getNextFlowNode(data) {
+  return request({
+    url: '/system/flowable/task/nextFlowNode',
+    method: 'post',
+    data: data
+  })
+}
+
+// 下一节点
+export function getNextFlowNodeByStart(data) {
+  return request({
+    url: '/system/flowable/task/nextFlowNodeByStart',
+    method: 'post',
+    data: data
+  })
+}
+
+// 部署流程实例
+export function deployStart(deployId) {
+  return request({
+    url: '/system/flowable/process/startFlow/' + deployId,
+    method: 'get',
+  })
+}
+
+// 查询流程定义详细
+export function getDeployment(id) {
+  return request({
+    url: '/system/system/deployment/' + id,
+    method: 'get'
+  })
+}
+
+// 新增流程定义
+export function addDeployment(data) {
+  return request({
+    url: '/system/system/deployment',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改流程定义
+export function updateDeployment(data) {
+  return request({
+    url: '/system/system/deployment',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除流程定义
+export function delDeployment(id) {
+  return request({
+    url: '/system/system/deployment/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出流程定义
+export function exportDeployment(query) {
+  return request({
+    url: '/system/system/deployment/export',
+    method: 'get',
+    params: query
+  })
+}
+// 流程节点表单
+export function flowTaskForm(query) {
+  return request({
+    url: '/system/flowable/task/flowTaskForm',
+    method: 'get',
+    params: query
+  })
+}

+ 1 - 1
src/benyun/utils/auth.ts

@@ -6,7 +6,7 @@ const ExpiresInKey = 'AdminOMS-Expires-In'
 
 export function getToken() {
   if(process.env.NODE_ENV === 'development'){
-    return 'eyJhbGciOiJIUzUxMiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX2tleSI6IjAwYTM1NDQ1LWU0NjMtNGE1Ni04ODAwLWM2ZWY0NWVkOTZiMyIsInVzZXJuYW1lIjoiYWRtaW4ifQ.vCwETSaP31hNDl17XLM6DKA7vnk4UYTSRn584xkpxo1bYoRjQ3oASyhcMRJIec6xFuavZSa5FyQMJlUGF3rD0g'
+    return 'eyJhbGciOiJIUzUxMiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX2tleSI6IjRkMzkxNTI0LWYzYmYtNDQxZS04OTgyLWE2NTcwZWE1OTJkNyIsInVzZXJuYW1lIjoiYWRtaW4ifQ.ggtNOVHV-mBJ_-8tSi4U_BnKgi0cGFV4a5j6ON9qGV7IxL6qsfl1qV_RY-kEtn_g2QM5yGDF3usPmljbzbkpHQ'
   }else{
     return Cookies.get(TokenKey)
   }

+ 36 - 0
src/components/iFrame/index.vue

@@ -0,0 +1,36 @@
+<template>
+  <div v-loading="loading" :style="'height:' + height">
+    <iframe
+      :src="src"
+      frameborder="no"
+      style="width: 100%; height: 100%"
+      scrolling="auto"
+    />
+  </div>
+</template>
+<script>
+export default {
+  props: {
+    src: {
+      type: String,
+      required: true
+    },
+  },
+  data() {
+    return {
+      height: document.documentElement.clientHeight - 94.5 + "px;",
+      loading: true,
+      url: this.src
+    };
+  },
+  mounted: function () {
+    setTimeout(() => {
+      this.loading = false;
+    }, 300);
+    const that = this;
+    window.onresize = function temp() {
+      that.height = document.documentElement.clientHeight - 94.5 + "px;";
+    };
+  }
+};
+</script>

+ 19 - 0
src/components/render/package.json

@@ -0,0 +1,19 @@
+{
+  "name": "form-gen-render",
+  "version": "1.0.4",
+  "description": "表单核心render",
+  "main": "lib/form-gen-render.umd.js",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/JakHuang/form-generator.git"
+  },
+  "author": "jakhuang",
+  "license": "MIT",
+  "bugs": {
+    "url": "https://github.com/JakHuang/form-generator/issues"
+  },
+  "homepage": "https://github.com/JakHuang/form-generator#readme"
+}

+ 122 - 0
src/components/render/render.js

@@ -0,0 +1,122 @@
+import { deepClone } from '@/benyun/utils/index'
+
+const componentChild = {}
+/**
+ * 将./slots中的文件挂载到对象componentChild上
+ * 文件名为key,对应JSON配置中的__config__.tag
+ * 文件内容为value,解析JSON配置中的__slot__
+ */
+const slotsFiles = require.context('./slots', false, /\.js$/)
+const keys = slotsFiles.keys() || []
+keys.forEach(key => {
+  const tag = key.replace(/^\.\/(.*)\.\w+$/, '$1')
+  const value = slotsFiles(key).default
+  componentChild[tag] = value
+})
+
+function vModel(dataObject, defaultValue) {
+  dataObject.props.value = defaultValue
+
+  dataObject.on.input = val => {
+    this.$emit('input', val)
+  }
+}
+
+function mountSlotFiles(h, confClone, children) {
+  const childObjs = componentChild[confClone.__config__.tag]
+  if (childObjs) {
+    Object.keys(childObjs).forEach(key => {
+      const childFunc = childObjs[key]
+      if (confClone.__slot__ && confClone.__slot__[key]) {
+        children.push(childFunc(h, confClone, key))
+      }
+    })
+  }
+}
+
+function emitEvents(confClone) {
+  ['on', 'nativeOn'].forEach(attr => {
+    const eventKeyList = Object.keys(confClone[attr] || {})
+    eventKeyList.forEach(key => {
+      const val = confClone[attr][key]
+      if (typeof val === 'string') {
+        confClone[attr][key] = event => this.$emit(val, event)
+      }
+    })
+  })
+}
+
+function buildDataObject(confClone, dataObject) {
+  Object.keys(confClone).forEach(key => {
+    const val = confClone[key]
+    if (key === '__vModel__') {
+      vModel.call(this, dataObject, confClone.__config__.defaultValue)
+    } else if (dataObject[key] !== undefined) {
+      if (dataObject[key] === null
+        || dataObject[key] instanceof RegExp
+        || ['boolean', 'string', 'number', 'function'].includes(typeof dataObject[key])) {
+        dataObject[key] = val
+      } else if (Array.isArray(dataObject[key])) {
+        dataObject[key] = [...dataObject[key], ...val]
+      } else {
+        dataObject[key] = { ...dataObject[key], ...val }
+      }
+    } else {
+      dataObject.attrs[key] = val
+    }
+  })
+
+  // 清理属性
+  clearAttrs(dataObject)
+}
+
+function clearAttrs(dataObject) {
+  delete dataObject.attrs.__config__
+  delete dataObject.attrs.__slot__
+  delete dataObject.attrs.__methods__
+}
+
+function makeDataObject() {
+  // 深入数据对象:
+  // https://cn.vuejs.org/v2/guide/render-function.html#%E6%B7%B1%E5%85%A5%E6%95%B0%E6%8D%AE%E5%AF%B9%E8%B1%A1
+  return {
+    class: {},
+    attrs: {},
+    props: {},
+    domProps: {},
+    nativeOn: {},
+    on: {},
+    style: {},
+    directives: [],
+    scopedSlots: {},
+    slot: null,
+    key: null,
+    ref: null,
+    refInFor: true
+  }
+}
+
+export default {
+  props: {
+    conf: {
+      type: Object,
+      required: true
+    }
+  },
+  render(h) {
+    const dataObject = makeDataObject()
+    const confClone = deepClone(this.conf)
+    const children = this.$slots.default || []
+
+    // 如果slots文件夹存在与当前tag同名的文件,则执行文件中的代码
+    mountSlotFiles.call(this, h, confClone, children)
+
+    // 将字符串类型的事件,发送为消息
+    emitEvents.call(this, confClone)
+
+    // 将json表单配置转化为vue render可以识别的 “数据对象(dataObject)”
+    buildDataObject.call(this, confClone, dataObject)
+
+    return h(this.conf.__config__.tag, dataObject, children)
+  }
+}

+ 5 - 0
src/components/render/slots/el-button.js

@@ -0,0 +1,5 @@
+export default {
+  default(h, conf, key) {
+    return conf.__slot__[key]
+  }
+}

+ 13 - 0
src/components/render/slots/el-checkbox-group.js

@@ -0,0 +1,13 @@
+export default {
+  options(h, conf, key) {
+    const list = []
+    conf.__slot__.options.forEach(item => {
+      if (conf.__config__.optionType === 'button') {
+        list.push(<el-checkbox-button label={item.value}>{item.label}</el-checkbox-button>)
+      } else {
+        list.push(<el-checkbox label={item.value} border={conf.border}>{item.label}</el-checkbox>)
+      }
+    })
+    return list
+  }
+}

+ 8 - 0
src/components/render/slots/el-input.js

@@ -0,0 +1,8 @@
+export default {
+  prepend(h, conf, key) {
+    return <template slot="prepend">{conf.__slot__[key]}</template>
+  },
+  append(h, conf, key) {
+    return <template slot="append">{conf.__slot__[key]}</template>
+  }
+}

+ 13 - 0
src/components/render/slots/el-radio-group.js

@@ -0,0 +1,13 @@
+export default {
+  options(h, conf, key) {
+    const list = []
+    conf.__slot__.options.forEach(item => {
+      if (conf.__config__.optionType === 'button') {
+        list.push(<el-radio-button label={item.value}>{item.label}</el-radio-button>)
+      } else {
+        list.push(<el-radio label={item.value} border={conf.border}>{item.label}</el-radio>)
+      }
+    })
+    return list
+  }
+}

+ 9 - 0
src/components/render/slots/el-select.js

@@ -0,0 +1,9 @@
+export default {
+  options(h, conf, key) {
+    const list = []
+    conf.__slot__.options.forEach(item => {
+      list.push(<el-option label={item.label} value={item.value} disabled={item.disabled}></el-option>)
+    })
+    return list
+  }
+}

+ 17 - 0
src/components/render/slots/el-upload.js

@@ -0,0 +1,17 @@
+export default {
+  'list-type': (h, conf, key) => {
+    const list = []
+    const config = conf.__config__
+    if (conf['list-type'] === 'picture-card') {
+      list.push(<i class="el-icon-plus"></i>)
+    } else {
+      list.push(<el-button size="small" type="primary" icon="el-icon-upload">{config.buttonText}</el-button>)
+    }
+    if (config.showTip) {
+      list.push(
+        <div slot="tip" class="el-upload__tip">只能上传不超过 {config.fileSize}{config.sizeUnit} 的{conf.accept}文件</div>
+      )
+    }
+    return list
+  }
+}

+ 3 - 0
src/layout/components/TagsView/index.vue

@@ -133,6 +133,9 @@ export default {
       const { name } = this.$route
       if (name) {
         this.$store.dispatch('tagsView/addView', this.$route)
+        if (this.$route.meta.link) {
+          this.$store.dispatch('tagsView/addIframeView', this.$route)
+        }
       }
       return false
     },

+ 1 - 1
src/main.ts

@@ -90,7 +90,7 @@ Vue.config.productionTip = false
 Vue.prototype.getDicts = getDicts
 Vue.prototype.$request = request;
 Vue.prototype.$lodash = lodash;
-Vue.prototype.$download = download; //下载
+// Vue.prototype.$download = download; //下载
 Vue.prototype.$XModal = VXETable.modal
 // 全局方法挂载
 Vue.prototype.getDicts = getDicts

+ 27 - 15
src/router/index.ts

@@ -194,21 +194,33 @@ export const dynamicRoutes = [
   //     }
   //   }]
   // },
-  // {
-  //   path: '/tool/gen-edit',
-  //   component: Layout,
-  //   hidden: true,
-  //   permissions: ['tool:gen:edit'],
-  //   children: [{
-  //     path: 'index/:tableId(\\d+)',
-  //     component: () => import('@/views/tool/gen/editTable'),
-  //     name: 'GenEdit',
-  //     meta: {
-  //       title: '修改生成配置',
-  //       activeMenu: '/tool/gen'
-  //     }
-  //   }]
-  // }
+  {
+    // path: '/tool/gen-edit',
+    // component: Layout,
+    // hidden: true,
+    // permissions: ['tool:gen:edit'],
+    // children: [{
+    //   path: 'index/:tableId(\\d+)',
+    //   component: () => import('@/views/tool/gen/editTable'),
+    //   name: 'GenEdit',
+    //   meta: {
+    //     title: '修改生成配置',
+    //     activeMenu: '/tool/gen'
+    //   }
+    // }]
+    path: '/tool/gen-edit',
+    component: Layout,
+    hidden: true,
+    permissions: ['tool:gen:edit'],
+    children: [
+      {
+        path: 'index/:tableId(\\d+)',
+        component: () => import('@/views/tool/gen/editTable.vue'),
+        name: 'GenEdit',
+        meta: { title: '修改生成配置', activeMenu: '/tool/gen' }
+      }
+    ]
+  }
 ]
 
 // 防止连续点击多次路由报错

+ 271 - 0
src/styles/home.scss

@@ -0,0 +1,271 @@
+$selectedColor: #f6f7ff;
+$lighterBlue: #409EFF;
+
+.container {
+  position: relative;
+  width: 100%;
+  height: 100%;
+}
+
+.components-list {
+  padding: 8px;
+  box-sizing: border-box;
+  height: 100%;
+  .components-item {
+    display: inline-block;
+    width: 48%;
+    margin: 1%;
+    transition: transform 0ms !important;
+  }
+}
+.components-draggable{
+  padding-bottom: 20px;
+}
+.components-title{
+  font-size: 14px;
+  color: #222;
+  margin: 6px 2px;
+  .svg-icon{
+    color: #666;
+    font-size: 18px;
+  }
+}
+
+.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;
+    }
+  }
+}
+
+.left-board {
+  width: 260px;
+  position: absolute;
+  left: 0;
+  top: 0;
+  height: 100vh;
+}
+.left-scrollbar{
+  height: calc(100vh - 42px);
+  overflow: hidden;
+}
+.center-scrollbar {
+  height: calc(100vh - 42px);
+  overflow: hidden;
+  border-left: 1px solid #f1e8e8;
+  border-right: 1px solid #f1e8e8;
+  box-sizing: border-box;
+}
+.center-board {
+  height: 100vh;
+  width: auto;
+  margin: 0 350px 0 260px;
+  box-sizing: border-box;
+}
+.empty-info{
+  position: absolute;
+  top: 46%;
+  left: 0;
+  right: 0;
+  text-align: center;
+  font-size: 18px;
+  color: #ccb1ea;
+  letter-spacing: 4px;
+}
+.action-bar{
+  position: relative;
+  height: 42px;
+  text-align: right;
+  padding: 0 15px;
+  box-sizing: border-box;;
+  border: 1px solid #f1e8e8;
+  border-top: none;
+  border-left: none;
+  .delete-btn{
+    color: #F56C6C;
+  }
+}
+.logo-wrapper{
+  position: relative;
+  height: 42px;
+  background: #fff;
+  border-bottom: 1px solid #f1e8e8;
+  box-sizing: border-box;
+}
+.logo{
+  position: absolute;
+  left: 12px;
+  top: 6px;
+  line-height: 30px;
+  color: #00afff;
+  font-weight: 600;
+  font-size: 17px;
+  white-space: nowrap;
+  > img{
+    width: 30px;
+    height: 30px;
+    vertical-align: top;
+  }
+  .github{
+    display: inline-block;
+    vertical-align: sub;
+    margin-left: 15px;
+    > img{
+      height: 22px;
+    }
+  }
+}
+
+.center-board-row {
+  padding: 12px 12px 15px 12px;
+  box-sizing: border-box;
+  & > .el-form {
+    // 69 = 12+15+42
+    height: calc(100vh - 69px);
+  }
+}
+.drawing-board {
+  height: 100%;
+  position: relative;
+  .components-body {
+    padding: 0;
+    margin: 0;
+    font-size: 0;
+  }
+  .sortable-ghost {
+    position: relative;
+    display: block;
+    overflow: hidden;
+    &::before {
+      content: " ";
+      position: absolute;
+      left: 0;
+      right: 0;
+      top: 0;
+      height: 3px;
+      background: rgb(89, 89, 223);
+      z-index: 2;
+    }
+  }
+  .components-item.sortable-ghost {
+    width: 100%;
+    height: 60px;
+    background-color: $selectedColor;
+  }
+  .active-from-item {
+    & > .el-form-item{
+      background: $selectedColor;
+      border-radius: 6px;
+    }
+    & > .drawing-item-copy, & > .drawing-item-delete{
+      display: initial;
+    }
+    & > .component-name{
+      color: $lighterBlue;
+    }
+  }
+  .el-form-item{
+    margin-bottom: 15px;
+  }
+}
+.drawing-item{
+  position: relative;
+  cursor: move;
+  &.unfocus-bordered:not(.active-from-item) > div:first-child {
+    border: 1px dashed #ccc;
+  }
+  .el-form-item{
+    padding: 12px 10px;
+  }
+}
+.drawing-row-item{
+  position: relative;
+  cursor: move;
+  box-sizing: border-box;
+  border: 1px dashed #ccc;
+  border-radius: 3px;
+  padding: 0 2px;
+  margin-bottom: 15px;
+  .drawing-row-item {
+    margin-bottom: 2px;
+  }
+  .el-col{
+    margin-top: 22px;
+  }
+  .el-form-item{
+    margin-bottom: 0;
+  }
+  .drag-wrapper{
+    min-height: 80px;
+  }
+  &.active-from-item{
+    border: 1px dashed $lighterBlue;
+  }
+  .component-name{
+    position: absolute;
+    top: 0;
+    left: 0;
+    font-size: 12px;
+    color: #bbb;
+    display: inline-block;
+    padding: 0 6px;
+  }
+}
+.drawing-item, .drawing-row-item{
+  &:hover {
+    & > .el-form-item{
+      background: $selectedColor;
+      border-radius: 6px;
+    }
+    & > .drawing-item-copy, & > .drawing-item-delete{
+      display: initial;
+    }
+  }
+  & > .drawing-item-copy, & > .drawing-item-delete{
+    display: none;
+    position: absolute;
+    top: -10px;
+    width: 22px;
+    height: 22px;
+    line-height: 22px;
+    text-align: center;
+    border-radius: 50%;
+    font-size: 12px;
+    border: 1px solid;
+    cursor: pointer;
+    z-index: 1;
+  }
+  & > .drawing-item-copy{
+    right: 56px;
+    border-color: $lighterBlue;
+    color: $lighterBlue;
+    background: #fff;
+    &:hover{
+      background: $lighterBlue;
+      color: #fff;
+    }
+  }
+  & > .drawing-item-delete{
+    right: 24px;
+    border-color: #F56C6C;
+    color: #F56C6C;
+    background: #fff;
+    &:hover{
+      background: #F56C6C;
+      color: #fff;
+    }
+  }
+}

+ 141 - 0
src/styles/index.scss

@@ -0,0 +1,141 @@
+$editorTabsborderColor: #5a9d6d;
+body, html{
+  margin: 0;
+  padding: 0;
+  background: #fff;
+  -moz-osx-font-smoothing: grayscale;
+  -webkit-font-smoothing: antialiased;
+  text-rendering: optimizeLegibility;
+  font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;
+}
+
+input, textarea{
+  font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;
+}
+
+.editor-tabs{
+  background: $editorTabsborderColor;
+  .el-tabs__header{
+    margin: 0;
+    border-bottom-color: $editorTabsborderColor;
+    .el-tabs__nav{
+      border-color: $editorTabsborderColor;
+    }
+  }
+  .el-tabs__item{
+    height: 32px;
+    line-height: 32px;
+    color: #888a8e;
+    border-left: 1px solid $editorTabsborderColor!important;
+    background: #363636;
+    margin-right: 5px;
+    user-select: none;
+  }
+  .el-tabs__item.is-active{
+    background: #1e1e1e;
+    border-bottom-color: #1e1e1e!important;
+    color: #fff;
+  }
+  .el-icon-edit{
+    color: #f1fa8c;
+  }
+  .el-icon-document{
+    color: #a95812;
+  }
+  :focus.is-active.is-focus:not(:active) {
+    box-shadow: none;
+    border-radius: 0;
+  }
+}
+
+// home
+.right-scrollbar {
+  .el-scrollbar__view {
+    padding: 12px 18px 15px 15px;
+  }
+}
+.el-scrollbar__wrap {
+  box-sizing: border-box;
+  overflow-x: hidden !important;
+  margin-bottom: 0 !important;
+}
+.center-tabs{
+  .el-tabs__header{
+    margin-bottom: 0!important;
+  }
+  .el-tabs__item{
+    width: 50%;
+    text-align: center;
+  }
+  .el-tabs__nav{
+    width: 100%;
+  }
+}
+.reg-item{
+  padding: 12px 6px;
+  background: #f8f8f8;
+  position: relative;
+  border-radius: 4px;
+  .close-btn{
+    position: absolute;
+    right: -6px;
+    top: -6px;
+    display: block;
+    width: 16px;
+    height: 16px;
+    line-height: 16px;
+    background: rgba(0, 0, 0, 0.2);
+    border-radius: 50%;
+    color: #fff;
+    text-align: center;
+    z-index: 1;
+    cursor: pointer;
+    font-size: 12px;
+    &:hover{
+      background: rgba(210, 23, 23, 0.5)
+    }
+  }
+  & + .reg-item{
+    margin-top: 18px;
+  }
+}
+.action-bar{
+  & .el-button+.el-button {
+    margin-left: 15px;
+  }
+  & i {
+    font-size: 20px;
+    vertical-align: middle;
+    position: relative;
+    top: -1px;
+  }
+}
+
+.custom-tree-node{
+  width: 100%;
+  font-size: 14px;
+  .node-operation{
+    float: right;
+  }
+  i[class*="el-icon"] + i[class*="el-icon"]{
+    margin-left: 6px;
+  }
+  .el-icon-plus{
+    color: #409EFF;
+  }
+  .el-icon-delete{
+    color: #157a0c;
+  }
+}
+
+.el-scrollbar__view{
+  overflow-x: hidden;
+}
+
+.el-rate{
+  display: inline-block;
+  vertical-align: text-top;
+}
+.el-upload__tip{
+  line-height: 1.2;
+}

+ 33 - 0
src/styles/mixin.scss

@@ -0,0 +1,33 @@
+@mixin action-bar {
+  .action-bar {
+    height: 39px;
+    background: #f5f7fa;
+    padding: 0 15px;
+    box-sizing: border-box;
+
+    .bar-btn {
+      display: inline-block;
+      padding: 0 6px;
+      line-height: 32px;
+      color: #8285f5;
+      cursor: pointer;
+      font-size: 14px;
+      user-select: none;
+      & i {
+        font-size: 20px;
+      }
+      &:hover {
+        color: #4348d4;
+      }
+    }
+    .bar-btn + .bar-btn {
+      margin-left: 8px;
+    }
+    .delete-btn {
+      color: #f56c6c;
+      &:hover {
+        color: #ea0b30;
+      }
+    }
+  }
+}

+ 56 - 0
src/utils/db.js

@@ -0,0 +1,56 @@
+import de from "element-ui/src/locale/lang/de";
+
+const DRAWING_ITEMS = 'drawingItems'
+const DRAWING_ITEMS_VERSION = '1.2'
+const DRAWING_ITEMS_VERSION_KEY = 'DRAWING_ITEMS_VERSION'
+const DRAWING_ID = 'idGlobal'
+const TREE_NODE_ID = 'treeNodeId'
+const FORM_CONF = 'formConf'
+
+export function getDrawingList() {
+  // 加入缓存版本的概念,保证缓存数据与程序匹配
+  const version = localStorage.getItem(DRAWING_ITEMS_VERSION_KEY)
+  if (version !== DRAWING_ITEMS_VERSION) {
+    localStorage.setItem(DRAWING_ITEMS_VERSION_KEY, DRAWING_ITEMS_VERSION)
+    saveDrawingList([])
+    return null
+  }
+
+  const str = localStorage.getItem(DRAWING_ITEMS)
+  if (str) return JSON.parse(str)
+  return null
+}
+
+export function saveDrawingList(list) {
+  localStorage.setItem(DRAWING_ITEMS, JSON.stringify(list))
+}
+
+export function getIdGlobal() {
+  const str = localStorage.getItem(DRAWING_ID)
+  if (str) return parseInt(str, 10)
+  return 100
+}
+
+export function saveIdGlobal(id) {
+  localStorage.setItem(DRAWING_ID, `${id}`)
+}
+
+export function getTreeNodeId() {
+  const str = localStorage.getItem(TREE_NODE_ID)
+  if (str) return parseInt(str, 10)
+  return 100
+}
+
+export function saveTreeNodeId(id) {
+  localStorage.setItem(TREE_NODE_ID, `${id}`)
+}
+
+export function getFormConf() {
+  const str = localStorage.getItem(FORM_CONF)
+  if (str) return JSON.parse(str)
+  return null
+}
+
+export function saveFormConf(obj) {
+  localStorage.setItem(FORM_CONF, JSON.stringify(obj))
+}

+ 28 - 0
src/utils/loadBeautifier.js

@@ -0,0 +1,28 @@
+import loadScript from './loadScript'
+import ELEMENT from 'element-ui'
+import pluginsConfig from './pluginsConfig'
+
+let beautifierObj
+
+export default function loadBeautifier(cb) {
+  const { beautifierUrl } = pluginsConfig
+  if (beautifierObj) {
+    cb(beautifierObj)
+    return
+  }
+
+  const loading = ELEMENT.Loading.service({
+    fullscreen: true,
+    lock: true,
+    text: '格式化资源加载中...',
+    spinner: 'el-icon-loading',
+    background: 'rgba(255, 255, 255, 0.5)'
+  })
+
+  loadScript(beautifierUrl, () => {
+    loading.close()
+    // eslint-disable-next-line no-undef
+    beautifierObj = beautifier
+    cb(beautifierObj)
+  })
+}

+ 40 - 0
src/utils/loadMonaco.js

@@ -0,0 +1,40 @@
+import loadScript from './loadScript'
+import ELEMENT from 'element-ui'
+import pluginsConfig from './pluginsConfig'
+
+// monaco-editor单例
+let monacoEidtor
+
+/**
+ * 动态加载monaco-editor cdn资源
+ * @param {Function} cb 回调,必填
+ */
+export default function loadMonaco(cb) {
+  if (monacoEidtor) {
+    cb(monacoEidtor)
+    return
+  }
+
+  const { monacoEditorUrl: vs } = pluginsConfig
+
+  // 使用element ui实现加载提示
+  const loading = ELEMENT.Loading.service({
+    fullscreen: true,
+    lock: true,
+    text: '编辑器资源初始化中...',
+    spinner: 'el-icon-loading',
+    background: 'rgba(255, 255, 255, 0.5)'
+  })
+
+  !window.require && (window.require = {})
+  !window.require.paths && (window.require.paths = {})
+  window.require.paths.vs = vs
+
+  loadScript(`${vs}/loader.js`, () => {
+    window.require(['vs/editor/editor.main'], () => {
+      loading.close()
+      monacoEidtor = window.monaco
+      cb(monacoEidtor)
+    })
+  })
+}

+ 60 - 0
src/utils/loadScript.js

@@ -0,0 +1,60 @@
+const callbacks = {}
+
+/**
+ * 加载一个远程脚本
+ * @param {String} src 一个远程脚本
+ * @param {Function} callback 回调
+ */
+function loadScript(src, callback) {
+  const existingScript = document.getElementById(src)
+  const cb = callback || (() => {})
+  if (!existingScript) {
+    callbacks[src] = []
+    const $script = document.createElement('script')
+    $script.src = src
+    $script.id = src
+    $script.async = 1
+    document.body.appendChild($script)
+    const onEnd = 'onload' in $script ? stdOnEnd.bind($script) : ieOnEnd.bind($script)
+    onEnd($script)
+  }
+
+  callbacks[src].push(cb)
+
+  function stdOnEnd(script) {
+    script.onload = () => {
+      this.onerror = this.onload = null
+      callbacks[src].forEach(item => {
+        item(null, script)
+      })
+      delete callbacks[src]
+    }
+    script.onerror = () => {
+      this.onerror = this.onload = null
+      cb(new Error(`Failed to load ${src}`), script)
+    }
+  }
+
+  function ieOnEnd(script) {
+    script.onreadystatechange = () => {
+      if (this.readyState !== 'complete' && this.readyState !== 'loaded') return
+      this.onreadystatechange = null
+      callbacks[src].forEach(item => {
+        item(null, script)
+      })
+      delete callbacks[src]
+    }
+  }
+}
+
+/**
+ * 顺序加载一组远程脚本
+ * @param {Array} list 一组远程脚本
+ * @param {Function} cb 回调
+ */
+export function loadScriptQueue(list, cb) {
+  const first = list.shift()
+  list.length ? loadScript(first, () => loadScriptQueue(list, cb)) : loadScript(first, cb)
+}
+
+export default loadScript

+ 13 - 0
src/utils/pluginsConfig.js

@@ -0,0 +1,13 @@
+const CDN = 'https://lib.baomitu.com/' // CDN Homepage: https://cdn.baomitu.com/
+const publicPath = process.env.BASE_URL
+
+function splicingPluginUrl(PluginName, version, fileName) {
+  return `${CDN}${PluginName}/${version}/${fileName}`
+}
+
+export default {
+  beautifierUrl: splicingPluginUrl('js-beautify', '1.13.5', 'beautifier.min.js'),
+  monacoEditorUrl: splicingPluginUrl('monaco-editor', '0.19.3', 'min/vs'), // 使用 monaco-editor CDN 链接
+  // monacoEditorUrl: `${publicPath}libs/monaco-editor/vs`, // 使用 monaco-editor 本地代码
+  tinymceUrl: splicingPluginUrl('tinymce', '5.7.0', 'tinymce.min.js')
+}

+ 85 - 0
src/views/pack/packBatchManage/compoments/addUserModal.vue

@@ -0,0 +1,85 @@
+<template>
+  <vxe-modal v-model="value" id="addQuest" width="60%" v-loading="load" @show="show" @hide="hide" height="500" show-footer :title="type == '1' ? '选择拣货员' : '选择播种员'">
+    <el-checkbox :indeterminate="isIndeterminate" v-model="checkAll" @change="handleCheckAllChange">全选</el-checkbox>
+    <div style="margin: 15px 0;"></div>
+    <el-checkbox-group v-model="checkedList" @change="handleCheckedCitiesChange">
+      <el-checkbox v-for="item in list" :label="item" :key="item">{{item}}</el-checkbox>
+    </el-checkbox-group>
+    <template #footer>
+      <div class="btn">
+        <el-button plain size="small" @click="value = false">取消</el-button>
+        <el-button type="primary" size="small" @click="btn">确定</el-button>
+      </div>
+    </template>
+  </vxe-modal>
+</template>
+
+<script lang="ts">
+import { Component, Prop, Vue, Watch } from "vue-property-decorator";
+import { listUser } from "@/api/system/user";
+@Component({components:{}})
+export default class AddQuestModel extends Vue {
+  value = false;
+  load = false;
+  type:string = '1'
+  checkAll= false
+  checkedList:Array<any>= []
+  list:Array<any>=[]
+  isIndeterminate= true
+  show(){
+    
+  }
+  setType(v:string) {
+    this.type = v;
+  }
+  hide(){
+    (this.$refs.form as any).clearValidate();
+    (this.$refs.form as any).clearValue();
+  }
+  handleCheckAllChange(val) {
+    this.checkedList = val ? this.list : [];
+    this.isIndeterminate = false;
+  }
+  handleCheckedCitiesChange(value) {
+    let checkedCount = value.length;
+    this.checkAll = checkedCount === this.list.length;
+    this.isIndeterminate = checkedCount > 0 && checkedCount < this.list.length;
+  }
+  loadList() {
+    this.list = []
+    listUser({
+      pageNum: 1,
+      pageSize: 10
+    }).then((response:any) => {
+      for(let item of response.rows) {
+        this.list.push(item.userName)
+      }
+    }).catch(()=>{});
+  }
+  setShow(v:boolean){
+    this.value = v;
+    this.loadList()
+  }
+  btn(){
+    this.$emit('handle',{
+      type: this.type,
+      data: this.checkedList
+    });
+    // (this.$refs.form as any).validate().then(()=>{
+    //   let data = (this.$refs.form as any).getValue();
+    //   this.load = true
+    //   save(data).then(()=>{
+    //     this.load = false;
+    //     this.$emit('handleSuccess');
+    //     this.value = false;
+    //   }).catch(()=>{
+    //     this.load = false;
+    //   })
+    // })
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+
+</style>

+ 231 - 0
src/views/pack/packBatchManage/compoments/batchList.vue

@@ -0,0 +1,231 @@
+<template>
+  <div class="generateBatch">
+    <module-view :propConfig="config" ref="view" v-loading="load" @pagination="pagination" @onRefresh="getList" 
+    @resert="queryList" @search="queryList" />
+    <addUserModal ref="addUserModalView" @handle="handle" />
+  </div>
+</template>
+
+<script lang="ts">
+import { Component, Prop, Vue, Watch } from "vue-property-decorator";
+import addUserModal from ".addUserModal.vue"
+import Cookies from 'js-cookie'
+@Component({components:{addUserModal}})
+export default class BatchList extends Vue {
+  load=false;
+  time:any;
+  timeNum = 0;
+  isSearch=false;
+  data:Array<any> = []
+  config:any={
+    attr:{
+      calculateH:true
+    },
+    search:{
+      attr:{
+        size:'small'
+      },
+      columns:[
+        [{
+          label:'拣货员',
+          prop:'shopName',
+          component:'by-input',
+          compConfig:{}
+        },{
+          label:'播种员',
+          prop:'shortName',
+          component:'by-input',
+          compConfig:{}
+        },
+        {
+          label:'状态',
+          prop:'shopStatus',
+          component:'by-input',
+          compConfig:{}
+        }]
+      ]
+    },
+    tool:{
+      tools:{
+        // add:true,
+        // delete:true,
+        search:true,
+        refresh:true
+      },
+      customTools:[
+        { name: '安排拣货员', event:{
+          click:() =>{
+            this.packHandle('1');
+          }
+        }},
+        { name: '安排播种员', event:{
+          click:() =>{
+            this.packHandle('2');
+          }
+        }},
+        { name: '结束任务', event:{
+          click:() =>{
+
+          }
+        }},
+        { name: '打印订单', event:{
+          click:() =>{
+
+          }
+        }},
+        { name: '按批次发货', event:{
+          click:() =>{
+
+          }
+        }},
+      ]
+    },
+    table:{
+      attr:{
+        size:'mini',
+        seq:true,
+        checkbox: true,
+        align:'center',
+        // checkbox:true
+      },
+      columns:[{
+        title:'批次号',
+        field:'number',
+      },{
+        title:'类型',
+        field:'type',
+      },{
+        title:'拣货员',
+        field:'user01',
+      },{
+        title:'播种员',
+        field:'user02'
+      },{
+        title:'订单数',
+        field:'orderNum'
+      },{
+        title:'单品类数',
+        field:'typeNum'
+      },{
+        title:'商品种数',
+        field:'num1'
+      },{
+        title:'已拣数',
+        field:'jNum1'
+      },{
+        title:'未拣数',
+        field:'jNum2'
+      },{
+        title:'缺货数',
+        field:'num3'
+      },{
+        title:'状态',
+        field:'state'
+      },{
+        title:'仓库',
+        field:'store'
+      },{
+        title:'生成日期',
+        field:'time'
+      },{
+        title:'创建人',
+        field:'createUser'
+      }
+      ]
+    },
+  }
+  mounted(){
+    this.$nextTick(()=>{
+      this.getList()
+    })
+  }
+
+  handle(parm:any) {
+    let data = (this.$refs.view as any).getSelectData();
+    let n = ''
+    for(const nItem of parm.data){
+      n = n ? n + ',' + nItem : nItem;
+    }
+    for (const item of data) {
+      for (const it of this.data) {
+        if(item.number == it.number) {
+          if(parm.type == '1'){
+            it.user01 = n
+          }else{
+            it.user02 = n
+          }
+          break
+        }
+      }
+    }
+  }
+  //安排拣货员/播种员
+  packHandle(n:string) {
+    let data = (this.$refs.view as any).getSelectData();
+    if(data.length == 0) {
+      this.$message('请选择数据!');
+      return
+    }
+    (this.$refs.addUserModalView as any).setShow(true);
+    (this.$refs.addUserModalView as any).setType(n);
+  }
+
+  //分页
+  pagination(){
+    if(this.isSearch){
+      this.queryList();
+    }else{
+      this.getList()
+    }
+  }
+  //列表请求(只有分页,不包含搜素条件)
+  getList(){
+    let d = Cookies.get('batchData');
+    if(d) {
+      try{
+        this.data = JSON.parse(d);
+      }catch(e){
+        console.error('数据转换异常!');
+      }
+    }
+
+    
+    if(!this.$refs.view){
+      if(this.timeNum > 5){
+        return
+      }
+      setTimeout(()=>{
+        this.getList()
+      },500) 
+      this.timeNum ++;
+      return
+    }
+    (this.$refs.view as any).setTableValue(this.data);
+    // this.isSearch = false;
+    // let data = (this.$refs.view as any).getPage();
+    // this.requestList(data);
+  }
+  //列表请求(包含分页和搜素条件)
+  queryList(){
+    this.isSearch = true;
+    let data = (this.$refs.view as any).getQuery();
+    this.requestList(data);
+  }
+  requestList(data:any){
+    this.load = true;
+    
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+
+</style>
+
+<style scoped>
+.generateBatch{
+  width: 100%;
+  height: 100%;
+  overflow-y: hidden;
+}
+</style>

+ 252 - 0
src/views/pack/packBatchManage/compoments/generateBatch.vue

@@ -0,0 +1,252 @@
+<template>
+  <div class="generateBatch">
+    <module-view :propConfig="config" ref="view" v-loading="load" @pagination="pagination" @onRefresh="getList" 
+    @resert="queryList" @search="queryList" />
+  </div>
+</template>
+
+<script lang="ts">
+import { Component, Prop, Vue, Watch } from "vue-property-decorator";
+import Format from '@/benyun/utils/dateFormat'
+import { query } from '@/api/omsOrder'
+import Cookies from 'js-cookie'
+@Component({components:{}})
+export default class GenerateBatch extends Vue {
+  load=false;
+  time:any;
+  timeNum = 0;
+  isSearch=false;
+  data:Array<any> = [];
+  config:any={
+    attr:{
+      calculateH:true
+    },
+    search:{
+      attr:{
+        size:'small'
+      },
+      columns:[
+        [{
+          label:'商品名称',
+          prop:'name',
+          component:'by-input',
+          compConfig:{}
+        },{
+          label:'商品编码',
+          prop:'code',
+          component:'by-input',
+          compConfig:{}
+        },
+        {
+          label:'规格',
+          prop:'spec',
+          component:'by-input',
+          compConfig:{}
+        }]
+      ]
+    },
+    tool:{
+      tools:{
+        // add:true,
+        // delete:true,
+        search:true,
+        refresh:true
+      },
+      customTools:[
+        { name: '生成批次', event:{
+          click:() =>{
+            this.batchHandle()
+          }
+        }},
+      ]
+    },
+    table:{
+      attr:{
+        size:'mini',
+        seq:true,
+        checkbox: true,
+        align:'center',
+        pageSize: 40
+        // checkbox:true
+      },
+      columns:[{
+        title:'商品编码',
+        field:'code',
+      },{
+        title:'商品名称',
+        field:'name',
+      },{
+        title:'规格',
+        field:'spec',
+      },{
+        title:'款式编码',
+        field:'styleId'
+      },{
+        title:'商品种类数',
+        field:'num1'
+      },{
+        title:'订单数',
+        field:'orderNum'
+      },{
+        title:'缺货订单数',
+        field:'num3'
+      },{
+        title:'重量',
+        field:'weight'
+      },{
+        title:'体积',
+        field:'volume'
+      },{
+        title:'仓位',
+        field:'store'
+      },{
+        title:'本次生成批次数',
+        field:'batchNum'
+      }
+      ]
+    },
+  }
+  mounted(){
+    this.$nextTick(()=>{
+      this.getList()
+    })
+  }
+  //生成批次
+  batchHandle() {
+    let data = (this.$refs.view as any).getSelectData()
+    let batList:Array<any> = [];
+    let d = Cookies.get('batchData');
+    if(data.length === 0) {
+      this.$message('请选择数据!');
+      return
+    } 
+    if(d) {
+      try{
+        batList = JSON.parse(d);
+      }catch(e){
+        console.error('数据转换异常!');
+      }
+    }
+    for(const item of data) {
+      batList.push({
+        number:this.getUuid(9),
+        type: '单SKU',
+        user01: '',
+        user02: '',
+        orderNum: item.orderNum,
+        typeNum: item.num1,
+        num1: item.num1,
+        jNum1: '',
+        jNum2: '',
+        num3: item.num3,
+        state:'等待拣货',
+        store: '',
+        time: Format(new Date(),'yyyy-MM-dd HH:mm:ss'),
+        createUser: (this as any).$store.getters.userInfo.userName
+      })
+    }
+    this.$message({
+      message:'生成批次成功!',
+      type:'success'
+    })
+    Cookies.set('batchData', JSON.stringify(batList));
+  }
+  getUuid(n){
+    return (((1 + Math.random()) * 0x10000) | 0).toString(n).substring(1);
+  }
+  //分页
+  pagination(){
+    if(this.isSearch){
+      this.queryList();
+    }else{
+      this.getList()
+    }
+  }
+  //列表请求(只有分页,不包含搜素条件)
+  getList(){
+    if(!this.$refs.view){
+      if(this.timeNum > 5){
+        return
+      }
+      setTimeout(()=>{
+        this.getList()
+      },500) 
+      this.timeNum ++;
+      return
+    }
+    this.isSearch = false;
+    let data = (this.$refs.view as any).getPage();
+    this.requestList(data);
+  }
+  //列表请求(包含分页和搜素条件)
+  queryList(){
+    this.isSearch = true;
+    let newData:Array<any> = []
+    let data = (this.$refs.view as any).getQuery();
+    // this.requestList(data);
+    for(const item of this.data) {
+      let isa = true
+      if(data.code && item.code.indexOf(data.code) === -1) {
+        isa = false
+      }
+      if(data.name && item.name.indexOf(data.name) === -1) {
+        isa = false
+      }
+      if(data.spec && item.spec.indexOf(data.spec) === -1) {
+        isa = false
+      }
+      if(isa) {
+        newData.push(item)
+      }
+    }
+    (this.$refs.view as any).setTableValue(newData);
+  }
+  requestList(data:any){
+    let param:any = {};
+    param.businessType = 'B2B';
+    this.data = [];
+    this.load = true;
+    query(data,param).then((res:any) => {
+      this.load = false;
+      for(const item of res.data.records) {
+        for(const itemChild of item.items)
+        this.data.push({
+          code: itemChild.skuId,
+          name: itemChild.name,
+          spec: itemChild.propertiesValue,
+          styleId: itemChild.styleId,
+          num1: item.items.length,
+          orderNum: itemChild.qty,
+          num3: 0,
+          weight: itemChild.weight,
+          volume: itemChild.volume,
+          store: '',
+          batchNum: ''
+        })
+      }
+      (this.$refs.view as any).setTableValue(this.data);
+      // let page = {
+      //   pageNo: res.data.current, //当前页
+      //   pageSize: res.data.size, //每页条数
+      //   total: res.data.total //总条数
+      // };
+      // (this.$refs.view as any).setPage(page)
+
+    }).catch(()=>{
+      this.load = false;
+    })
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+
+</style>
+
+<style scoped>
+.generateBatch{
+  width: 100%;
+  height: 100%;
+  overflow-y: hidden;
+}
+</style>

+ 58 - 0
src/views/pack/packBatchManage/index.vue

@@ -0,0 +1,58 @@
+<template>
+  <div class="pack-box">
+    <el-tabs v-model="activeName" @tab-click="handleClick">
+      <el-tab-pane label="生成批次" name="first">
+        <generate-batch />
+      </el-tab-pane>
+      <el-tab-pane label="批次列表" name="second">
+        <batch-list ref="list" />
+      </el-tab-pane>
+    </el-tabs>
+  </div>
+</template>
+
+<script lang="ts">
+import { Component, Prop, Vue, Watch } from "vue-property-decorator";
+import GenerateBatch from "./compoments/generateBatch.vue";
+import BatchList from "./compoments/batchList.vue";
+@Component({components:{GenerateBatch, BatchList}})
+export default class PackBatchManage extends Vue {
+  activeName:string='first'
+
+  handleClick(v){
+    console.log(v)
+    if(v.name =='second') {
+      (this.$refs.list as any).getList();
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+
+</style>
+<style lang="scss">
+.pack-box{
+  width: 100%;
+  height: 100%;
+  box-sizing: border-box;
+  padding: 0 16px;
+  .el-tabs{
+    width: 100%;
+    height: 100%;
+  }
+  .el-tabs__header{
+    margin: 0 !important;
+  }
+  .el-tabs__content{
+    height: calc(100% - 40px);
+    padding-top: 8px;
+    box-sizing: border-box;
+    overflow: hidden;
+    .el-tab-pane{
+      width: 100%;
+      height: 100%;
+    }
+  }
+}
+</style>