doum
2026-01-29 e1b74e9a33f947f87bc87b2921db9a72598d4d47
提交忽略文件
已添加9个文件
已修改23个文件
1606 ■■■■ 文件已修改
admin/public/template/casees.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
admin/public/template/member.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/api/business/category.js 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/api/business/importRecord.js 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/api/business/member.js 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/business/OperaCategoryWindow.vue 87 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/business/OperaMemberImportWindow.vue 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/common/UploadAvatarImage.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/common/UploadImage.vue 124 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/business/category.vue 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/business/categoryBusType.vue 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/business/categoryField.vue 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/business/categoryLevel.vue 121 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/business/member.vue 246 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/admin/src/main/java/com/doumee/api/business/CategoryController.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/admin/src/main/java/com/doumee/api/business/ImportRecordController.java 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/admin/src/main/java/com/doumee/api/business/MemberController.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/pom.xml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/pom.xml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/core/annotation/excel/ExcelImporter.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/core/annotation/excel/ExcelPictureUtil.java 305 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/core/constants/Constants.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/dao/business/dto/CasesImport.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/dao/business/dto/MemberImport.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/dao/business/model/Category.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/dao/business/model/ImportRecord.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/dao/business/model/Multifile.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/ImportRecordService.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/MemberService.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/impl/CategoryServiceImpl.java 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/impl/ImportRecordServiceImpl.java 135 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/impl/MemberServiceImpl.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/public/template/casees.xlsx
Binary files differ
admin/public/template/member.xlsx
Binary files differ
admin/src/api/business/category.js
@@ -6,6 +6,11 @@
    trim: true
  })
}
export function findAll (data) {
  return request.post('/business/category/list', data, {
    trim: true
  })
}
// åˆ›å»º
export function create (data) {
admin/src/api/business/importRecord.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,48 @@
import request from '../../utils/request'
// æŸ¥è¯¢
export function fetchList (data) {
  return request.post('/business/importRecord/page', data, {
    trim: true
  })
}
// åˆ›å»º
export function create (data) {
  return request.post('/business/importRecord/create', data)
}
export function updateStatus (data) {
  return request.post('/business/importRecord/updateStatus', data)
}
// å¯¼å‡ºExcel
export function exportExcel (data) {
  return request.post('/business/importRecord/exportExcel', data, {
    download: true
  })
}
export function importExcel (data) {
  return request.post('/business/importRecord/importExcel', data)
}
// ä¿®æ”¹
export function updateById (data) {
  return request.post('/business/importRecord/updateById', data)
}
// åˆ é™¤
export function deleteById (id) {
  return request.get(`/business/importRecord/delete/${id}`)
}
export function getById (id) {
  return request.get(`/business/importRecord/${id}`)
}
// æ‰¹é‡åˆ é™¤
export function deleteByIdInBatch (ids) {
  return request.get('/business/importRecord/delete/batch', {
    params: {
      ids
    }
  })
}
admin/src/api/business/member.js
@@ -21,6 +21,9 @@
    download: true
  })
}
export function importExcel (data) {
  return request.post('/business/member/importExcel', data)
}
// ä¿®æ”¹
export function updateById (data) {
admin/src/components/business/OperaCategoryWindow.vue
@@ -7,45 +7,34 @@
  >
    <el-form :model="form" ref="form" :rules="rules">
      <el-form-item label="名称" prop="name">
        <el-input v-if="form.type !=3"  v-model="form.name" placeholder="请输入名称" v-trim/>
        <el-select v-else  v-model="form.name" placeholder="请选择订单类型" v-trim>
          <el-option :value="'0'" label="用工单"></el-option>
          <el-option :value="'1'" label="货运单"></el-option>
          <el-option :value="'2'" label="订餐单"></el-option>
        </el-select>
        <el-input   v-model="form.name" placeholder="请输入名称" v-trim/>
      </el-form-item>
      <el-form-item v-if="form.type ==3 " label="手续费(%)" prop="detail">
        <el-input  type="number"   v-model="form.detail" placeholder="请输入名称" v-trim/>
      <el-form-item label="战区编码" prop="detail"  v-if="form.type ==0" >
        <el-input v-model="form.detail" placeholder="请输入战区编码" v-trim/>
      </el-form-item>
      <el-form-item v-if="form.type == 1 || form.type == 2" :label=" form.type == 1?'车辆规格':'餐标配置(元)'" prop="detailList">
        <div style="display: flex;flex-direction: column">
          <div style="position: relative;display: block;width: 100%;" v-for="(item,index) in form.detailList"   >
            <el-input  :type="form.type == 1?'text':'number'" style="display:inline-block;width: 60%;margin:5px ;float: left" v-model="form.detailList[index]"   placeholder="请输入内容" v-trim/>
            <el-button  style="display:inline-block;margin : 5px " @click="del(index)" v-if="form.detailList.length>0">x</el-button>
          </div>
          <div style="position: relative;display: block;width: 100%;">
            <el-button style="width: 100px;margin: 5px;" type="primary" @click="add()">添加规格</el-button>
          </div>
        </div>
      </el-form-item>
      <el-form-item v-if="form.type == 1" label="图标" prop="icon">
      <el-form-item v-if="form.type == 3" label="图标" prop="icon">
        <UploadAvatarImage
            :file="{ imgurlfull: form.iconFull, imgurl: form.icon }"
            :uploadData="uploadData"
            @uploadSuccess="uploadAvatarSuccess"
        />
      </el-form-item>
      <el-form-item  v-if="form.id ==null && form.type == 1"  label="是否固定车辆" prop="isFixed">
        <el-radio-group v-model="form.isFixed">
          <el-radio :label="0">非固定</el-radio>
          <el-radio :label="1">固定车型</el-radio>
        </el-radio-group>
      <el-form-item v-if="form.type == 1" label="排行榜图集" prop="icon">
        <UploadImage
            :fileList="tempfileList"
            :uploadData="uploadData"
            @beginUpload="isUploading=true"
            @endUpload="isUploading=false"/>
        <p class="tip-warn">
          å»ºè®®å°ºå¯¸ï¼š750px X 750px,上限6å¼ 
          æ”¯æŒpng、jpg、jpeg格式,大小不超过2M,上传图片不允许涉及政治敏感与色情,
        </p>
      </el-form-item>
      <el-form-item label="排序码" prop="sortnum">
        <el-input v-model="form.sortnum" placeholder="请输入排序码" v-trim/>
        <el-input v-model="form.sortnum" type="" placeholder="请输入排序码" v-trim/>
      </el-form-item>
      <el-form-item label="描述" prop="remark">
        <el-input v-model="form.remark" placeholder="请输入描述" v-trim/>
        <el-input type="textarea" v-model="form.remark" placeholder="请输入描述" v-trim/>
      </el-form-item>
    </el-form>
  </GlobalWindow>
@@ -54,16 +43,17 @@
<script>
import BaseOpera from '@/components/base/BaseOpera'
import GlobalWindow from '@/components/common/GlobalWindow'
import UploadImage from '@/components/common/UploadImage'
import UploadAvatarImage from '@/components/common/UploadAvatarImage'
export default {
  name: 'OperaCategoryWindow',
  extends: BaseOpera,
  components: { GlobalWindow ,UploadAvatarImage},
  components: { GlobalWindow, UploadAvatarImage,UploadImage },
  data () {
    return {
      isUploading: false,
      uploadData: {
        folder: 'category'
        folder: 'dianjiang/category'
      },
      // è¡¨å•数据
      form: {
@@ -74,14 +64,15 @@
        type: null,
        detail: null,
        remark: null,
        detailList: [''],
        fileList: [],
        icon: '',
        iconFull: '',
        isFixed: 0
      },
      tempfileList: [],
      // éªŒè¯è§„则
      rules: {
        name: [{ required: true, message: '请输入配置名称' }]
        name: [{ required: true, message: '请输入名称' }]
      }
    }
  },
@@ -91,23 +82,32 @@
      'field.id': 'id'
    })
  },
  methods:{
    del(index){
      if(this.form.detailList.length<=1){
  methods: {
    del (index) {
      if (this.form.detailList.length <= 1) {
        return
      }
      this.form.detailList.splice(index,1)
      this.form.detailList.splice(index, 1)
    },
    add(){
    add () {
      this.form.detailList.push('')
    },
    uploadAvatarSuccess (file) {
      this.$set(this.form, 'icon', file.imgurl)
      this.$set(this.form, 'iconFull', file.imgurlfull)
    },
    open(title, target, type) {
    confirm () {
      this.form.fileList = this.tempfileList
      if (this.form[this.configData['field.id']] == null || this.form[this.configData['field.id']] === '') {
        this.__confirmCreate()
        return
      }
      this.__confirmEdit()
    },
    open (title, target, type) {
      this.title = title
      this.visible = true
      this.tempfileList = []
      this.form = {
        id: null,
        status: 0,
@@ -116,7 +116,7 @@
        detail: null,
        type: type,
        remark: null,
        detailList: [''],
        fileList: [],
        icon: '',
        iconFull: '',
        isFixed: 0
@@ -135,9 +135,14 @@
        for (const key in this.form) {
          this.form[key] = target[key]
        }
        if(this.form.detailList==null){
          this.form.detailList = ['']
        }
        this.form.fileList = this.form.fileList||[]
        this.form.fileList.forEach(item=>{
          this.tempfileList.push({
            fileurl: item.fileurl,
            name: item.name,
            url: item.url
          })
        })
      })
    }
  }
admin/src/components/business/OperaMemberImportWindow.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,86 @@
<template>
  <el-dialog
      class="center-title"
      :title="title"
      width="500px"
      top="30vh"
      :visible.sync="visible"
      :confirm-working="isWorking"
      @confirm="confirm"
  >
    <p class="tip-warn"><i class="el-icon-warning"></i>导入说明:<br>
      1.请先下载文件模板,并按照模板要去填写表格内容;<br>
    </p>
    <el-form class="demo-form-inline" >
      <el-form-item label="老师名单" required>
        <div style="width: 100%;display: flex;align-items: center;">
          <el-button type="primary" :loading="importing"   @click="clickRef">点击上传</el-button>
          <el-button type="text" @click="exportTemplate">点击下载模版.EXCEL</el-button>
        </div>
        <div style="font-size: 14px; color: black;" v-if="fileName">{{fileName}}</div>
      </el-form-item>
    </el-form>
    <input type="file" style="position: fixed; left: 0; top: -50px;" accept=".xlsx" ref="fileExcel" @change="result" />
    <template   v-slot:footer>
      <el-button @click="visible=false">返回</el-button>
    </template>
  </el-dialog>
</template>
<script>
import BaseOpera from '@/components/base/BaseOpera'
import GlobalWindow from '@/components/common/GlobalWindow'
import { importExcel } from '@/api/business/importRecord'
export default {
  name: 'OperaMemberImportWindow',
  extends: BaseOpera,
  // eslint-disable-next-line vue/no-unused-components
  components: { GlobalWindow },
  data () {
    return {
      importing: false,
      fileName: '',
      type: 0
    }
  },
  methods: {
    open (title) {
      this.title = title
      this.fileName = ''
      this.visible = true
      this.type = 0
    },
    // å¯¼å‡ºæ¨¡æ¿
    exportTemplate () {
      // æŠ•保申请
      window.open('/template/member.xlsx')
    },
    clickRef () {
      this.$refs.fileExcel.click()
    },
    result (e) {
      this.importing=true
      const data = new FormData()
      data.append('file', e.target.files[0])
      data.append('type', this.type)
      importExcel(data)
        .then(res => {
          this.$message.success('名单已上传成功,可前往【导入记录】菜单查看任务执行进度。')
          this.$emit('success')
          this.visible = false
        })
        .catch(err => {
          this.fileName = ''
        })
        .finally(() => {
          this.$refs.fileExcel.value = null
          this.importing=false
        })
    }
  }
}
</script>
<style lang="scss" scoped>
</style>
admin/src/components/common/UploadAvatarImage.vue
@@ -31,7 +31,7 @@
  data() {
    return {
      loading: null,
      uploadImgUrl: process.env.VUE_APP_API_PREFIX + '/web/public/upload'
      uploadImgUrl: process.env.VUE_APP_API_PREFIX + '/public/upload'
    }
  },
admin/src/components/common/UploadImage.vue
@@ -8,32 +8,13 @@
      accept=".jpg,.png"
      :before-upload="beforeUpload"
      :on-success="uploadSuccess"
      :on-preview="handlePreview"
      :on-remove="handleRemove"
      :on-error="fail"
    >
      <i class="el-icon-plus icon"></i>
      <div slot="file" slot-scope="{file}">
        <img
          class="el-upload-list__item-thumbnail"
          :src="file.url" alt=""
          style="width: 100px;height: 100px;"
        >
        <span class="el-upload-list__item-actions">
          <span
            class="el-upload-list__item-preview"
            @click="handlePictureCardPreview(file)"
          >
            <i class="el-icon-zoom-in"></i>
          </span>
          <span
            class="el-upload-list__item-delete"
            @click="handleRemove(file)"
          >
            <i class="el-icon-delete"></i>
          </span>
        </span>
      </div>
    </el-upload>
    <el-image-viewer
   <el-image-viewer
      v-if="showViewer"
      :on-close="closeViewer"
      :initialIndex="tempIndex"
@@ -55,79 +36,77 @@
      type: Array,
      default: () => []
    },
    uploadData: Object,
    maxNum: {
      type: Number,
      default: () => null
    },
    uploadData: Object
  },
  data() {
  data () {
    return {
      uploadImgUrl: process.env.VUE_APP_API_PREFIX + '/web/public/uploadLocal',
      uploadImgUrl: process.env.VUE_APP_API_PREFIX + '/public/upload',
      realList: [],
      srcList: [],
      // srcList: [],
      tempIndex: 0,
      showViewer: false,
      showViewer: false
    }
  },
  computed:{
    srcList(){
      return this.fileList.map(item => { return item.url })
    }
  },
  watch: {
    fileList: {
      handler(val) {
        console.log(val);
        if (val.length==0) {
          this.realList = []
          this.srcList = []
        }
      }
    }
  },
  methods: {
    beforeUpload(file) {
    handlePreview(file) {
      // console.log('预览文件:', file,this.fileList);
      this.tempIndex = this.srcList.findIndex(item => item == file.url)
      this.showViewer = true
    },
    beforeUpload (file) {
      this.$emit('beginUpload')
      const isJPGOrPNG = file.type === 'image/jpeg' || file.type === 'image/png'
      const isLt2M = file.size / 1024 / 1024 < 1; // 500kb
      if (!isJPGOrPNG) {
        this.$message.error('上传头像图片只能是 JPG/PNG æ ¼å¼!');
        return false
      }
      if (!isLt2M) {
        this.$message.error('上传头像图片大小不能超过 500KB!');
        return false
      }
      return true
    },
     // ä¸Šä¼ å›¾ç‰‡æˆåŠŸ
     uploadSuccess (res, file, fileList) {
      // console.log('this.fileList', this.fileList);
      // console.log('fileList', fileList);
      this.$emit('uploadEnd')
      this.realList = fileList
      this.srcList.push(res.data.url)
      // console.log('file', file);
    // ä¸Šä¼ å›¾ç‰‡æˆåŠŸ
    uploadSuccess (res, file, fileList) {
      this.$emit('endUpload')
      console.log('上传成功1:',fileList);
      if (res.code === 200) {
        this.fileList.push(
          {
            fileurl: res.data.imgaddr,
            name: res.data.originname,
            url: res.data.url
          }
        )
        this.fileList.push({
          fileurl: res.data.imgaddr,
          name: res.data.originname,
          url: res.data.url
        })
        console.log('上传成功2:', this.fileList);
      } else {
        this.$message.error(res.msg || '上传失败')
      }
    },
    fail (err, file, fileList) {
      this.$emit('uploadEnd')
      this.$emit('endUpload')
      this.$message.error('上传失败')
    },
    handlePictureCardPreview(file) {
      // this.tempIndex = this.srcList.findIndex(item => item == file.response.data.url )
      // console.log(file);
      this.tempIndex = this.fileList.findIndex(item => item.url == file.url )
      // console.log( this.tempIndex);
      this.srcList = this.fileList.map(item => item.url)
      this.showViewer = true
    },
    closeViewer() {
    closeViewer () {
      this.showViewer = false
    },
    handleRemove(file) {
      console.log(this.fileList);
      let tempIndex = this.realList.findIndex(item => item.url === file.url)
      // debugger
      this.realList.splice(tempIndex, 1)
      this.fileList.splice(tempIndex, 1)
      this.srcList.splice(tempIndex, 1)
    handleRemove (file) {
      const tempIndex = this.fileList.findIndex(item => item.url === file.url)
      if(tempIndex >= 0){
        this.fileList.splice(tempIndex, 1)
      }
    }
  },
  }
}
</script>
@@ -150,4 +129,3 @@
  height: 90px !important;
}
</style>
admin/src/views/business/category.vue
@@ -13,8 +13,9 @@
    <!-- è¡¨æ ¼å’Œåˆ†é¡µ -->
    <template v-slot:table-wrap>
      <ul class="toolbar" v-permissions="['business:category:create', 'business:category:delete']">
        <li><el-button type="primary" @click="$refs.operaCategoryWindow.open('新建品种配置',null,searchForm.type)" icon="el-icon-plus" v-permissions="['business:category:create']">新建</el-button></li>
        <li><el-button @click="deleteByIdInBatch" icon="el-icon-delete" v-permissions="['business:category:delete']">删除</el-button></li>
        <li><el-button type="primary" @click="$refs.operaCategoryWindow.open('新建战区',null,searchForm.type)" icon="el-icon-plus" v-permissions="['business:category:create']">新建</el-button></li>
        <li><el-button type="primary" icon="el-icon-refresh" v-permissions="['business:category:create']">同步</el-button></li>
        <li><el-button type="danger" @click="deleteByIdInBatch" icon="el-icon-delete" v-permissions="['business:category:delete']">删除</el-button></li>
      </ul>
      <el-table
          :height="tableHeightNew"
@@ -24,7 +25,8 @@
        @selection-change="handleSelectionChange"
      >
        <el-table-column type="selection" width="55"></el-table-column>
        <el-table-column prop="name" label="单位名称" min-width="100px"></el-table-column>
        <el-table-column prop="name" label="战区名称" min-width="100px"></el-table-column>
        <el-table-column prop="detail" label="战区编码" min-width="100px"></el-table-column>
        <el-table-column label="状态">
          <template slot-scope="{row}">
            <el-switch @change="changeStatus($event, row)" v-model="row.status" active-color="#13ce66"
@@ -42,8 +44,8 @@
          fixed="right"
        >
          <template slot-scope="{row}">
            <el-button type="text" @click="$refs.operaCategoryWindow.open('编辑新建品种配置', row,searchForm.type)" icon="el-icon-edit" v-permissions="['business:category:update']">编辑</el-button>
            <el-button type="text" @click="deleteById(row)" icon="el-icon-delete" v-permissions="['business:category:delete']">删除</el-button>
            <el-button type="text" @click="$refs.operaCategoryWindow.open('编辑战区', row,searchForm.type)" icon="el-icon-edit" v-permissions="['business:category:update']">编辑</el-button>
            <el-button type="text" style="color: red" @click="deleteById(row)" icon="el-icon-delete" v-permissions="['business:category:delete']">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
admin/src/views/business/categoryBusType.vue
@@ -13,7 +13,7 @@
    <!-- è¡¨æ ¼å’Œåˆ†é¡µ -->
    <template v-slot:table-wrap>
      <ul class="toolbar" v-permissions="['business:category:create', 'business:category:delete']">
        <li><el-button type="primary" @click="$refs.operaCategoryWindow.open('新建货运配置',null,searchForm.type)" icon="el-icon-plus" v-permissions="['business:category:create']">新建</el-button></li>
        <li><el-button type="primary" @click="$refs.operaCategoryWindow.open('新建商业化类型',null,searchForm.type)" icon="el-icon-plus" v-permissions="['business:category:create']">新建</el-button></li>
        <li><el-button @click="deleteByIdInBatch" icon="el-icon-delete" v-permissions="['business:category:delete']">删除</el-button></li>
      </ul>
      <el-table
@@ -24,14 +24,19 @@
        @selection-change="handleSelectionChange"
      >
        <el-table-column type="selection" :selectable="isChangeSelected" width="55"></el-table-column>
        <el-table-column  prop="icon" label="图标" min-width="100px">
        <el-table-column prop="name" label="名称" min-width="100px"></el-table-column>
        <el-table-column  prop="icon" label="排行榜图集" min-width="220px">
          <template slot-scope="{row}">
            <el-image v-if="row.iconFull" style="width: 50px; height: 50px; margin-right: 10px" :src="row.iconFull"
                      :preview-src-list="[row.iconFull]">
            </el-image>
            <div style="display: flex; flex-wrap: wrap;width: 200px;"  v-if="row.fileList && row.fileList.length">
              <div v-for="item in row.fileList" :key="row.id+'_img'+item.id" style=" box-sizing: border-box;  margin-right: 10px; " >
                <el-image  style="width: 50px; height: 50px;" :src="item.url"
                          :preview-src-list="[item.url]">
                </el-image>
              </div>
            </div>
          </template>
        </el-table-column>
        <el-table-column prop="name" label="名称" min-width="100px"></el-table-column>
        <el-table-column label="状态">
          <template slot-scope="{row}">
            <el-switch :disabled="row.isFixed ==1" @change="changeStatus($event, row)" v-model="row.status" active-color="#13ce66"
@@ -50,7 +55,7 @@
          fixed="right"
        >
          <template slot-scope="{row}">
            <el-button type="text"   @click="$refs.operaCategoryWindow.open('编辑新建货运配置', row,searchForm.type)" icon="el-icon-edit" v-permissions="['business:category:update']">编辑</el-button>
            <el-button type="text"   @click="$refs.operaCategoryWindow.open('编辑商业化类型', row,searchForm.type)" icon="el-icon-edit" v-permissions="['business:category:update']">编辑</el-button>
            <el-button type="text"   @click="deleteById(row)" icon="el-icon-delete" v-permissions="['business:category:delete']">删除</el-button>
          </template>
        </el-table-column>
admin/src/views/business/categoryField.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,113 @@
<template>
  <TableLayout :permissions="['business:category:query']">
    <!-- æœç´¢è¡¨å• -->
    <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline>
      <el-form-item label="名称" prop="name">
        <el-input v-model="searchForm.name" placeholder="请输入名称" @keypress.enter.native="search"></el-input>
      </el-form-item>
      <section>
        <el-button type="primary" @click="search">搜索</el-button>
        <el-button @click="reset">重置</el-button>
      </section>
    </el-form>
    <!-- è¡¨æ ¼å’Œåˆ†é¡µ -->
    <template v-slot:table-wrap>
      <ul class="toolbar" v-permissions="['business:category:create', 'business:category:delete']">
        <li><el-button type="primary" @click="$refs.operaCategoryWindow.open('新建擅长领域',null,searchForm.type)" icon="el-icon-plus" v-permissions="['business:category:create']">新建</el-button></li>
        <li><el-button @click="deleteByIdInBatch" icon="el-icon-delete" v-permissions="['business:category:delete']">删除</el-button></li>
      </ul>
      <el-table
          :height="tableHeightNew"
        v-loading="isWorking.search"
        :data="tableData.list"
        stripe
        @selection-change="handleSelectionChange"
      >
        <el-table-column type="selection" :selectable="isChangeSelected" width="55"></el-table-column>
        <el-table-column prop="name" label="名称" min-width="100px"></el-table-column>
        <el-table-column label="状态">
          <template slot-scope="{row}">
            <el-switch :disabled="row.isFixed ==1" @change="changeStatus($event, row)" v-model="row.status" active-color="#13ce66"
            inactive-color="#ff4949" :active-value="0" :inactive-value="1">
            </el-switch>
          </template>
        </el-table-column>
        <el-table-column prop="remark" label="描述" min-width="100px"></el-table-column>
        <el-table-column prop="sortnum" label="排序码" min-width="100px"></el-table-column>
        <el-table-column prop="updateUserName" label="操作人" min-width="100px"></el-table-column>
        <el-table-column prop="updateTime" label="最近操作时间" min-width="150px"></el-table-column>
        <el-table-column
          v-if="containPermissions(['business:category:update', 'business:category:delete'])"
          label="操作"
          min-width="120"
          fixed="right"
        >
          <template slot-scope="{row}">
            <el-button type="text"   @click="$refs.operaCategoryWindow.open('编辑擅长领域', row,searchForm.type)" icon="el-icon-edit" v-permissions="['business:category:update']">编辑</el-button>
            <el-button type="text"   @click="deleteById(row)" icon="el-icon-delete" v-permissions="['business:category:delete']">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <pagination
        @size-change="handleSizeChange"
        @current-change="handlePageChange"
        :pagination="tableData.pagination"
      >
      </pagination>
    </template>
    <!-- æ–°å»º/修改 -->
    <OperaCategoryWindow ref="operaCategoryWindow" @success="handlePageChange"/>
  </TableLayout>
</template>
<script>
import BaseTable from '@/components/base/BaseTable'
import TableLayout from '@/layouts/TableLayout'
import Pagination from '@/components/common/Pagination'
import OperaCategoryWindow from '@/components/business/OperaCategoryWindow'
export default {
  name: 'Category',
  extends: BaseTable,
  components: { TableLayout, Pagination, OperaCategoryWindow },
  data () {
    return {
      // æœç´¢
      searchForm: {
        name: '',
        type: 2
      }
    }
  },
  created () {
    this.config({
      module: '分类信息表',
      api: '/business/category',
      'field.id': 'id',
      'field.main': 'id'
    })
    this.search()
  },
  methods: {
    isChangeSelected(row,index){
      // if(row.isFixed ==1) {
      //   return false
      // }
      return true
    },
    changeStatus (e, row) {
      this.working = true
      this.api.updateStatus({ id: row.id, status: e })
        .then(res => {
          this.$tip.apiSuccess(res || '操作成功')
          this.search()
        })
        .catch(e => {
          this.$tip.apiFailed(e)
        })
        .finally(() => {
          this.working = false
        })
    }
  }
}
</script>
admin/src/views/business/categoryLevel.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,121 @@
<template>
  <TableLayout :permissions="['business:category:query']">
    <!-- æœç´¢è¡¨å• -->
    <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline>
      <el-form-item label="名称" prop="name">
        <el-input v-model="searchForm.name" placeholder="请输入名称" @keypress.enter.native="search"></el-input>
      </el-form-item>
      <section>
        <el-button type="primary" @click="search">搜索</el-button>
        <el-button @click="reset">重置</el-button>
      </section>
    </el-form>
    <!-- è¡¨æ ¼å’Œåˆ†é¡µ -->
    <template v-slot:table-wrap>
      <ul class="toolbar" v-permissions="['business:category:create', 'business:category:delete']">
        <li><el-button type="primary" @click="$refs.operaCategoryWindow.open('新建老师等级',null,searchForm.type)" icon="el-icon-plus" v-permissions="['business:category:create']">新建</el-button></li>
        <li><el-button @click="deleteByIdInBatch" icon="el-icon-delete" v-permissions="['business:category:delete']">删除</el-button></li>
      </ul>
      <el-table
          :height="tableHeightNew"
        v-loading="isWorking.search"
        :data="tableData.list"
        stripe
        @selection-change="handleSelectionChange"
      >
        <el-table-column type="selection" :selectable="isChangeSelected" width="55"></el-table-column>
        <el-table-column prop="name" label="名称" min-width="100px"></el-table-column>
        <el-table-column  prop="icon" label="图标" min-width="100px">
          <template slot-scope="{row}">
            <el-image v-if="row.iconFull" style="width: 50px; height: 50px; margin-right: 10px" :src="row.iconFull"
                      :preview-src-list="[row.iconFull]">
            </el-image>
          </template>
        </el-table-column>
        <el-table-column label="状态">
          <template slot-scope="{row}">
            <el-switch :disabled="row.isFixed ==1" @change="changeStatus($event, row)" v-model="row.status" active-color="#13ce66"
            inactive-color="#ff4949" :active-value="0" :inactive-value="1">
            </el-switch>
          </template>
        </el-table-column>
        <el-table-column prop="remark" label="描述" min-width="100px"></el-table-column>
        <el-table-column prop="sortnum" label="排序码" min-width="100px"></el-table-column>
        <el-table-column prop="updateUserName" label="操作人" min-width="100px"></el-table-column>
        <el-table-column prop="updateTime" label="最近操作时间" min-width="150px"></el-table-column>
        <el-table-column
          v-if="containPermissions(['business:category:update', 'business:category:delete'])"
          label="操作"
          min-width="120"
          fixed="right"
        >
          <template slot-scope="{row}">
            <el-button type="text"   @click="$refs.operaCategoryWindow.open('编辑老师等级', row,searchForm.type)" icon="el-icon-edit" v-permissions="['business:category:update']">编辑</el-button>
            <el-button type="text"   @click="deleteById(row)" icon="el-icon-delete" v-permissions="['business:category:delete']">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <pagination
        @size-change="handleSizeChange"
        @current-change="handlePageChange"
        :pagination="tableData.pagination"
      >
      </pagination>
    </template>
    <!-- æ–°å»º/修改 -->
    <OperaCategoryWindow ref="operaCategoryWindow" @success="handlePageChange"/>
  </TableLayout>
</template>
<script>
import BaseTable from '@/components/base/BaseTable'
import TableLayout from '@/layouts/TableLayout'
import Pagination from '@/components/common/Pagination'
import OperaCategoryWindow from '@/components/business/OperaCategoryWindow'
export default {
  name: 'Category',
  extends: BaseTable,
  components: { TableLayout, Pagination, OperaCategoryWindow },
  data () {
    return {
      // æœç´¢
      searchForm: {
        name: '',
        type: 3
      }
    }
  },
  created () {
    this.config({
      module: '分类信息表',
      api: '/business/category',
      'field.id': 'id',
      'field.main': 'id'
    })
    this.search()
  },
  methods: {
    isChangeSelected(row,index){
      // if(row.isFixed ==1) {
      //   return false
      // }
      return true
    },
    changeStatus (e, row) {
      this.working = true
      this.api.updateStatus({ id: row.id, status: e })
        .then(res => {
          this.$tip.apiSuccess(res || '操作成功')
          this.search()
        })
        .catch(e => {
          this.$tip.apiFailed(e)
        })
        .finally(() => {
          this.working = false
        })
    }
  }
}
</script>
admin/src/views/business/member.vue
@@ -2,42 +2,104 @@
  <TableLayout :permissions="['business:member:query']">
    <!-- æœç´¢è¡¨å• -->
    <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline>
      <el-form-item label="手机号" prop="telephone">
        <el-input v-model="searchForm.telephone" clearable placeholder="请输入手机号" @keypress.enter.native="search"></el-input>
      <el-form-item label="名称" prop="name">
        <el-input v-model="searchForm.name"  style="width: 150px" placeholder="请输入名称" @keypress.enter.native="search"></el-input>
      </el-form-item>
      <el-form-item label="真实姓名" prop="name">
        <el-input v-model="searchForm.name" clearable placeholder="请输入真实姓名" @keypress.enter.native="search"></el-input>
      <el-form-item label="工号" prop="code">
        <el-input v-model="searchForm.code" style="width: 150px" placeholder="请输入工号" @keypress.enter.native="search"></el-input>
      </el-form-item>
      <el-form-item label="类型" prop="type">
        <el-select v-model="searchForm.type" clearable placeholder="请选择类型" @change="search">
            <el-option :value="0" label="全部"></el-option>
            <el-option :value="1" label="接单方"></el-option>
      <el-form-item label="战区" prop="fieldIdList">
        <el-select
            v-model="searchForm.fieldIdList"
            style="width: 150px"
            placeholder="战区"
            clearable
            multiple
            @change="search"
        >
          <el-option
              v-for="item in cateList"
              :key="item.id"
              :value="item.id"
              :label="item.name"
          ></el-option>
        </el-select>
      </el-form-item>
<!--      <el-form-item label="状态" prop="status">
        <el-select v-model="searchForm.status"  @keypress.enter.native="search" clearable placeholder="状态">
          <el-option label="启用" value="0"></el-option>
          <el-option label="禁用" value="1"></el-option>
      <el-form-item label="商业化类型" prop="busTypeIdList">
        <el-select
            v-model="searchForm.busTypeIdList"
            style="width: 150px"
            placeholder="商业化类型"
            clearable
            multiple
            @change="search"
        >
          <el-option
              v-for="item in cateList1"
              :key="item.id"
              :value="item.id"
              :label="item.name"
          ></el-option>
        </el-select>
      </el-form-item>-->
      <el-form-item label="注册时间" prop="eventType">
        <el-date-picker type="datetime" style="width: 120px" v-model="searchForm.startTime" clearable value-format="yyyy-MM-dd HH:mm:ss"
                        placeholder="开始时间" />-
        <el-date-picker type="datetime"  style="width: 120px"  v-model="searchForm.endTime" clearable value-format="yyyy-MM-dd HH:mm:ss"
                        placeholder="结束时间" />
      </el-form-item>
      <el-form-item label="擅长领域" prop="levelIdList">
        <el-select
            v-model="searchForm.levelIdList"
            style="width: 150px"
            placeholder="擅长领域"
            clearable
            multiple
            @change="search"
        >
          <el-option
              v-for="item in cateList2"
              :key="item.id"
              :value="item.id"
              :label="item.name"
          ></el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="老师等级" prop="levelIdList">
        <el-select
            v-model="searchForm.levelIdList"
            style="width: 150px"
            placeholder="老师等级"
            clearable
            multiple
            @change="search"
        >
          <el-option
              v-for="item in cateList3"
              :key="item.id"
              :value="item.id"
              :label="item.name"
          ></el-option>
        </el-select>
        <el-form-item label="状态" prop="status">
          <el-select
              v-model="searchForm.status"
              placeholder="状态"
              clearable
              style="width: 150px"
              @change="search"
          >
            <el-option :key="0" :value="0" label="启用"></el-option>
            <el-option :key="1" :value="1" label="禁用"></el-option>
          </el-select>
        </el-form-item>
      </el-form-item>
      <section>
        <el-button type="primary" @click="search">搜索</el-button>
        <el-button @click="reset">重置</el-button>
        <el-button type="primary" :loading="isWorking.export" @click="exportExcel">导出</el-button>
      </section>
    </el-form>
    <!-- è¡¨æ ¼å’Œåˆ†é¡µ -->
    <template v-slot:table-wrap>
<!--      <ul class="toolbar" v-permissions="['business:member:create', 'business:member:delete']">
        <li><el-button type="primary" @click="$refs.operaMemberWindow.open('新建会员信息表')" icon="el-icon-plus" v-permissions="['business:member:create']">新建</el-button></li>
        <li><el-button @click="deleteByIdInBatch" icon="el-icon-delete" v-permissions="['business:member:delete']">删除</el-button></li>
      </ul>-->
      <ul class="toolbar" v-permissions="['business:member:create', 'business:member:delete']">
        <li><el-button type="primary" @click="$refs.operaMemberWindow.open('新建老师',null)" icon="el-icon-plus" v-permissions="['business:member:create']">新建</el-button></li>
        <li><el-button type="primary" icon="el-icon-refresh" v-permissions="['business:member:create']" @click="$refs.OperaMemberImportWindow.open('老师导入', searchForm.companyType)">批量导入</el-button></li>
        <li><el-button type="danger" @click="deleteByIdInBatch" icon="el-icon-delete" v-permissions="['business:member:delete']">删除</el-button></li>
      </ul>
      <el-table
          :height="tableHeightNew"
        v-loading="isWorking.search"
@@ -46,55 +108,57 @@
        @selection-change="handleSelectionChange"
      >
        <el-table-column type="selection" width="55"></el-table-column>
        <el-table-column prop="openid" label="openid" min-width="100px">
        <el-table-column  prop="imgurl" label="图片" min-width="100px">
          <template slot-scope="{row}">
           <span style="cursor: pointer;color: #2E68EC" @click="openDetail(row)">{{row.openid}}</span>
            <el-image v-if="row.imgurlfull" style="width: 50px; height: 50px; margin-right: 10px" :src="row.imgurlfull"
                      :preview-src-list="[row.imgurlfull]">
            </el-image>
          </template>
        </el-table-column>
        <el-table-column prop="nickName" label="昵称" min-width="100px"></el-table-column>
        <el-table-column prop="name" label="真实姓名" min-width="100px"></el-table-column>
        <el-table-column prop="telephone" label="手机号" min-width="100px"></el-table-column>
        <el-table-column prop="workerIdentity" label="身份" min-width="100px">
        <el-table-column prop="code" label="工号" min-width="100px"></el-table-column>
        <el-table-column prop="name" label="姓名" min-width="100px"></el-table-column>
        <el-table-column prop="sex" label="性别" min-width="100px">
          <template slot-scope="{row}">
            å‘单方<span v-if="row.workerIdentity == 2 || row.driverIdentity == 2 || row.chefIdentity == 2">{{'  |  æŽ¥å•æ–¹'}}</span>
            <span v-if="row.sex ==0">男</span>
            <span v-if="row.sex ==1">女</span>
          </template>
        </el-table-column>
        <el-table-column prop="workerIdentity" label="接单认证身份"  width="120px">
        <el-table-column prop="position" label="岗位" min-width="120px"></el-table-column>
        <el-table-column prop="levelName" label="等级" min-width="100px"></el-table-column>
        <el-table-column prop="jobYear" label="从业年份" min-width="100px"></el-table-column>
        <el-table-column prop="serveNum" label="服务商场" min-width="100px">
          <template slot-scope="{row}">
            <div v-if="row.workerIdentity == 2" class="renzhen">工人</div>
            <div v-if=" row.driverIdentity == 2"  class="renzhen">司机</div>
            <div v-if="row.chefIdentity == 2"    class="renzhen">供餐</div>
            <span v-if="row.serveNum">{{row.serveNum}}个</span>
          </template>
        </el-table-column>
        <el-table-column prop="amount" label="当前余额(元)" min-width="100px">
        <el-table-column prop="caseNum" label="标杆案例" min-width="100px">
          <template slot-scope="{row}">
            <span class="yellowstate">{{((row.amount || 0)/100).toFixed(2)}}</span>
            <span v-if="row.caseNum">{{row.caseNum}}个</span>
          </template>
        </el-table-column>
        <el-table-column prop="createTime" label="注册时间" min-width="100px"></el-table-column>
        <el-table-column prop="autoReciveStatus" label="接受自动派单" min-width="100px">
            <template slot-scope="{row}">
              {{row.autoReceiveStatus ==1?"是":"否"}}
            </template>
        </el-table-column>
<!--        <el-table-column label="状态">
        <el-table-column prop="busTypeNames" label="商业化类型" min-width="200px"></el-table-column>
        <el-table-column prop="areaNames" label="服务战区" min-width="200px"></el-table-column>
        <el-table-column prop="fieldNames" label="擅长领域" min-width="200px"></el-table-column>
        <el-table-column label="状态">
          <template slot-scope="{row}">
            <el-switch @change="changeStatus($event, row)" v-model="row.status" active-color="#13ce66"
                       inactive-color="#ff4949" :active-value="0" :inactive-value="1">
            inactive-color="#ff4949" :active-value="0" :inactive-value="1">
            </el-switch>
          </template>
        </el-table-column>
      <el-table-column
              v-if="containPermissions(['business:member:update', 'business:member:delete'])"
              label="操作"
              min-width="120"
              fixed="right"
            >
        <el-table-column prop="updateUserName" label="操作人" min-width="100px"></el-table-column>
        <el-table-column prop="updateTime" label="最近操作时间" min-width="150px"></el-table-column>
        <el-table-column
          v-if="containPermissions(['business:member:update', 'business:member:delete'])"
          label="操作"
          min-width="120"
          fixed="right"
        >
          <template slot-scope="{row}">
            <el-button type="text" @click="$refs.operaMemberWindow.open('编辑会员信息表', row)" icon="el-icon-edit" v-permissions="['business:member:update']">编辑</el-button>
            <el-button type="text" @click="deleteById(row)" icon="el-icon-delete" v-permissions="['business:member:delete']">删除</el-button>
            <el-button type="text" @click="$refs.operaMemberWindow.open('编辑老师', row,searchForm.type)" icon="el-icon-edit" v-permissions="['business:member:update']">编辑</el-button>
            <el-button type="text" style="color: red" @click="deleteById(row)" icon="el-icon-delete" v-permissions="['business:member:delete']">删除</el-button>
          </template>
        </el-table-column>-->
        </el-table-column>
      </el-table>
      <pagination
        @size-change="handleSizeChange"
@@ -104,8 +168,8 @@
      </pagination>
    </template>
    <!-- æ–°å»º/修改 -->
    <OperaMemberDetailWindow ref="OperaMemberDetailWindow" />
    <OperaMemberWindow ref="operaMemberWindow" @success="handlePageChange"/>
    <OperaMemberImportWindow ref="OperaMemberImportWindow" @success="handlePageChange" />
  </TableLayout>
</template>
@@ -114,51 +178,63 @@
import TableLayout from '@/layouts/TableLayout'
import Pagination from '@/components/common/Pagination'
import OperaMemberWindow from '@/components/business/OperaMemberWindow'
import OperaMemberDetailWindow from '@/components/business/OperaMemberDetailWindow'
import OperaMemberImportWindow from '@/components/business/OperaMemberImportWindow'
import { findAll as cateList } from '@/api/business/category'
export default {
  name: 'Member',
  name: 'Category',
  extends: BaseTable,
  components: { TableLayout, Pagination, OperaMemberDetailWindow, OperaMemberWindow },
  components: { TableLayout, Pagination, OperaMemberWindow ,OperaMemberImportWindow},
  data () {
    return {
      // æœç´¢
      searchForm: {
        type: 0,
        startTime: '',
        endTime: '',
        telephone: '',
        name: '',
        status: ''
      }
        code: '',
        status: null,
        levelIdList:[],
        fieldIdList: [],
        busTypeIdList:[],
        type: 0
      },
      cateList:[],
      cateList1:[],
      cateList2:[],
      cateList3:[],
    }
  },
  created () {
    this.config({
      module: '会员信息表',
      module: '讲师信息表',
      api: '/business/member',
      'field.id': 'id',
      'field.main': 'id'
    })
    this.search()
    cateList({
      type: 0 , //战区
    }).then(res => {
      this.cateList = res
    })
    cateList({
      type: 1 , //商业化
    }).then(res => {
      this.cateList1 = res
    })
    cateList({
      type: 2 , //擅长领用
    }).then(res => {
      this.cateList2 = res
    })
    cateList({
      type: 3 , //等级
    }).then(res => {
      this.cateList3 = res
    })
  },
  methods: {
    reset () {
      this.searchForm = {
        type: 0,
        startTime: '',
        endTime: '',
        telephone: '',
        name: '',
        status: ''
      }
      this.search()
    },
    openDetail (row) {
      this.$refs.OperaMemberDetailWindow.open('用户详情', row.id)
    },
    changeStatus (e, row) {
      this.working = true
      this.api.updateStatus({ id: row.id, workStatus: e })
      this.api.updateStatus({ id: row.id, status: e })
        .then(res => {
          this.$tip.apiSuccess(res || '操作成功')
          this.search()
@@ -169,19 +245,7 @@
        .finally(() => {
          this.working = false
        })
        .catch(() => { })
    }
  }
}
</script>
<style  scoped lang="scss">
.renzhen{
  margin: 5px;
  line-height: 30px;
  color:#67c23a;
  height: 30px;
  text-align:center;
  border-color: #e1f3d8;
  background-color: #f0f9eb;
}
</style>
server/admin/src/main/java/com/doumee/api/business/CategoryController.java
@@ -85,6 +85,12 @@
    public ApiResponse<PageData<Category>> findPage (@RequestBody PageWrap<Category> pageWrap) {
        return ApiResponse.success(categoryService.findPage(pageWrap));
    }
    @ApiOperation("列表查询")
    @PostMapping("/list")
    @RequiresPermissions("business:category:query")
    public ApiResponse<List<Category>> findList (@RequestBody  Category pageWrap) {
        return ApiResponse.success(categoryService.findList(pageWrap));
    }
    @ApiOperation("导出Excel")
    @PostMapping("/exportExcel")
server/admin/src/main/java/com/doumee/api/business/ImportRecordController.java
@@ -9,14 +9,17 @@
import com.doumee.dao.business.model.ImportRecord;
import com.doumee.core.utils.Utils;
import com.doumee.service.business.ImportRecordService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.*;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import  com.doumee.api.BaseController;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
/**
 * åˆ†ç±»ä¿¡æ¯è¡¨Controller定义
 * @author doumee
@@ -82,4 +85,16 @@
    public ApiResponse findById(@PathVariable Integer id) {
        return ApiResponse.success(importRecordService.findById(id));
    }
    @ApiOperation(value = "信息导入" ,notes = "保单申请")
    @PostMapping("/importExcel")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "file", value = "file", required = true, paramType = "query", dataType = "file", dataTypeClass = File.class),
            @ApiImplicitParam(name = "导入类型 0人员 1案例", value = "type", required = true, paramType = "query", dataType = "Integer",example = "0",dataTypeClass = Integer.class),
    })
    public ApiResponse<String> importExcel (@ApiParam(value = "file") MultipartFile file, @ApiParam(value = "type") Integer type) {
        ImportRecord importRecord = importRecordService.importBatch(file,type);
        importRecordService.dealImporTask(importRecord);
        return ApiResponse.success("文件上传成功");
    }
}
server/admin/src/main/java/com/doumee/api/business/MemberController.java
@@ -9,14 +9,17 @@
import com.doumee.dao.business.model.Member;
import com.doumee.core.utils.Utils;
import com.doumee.service.business.MemberService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.*;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import  com.doumee.api.BaseController;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
/**
 * ä¼šå‘˜ä¿¡æ¯è¡¨Controller定义
 * @author doumee
@@ -76,6 +79,7 @@
        ExcelExporter.build(Member.class).export(memberService.findPage(pageWrap).getRecords(), "会员信息表", response);
    }
    @ApiOperation("根据ID查询")
    @GetMapping("/{id}")
    @RequiresPermissions("business:member:query")
server/pom.xml
@@ -46,6 +46,11 @@
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <dependency>
      <groupId>cn.hutool</groupId>
      <artifactId>hutool-all</artifactId>
      <version>5.8.40</version>
    </dependency>
    <!-- Shiro -->
    <dependency>
      <groupId>org.apache.shiro</groupId>
server/services/pom.xml
@@ -19,6 +19,11 @@
      <!--本地的jacob.jar的路径-->
      <systemPath>${project.basedir}/lib/zos-sdk.jar</systemPath>
    </dependency>
    <dependency>
      <groupId>cn.hutool</groupId>
      <artifactId>hutool-all</artifactId>
      <version>5.8.40</version>
    </dependency>
  </dependencies>
  <properties>
    <maven.compiler.source>8</maven.compiler.source>
server/services/src/main/java/com/doumee/core/annotation/excel/ExcelImporter.java
@@ -4,6 +4,7 @@
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFPictureData;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -42,7 +43,7 @@
     * æ ‡é¢˜è¡Œå·
     */
    private CellType changeType;
    private Map<String, XSSFPictureData> pictureList;
    /**
     * æž„造函数
     * @param--path å¯¼å…¥æ–‡ä»¶ï¼Œè¯»å–第一个工作表
@@ -161,6 +162,7 @@
        this.sheet = this.wb.getSheetAt(sheetIndex);
        this.headerNum = headerNum;
        this.changeType = cellType;
        this.pictureList = ExcelPictureUtil.getExcelPictures(in);
        log.debug("Initialize success.");
    }
@@ -228,6 +230,9 @@
        }
        return val;
    }
    public Map<String,XSSFPictureData> getExcelPictures(){
        return this.pictureList;
    }
    /**
     * èŽ·å–å¯¼å…¥æ•°æ®åˆ—è¡¨
server/services/src/main/java/com/doumee/core/annotation/excel/ExcelPictureUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,305 @@
package com.doumee.core.annotation.excel;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.XML;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.map.HashedMap;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.openxml4j.opc.PackagePartName;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.xssf.usermodel.*;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
/**
 * @author bianhl
 * @version 1.0
 * @description èŽ·å–å›¾ç‰‡èµ„æº
 * @date 2024å¹´4月28日08:44:42
 */
@Slf4j
public class ExcelPictureUtil {
    public static Map<String, XSSFPictureData> getExcelPictures(InputStream is) {
        byte[] fileData =  getFileStream(is);
        Map<String, XSSFPictureData> pictures = getPictures(fileData);
        pictures.forEach((id, xssfPictureData) -> {
            System.out.println("id:" + id);
            String fileName = xssfPictureData.getPackagePart().getPartName().getName();
            System.out.println("fileName:" + fileName);
        });
        return pictures;
    }
    /**
     * èŽ·å–æµ®åŠ¨å›¾ç‰‡ï¼Œä»¥ map å½¢å¼è¿”回,键为行列格式 x-y。
     *
     * @param xssfSheet WPS å·¥ä½œè¡¨
     * @return æµ®åŠ¨å›¾ç‰‡çš„ map
     */
    public static Map<String, XSSFPictureData> getFloatingPictures(XSSFSheet xssfSheet) {
        Map<String, XSSFPictureData> mapFloatingPictures = new HashMap<>();
        XSSFDrawing drawingPatriarch = xssfSheet.getDrawingPatriarch();
        if (drawingPatriarch != null) {
            List<XSSFShape> shapes = drawingPatriarch.getShapes();
            for (XSSFShape shape : shapes) {
                if (shape instanceof XSSFPicture ) {
                    XSSFPicture picture = (XSSFPicture)shape;
                    XSSFClientAnchor anchor = (XSSFClientAnchor) picture.getAnchor();
                    XSSFPictureData pictureData = picture.getPictureData();
                    String key = anchor.getRow1() + "-" + anchor.getCol1();
                    mapFloatingPictures.put(key, pictureData);
                }
            }
        }
        return mapFloatingPictures;
    }
    /**
     * å¤„理 WPS æ–‡ä»¶ä¸­çš„图片数据,返回图片信息 map。
     *
     * @param stream    è¾“入流
     * @param mapConfig é…ç½®æ˜ å°„
     * @return å›¾ç‰‡ä¿¡æ¯çš„ map
     * @throws IOException
     */
    private static Map<String, XSSFPictureData> processPictures(ByteArrayInputStream stream, Map<String, String> mapConfig) throws IOException {
        Map<String, XSSFPictureData> mapPictures = new HashedMap<>();
        Workbook workbook = WorkbookFactory.create(stream);
        List<XSSFPictureData> allPictures = (List<XSSFPictureData>) workbook.getAllPictures();
        for (XSSFPictureData pictureData : allPictures) {
            PackagePartName partName = pictureData.getPackagePart().getPartName();
            String uri = partName.getURI().toString();
            if (mapConfig.containsKey(uri)) {
                String strId = mapConfig.get(uri);
                mapPictures.put(strId, pictureData);
            }
        }
        return mapPictures;
    }
    /**
     * èŽ·å– WPS æ–‡æ¡£ä¸­çš„图片,包括嵌入式图片和浮动式图片。
     *
     * @param data äºŒè¿›åˆ¶æ•°æ®
     * @return å›¾ç‰‡ä¿¡æ¯çš„ map
     * @throws IOException
     */
    public static Map<String, XSSFPictureData> getPictures(byte[] data) {
        try {
            Map<String, String> mapConfig = processZipEntries(new ByteArrayInputStream(data));
            Map<String, XSSFPictureData> mapPictures = processPictures(new ByteArrayInputStream(data), mapConfig);
            Iterator<Sheet> sheetIterator = WorkbookFactory.create(new ByteArrayInputStream(data)).sheetIterator();
            while (sheetIterator.hasNext()) {
                mapPictures.putAll(getFloatingPictures((XSSFSheet) sheetIterator.next()));
            }
            return mapPictures;
        } catch (IOException e) {
            return new HashedMap<>();
        }
    }
    /**
     * å¤„理 Zip æ–‡ä»¶ä¸­çš„æ¡ç›®ï¼Œæ›´æ–°å›¾ç‰‡é…ç½®ä¿¡æ¯ã€‚
     *
     * @param stream Zip è¾“入流
     * @return é…ç½®ä¿¡æ¯çš„ map
     * @throws IOException
     */
    private static Map<String, String> processZipEntries(ByteArrayInputStream stream) throws IOException {
        Map<String, String> mapConfig = new HashedMap<>();
        ZipInputStream zipInputStream = new ZipInputStream(stream);
        ZipEntry zipEntry;
        while ((zipEntry = zipInputStream.getNextEntry()) != null) {
            try {
                final String fileName = zipEntry.getName();
                if ("xl/cellimages.xml".equals(fileName)) {
                    processCellImages(zipInputStream, mapConfig);
                } else if ("xl/_rels/cellimages.xml.rels".equals(fileName)) {
                    return processCellImagesRels(zipInputStream, mapConfig);
                }
            } finally {
                zipInputStream.closeEntry();
            }
        }
        return new HashedMap<>();
    }
    /**
     * å¤„理 Zip æ–‡ä»¶ä¸­çš„ cellimages.xml æ–‡ä»¶ï¼Œæ›´æ–°å›¾ç‰‡é…ç½®ä¿¡æ¯ã€‚
     *
     * @param zipInputStream Zip è¾“入流
     * @param mapConfig      é…ç½®ä¿¡æ¯çš„ map
     * @throws IOException
     */
    private static void processCellImages(ZipInputStream zipInputStream, Map<String, String> mapConfig) throws IOException {
        String content = IOUtils.toString(zipInputStream);
        JSONObject jsonObject = XML.toJSONObject(content);
        if (jsonObject != null) {
            JSONObject cellImages = jsonObject.getJSONObject("etc:cellImages");
            if (cellImages != null) {
                JSONArray cellImageArray = null;
                Object cellImage = cellImages.get("etc:cellImage");
                if (cellImage != null && cellImage instanceof JSONArray) {
                    cellImageArray = (JSONArray) cellImage;
                } else if (cellImage != null && cellImage instanceof JSONObject) {
                    JSONObject cellImageObj = (JSONObject) cellImage;
                    if (cellImageObj != null) {
                        cellImageArray = new JSONArray();
                        cellImageArray.add(cellImageObj);
                    }
                }
                if (cellImageArray != null) {
                    processImageItems(cellImageArray, mapConfig);
                }
            }
        }
    }
    /**
     * å¤„理 cellImageArray ä¸­çš„图片项,更新图片配置信息。
     *
     * @param cellImageArray å›¾ç‰‡é¡¹çš„ JSONArray
     * @param mapConfig      é…ç½®ä¿¡æ¯çš„ map
     */
    private static  void processImageItems(JSONArray cellImageArray, Map<String, String> mapConfig) {
        for (int i = 0; i < cellImageArray.size(); i++) {
            JSONObject imageItem = cellImageArray.getJSONObject(i);
            if (imageItem != null) {
                JSONObject pic = imageItem.getJSONObject("xdr:pic");
                if (pic != null) {
                    processPic(pic, mapConfig);
                }
            }
        }
    }
    /**
     * å¤„理 pic ä¸­çš„图片信息,更新图片配置信息。
     *
     * @param pic       å›¾ç‰‡çš„ JSONObject
     * @param mapConfig é…ç½®ä¿¡æ¯çš„ map
     */
    private static  void processPic(JSONObject pic, Map<String, String> mapConfig) {
        JSONObject nvPicPr = pic.getJSONObject("xdr:nvPicPr");
        if (nvPicPr != null) {
            JSONObject cNvPr = nvPicPr.getJSONObject("xdr:cNvPr");
            if (cNvPr != null) {
                String name = cNvPr.getStr("name");
                if (StringUtils.isNotEmpty(name)) {
                    String strImageEmbed = updateImageEmbed(pic);
                    if (strImageEmbed != null) {
                        mapConfig.put(strImageEmbed, name);
                    }
                }
            }
        }
    }
    /**
     * èŽ·å–åµŒå…¥å¼å›¾ç‰‡çš„ embed ä¿¡æ¯ã€‚
     *
     * @param pic å›¾ç‰‡çš„ JSONObject
     * @return embed ä¿¡æ¯
     */
    private  static String updateImageEmbed(JSONObject pic) {
        JSONObject blipFill = pic.getJSONObject("xdr:blipFill");
        if (blipFill != null) {
            JSONObject blip = blipFill.getJSONObject("a:blip");
            if (blip != null) {
                return blip.getStr("r:embed");
            }
        }
        return null;
    }
    /**
     * å¤„理 Zip æ–‡ä»¶ä¸­çš„ relationship æ¡ç›®ï¼Œæ›´æ–°é…ç½®ä¿¡æ¯ã€‚
     *
     * @param zipInputStream Zip è¾“入流
     * @param mapConfig      é…ç½®ä¿¡æ¯çš„ map
     * @return é…ç½®ä¿¡æ¯çš„ map
     * @throws IOException
     */
    private static Map<String, String> processCellImagesRels(ZipInputStream zipInputStream, Map<String, String> mapConfig) throws IOException {
        String content = IOUtils.toString(zipInputStream );
        JSONObject jsonObject = XML.toJSONObject(content);
        JSONObject relationships = jsonObject.getJSONObject("Relationships");
        if (relationships != null) {
            JSONArray relationshipArray = null;
            Object relationship = relationships.get("Relationship");
            if (relationship != null && relationship instanceof JSONArray) {
                relationshipArray = (JSONArray) relationship;
            } else if (relationship != null && relationship instanceof JSONObject  ) {
                JSONObject relationshipObj = (JSONObject) relationship;
                if (relationshipObj != null) {
                    relationshipArray = new JSONArray();
                    relationshipArray.add(relationshipObj);
                }
            }
            if (relationshipArray != null) {
                return processRelationships(relationshipArray, mapConfig);
            }
        }
        return null;
    }
    /**
     * å¤„理 relationshipArray ä¸­çš„关系项,更新配置信息。
     *
     * @param relationshipArray å…³ç³»é¡¹çš„ JSONArray
     * @param mapConfig         é…ç½®ä¿¡æ¯çš„ map
     * @return é…ç½®ä¿¡æ¯çš„ map
     */
    private static Map<String, String> processRelationships(JSONArray relationshipArray, Map<String, String> mapConfig) {
        Map<String, String> mapRelationships = new HashedMap<>();
        for (int i = 0; i < relationshipArray.size(); i++) {
            JSONObject relaItem = relationshipArray.getJSONObject(i);
            if (relaItem != null) {
                String id = relaItem.getStr("Id");
                String value = "/xl/" + relaItem.getStr("Target");
                if (mapConfig.containsKey(id)) {
                    String strImageId = mapConfig.get(id);
                    mapRelationships.put(value, strImageId);
                }
            }
        }
        return mapRelationships;
    }
    /**
     * @return {@link byte[]}
     * @description
     * @author bianhl
     * @date 2024/4/26 13:52
     */
    private static byte[] getFileStream(InputStream inputStream) {
            // åˆ›å»º ByteArrayOutputStream æ¥æš‚存流数据
        try {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            // å°† inputStream è¯»å–到 byteArrayOutputStream ä¸­
            byte[] buffer = new byte[1024];
            int length;
            while ((length = inputStream.read(buffer)) != -1) {
                byteArrayOutputStream.write(buffer, 0, length);
            }
            // å°† byteArrayOutputStream çš„内容获取为字节数组
            return byteArrayOutputStream.toByteArray();
        } catch (IOException e) {
            return null;
        }
    }
}
server/services/src/main/java/com/doumee/core/constants/Constants.java
@@ -111,7 +111,8 @@
    interface CacheKey {
    }
    public interface RedisKeys {
        public static final String ORDER_CODE = "ORDER_CODE";
       String IMPORTING_RECORD = "IMPORTING_RECORD";
       String ORDER_CODE = "ORDER_CODE";
    }
    /**
     * æ“ä½œç±»åž‹ï¼Œç”¨äºŽåšæŽ¥å£éªŒè¯åˆ†ç»„
server/services/src/main/java/com/doumee/dao/business/dto/CasesImport.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,36 @@
package com.doumee.dao.business.dto;
import com.doumee.core.annotation.excel.ExcelColumn;
import io.swagger.annotations.ApiModel;
import lombok.Data;
/**
 * å‘˜å·¥ä¿¡æ¯å¯¼å…¥è¡¨
 * @author æ±Ÿè¹„蹄
 * @date 2024/01/16 10:03
 */
@Data
@ApiModel("员工信息导入")
public class CasesImport {
//    @ExcelColumn(name="序号",value = "sn")
    private Integer sn;
    @ExcelColumn(name="姓名",value = "name",index = 1)
    private String name;
    @ExcelColumn(name="手机号",value = "phone",index = 2)
    private String phone;
    @ExcelColumn(name="身份证号",value = "idcardNo",index = 3)
    private String idcardNo;
    @ExcelColumn(name="组织名称" , value = "companyName" ,index = 4)
    private String companyName;
    @ExcelColumn(name="工号" , value = "code")
    private String code;
    @ExcelColumn(name="岗位" , value = "code")
    private String positionName;
}
server/services/src/main/java/com/doumee/dao/business/dto/MemberImport.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,42 @@
package com.doumee.dao.business.dto;
import com.doumee.core.annotation.excel.ExcelColumn;
import io.swagger.annotations.ApiModel;
import lombok.Data;
/**
 * å‘˜å·¥ä¿¡æ¯å¯¼å…¥è¡¨
 * @author æ±Ÿè¹„蹄
 * @date 2024/01/16 10:03
 */
@Data
@ApiModel("员工信息导入")
public class MemberImport {
    @ExcelColumn(name="工号",value = "code",index = 1)
    private String code;
    @ExcelColumn(name="姓名",value = "name",index = 2)
    private String name;
    @ExcelColumn(name="职业照",value = "imgurl",index = 3)
    private String imgurl;
    @ExcelColumn(name="等级",value = "levelName",index = 4)
    private String levelName;
    @ExcelColumn(name="性别" , value = "sex" ,index = 5)
    private String sex;
    @ExcelColumn(name="岗位" , value = "position",index = 6)
    private String position;
    @ExcelColumn(name="从业年份(å¹´)" , value = "jobYear",index = 7)
    private String jobYear;
    @ExcelColumn(name="服务战区", value = "zqNames",index = 8)
    private String zqNames;
    @ExcelColumn(name="商业化类型", value = "typeNames",index = 9)
    private String typeNames;
    @ExcelColumn(name="擅长领域", value = "fieldNames",index = 10)
    private String fieldNames;
    @ExcelColumn(name="服务商场数(个)", value = "serveNum",index = 11)
    private String serveNum;
    @ExcelColumn(name="费用标准(元/周)", value = "fee",index = 12)
    private String fee;
    @ExcelColumn(name="老师简介", value = "fee",index = 13)
    private String info;
}
server/services/src/main/java/com/doumee/dao/business/model/Category.java
@@ -63,8 +63,8 @@
    @ExcelColumn(name="单位名称")
    private String name;
    @ApiModelProperty(value = "类型:0=品种配置;1=车辆类型配置;2=餐标配置;3=手续费配置;", example = "1")
    @ExcelColumn(name="类型:0=品种配置;1=车辆类型配置;2=餐标配置;3=手续费配置;")
    @ApiModelProperty(value = "类型:0=战区;1=商业化;2=擅长领域;3=讲师等级;", example = "1")
    @ExcelColumn(name="类型:0=战区;1=商业化;2=擅长领域;3=讲师等级;")
    private Integer type;
    @ApiModelProperty(value = "内容(车辆规格、餐标、手续费比例)")
@@ -78,15 +78,15 @@
    @ExcelColumn(name="排序码(升序)")
    private Integer sortnum;
    @ApiModelProperty(value = "是否固定车辆(车辆类型使用):0=否;1=是;", example = "1")
    @ExcelColumn(name="是否固定车辆(车辆类型使用):0=否;1=是;")
    @ApiModelProperty(value = "是否固定):0=否;1=是;", example = "1")
    @ExcelColumn(name="是否固定 :0=否;1=是;")
    private Integer isFixed;
    @ApiModelProperty(value = "是否固定车辆(车辆类型使用):0=否;1=是;", example = "1")
    @ApiModelProperty(value = "最后操作人员;", example = "1")
    @TableField(exist = false)
    private String updateUserName;
    @ApiModelProperty(value = "餐标等配置项集合", example = "1")
    @ApiModelProperty(value = "附件集合", example = "1")
    @TableField(exist = false)
    private JSONArray detailList;
    private List<Multifile> fileList;
    @ApiModelProperty(value = "图标全路径")
    @TableField(exist = false)
    private String iconFull;
server/services/src/main/java/com/doumee/dao/business/model/ImportRecord.java
@@ -2,6 +2,8 @@
import com.baomidou.mybatisplus.annotation.TableField;
import com.doumee.core.annotation.excel.ExcelColumn;
import com.doumee.dao.business.dto.CasesImport;
import com.doumee.dao.business.dto.MemberImport;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
@@ -9,8 +11,12 @@
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.apache.poi.ss.usermodel.PictureData;
import java.util.Date;
import java.math.BigDecimal;
import java.util.List;
/**
 * åˆ†ç±»ä¿¡æ¯è¡¨Model定义
 * @author doumee
@@ -76,4 +82,12 @@
    @ApiModelProperty("导入失败记录数")
    @ExcelColumn(name="导入失败记录数",index=18 ,width=10)
    private Integer errorNum;
    @TableField(exist = false)
    private List<CasesImport> caseList;
    @TableField(exist = false)
    private List<MemberImport> memberList;
    @TableField(exist = false)
    private  List<PictureData> pictureDataList;
}
server/services/src/main/java/com/doumee/dao/business/model/Multifile.java
@@ -53,9 +53,7 @@
    @ApiModelProperty(value = "类型0图片 1视频 2其他", example = "1")
    private Integer type;
//    @ApiModelProperty(value = "关联对象类型 0SHE上报 1跌绊滑上报 2跌绊滑处理 3跌绊滑分配物业主管 4跌绊滑分配处理人 5DCA风险上报 6DCA风险处理 7DCA工单图片", example = "1")
//    @ExcelExportColumn(name="关联对象类型 0SHE上报 1跌绊滑上报 2跌绊滑处理 3跌绊滑分配物业主管 4跌绊滑分配处理人 5DCA风险上报 6DCA风险处理 7DCA工单图片")
    @ApiModelProperty(value = "关联对象类型 0身份申请资料 1订单附件", example = "1")
    @ApiModelProperty(value = "关联对象类型 0商业化类型多图 1案例", example = "1")
    private Integer objType;
    @ApiModelProperty(value = "文件地址")
@@ -66,7 +64,7 @@
  
    @ApiModelProperty(value = "文件地址")
    @TableField(exist = false)
    private String fileurlFull;
    private String url;
    @ApiModelProperty(value = "内网文件地址")
server/services/src/main/java/com/doumee/service/business/ImportRecordService.java
@@ -3,6 +3,8 @@
import com.doumee.core.model.PageData;
import com.doumee.core.model.PageWrap;
import com.doumee.dao.business.model.ImportRecord;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
@@ -94,4 +96,7 @@
     * @return long
     */
    long count(ImportRecord model);
    ImportRecord importBatch(MultipartFile file, int type );
    void dealImporTask(ImportRecord importRecord);
}
server/services/src/main/java/com/doumee/service/business/MemberService.java
@@ -3,6 +3,8 @@
import com.doumee.core.model.PageData;
import com.doumee.core.model.PageWrap;
import com.doumee.dao.business.model.Member;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
@@ -94,4 +96,5 @@
     * @return long
     */
    long count(Member model);
}
server/services/src/main/java/com/doumee/service/business/impl/CategoryServiceImpl.java
@@ -11,7 +11,9 @@
import com.doumee.core.model.PageWrap;
import com.doumee.core.utils.Utils;
import com.doumee.dao.business.CategoryMapper;
import com.doumee.dao.business.MultifileMapper;
import com.doumee.dao.business.model.Category;
import com.doumee.dao.business.model.Multifile;
import com.doumee.dao.system.model.SystemUser;
import com.doumee.service.business.CategoryService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@@ -28,6 +30,7 @@
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
@@ -42,6 +45,8 @@
    @Autowired
    private CategoryMapper categoryMapper;
    @Autowired
    private MultifileMapper multifileMapper;
    @Autowired
    private SystemDictDataBiz systemDictDataBiz;
@@ -49,12 +54,11 @@
    @Override
    @Transactional(rollbackFor = {Exception.class,BusinessException.class})
    public Integer create(Category category) {
//        ç±»åž‹:0=战区;1=商业化;2=擅长领域;3=讲师等级;
        if(Objects.isNull(category)
        || Objects.isNull(category.getType())
        || Objects.isNull(category.getName())
        || (!Constants.equalsInteger(category.getType(),Constants.ZERO)&& CollectionUtils.isEmpty(category.getDetailList()))
        || (Constants.equalsInteger(category.getType(),Constants.ONE) && (Objects.isNull(category.getIcon())||Objects.isNull(category.getIsFixed())) )
        ){
        || (Constants.equalsInteger(category.getType(),Constants.ZERO)&& StringUtils.isBlank(category.getDetail()))   ){
            throw new BusinessException(ResponseStatus.BAD_REQUEST);
        }
        LoginUserInfo loginUserInfo = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal();
@@ -63,22 +67,40 @@
        category.setCreateUser(loginUserInfo.getId());
        category.setUpdateTime(new Date());
        category.setUpdateUser(loginUserInfo.getId());
        if(com.github.xiaoymin.knife4j.core.util.CollectionUtils.isNotEmpty(category.getDetailList())
                && !Constants.equalsInteger(category.getType(),Constants.THREE)){
            category.setDetail(category.getDetailList().toJSONString());
        }
        if(!Constants.equalsInteger(category.getType(),Constants.ONE)){
            category.setIsFixed(Constants.ZERO);
        }
        categoryMapper.insert(category);
        dealBatchMultiFiles(category, category.getFileList(), loginUserInfo,false);
        return category.getId();
    }
    public void dealBatchMultiFiles(Category category, List<Multifile> fileList, LoginUserInfo user,boolean update) {
        Date today = new Date();
        //清空原有的
        if(update){
            multifileMapper.delete(new UpdateWrapper<Multifile>().lambda()
                    .eq(Multifile::getIsdeleted,Constants.ZERO)
                    .eq(Multifile::getObjType,Constants.ZERO)
                    .eq(Multifile::getObjId,category.getId()));
        }
        if(fileList!=null && fileList.size()>0){
            List<Multifile> multifileList = new ArrayList<>();
            fileList.stream().forEach(s -> {
                if(StringUtils.isNotBlank(s.getFileurl())){
                    s.setIsdeleted(Constants.ZERO);
                    s.setCreator(user.getId());
                    s.setCreateDate(today);
                    s.setObjId(category.getId());
                    s.setType(Constants.ZERO);
                    s.setObjType(Constants.ZERO);
                    multifileList.add(s);
                }
            });
            if(multifileList.size()>0){
                multifileMapper.insert(multifileList);
            }
        }
    }
    @Override
    public void deleteById(Integer id) {
        categoryMapper.update(new UpdateWrapper<Category>().lambda().set(Category::getDeleted,Constants.ONE).eq(Category::getId,id));
//        categoryMapper.deleteById(id);
    }
    @Override
@@ -102,8 +124,6 @@
                || Objects.isNull(category.getId())
                || Objects.isNull(category.getType())
                || Objects.isNull(category.getName())
                || (!Constants.equalsInteger(category.getType(),Constants.ZERO)&& CollectionUtils.isEmpty(category.getDetailList()))
                || (Constants.equalsInteger(category.getType(),Constants.ONE) && (Objects.isNull(category.getIcon())||Objects.isNull(category.getIsFixed())) )
        ){
            throw new BusinessException(ResponseStatus.BAD_REQUEST);
        }
@@ -111,25 +131,18 @@
        category.setUpdateTime(new Date());
        category.setIsFixed(null);
        category.setUpdateUser(loginUserInfo.getId());
        if(com.github.xiaoymin.knife4j.core.util.CollectionUtils.isNotEmpty(category.getDetailList())
                && !Constants.equalsInteger(category.getType(),Constants.THREE)){
            category.setDetail(category.getDetailList().toJSONString());
        }
        categoryMapper.updateById(category);
        dealBatchMultiFiles(category, category.getFileList(), loginUserInfo,true);
    }
    @Override
    public void updateStatus(Category category) {
        if(Objects.isNull(category)
                || Objects.isNull(category.getId())){
        if(Objects.isNull(category) || Objects.isNull(category.getId())){
            throw new BusinessException(ResponseStatus.BAD_REQUEST);
        }
        LoginUserInfo loginUserInfo = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal();
        category.setUpdateTime(new Date());
        category.setIsFixed(null);
        category.setUpdateUser(loginUserInfo.getId());
        if(com.github.xiaoymin.knife4j.core.util.CollectionUtils.isNotEmpty(category.getDetailList())){
            category.setDetail(category.getDetailList().toJSONString());
        }
        categoryMapper.updateById(category);
    }
@@ -149,12 +162,9 @@
        if(Objects.isNull(category)){
            throw new BusinessException(ResponseStatus.DATA_EMPTY);
        }
        if(StringUtils.isNotBlank(category.getDetail())){
            category.setDetailList(JSONArray.parseArray(category.getDetail()));
        }
        if(StringUtils.isNotBlank(category.getIcon())){
            String path  = systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.RESOURCE_PATH).getCode()
                    +systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.CATEGORY_FILES).getCode();
            String path  = systemDictDataBiz.queryByCode(Constants.OBJCET_STORAGE,Constants.RESOURCE_PATH).getCode()
                    +systemDictDataBiz.queryByCode(Constants.OBJCET_STORAGE,Constants.CATEGORY_FILES).getCode();
            category.setIconFull(path + category.getIcon());
        }
        return category;
