whj 7 miesięcy temu
rodzic
commit
0daa61a2a7

+ 124 - 0
src/components/Upload/CUpload.vue

@@ -0,0 +1,124 @@
+<template>
+  <div class="clearfix">
+    <a-upload
+      :action="action"
+      multiple
+      :fileList="fileList"
+      list-type="picture-card"
+      @preview="handlePreview"
+      @change="handleChange"
+      :customRequest="customRequest"
+      :remove="handleRemove"
+      :beforeUpload="beforeUpload">
+      <div v-if="fileList.length < maxSize">
+        <a-icon type="upload" style="margin-left: 15px" />
+        <div class="ant-upload-text">上传文件</div>
+      </div>
+    </a-upload>
+    <a-modal :visible="previewVisible" :footer="null" @cancel="handleCancel" :width="1200">
+      <img style="width: 100%" :src="previewImage" />
+    </a-modal>
+  </div>
+</template>
+
+<script>
+import { uploadFile } from '@/api/upms/file'
+export default {
+  name: 'UploadImg',
+  data () {
+    return {
+      previewVisible: false,
+      previewImage: '',
+      fileList: [],
+      action: process.env.VUE_APP_API_BASE_URL + '/upms/files/upload'
+    }
+  },
+  props: {
+    maxSize: {
+      type: Number,
+      default: 1
+    },
+    files: {
+      type: Array,
+      default () {
+        return []
+      }
+    }
+  },
+  watch: {
+    files (newVal) {
+      this.fileList = this.BaseTool.UPLOAD.transImg2(newVal)
+    }
+  },
+  methods: {
+    handleCancel () {
+      this.previewVisible = false
+    },
+    handlePreview (file) {
+      this.previewImage = file.url || file.thumbUrl
+      this.previewVisible = true
+    },
+    handleChange ({ fileList }) {
+      // this.fileList = fileList
+      // this.$emit('catchFile', fileList)
+    },
+    async customRequest (data) {
+      const formData = new FormData()
+      formData.append('file', data.file)
+      data.onProgress()
+      uploadFile(formData).then((res) => {
+        data.onSuccess()
+        const reg = new RegExp('[;,。!?;,]')
+        if (reg.test(res.data.fileName)) {
+          this.$message.error(`文件名包含非法字符`)
+        } else {
+          this.fileList.push({
+            uid: '-1',
+            name: res.data.name,
+            status: 'done',
+            url: this.BaseTool.Constant.FILE_URL + res.data.url
+          })
+        }
+        this.$emit('catchFile', this.fileList)
+      })
+    },
+    handleRemove (file) {
+      const index = this.fileList.indexOf(file)
+      const newFileList = this.fileList.slice()
+      newFileList.splice(index, 1)
+      this.fileList = newFileList
+      this.$emit('catchFile', this.fileList)
+      return true
+    },
+    beforeUpload (file, fileList) {
+      const reg = /\.(doc|docx|html|pdf|txt|mht|xlsx|xls|jpg|png|zip|png|jpg|gif|jpeg|webp|zip|rar|7z|dxf)(\?.*)?$/
+      // if (this.fileType === 1) {
+      //   reg = /\.(jpg|png|gif)(\?.*)?$/
+      // }
+      return new Promise((resolve, reject) => {
+        if (reg.test(file.name.toLowerCase())) {
+          resolve()
+        } else {
+          this.$message.error(`请上传正确的文件格式`)
+          reject(new Error('请上传正确的文件格式'))
+        }
+      })
+    }
+  }
+}
+</script>
+<style>
+/* you can make up upload button and sample style by using stylesheets */
+.ant-upload-select-picture-card i {
+  font-size: 32px;
+  color: #999;
+}
+
+.ant-upload-select-picture-card .ant-upload-text {
+  margin-top: 8px;
+  color: #666;
+}
+.ant-upload-btn {
+  margin-top: 20px;
+}
+</style>

+ 17 - 0
src/utils/tool.js

@@ -999,6 +999,23 @@ BaseTool.UPLOAD = {
     })
     return temp
   },
+  transImg2 (imgArr = []) {
+    const temp = []
+    if (BaseTool.Object.isBlank(imgArr)) {
+      return temp
+    }
+    imgArr.forEach((item) => {
+      if (BaseTool.String.isNotBlank(item.url)) {
+        temp.push({
+          url: GlobalConstant.BaseImageUrl + item.url,
+          uid: item.id ? item.id : item.uid,
+          name: item.name,
+          value: item
+        })
+      }
+    })
+    return temp
+  },
   filePreview (file) {
     if (file.url == null) {
       return

+ 1 - 1
src/views/store/store/Store.vue

@@ -79,7 +79,7 @@
       <span slot="action" slot-scope="record">
         <template>
           <a @click="handleView(record)">查看</a>
-          <operation-button @click="handleEdit(record)">修改</operation-button>
+          <operation-button v-if="$auth('store-stores-edit')" @click="handleEdit(record)">修改</operation-button>
           <operation-button v-if="$auth('store-stores-del')" :type="2" title="删除仓库,将清空仓库所有物资数据??" @confirm="batchDelete(record.id)">
             <a>删除</a>
           </operation-button>

+ 240 - 114
src/views/store/store/modules/BaseForm.vue

@@ -1,7 +1,7 @@
 <template>
   <a-modal
     :title="modalTitle"
-    :width="800"
+    :width="1300"
     :visible="visible"
     :confirmLoading="confirmLoading"
     @cancel="handleCancel"
@@ -11,18 +11,21 @@
       <a-form-item v-show="false" >
         <a-input v-decorator="['id']" type="hidden"/>
       </a-form-item>
+      <row-list :col="2">
+        <row-item>
+          <a-form-item
+            label="编码"
+            :labelCol="BaseTool.Constant.labelCol"
+            :wrapperCol="BaseTool.Constant.wrapperCol"
+          >
+            <a-input
+              disabled
+              v-decorator="['no', {rules: [{required: false, message: '编码不能为空'}]}]" />
+          </a-form-item>
+        </row-item>
 
+        <!--      <row-item>
       <a-form-item
-        label="编码"
-        :labelCol="BaseTool.Constant.labelCol"
-        :wrapperCol="BaseTool.Constant.wrapperCol"
-      >
-        <a-input
-          disabled
-          v-decorator="['no', {rules: [{required: false, message: '编码不能为空'}]}]" />
-      </a-form-item>
-
-      <!--      <a-form-item
         label="所属公司"
         :labelCol="BaseTool.Constant.labelCol"
         :wrapperCol="BaseTool.Constant.wrapperCol"
@@ -36,6 +39,8 @@
           </a-select-option>
         </a-select>
       </a-form-item>
+              </row-item>
+      <row-item>
       <a-form-item
         label="所属项目部"
         :labelCol="BaseTool.Constant.labelCol"
@@ -49,77 +54,123 @@
             :value="deptId">{{ name }}
           </a-select-option>
         </a-select>
-      </a-form-item>-->
-      <a-form-item
-        label="等級"
-        :labelCol="BaseTool.Constant.labelCol"
-        :wrapperCol="BaseTool.Constant.wrapperCol"
-      >
-        <a-select v-decorator="['level']" placeholder="请选择" @change="(val)=>level=val">
-          <a-select-option
-            v-for="(label,value) in levelMap"
-            :key="value"
-            :label="label"
-            :value="parseInt(value)">{{ label }}
-          </a-select-option>
-        </a-select>
-      </a-form-item>
-      <a-form-item
-        v-if="level===2"
-        label="所属仓库"
-        :labelCol="BaseTool.Constant.labelCol"
-        :wrapperCol="BaseTool.Constant.wrapperCol"
-      >
-        <a-tree-select
-          style="width: 100%"
-          :dropdownStyle="{ maxHeight: '400px', overflow: 'auto' }"
-          :treeData="storeTreeDate"
-          :treeNodeFilterProp="'title'"
-          :showSearch="true"
-          v-decorator="['parentId', {rules: [{required: true, message: '上层仓库不能为空'}]}]"
-          placeholder="请选择"
-        >
-        </a-tree-select>
-      </a-form-item>
-      <a-form-item
-        v-else-if="level===1"
-        label="所属厂区"
-        :labelCol="BaseTool.Constant.labelCol"
-        :wrapperCol="BaseTool.Constant.wrapperCol"
-      >
-        <a-select @change="handleProjectChange" v-decorator="['factoryArea', {rules: [{required: true, message: '所属厂区不能为空'}]}]" placeholder="请选择">
-          <a-select-option
-            v-for="({deptId, name}) in projectList"
-            :key="deptId"
-            :label="name"
-            :value="deptId">{{ name }}
-          </a-select-option>
-        </a-select>
       </a-form-item>
+              </row-item>-->
+        <row-item>
+          <a-form-item
+            label="等級"
+            :labelCol="BaseTool.Constant.labelCol"
+            :wrapperCol="BaseTool.Constant.wrapperCol"
+          >
+            <a-select v-decorator="['level']" placeholder="请选择" @change="(val)=>level=val">
+              <a-select-option
+                v-for="(label,value) in levelMap"
+                :key="value"
+                :label="label"
+                :value="parseInt(value)">{{ label }}
+              </a-select-option>
+            </a-select>
+          </a-form-item>
+        </row-item>
+        <row-item v-if="level===2">
+          <a-form-item
+            label="所属仓库"
+            :labelCol="BaseTool.Constant.labelCol"
+            :wrapperCol="BaseTool.Constant.wrapperCol"
+          >
+            <a-tree-select
+              style="width: 100%"
+              :dropdownStyle="{ maxHeight: '400px', overflow: 'auto' }"
+              :treeData="storeTreeDate"
+              :treeNodeFilterProp="'title'"
+              :showSearch="true"
+              v-decorator="['parentId', {rules: [{required: true, message: '上层仓库不能为空'}]}]"
+              placeholder="请选择"
+            >
+            </a-tree-select>
+          </a-form-item>
+        </row-item>
+        <row-item v-else-if="level===1">
+          <a-form-item
+            label="所属厂区"
+            :labelCol="BaseTool.Constant.labelCol"
+            :wrapperCol="BaseTool.Constant.wrapperCol"
+          >
+            <a-select @change="handleAreaChange" v-decorator="['factoryArea', {rules: [{required: true, message: '所属厂区不能为空'}]}]" placeholder="请选择">
+              <a-select-option
+                v-for="area in areaList"
+                :key="area.id"
+                :label="area.name"
+                :value="area.id">{{ area.name }}
+              </a-select-option>
+            </a-select>
+          </a-form-item>
+        </row-item>
+        <row-item>
+          <a-form-item
+            label="名称"
+            :labelCol="BaseTool.Constant.labelCol"
+            :wrapperCol="BaseTool.Constant.wrapperCol"
+          >
+            <a-input
+              v-decorator="['name', {rules: [{required: true, message: '名称不能为空'}]}]" />
+          </a-form-item>
+        </row-item>
+        <row-item>
+          <a-form-item
+            label="仓库负责人"
+            :labelCol="BaseTool.Constant.labelCol"
+            :wrapperCol="BaseTool.Constant.wrapperCol"
+          >
+            <a-select v-decorator="['userId', {rules: [{required: true, message: '仓库负责人不能为空'}]}]" placeholder="请选择">
+              <a-select-option
+                v-for="({userId, realName}) in userList"
+                :key="userId"
+                :label="realName"
+                :value="userId">{{ realName }}
+              </a-select-option>
+            </a-select>
+          </a-form-item>
+        </row-item>
+        <row-item>
+          <a-form-item
+            label="仓库位置"
+            :labelCol="BaseTool.Constant.labelCol"
+            :wrapperCol="BaseTool.Constant.wrapperCol"
+          >
+            <a-input-group size="large">
+              <a-row :gutter="8">
+                <a-col :span="10">
+                  <a-input-number
+                    :min="0"
+                    :max="100"
+                    style="width:100%"
+                    disabled
+                    :formatter="value => `X ${value}`"
+                    :parser="value => value.replace('X', '')"
+                    v-decorator="['positionX', {rules: [{required: true, message: 'X坐标不能为空'}]}]"
+                  />
+                </a-col>
+                <a-col :span="10">
+                  <a-input-number
+                    :min="0"
+                    :max="100"
+                    style="width:100%"
+                    disabled
+                    :formatter="value => `Y ${value}`"
+                    :parser="value => value.replace('Y', '')"
+                    v-decorator="['positionY', {rules: [{required: true, message: 'Y坐标不能为空'}]}]"
+                  />
+                </a-col>
+                <a-col :span="4">
+                  <a-button :disabled="!opcImg" @click="openPositionMap" type="primary">选择</a-button>
+                </a-col>
+              </a-row>
+            </a-input-group>
+          </a-form-item>
+        </row-item>
+        <!--      <row-item>
       <a-form-item
-        label="名称"
-        :labelCol="BaseTool.Constant.labelCol"
-        :wrapperCol="BaseTool.Constant.wrapperCol"
-      >
-        <a-input
-          v-decorator="['name', {rules: [{required: true, message: '名称不能为空'}]}]" />
-      </a-form-item>
-      <a-form-item
-        label="仓库负责人"
-        :labelCol="BaseTool.Constant.labelCol"
-        :wrapperCol="BaseTool.Constant.wrapperCol"
-      >
-        <a-select v-decorator="['userId', {rules: [{required: true, message: '仓库负责人不能为空'}]}]" placeholder="请选择">
-          <a-select-option
-            v-for="({userId, realName}) in userList"
-            :key="userId"
-            :label="realName"
-            :value="userId">{{ realName }}
-          </a-select-option>
-        </a-select>
-      </a-form-item>
-
-      <!--      <a-form-item
         label="类型"
         :labelCol="BaseTool.Constant.labelCol"
         :wrapperCol="BaseTool.Constant.wrapperCol"
@@ -132,18 +183,22 @@
             :value="parseInt(value)">{{ label }}
           </a-select-option>
         </a-select>
-      </a-form-item>-->
-      <a-form-item
-        label="排序"
-        :labelCol="BaseTool.Constant.labelCol"
-        :wrapperCol="BaseTool.Constant.wrapperCol"
-      >
-        <a-input-number
-          style="width: 100%"
-          :min="1"
-          v-decorator="['sort', {initialValue:1,rules: [{required: true, message: '排序不能为空'}]}]" />
       </a-form-item>
-      <!--      <a-form-item
+              </row-item>-->
+        <row-item>
+          <a-form-item
+            label="排序"
+            :labelCol="BaseTool.Constant.labelCol"
+            :wrapperCol="BaseTool.Constant.wrapperCol"
+          >
+            <a-input-number
+              style="width: 100%"
+              :min="1"
+              v-decorator="['sort', {initialValue:1,rules: [{required: true, message: '排序不能为空'}]}]" />
+          </a-form-item>
+        </row-item>
+        <!--      <row-item>
+      <a-form-item
         label="是否删除"
         :labelCol="BaseTool.Constant.labelCol"
         :wrapperCol="BaseTool.Constant.wrapperCol"
@@ -156,29 +211,46 @@
             :value="parseInt(value)">{{ label }}
           </a-select-option>
         </a-select>
-      </a-form-item>-->
-      <a-form-item
-        label="备注"
-        :labelCol="BaseTool.Constant.labelCol"
-        :wrapperCol="BaseTool.Constant.wrapperCol"
-      >
-        <a-textarea
-          :rows="4"
-          v-decorator="['remark', {rules: [{required: false, message: '备注不能为空'}]}]"/>
-      </a-form-item>
-      <a-form-item
-        label="是否存在库位"
-        :labelCol="BaseTool.Constant.labelCol"
-        :wrapperCol="BaseTool.Constant.wrapperCol"
-      >
-        <a-switch
-          :rows="4"
-          v-decorator="['remark', {rules: [{required: false, message: '备注不能为空'}]}]"/>
       </a-form-item>
+              </row-item>-->
+        <row-item>
+          <a-form-item
+            label="备注"
+            :labelCol="BaseTool.Constant.labelCol"
+            :wrapperCol="BaseTool.Constant.wrapperCol"
+          >
+            <a-textarea
+              :rows="4"
+              v-decorator="['remark', {rules: [{required: false, message: '备注不能为空'}]}]"/>
+          </a-form-item>
+        </row-item>
+        <row-item>
+          <a-form-item
+            label="是否存在库位"
+            :labelCol="BaseTool.Constant.labelCol"
+            :wrapperCol="BaseTool.Constant.wrapperCol"
+          >
+            <a-switch
+              @change="val=>existPosition=val"
+              v-decorator="['existPosition', {initialValue: true,valuePropName: 'checked',rules: [{required: false, message: '备注不能为空'}]}]"/>
+          </a-form-item>
+        </row-item>
+        <row-item v-if="existPosition">
+          <a-form-item
+            label="库位图"
+            :labelCol="BaseTool.Constant.labelCol"
+            :wrapperCol="BaseTool.Constant.wrapperCol"
+          >
+            <Upload :files="fileList" :maxSize="1" @catchFile="catchFile"/>
+          </a-form-item>
+        </row-item>
+      </row-list>
+
     </a-form>
     <template slot="footer">
       <a-button :loading="confirmLoading" type="primary" @click="save()">保存</a-button>
     </template>
+    <PositionMap ref="position" @ok="handleSelectPosition" :opcImg="opcImg" />
   </a-modal>
 </template>
 
@@ -187,9 +259,15 @@ import pick from 'lodash.pick'
 import { addStore, updateStore, fetchStoreTree } from '@/api/store/store'
 import { queryDept, getDeptsAllByParentId } from '@/api/upms/dept'
 import { queryUser, queryUsersByParentDeptNatureAll } from '@/api/upms/user'
-
+import { querySbPosition, fetchSbPosition } from '@/api/sb/position'
+import Upload from '@/components/Upload/CUpload.vue'
+import PositionMap from './PositionMap.vue'
 export default {
   name: 'BaseStore',
+  components: {
+    Upload,
+    PositionMap
+  },
   data () {
     return {
       confirmLoading: false,
@@ -197,6 +275,7 @@ export default {
       level: null,
       form: this.$form.createForm(this),
       visible: false,
+      opcImg: '',
       // 下拉框map
       typeMap: {},
       levelMap: {},
@@ -204,7 +283,10 @@ export default {
       projectList: {},
       userList: {},
       delFlagMap: {},
-      storeTreeDate: []
+      storeTreeDate: [],
+      areaList: [],
+      fileList: [],
+      existPosition: true
     }
   },
   props: {
@@ -214,6 +296,9 @@ export default {
     this.levelMap = this.DictCache.getLabelByValueMapByType(this.DictCache.TYPE.STORE_LEVEL)
     this.typeMap = this.DictCache.getLabelByValueMapByType(this.DictCache.TYPE.STORE_TYPE)
     this.delFlagMap = this.DictCache.getLabelByValueMapByType(this.DictCache.TYPE.DELFLAG)
+    querySbPosition({ type: 1 }).then(res => {
+      this.areaList = res.data
+    })
   },
   methods: {
     base (record) {
@@ -228,16 +313,24 @@ export default {
       if (this.BaseTool.Object.isBlank(record.id)) {
         this.modalTitle = '复制'
       }
-
+      this.modal = record
       const params = { includeMy: true }
       params.deptId = record.useCompany
+      this.level = record.level
       params.nature = this.DictCache.VALUE.SYS_DEPT_NATURE.FEN_GONG_SI
       // params.code = this.DictCache.VALUE.SYS_DEPT_CODE.CANG_KU
       queryUsersByParentDeptNatureAll(params).then(res => {
         this.userList = res.data
       })
       const { form: { setFieldsValue } } = this
-
+      record.existPosition = Boolean(record.existPosition)
+      this.existPosition = record.existPosition
+      this.fileList = [{
+        uid: '-1',
+        name: record.no,
+        status: 'done',
+        url: record.backGroundMap
+      }]
       // 日期处理
       this.$nextTick(() => {
         setFieldsValue(Object.assign(pick(record, [
@@ -252,8 +345,12 @@ export default {
           'sort',
           'delFlag',
           'parentId',
+          'factoryArea',
           'remark',
-          'parentName'
+          'existPosition',
+          'parentName',
+          'positionY',
+          'positionX'
         ])))
       })
     },
@@ -266,6 +363,8 @@ export default {
           return
         }
         // 日期处理
+        values.existPosition = values.existPosition !== null && values.existPosition !== undefined ? Number(values.existPosition) : values.existPosition
+        values.backGroundMap = this.fileList.length > 0 ? this.fileList[0].url : null
         if (this.BaseTool.String.isBlank(values.id)) {
           addStore(values)
             .then(() => {
@@ -283,14 +382,33 @@ export default {
         }
       })
     },
+
     handleCancel (values) {
       this.visible = false
       this.confirmLoading = false
+      this.level = null
+      this.fileList = []
+      this.existPosition = true
       this.form.resetFields()
       if (this.BaseTool.Object.isNotBlank(values)) {
         this.$emit('ok', values)
       }
     },
+    openPositionMap () {
+      const { form: { getFieldsValue } } = this
+      this.$refs.position.base(getFieldsValue(['positionY',
+        'positionX']))
+    },
+    handleSelectPosition (val) {
+      const { form: { setFieldsValue } } = this
+
+      this.$nextTick(() => {
+        setFieldsValue(Object.assign(pick(val, [
+          'positionY',
+          'positionX'
+        ])))
+      })
+    },
     setTree (record = {}) {
       fetchStoreTree({ id: record.id }).then(res => {
         this.storeTreeDate = res.data
@@ -310,6 +428,9 @@ export default {
         this.projectList = res.data
       })
     },
+    catchFile (files) {
+      this.fileList = files
+    },
     handleProjectChange (value) {
       const params = { includeMy: true }
       if (this.BaseTool.Object.isBlank(value)) {
@@ -329,6 +450,11 @@ export default {
       //    setFieldsValue({ name: item.name + '-' })
       //  }
       // })
+    },
+    handleAreaChange (id) {
+      fetchSbPosition({ id }).then(res => {
+        this.opcImg = res.data.opcImg
+      })
     }
 
   }

+ 77 - 0
src/views/store/store/modules/PositionMap.vue

@@ -0,0 +1,77 @@
+<template>
+  <a-modal
+    title="点位选择"
+    :width="1000"
+    :visible="visible"
+    :confirmLoading="confirmLoading"
+    @cancel="handleCancel"
+    @ok="save"
+  >
+    <div style="position: relative;">
+      <div class="point" ref="point" />
+      <img @click="handleSelect" :src="opcImg" width="100%" alt="">
+    </div>
+  </a-modal>
+</template>
+
+<script>
+export default {
+  props: {
+    opcImg: {
+      type: String,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      visible: false,
+      confirmLoading: false,
+      position: { positionX: 0, positionY: 0 }
+    }
+  },
+  methods: {
+    base (record) {
+      this.visible = true
+      this.position = {
+        positionX: 0,
+        positionY: 0
+      }
+      // calc(~"50% - 5px")
+      if (record.positionX && record.positionY) this.position = { ...record }
+      this.$nextTick(() => {
+        console.log(this.$refs.point.style, this.position)
+        this.$refs.point.style.left = `calc(~"${this.position.positionX}% - 5px")`
+        this.$refs.point.style.top = `calc(~"${this.position.positionY}% - 5px")`
+      })
+    },
+    handleSelect (e) {
+      this.$refs.point.style.left = e.offsetX - 5 + 'px'
+      this.$refs.point.style.top = e.offsetY - 5 + 'px'
+      this.position.positionX = +(e.offsetX * 100 / e.target.width).toFixed(2)
+      this.position.positionY = +(e.offsetY * 100 / e.target.height).toFixed(2)
+    },
+    save () {
+      this.visible = false
+      this.$refs.point.style.left = 0 + 'px'
+      this.$refs.point.style.top = 0 + 'px'
+      this.$emit('ok', this.position)
+    },
+    handleCancel () {
+      this.visible = false
+      this.$refs.point.style.left = 0 + 'px'
+      this.$refs.point.style.top = 0 + 'px'
+      this.$emit('ok')
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.point {
+  position: absolute;
+  width: 10px;
+  height: 10px;
+  background: rgb(10, 233, 58);
+  border-radius: 50%;
+}
+</style>