@@ -168,6 +178,7 @@
    @Override
    public List<Category> findList(Category category) {
        category.setDeleted(Constants.ZERO);
        QueryWrapper<Category> wrapper = new QueryWrapper<>(category);
        return categoryMapper.selectList(wrapper);
    }
@@ -225,22 +236,38 @@
        queryWrapper.orderByAsc(Category::getSortnum);
        PageData<Category> result =PageData.from(categoryMapper.selectJoinPage(page, Category.class,queryWrapper));
        if(result!=null && result.getRecords()!=null){
            String path  = systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.RESOURCE_PATH).getCode()
                    +systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.CATEGORY_FILES).getCode();
            String path  = systemDictDataBiz.queryByCode(Constants.OBJCET_STORAGE,Constants.RESOURCE_PATH).getCode()
                    +systemDictDataBiz.queryByCode(Constants.OBJCET_STORAGE,Constants.CATEGORY_FILES).getCode();
            for(Category cate : result.getRecords()){
                try {
                    if(StringUtils.isNotBlank(cate.getDetail())){
                        cate.setDetailList(JSONArray.parseArray(cate.getDetail()));
                    }
                    if(StringUtils.isNotBlank(cate.getIcon())){
                        cate.setIconFull(path + cate.getIcon());
                    }
                }catch (Exception e){
                if(Constants.equalsInteger(cate.getType(),Constants.ONE) ){
                    initMultifileList(cate);
                }
                if(StringUtils.isNotBlank(cate.getIcon())){
                    cate.setIconFull(path + cate.getIcon());
                }
            }
        }
        return result;
    }
    private void initMultifileList(Category cate) {
        String path = systemDictDataBiz.queryByCode(Constants.OBJCET_STORAGE, Constants.RESOURCE_PATH).getCode()
                + systemDictDataBiz.queryByCode(Constants.OBJCET_STORAGE, Constants.CATEGORY_FILES).getCode();
        Multifile find = new Multifile();
        find.setObjId(cate.getId());
        find.setObjType(Constants.ZERO);
        find.setIsdeleted(Constants.ZERO);
        List<Multifile> fileList=  multifileMapper.selectList(new QueryWrapper<>(find));
        if(fileList!=null){
            for(Multifile f : fileList){
                if(StringUtils.isNotBlank(f.getFileurl())){
                        f.setUrl(path+f.getFileurl());
                }
            }
        }
        cate.setFileList(fileList);
    }
    @Override
@@ -259,12 +286,12 @@
            String path  = systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.RESOURCE_PATH).getCode()
                    +systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.CATEGORY_FILES).getCode();
            for (Category category:categoryList) {
                if(StringUtils.isNotBlank(category.getDetail())){
                    category.setDetailList(JSONArray.parseArray(category.getDetail()));
                }
                if(StringUtils.isNotBlank(category.getIcon())){
                    category.setIconFull(path + category.getIcon());
                }
                if(Constants.equalsInteger(category.getType(),Constants.ONE) ){
                    initMultifileList(category);
                }
            }
        }
        return categoryList;
server/services/src/main/java/com/doumee/service/business/impl/ImportRecordServiceImpl.java
@@ -1,20 +1,41 @@
package com.doumee.service.business.impl;
import com.doumee.core.annotation.excel.ExcelImporter;
import com.doumee.core.constants.Constants;
import com.doumee.core.constants.ResponseStatus;
import com.doumee.core.exception.BusinessException;
import com.doumee.core.model.LoginUserInfo;
import com.doumee.core.model.PageData;
import com.doumee.core.model.PageWrap;
import com.doumee.core.utils.DateUtil;
import com.doumee.dao.business.dto.CasesImport;
import com.doumee.dao.business.dto.MemberImport;
import com.doumee.dao.business.model.ImportRecord;
import com.doumee.core.utils.Utils;
import com.doumee.dao.business.ImportRecordMapper;
import com.doumee.dao.business.model.Member;
import com.doumee.service.business.ImportRecordService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
 * åˆ†ç±»ä¿¡æ¯è¡¨Service实现
@@ -26,9 +47,21 @@
    @Autowired
    private ImportRecordMapper importRecordMapper;
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Override
    public Integer create(ImportRecord importRecord) {
        if(StringUtils.isBlank(importRecord.getImgurl())){
            throw new BusinessException(ResponseStatus.BAD_REQUEST);
        }
        LoginUserInfo loginUserInfo = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal();
        importRecord.setDeleted(Constants.ZERO);
        importRecord.setStatus(Constants.ZERO);
        importRecord.setCreateTime(new Date());
        importRecord.setCreateUser(loginUserInfo.getId());
        importRecord.setUpdateTime(new Date());
        importRecord.setUpdateUser(loginUserInfo.getId());
        importRecordMapper.insert(importRecord);
        return importRecord.getId();
    }
@@ -134,4 +167,106 @@
        QueryWrapper<ImportRecord> wrapper = new QueryWrapper<>(importRecord);
        return importRecordMapper.selectCount(wrapper);
    }
    @Override
    public ImportRecord importBatch(MultipartFile file,int type ){
        Boolean importing = (Boolean) redisTemplate.opsForValue().get(Constants.RedisKeys.IMPORTING_RECORD);
        if(importing!=null && importing){
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(),"对不起,已存在导入任务正在执行中,请稍后再试!");
        }
        redisTemplate.opsForValue().set(Constants.RedisKeys.IMPORTING_RECORD,true,30, TimeUnit.MINUTES);
        try {
            ImportRecord model = new ImportRecord();
            LoginUserInfo loginUserInfo = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal();
            model.setDeleted(Constants.ZERO);
            model.setStatus(Constants.ONE);//异步处理中
            model.setCreateTime(new Date());
            model.setCreateUser(loginUserInfo.getId());
            model.setUpdateTime(model.getCreateTime());
            model.setUpdateUser(loginUserInfo.getId());
            model.setType(type);
            model.setTitle((type==1?"案例信息批量导入":"老师信息批量导入")+ DateUtil.getPlusTime2(model.getCreateTime()));
            model.setTotalNum(0);
            ExcelImporter ie= new ExcelImporter(file,0,0, CellType.STRING); // ç¡®ä¿å•元格类型为字符串);
            if(type == 1) {
              model.setCaseList(ie.getDataList(CasesImport.class,null));
              if(model.getCaseList() ==null || model.getCaseList().size()==0){
                  throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(),"导入文件案例信息内容为空!");
              }
              model.setTotalNum(model.getCaseList().size());
            }else{
              model.setMemberList(ie.getDataList(MemberImport.class,null));
              if(model.getMemberList() ==null || model.getMemberList().size()==0){
                  throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(),"导入文件老师信息内容为空!");
              }
              model.setTotalNum(model.getMemberList().size());
            }
//            model.setPictureDataList(ie);
            importRecordMapper.insert(model);
            return model;
        }catch (Exception e){
            throw  new BusinessException(ResponseStatus.DATA_EMPTY.getCode(),"文件信息读取失败,请检查文件内容后重试!");
        }finally {
            redisTemplate.delete(Constants.RedisKeys.IMPORTING_RECORD);
        }
    }
    /**
     * å¼‚步执行文件任务
     * @param importRecord
     */
    @Override
    @Async
    public void dealImporTask(ImportRecord importRecord){
        int success = 0;
        if(Constants.equalsInteger(importRecord.getType(),0)){
           dealUserImportBiz(importRecord);
        }else{
            dealCaseImportBiz(importRecord);
        }
        importRecord.setStatus(Constants.TWO);
        importRecord.setUpdateTime(new Date());
        importRecordMapper.updateById(importRecord);
    }
    /**
     * å¤„理案例导入任务
     * @param importRecord
     */
    private int dealCaseImportBiz(ImportRecord importRecord) {
        int success=0;
        String msg ="";
        try {
            for(CasesImport param:importRecord.getCaseList()){
            }
        }catch (Exception e){
        }
        importRecord.setDoneNum(success);
        importRecord.setErrorNum(importRecord.getTotalNum() - success);
        return success;
    }
    /**
     * å¤„理人员导入记录
     * @param importRecord
     */
    private int dealUserImportBiz(ImportRecord importRecord) {
        int success=0;
        String msg = "";
        try {
            for(MemberImport param:importRecord.getMemberList()){
            }
        }catch (Exception e){
        }
        importRecord.setDoneNum(success);
        importRecord.setErrorNum(importRecord.getTotalNum() - success);
        importRecord.setDetail(msg);
        return success;
    }
}
server/services/src/main/java/com/doumee/service/business/impl/MemberServiceImpl.java
@@ -1,7 +1,12 @@
package com.doumee.service.business.impl;
import com.doumee.core.annotation.excel.ExcelImporter;
import com.doumee.core.constants.ResponseStatus;
import com.doumee.core.exception.BusinessException;
import com.doumee.core.model.PageData;
import com.doumee.core.model.PageWrap;
import com.doumee.dao.business.ImportRecordMapper;
import com.doumee.dao.business.dto.MemberImport;
import com.doumee.dao.business.model.Member;
import com.doumee.core.utils.Utils;
import com.doumee.dao.business.MemberMapper;
@@ -10,11 +15,18 @@
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.CellType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
 * ä¼šå‘˜ä¿¡æ¯è¡¨Service实现
@@ -141,4 +153,6 @@
        QueryWrapper<Member> wrapper = new QueryWrapper<>(member);
        return memberMapper.selectCount(wrapper);
    }
}