c6675b55023dff3c4f441ab0bb9493198949126e..80fd41ea0dc602ac3ca33778f17fce5bc2e817b1
2026-01-16 doum
Merge remote-tracking branch 'origin/master'
80fd41 对比 | 目录
2026-01-16 doum
经销商管理
22aaac 对比 | 目录
已添加10个文件
已修改24个文件
1770 ■■■■■ 文件已修改
admin/src/api/business/member.js 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/api/business/shop.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/api/business/userAction.js 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/base/BaseOpera.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/business/OperaChangeIntegralWindow.vue 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/business/OperaChangeShopRecordWindow.vue 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/business/OperaChangeShopWindow.vue 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/business/OperaCouponGoodsWindow.vue 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/business/OperaMemberCouponWindow.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/business/OperaMemberDetail.vue 212 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/business/OperaShopGoodsWindow.vue 217 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/business/member.vue 79 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/business/memberCoupon.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/business/platformGoods.vue 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_admin/src/main/java/com/doumee/api/business/IntegralController.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_admin/src/main/java/com/doumee/api/business/MemberController.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_admin/src/main/java/com/doumee/api/business/ShopController.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_admin/src/main/java/com/doumee/api/business/UserActionController.java 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_service/src/main/java/com/doumee/core/utils/Constants.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_service/src/main/java/com/doumee/dao/business/MemberMapper.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_service/src/main/java/com/doumee/dao/business/UserActionMapper.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_service/src/main/java/com/doumee/dao/business/model/Goods.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_service/src/main/java/com/doumee/dao/business/model/Member.java 69 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_service/src/main/java/com/doumee/dao/business/model/Shop.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_service/src/main/java/com/doumee/dao/business/model/ShopGoodsRelation.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_service/src/main/java/com/doumee/dao/business/model/UserAction.java 97 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_service/src/main/java/com/doumee/service/business/MemberService.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_service/src/main/java/com/doumee/service/business/ShopService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_service/src/main/java/com/doumee/service/business/UserActionService.java 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_service/src/main/java/com/doumee/service/business/impl/GoodsServiceImpl.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_service/src/main/java/com/doumee/service/business/impl/IntegralServiceImpl.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_service/src/main/java/com/doumee/service/business/impl/MemberServiceImpl.java 122 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_service/src/main/java/com/doumee/service/business/impl/ShopServiceImpl.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/dmmall_service/src/main/java/com/doumee/service/business/impl/UserActionServiceImpl.java 158 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/api/business/member.js
@@ -11,8 +11,19 @@
export function findAll (data) {
  return request.post('/business/member/findAll', data)
}
export function updateShop (data) {
  return request.post('/business/member/updateShop', data)
}
export function updateIntegral (data) {
  return request.post('/business/member/updateIntegral', data)
}
export function updateById (data) {
  return request.post('/business/member/updateById', data)
}
export function exportExcel (data) {
  return request.post('/business/member/exportExcelList', data, {
    trim: true,
    download: true
  })
}
admin/src/api/business/shop.js
@@ -6,6 +6,11 @@
    trim: true
  })
}
export function allList (data) {
  return request.post('/business/shop/findAll', data, {
    trim: true
  })
}
// åˆ›å»º
export function create (data) {
@@ -16,10 +21,14 @@
export function updateById (data) {
  return request.post('/business/shop/updateById', data)
}
// ä¿®æ”¹
export function updateIsRecById (data) {
  return request.post('/business/shop/updateIsRecById', data)
}
export function setGoodsPrice (data) {
  return request.post('/business/shop/setGoodsPrice', data)
}
// åˆ é™¤
export function deleteById (id) {
admin/src/api/business/userAction.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
import request from '../../utils/request'
// æŸ¥è¯¢
export function fetchList (data) {
  return request.post('/business/userAction/page', data, {
    trim: true
  })
}
// å¯¼å‡ºExcel
export function exportExcel (data) {
  return request.post('/business/userAction/exportExcel', data, {
    trim: true,
    download: true
  })
}
admin/src/components/base/BaseOpera.vue
@@ -68,7 +68,11 @@
        this.api.create(this.form)
          .then((res) => {
            this.visible = false
            this.$tip.apiSuccess(res  || '新建成功')
            if (res && res.length > 8) {
              this.$tip.apiSuccess(res)
            } else {
              this.$tip.apiSuccess('新建成功')
            }
            this.$emit('success')
          })
          .catch(e => {
admin/src/components/business/OperaChangeIntegralWindow.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,104 @@
<template>
  <GlobalWindow
      :title="title"
      width="60%"
      :visible.sync="visible"
      :confirm-working="isWorking"
      @confirm="confirm"
  >
    <p class="tip-warn" style="margin: 30px;"><i class="el-icon-warning"></i>操作说明:积分增加或减少后会在消费者端展示,请谨慎操作!</p>
    <el-form :model="form" ref="form" :rules="rules" label-width="100px"  label-suffix=":" inline>
      <el-form-item label="当前余额"   >
        <span class="green" ><b>{{info.integral}}</b></span>
      </el-form-item>
      <el-form-item label="调整方式"   prop="type"   >
        <el-radio-group v-model="form.type">
          <el-radio :value="0" :label="0">增加</el-radio>
          <el-radio :value="1" :label="1">减少</el-radio>
        </el-radio-group>
      </el-form-item>
      <el-form-item label="数量"   prop="num"   >
        <el-input v-model="form.num" type="number"   placeholder="请输入数量"  ></el-input>
      </el-form-item>
      <el-form-item label="备注"   prop="remark"   >
        <el-input v-model="form.remark" type="textarea"   placeholder="请输入备注"  ></el-input>
      </el-form-item>
    </el-form>
  </GlobalWindow>
</template>
<script>
import BaseOpera from '@/components/base/BaseOpera'
import GlobalWindow from '@/components/common/GlobalWindow'
import { allList as shopList } from '@/api/business/shop'
export default {
  name: 'OperaChangeShopWindow',
  extends: BaseOpera,
  components: { GlobalWindow },
  data () {
    return {
      searchLoading: false,
      info:{},
      // è¡¨å•数据
      form: {
        memberId: null,
        remark: null,
        num: null,
        type: 0
      },
      rules: {
        type: [
          { required: true, message: '请选择调整方式' }
        ],
        num: [
          { required: true, message: '请输入调整数量' }
        ]
      }
    }
  },
  created () {
    this.config({
      api: '/business/member',
      'field.id': 'id'
    })
  },
  methods: {
    confirm () {
      this.$refs.form.validate((valid) => {
        if (!valid) {
          return
        }
        this.isWorking = true
        this.api.updateIntegral(this.form)
          .then(() => {
            this.visible = false
            this.$tip.apiSuccess('操作成功')
            this.$emit('success')
          })
          .catch(e => {
            this.$tip.apiFailed(e)
          })
          .finally(() => {
            this.isWorking = false
          })
      })
    },
    open (title, target) {
      this.title = title
      this.visible = true
      this.info = target
      this.form.type = 0
      this.form.memberId = target.id
      this.form.num = null
      this.form.remark = null
    }
  }
}
</script>
<style lang="scss" scoped>
@import "@/assets/style/alertstyle.scss";
::v-deep .el-form-item__content {
  flex: 0.6;
}
</style>
admin/src/components/business/OperaChangeShopRecordWindow.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,120 @@
<template>
  <GlobalWindow
      :title="title"
      width="80%"
      :visible.sync="visible"
  >
    <div style="display: block;">
      <TableLayout >
        <!-- è¡¨æ ¼å’Œåˆ†é¡µ -->
        <template v-slot:table-wrap>
            <el-table
                v-loading="isWorking.search"
                :data="tableData.list"
                stripe
                border
                @selection-change="handleSelectionChange"
            >
              <el-table-column prop="beforeInfo" label="变更前" fixed align="center" min-width="150px">  </el-table-column>
              <el-table-column prop="afterInfo" label="变更后" fixed align="center" min-width="150px">  </el-table-column>
              <el-table-column prop="remark" label="备注" align="center" min-width="300px"></el-table-column>
              <el-table-column prop="createName" label="操作人" align="center" min-width="100px"></el-table-column>
              <el-table-column prop="createDate" label="操作时间" align="center" min-width="150px"></el-table-column>
            </el-table>
            <pagination
                @size-change="handleSizeChange"
                @current-change="handlePageChange"
                :pagination="tableData.pagination"
            >
            </pagination>
        </template>
      </TableLayout>
    </div>
    <template  v-slot:footer>
      <el-button @click="visible=false">返回</el-button>
    </template>
  </GlobalWindow>
</template>
<script>
import GlobalWindow from '@/components/common/GlobalWindow'
import BaseTable from '@/components/base/BaseTable'
import TableLayout from '@/layouts/TableLayout'
import Pagination from '@/components/common/Pagination'
export default {
  name: 'OperaChangeShopRecordWindow',
  extends: BaseTable,
  components: { GlobalWindow, TableLayout, Pagination },
  data () {
    return {
      title: '',
      visible: false,
      // æœç´¢
      searchForm: {
        memberId: '',
        type: 0
      }
    }
  },
  created () {
    this.config({
      module: '用户操作记录表信息表',
      api: '/business/userAction',
      'field.id': 'id',
      'field.main': 'id'
    })
  },
  methods: {
    open (title, goods) {
      this.title = title
      this.visible = true
      this.searchForm.memberId = goods.id
      this.search()
    }
  }
}
</script>
<style scoped>
.table-pagination{
  position: fixed !important;
  bottom: 50px;
}
.header-b{
  display: inline-block;
  font-size: 16px;
  font-weight: bold;
}
.header-blue{
  display: inline-block;
  font-size: 12px;
  border: 1px solid #216EEE;
  padding: 2px 10px;
  margin-left: 20px;
  color: #216EEE;
  border-radius: 5px ;
}
.header-btn{
  display: inline-block;
  border: none;
  padding: 2px 10px;
  margin-left: 20px;
}
.info-item{
  display: flex;
  width: 100%;
  margin: 15px;
}
.info-item-a{
  flex: 1;
  font-size: 14px;
}
.info-item-a span{
  font-weight: 600;
}
.info-item-a  .btn{
  font-size: 12px !important;
  cursor: pointer !important;
}
</style>
admin/src/components/business/OperaChangeShopWindow.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,109 @@
<template>
  <GlobalWindow
      :title="title"
      width="60%"
      :visible.sync="visible"
      :confirm-working="isWorking"
      @confirm="confirm"
  >
    <p class="tip-warn" style="margin: 30px;"><i class="el-icon-warning"></i>操作说明:该操作只针对已绑定经销商的客户有效!</p>
    <el-form :model="form" ref="form" :rules="rules"  label-suffix=":" inline>
      <el-form-item label="当前已绑定的经销商"   label-width="200px" >
        <span>{{form.shopName}}</span>
      </el-form-item>
      <el-form-item label="选择新的经销商" label-width="200px" prop="bindShopId"   >
        <el-select v-model="form.bindShopId" clearable filterable   placeholder="请选择优惠券"  >
          <el-option  v-for="item in shops"  :key="item.id" :label="item.name"  :value="item.id">  </el-option>
        </el-select>
      </el-form-item>
    </el-form>
  </GlobalWindow>
</template>
<script>
import BaseOpera from '@/components/base/BaseOpera'
import GlobalWindow from '@/components/common/GlobalWindow'
import { allList as shopList } from '@/api/business/shop'
export default {
  name: 'OperaChangeShopWindow',
  extends: BaseOpera,
  components: { GlobalWindow },
  data () {
    return {
      searchLoading: false,
      users: [],
      // è¡¨å•数据
      oldId:null,
      form: {
        id: null,
        shopName: null,
        bindShopId: null
      },
      shops: [],
      rules: {
        bindShopId: [
          { required: true, message: '请选择新的经销商' }
        ]
      }
    }
  },
  created () {
    this.config({
      api: '/business/member',
      'field.id': 'id'
    })
  },
  methods: {
    confirm () {
      this.$refs.form.validate((valid) => {
        if (!valid) {
          return
        }
        this.isWorking = true
        this.api.updateShop(this.form)
          .then(() => {
            this.visible = false
            this.$tip.apiSuccess('操作成功')
            this.$emit('success')
          })
          .catch(e => {
            this.$tip.apiFailed(e)
          })
          .finally(() => {
            this.isWorking = false
          })
      })
    },
    getShopList () {
      shopList({ status: 0 })
        .then(res => {
          if (res) {
            this.shops = res || []
          }
        })
    },
    open (title, target) {
      this.title = title
      this.visible = true
      this.oldId=target.bindShopId
      this.form.id = target.id
      this.form.shopName = target.shopName
      this.form.bindShopId = null
      this.getShopList()
    }
  }
}
</script>
<style lang="scss" scoped>
@import "@/assets/style/alertstyle.scss";
::v-deep .el-form-item__content {
  flex: 0.6;
}
::v-deep .el-select {
  width: 100%;
  .el-input__inner {
    width: 100%;
  }
}
</style>
admin/src/components/business/OperaCouponGoodsWindow.vue
@@ -5,7 +5,7 @@
    :visible.sync="visible"
    @confirm="confirm"
  >
    <TableLayout :permissions="['business:goods:query']">
    <TableLayout>
      <!-- æœç´¢è¡¨å• -->
      <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" style="display: block;" >
        <el-form-item label="" prop="name" label-width="5px" style="display: inline-block;margin-right: 30px;">
@@ -100,31 +100,15 @@
  components: { GlobalWindow, TableLayout, Pagination },
  data () {
    return {
      activeName: 'first',
      title: '',
      visible: false,
      tabelHeight: null,
      // æœç´¢
      searchForm: {
        name: '',
        categoryId: '',
        brandId: '',
        type: '0', // å¹³å°å•†å“
        status: '',
        isrec: '',
        labels: ''
        id: '',
        bindShopId: ''
      },
      labels: [],
      serials: [],
      brands: [],
      selectGoods: []
      shops: []
    }
  },
  mounted() {
    window.addEventListener('resize', this.handleResize);
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.handleResize);
  },
  created () {
    this.config({
admin/src/components/business/OperaMemberCouponWindow.vue
@@ -6,6 +6,7 @@
      :confirm-working="isWorking"
      @confirm="confirm"
  >
    <p class="tip-warn" style="margin: 30px;"><i class="el-icon-warning"></i>操作说明:定向发放不受发放总数限制,定向发放优惠券不计入优惠券已发放统计</p>
    <el-form :model="form" ref="form" :rules="rules" label-width="120px" label-suffix=":" inline>
      <el-form-item label="发放对象" prop="addType" >
        <el-radio-group v-model="form.addType" @change="changeType">
admin/src/components/business/OperaMemberDetail.vue
@@ -1,65 +1,187 @@
<template>
  <GlobalAlertWindow
    :title="title"
    :visible.sync="visible"
    :confirm-working="isWorking"
    @confirm="confirm"
  <GlobalWindow
      :title="title"
      width="100%"
      :visible.sync="visible"
  >
    <el-descriptions direction="horizontal" labelClassName="descriptions-label" :column="1">
      <el-descriptions-item label="会员昵称">{{ form.nickName }}</el-descriptions-item>
      <el-descriptions-item label="真实姓名">{{ form.name }}</el-descriptions-item>
      <el-descriptions-item label="手机号">{{ form.phone }}</el-descriptions-item>
      <el-descriptions-item label="身份证号">{{ form.idcard }}</el-descriptions-item>
      <el-descriptions-item label="性别">{{ form.sex==0?'男':form.sex==1?'女':'未知' }}</el-descriptions-item>
      <el-descriptions-item label="地区">{{ form.addr }}</el-descriptions-item>
      <el-descriptions-item label="一句话介绍">{{ form.info }}</el-descriptions-item>
    </el-descriptions>
    <div slot="footer"></div>
  </GlobalAlertWindow>
    <div style="display: block">
      <div class="header">
        <div  class="header-b">用户信息</div>
        <div v-if="info.phone!=null && info.phone!=''" class="header-blue">已授权手机号</div>
      </div>
      <div class="info-item">
          <div class="info-item-a">微信openid:<span>{{info.openId}}</span></div>
          <div class="info-item-a">昵称:<span>{{info.nickname}}</span></div>
          <div class="info-item-a">客户姓名:<span>{{info.name}}</span></div>
      </div>
      <div class="info-item">
        <div class="info-item-a">授权手机号:<span>{{info.phone}}</span></div>
        <div class="info-item-a">关联经销商:<span>{{info.shopName}}</span> <span class="blue btn" @click="showChangeRecord">变更记录</span></div>
        <div class="info-item-a"></div>
      </div>
      <div class="info-item"></div>
    </div>
    <div style="display: block">
      <div class="header">
        <div  class="header-b">积分明细</div>
        <div v-if="info.phone!=null && info.phone!=''" class="header-btn">
          <el-button style="display: inline" type="primary" @click="changeIntegral">积分调整</el-button>
        </div>
      </div>
      <TableLayout >
        <!-- è¡¨æ ¼å’Œåˆ†é¡µ -->
        <template v-slot:table-wrap>
            <div >
              <div style="float: left; margin-bottom: 20px;width:50%;">
                  <div class="info-item">
                    <div class="info-item-a">现有积分:<span>{{info.integral || 0}}</span></div>
                    <div class="info-item-a">累计积分:<span>{{info.totalIntegral||0}}</span></div>
                  </div>
              </div>
              <div style="float: right; margin-bottom: 20px;">
                <el-select  v-model="searchForm.type"  placeholder="全部"  clearable @change="search" style="width: 120px;" >
                  <el-option  :key="0" :value="0"  label="获得"  ></el-option>
                  <el-option   :key="1" :value="1" label="扣除"  ></el-option>
                </el-select>
                <el-button @click="search" type="点击刷新"  icon="el-icon-refresh"  style="margin-left: 10px;" ></el-button>
              </div>
            </div>
            <el-table
                v-loading="isWorking.search"
                :data="tableData.list"
                stripe
                border
                @selection-change="handleSelectionChange"
            >
              <el-table-column prop="type"  label="获得/扣除" align="center" min-width="150px">
                <template slot-scope="{row}">
                  {{ row.saleType == 1?'扣除':'获得'}}
                </template>
              </el-table-column>
              <el-table-column prop="num" label="数量" fixed align="center" min-width="100px">  </el-table-column>
              <el-table-column prop="strObjType" label="消费类型" align="center" min-width="100px"></el-table-column>
              <el-table-column prop="orderCode" label="关联订单" align="center" min-width="150px"></el-table-column>
              <el-table-column prop="remark" label="备注" align="center" min-width="200px"></el-table-column>
              <el-table-column prop="createDate" label="变动时间" align="center" min-width="200px"></el-table-column>
            </el-table>
            <pagination
                @size-change="handleSizeChange"
                @current-change="handlePageChange"
                :pagination="tableData.pagination"
            >
            </pagination>
        </template>
      </TableLayout>
    </div>
    <template  v-slot:footer>
      <el-button @click="visible=false">返回</el-button>
    </template>
    <OperaChangeShopRecordWindow ref="OperaChangeShopRecordWindow"/>
    <OperaChangeIntegralWindow ref="OperaChangeIntegralWindow" @success="successBiz"/>
  </GlobalWindow>
</template>
<script>
import BaseOpera from '@/components/base/BaseOpera'
import GlobalAlertWindow from '@/components/common/GlobalAlertWindow'
import GlobalWindow from '@/components/common/GlobalWindow'
import BaseTable from '@/components/base/BaseTable'
import TableLayout from '@/layouts/TableLayout'
import Pagination from '@/components/common/Pagination'
import OperaChangeShopRecordWindow from '@/components/business/OperaChangeShopRecordWindow'
import OperaChangeIntegralWindow from '@/components/business/OperaChangeIntegralWindow'
export default {
  name: 'OperaCouponWindow',
  extends: BaseOpera,
  components: { GlobalAlertWindow },
  name: 'OperaShopGoodsWindow',
  extends: BaseTable,
  components: { GlobalWindow, TableLayout, Pagination, OperaChangeShopRecordWindow,OperaChangeIntegralWindow },
  data () {
    return {
      getDate: [],
      // è¡¨å•数据
      form: {
        id: null,
        name: '',
        nickName: '',
        sex: '',
        addr: '',
        phone: '',
        idcard: '',
        info: ''
      },
      title: '',
      visible: false,
      tabelHeight: null,
      info: {},
      // æœç´¢
      searchForm: {
        memberId: '',
        userType: 0,
        type: null
      }
    }
  },
  created () {
    this.config({
      api: '/business/coupon',
      'field.id': 'id'
      module: '用户信息表',
      api: '/business/integral',
      'field.id': 'id',
      'field.main': 'id'
    })
  },
  methods: {
  },
    successBiz(){
      this.handlePageChange()
      this.$emit('success')
    },
    showChangeRecord () {
      if (this.info) {
        this.$refs.OperaChangeShopRecordWindow.open('客户经销商变更记录', this.info)
      }
    },
    changeIntegral () {
      if (this.info) {
        this.$refs.OperaChangeIntegralWindow.open('客户积分调整', this.info)
      }
    },
    open (title, goods) {
      this.title = title
      this.visible = true
      this.info = goods
      this.searchForm.memberId = goods.id
      this.search()
    },
    handleClick (val) {
    }
  }
}
</script>
<style scoped>
.table-pagination{
  position: fixed !important;
  bottom: 50px;
}
.header-b{
  display: inline-block;
  font-size: 16px;
  font-weight: bold;
}
.header-blue{
  display: inline-block;
  font-size: 12px;
  border: 1px solid #216EEE;
  padding: 2px 10px;
  margin-left: 20px;
  color: #216EEE;
  border-radius: 5px ;
}
.header-btn{
  display: inline-block;
  border: none;
  padding: 2px 10px;
  margin-left: 20px;
}
.info-item{
  display: flex;
  width: 100%;
  margin: 15px;
}
.info-item-a{
  flex: 1;
  font-size: 14px;
<style lang="scss">
.descriptions-label {
  width: 80px;
  text-align: right !important;
  display: block !important;;
}
.info-item-a span{
  font-weight: 600;
}
.info-item-a  .btn{
  font-size: 12px !important;
  cursor: pointer !important;
}
</style>
admin/src/components/business/OperaShopGoodsWindow.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,217 @@
<template>
  <GlobalWindow
    :title="title"
    width="80%"
    :visible.sync="visible"
  >
    <TableLayout >
      <!-- æœç´¢è¡¨å• -->
      <el-form ref="searchForm" slot="search-form" :model="searchForm"  label-width="10px" style="display: block;" >
        <el-form-item label="" prop="name" style="display: inline-block;margin-right: 30px;">
          <el-input v-model="searchForm.name" placeholder="请输入名称" @keypress.enter.native="search"></el-input>
        </el-form-item>
        <el-form-item label="" prop="code" style="display: inline-block;margin-right: 30px;">
          <el-input v-model="searchForm.code" placeholder="请输入门店ID" @keypress.enter.native="search"></el-input>
        </el-form-item>
        <el-form-item label="" prop="saleType" style="display: inline-block;margin-right: 30px;">
          <!-- 0正常 1禁用 -->
          <el-select     v-model="searchForm.saleType"  placeholder="销售模式"  @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 label="" prop="status" style="display: inline-block;margin-right: 30px;">
          <!-- 0正常 1禁用 -->
          <el-select     v-model="searchForm.status"  placeholder="请选择状态"    @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>
        <section>
          <el-button type="primary" @click="search">搜索</el-button>
          <el-button @click="reset">重置</el-button>
        </section>
      </el-form>
      <!-- è¡¨æ ¼å’Œåˆ†é¡µ -->
      <template v-slot:table-wrap>
        <div :style="'display: flex;height:'+tabelHeight+'px;'">
          <el-table
              v-loading="isWorking.search"
              :data="tableData.list"
              stripe
              border
              @selection-change="handleSelectionChange"
          >
            <!-- <el-table-column type="selection" width="55"></el-table-column> -->
            <el-table-column prop="name" label="名称" fixed align="center" min-width="100px">  </el-table-column>
            <el-table-column prop="code" label="门店ID" align="center" min-width="100px"></el-table-column>
            <el-table-column prop="bigAreaName" label="所属区域" align="center" min-width="100px"></el-table-column>
            <el-table-column prop="areaFullName" label="省市区" align="center" min-width="150px" show-overflow-tooltip>
              <template slot-scope="{row}">
                <span v-if="row.areas!=null">{{(row.areas.provinceName||'') + (row.areas.cityName||'') + (row.areas.name||'')}}</span>
              </template>
            </el-table-column>
            <el-table-column prop="saleType"  label="销售模式" align="center" min-width="150px">
              <template slot-scope="{row}">
                {{ row.saleType == 1?'自主采购':'平台铺货'}}
              </template>
            </el-table-column>
            <el-table-column prop="status" label="状态" align="center" min-width="100px" fixed="right">
              <template slot-scope="{row}">
                {{ row.status == 1?'禁用':'正常'}}
              </template>
            </el-table-column>
            <el-table-column prop="price" label="销售价" align="center" min-width="100px" fixed="right">
                {{ price}}
            </el-table-column>
            <el-table-column prop="goodsPrice" label="供货价" align="center" min-width="100px" fixed="right">
              <template slot-scope="scope">
                <el-input v-if="scope.row.isPriceSelected" v-model="scope.row.goodsPrice"
                          @focus="focusEvent(scope.row,scope.$index,scope.column)"
                          @blur="blurEvent(scope.row,scope.$index,scope.column)" v-focus></el-input>
                <p style="cursor: pointer" class="blue" title="点击编辑" @click="cellClick(scope.row, scope.column)" v-else>{{scope.row.goodsPrice || '未设置' }}</p>
              </template>
            </el-table-column>
          </el-table>
          <pagination
              @size-change="handleSizeChange"
              @current-change="handlePageChange"
              :pagination="tableData.pagination"
          >
          </pagination>
          </div>
      </template>
    </TableLayout>
    <template  v-slot:footer>
      <el-button @click="visible=false">返回</el-button>
    </template>
  </GlobalWindow>
</template>
<script>
import GlobalWindow from '@/components/common/GlobalWindow'
import BaseTable from '@/components/base/BaseTable'
import TableLayout from '@/layouts/TableLayout'
import Pagination from '@/components/common/Pagination'
export default {
  name: 'OperaShopGoodsWindow',
  extends: BaseTable,
  components: { GlobalWindow, TableLayout, Pagination },
  data () {
    return {
      activeName: 'first',
      title: '',
      price : null,
      visible: false,
      tabelHeight: null,
      // æœç´¢
      searchForm: {
        name: '',
        goodsId: null,
        username: '',
        status: '',
        saleType: '',
        isrec: ''
      }
    }
  },
  mounted () {
    window.addEventListener('resize', this.handleResize)
  },
  beforeDestroy () {
    window.removeEventListener('resize', this.handleResize)
  },
  created () {
    this.config({
      module: '商品信息表',
      api: '/business/shop',
      'field.id': 'id',
      'field.main': 'id'
    })
    this.handleResize()
  },
  directives: {
    focus: {
      inserted: function (el) {
        el.querySelector('input').focus()
      }
    }
  },
  methods: {
    handleResize () {
      this.tabelHeight = window.innerHeight - 300
    },
    open (title, goods) {
      this.title = title
      this.visible = true
      this.price = goods.skuPrice
      this.searchForm.goodsId = goods.id
      this.search()
    },
    handlePageChange: function (pageIndex) {
      this.__checkApi()
      this.tableData.pagination.pageIndex = pageIndex || this.tableData.pagination.pageIndex
      this.isWorking.search = true
      this.api.fetchList({
        page: this.tableData.pagination.pageIndex,
        capacity: this.tableData.pagination.pageSize,
        model: this.searchForm,
        sorts: this.tableData.sorts
      })
        .then(data => {
          (data.records|| []).forEach((item) => {
            item.isPriceSelected = false
          })
          this.tableData.list = data.records || []
          this.tableData.pagination.total = data.total
          console.log(this.tableData.list)
        })
        .catch(e => {
          this.$tip.apiFailed(e)
        })
        .finally(() => {
          this.isWorking.search = false
        })
    },
    cellClick (row, column) {
      row.isPriceSelected = !row.isPriceSelected
    },
    focusEvent (row, index, column) {
      row.oldGoodsPrice = row.goodsPrice
    },
    blurEvent (row, curIndex, column) {
      if(this.price >= row.goodsPrice) {
        this.$tip.error('供货价不能低于销售价')
        row.isPriceSelected = !row.isPriceSelected
        row.goodsPrice = row.oldGoodsPrice// ä»·æ ¼è¿˜åŽŸ
        return
      }
      if( row.goodsPrice == row.oldGoodsPrice){
        row.isPriceSelected = !row.isPriceSelected
        return;
      }
      this.api.setGoodsPrice({
        id: row.id,
        goodsId: this.searchForm.goodsId,
        goodsPrice: row.goodsPrice
      }).then(res => {
        row.oldGoodsPrice = row.goodsPrice
        this.$tip.success('修改成功')
        this.$emit('success')
      }).catch(e => {
        row.goodsPrice = row.oldGoodsPrice// ä»·æ ¼è¿˜åŽŸ
      }).finally(() => {
        row.isPriceSelected = !row.isPriceSelected
      })
    },
    handleClick (val) {
    }
  }
}
</script>
<style scoped>
.table-pagination{
  position: fixed !important;
  bottom: 50px;
}
</style>
admin/src/views/business/member.vue
@@ -2,9 +2,43 @@
  <TableLayout :permissions="['business:member:query']">
    <!-- æœç´¢è¡¨å• -->
    <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline>
      <el-form-item label="用户" prop="nickname">
        <el-input v-model="searchForm.nickname" placeholder="请输入昵称/手机号/真实姓名" @keypress.enter.native="search"></el-input>
      <el-form-item label="用户" prop="nickname ">
        <el-input v-model="searchForm.nickname"  style="width: 160px" placeholder="昵称/手机号/真实姓名" @keypress.enter.native="search"></el-input>
      </el-form-item>
      <el-form-item label="状态" prop="status"  >
        <el-select   v-model="searchForm.status" placeholder="状态"  clearable @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 label="关联经销商" prop="shopName ">
        <el-input v-model="searchForm.shopName"  style="width: 160px" placeholder="经销商名称" @keypress.enter.native="search"></el-input>
      </el-form-item>
      <div class="date-style" style="display: inline">
        <el-form-item label="创建时间" prop="queryStartDate" >
          <el-date-picker
              style="width: 160px"
            v-model="searchForm.starttime"
            type="datetime"
            value-format="yyyy-MM-dd HH:mm:ss"
            format="yyyy-MM-dd HH:mm:ss"
            range-separator="至"
            placeholder="开始时间"
        ></el-date-picker>
        </el-form-item>
        <el-form-item label="-" label-width="10px" prop="queryEndDate" >
          <el-date-picker
              style="width: 160px"
              v-model="searchForm.endtime"
              type="datetime"
              value-format="yyyy-MM-dd HH:mm:ss"
              format="yyyy-MM-dd HH:mm:ss"
              range-separator="至"
              placeholder="截止时间"
          ></el-date-picker>
        </el-form-item>
      </div>
      <section>
        <el-button type="primary" @click="search">搜索</el-button>
        <el-button @click="reset">重置</el-button>
@@ -12,23 +46,24 @@
    </el-form>
    <!-- è¡¨æ ¼å’Œåˆ†é¡µ -->
    <template v-slot:table-wrap>
      <ul class="toolbar" v-permissions="['business:member:exportExcel' ]">
        <li> <el-button type="primary" :loading="isWorking.export" v-permissions="['business:member:exportExcel']" @click="exportExcel">导出</el-button></li>
      </ul>
      <el-table
        v-loading="isWorking.search"
        :data="tableData.list"
        stripe
        border
      >
        <el-table-column prop="creator" label="用户" align="center" min-width="100px">
          <template slot-scope="{row}">
            <el-image style="width: 60px; height: 60px; border-radius: 50%;" :src="row.imgFullUrl"></el-image>
            {{ row.nickName }}
          </template>
        </el-table-column>
        <el-table-column prop="openid" label="微信openid" align="center"  min-width="100px"></el-table-column>
        <el-table-column prop="nickname" label="昵称" align="center"  min-width="100px"></el-table-column>
        <el-table-column prop="name" label="真实姓名" align="center"  min-width="100px"></el-table-column>
        <el-table-column prop="phone" label="手机号" align="center"  min-width="100px"></el-table-column>
        <el-table-column prop="name" label="客户姓名" align="center"  min-width="100px"></el-table-column>
        <el-table-column prop="phone" label="授权手机号" align="center"  min-width="100px"></el-table-column>
        <el-table-column prop="idcard" label="身份证号" align="center"  min-width="100px"></el-table-column>
        <el-table-column prop="integral" label="积分数量" align="center"  min-width="100px"></el-table-column>
        <el-table-column prop="integral" label="现有积分" align="center"  min-width="100px"></el-table-column>
        <el-table-column prop="totalIntegral" label="累计积分" align="center"  min-width="100px"></el-table-column>
        <el-table-column prop="totalIntegral" label="累计扣除" align="center"  min-width="100px"></el-table-column>
        <el-table-column prop="shopName" label="关联经销商" align="center"  min-width="100px"></el-table-column>
        <el-table-column prop="createDate" label="创建时间" align="center"  min-width="140px"></el-table-column>
        <el-table-column label="状态" align="center"  min-width="100px">
          <template slot-scope="{row}">
@@ -42,9 +77,10 @@
            ></el-switch>
          </template>
        </el-table-column>
        <el-table-column label="操作" align="center"  min-width="100px">
        <el-table-column label="操作" align="center"  min-width="200px">
          <template slot-scope="{row}">
            <el-button type="text" @click="showMemberDetail(row)">详情</el-button>
            <el-button type="text" v-if="row.bindShopId !=null" @click="changeShop(row)">更换经销商</el-button>
          </template>
        </el-table-column>
      </el-table>
@@ -54,7 +90,8 @@
        :pagination="tableData.pagination"
      >
      </pagination>
      <OperaMemberDetail ref="operaMemberDetail" />
      <OperaChangeShopWindow ref="OperaChangeShopWindow" @success="handlePageChange" />
      <OperaMemberDetail ref="operaMemberDetail" @success="handlePageChange"/>
    </template>
  </TableLayout>
</template>
@@ -64,16 +101,21 @@
import TableLayout from '@/layouts/TableLayout'
import Pagination from '@/components/common/Pagination'
import OperaMemberDetail from '@/components/business/OperaMemberDetail'
import OperaChangeShopWindow from '@/components/business/OperaChangeShopWindow'
import { updateById } from '@/api/business/member'
export default {
  name: 'Member',
  extends: BaseTable,
  components: { TableLayout, Pagination, OperaMemberDetail },
  components: { TableLayout, Pagination, OperaMemberDetail ,OperaChangeShopWindow},
  data () {
    return {
      // æœç´¢
      searchForm: {
        nickname: ''
        starttime: null,
        endtime: null,
        status: null,
        nickname: '',
        shopName: ''
      }
    }
  },
@@ -87,6 +129,9 @@
    this.search()
  },
  methods: {
    changeShop(row){
      this.$refs.OperaChangeShopWindow.open('更换经销商',row)
    },
    statusChange(row) {
      console.log(row);
      updateById(row)
@@ -108,7 +153,7 @@
</script>
<style scoped>
::v-deep .el-input{
/*::v-deep .el-input{
  width: 200px;
}
}*/
</style>
admin/src/views/business/memberCoupon.vue
@@ -2,7 +2,7 @@
  <TableLayout :permissions="['business:membercoupon:query']">
    <!-- æœç´¢è¡¨å• -->
    <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline>
      <el-form-item label="用户" prop="nikeName">
      <el-form-item label="用户" prop="nikeName" >
        <el-input v-model="searchForm.nikeName" placeholder="请输入用户昵称/手机号 " clearable @keypress.enter.native="search"></el-input>
      </el-form-item>
      <el-form-item label="优惠券名称" prop="name">
@@ -47,7 +47,7 @@
        :data="tableData.list"
        stripe
      >
        <el-table-column prop="nikeName" label="用户" min-width="100px"></el-table-column>
        <el-table-column prop="nikeName" label="用户" min-width="180px"></el-table-column>
        <el-table-column prop="name" label="优惠券名称" min-width="100px"></el-table-column>
        <el-table-column prop="couponType" label="优惠券类型" min-width="100px">
          <template slot-scope="{row}">
admin/src/views/business/platformGoods.vue
@@ -68,9 +68,9 @@
        @selection-change="handleSelectionChange"
      >
        <el-table-column type="selection" width="55"></el-table-column>
        <el-table-column prop="imgurl" label="商品信息" min-width="100px">
        <el-table-column prop="imgurl" label="商品信息" min-width="80px">
          <template slot-scope="{row}">
            <el-image style="width: 80px;height: 80px;" v-if="row.imgurl && row.imgurl!=''" :src="row.resourcePath+row.imgurl" :preview-src-list="[row.resourcePath+row.imgurl]"></el-image>
            <el-image style="width: 50px;height: 50px;" v-if="row.imgurl && row.imgurl!=''" :src="row.resourcePath+row.imgurl" :preview-src-list="[row.resourcePath+row.imgurl]"></el-image>
          </template>
        </el-table-column>
        <el-table-column prop="id" label="商品ID" min-width="150px" ></el-table-column>
@@ -78,14 +78,14 @@
        <el-table-column prop="categoryName" label="所属分类" min-width="120px"></el-table-column>
        <el-table-column prop="brandName" label="所属品牌" min-width="120px"></el-table-column>
        <el-table-column prop="price" label="展示价格" min-width="100px"></el-table-column>
        <el-table-column prop="stockNum" label="剩余库存量" min-width="100px"></el-table-column>
        <el-table-column prop="salesVolume" label="实际销量" min-width="100px"></el-table-column>
        <el-table-column prop="skuPrice" label="零售价(元)" min-width="100px"></el-table-column>
        <el-table-column prop="skuPrice" label="销售价(元)" min-width="100px"></el-table-column>
        <el-table-column prop="shopPrice" label="供货价设置" min-width="100px" align="center">
          <template slot-scope="{row}" >
          <div @click="goPriceSet(row)" style="cursor:pointer;"><span  class="red"> {{row.shopPriceNum||0}}</span> / <span class="green"> {{row.shopNum||0}}</span>  </div>
            <div @click="goPriceSet(row)" style="cursor:pointer;"><span  class="red"> {{row.pricedShopNum||0}}</span> / <span class="green"> {{row.shopNum||0}}</span>  </div>
          </template>
        </el-table-column>
        <el-table-column prop="stockNum" label="剩余库存量" min-width="100px"></el-table-column>
        <el-table-column prop="salesVolume" label="实际销量" min-width="100px"></el-table-column>
        <el-table-column prop="editDate" label="最近更新时间" min-width="100px"></el-table-column>
        <el-table-column prop="status" label="上下架状态" min-width="100px" fixed="right" align="center">
          <template slot-scope="{row}">
@@ -105,10 +105,10 @@
          fixed="right"
        >
          <template slot-scope="{row}">
             <el-button type="text" @click="$refs.operaGoodsWindow.open('编辑商品', row, 0)" v-permissions="['business:goods:update']">编辑</el-button>
             <el-button type="text" v-if="row.status == 1" @click="$refs.operaGoodsWindow.open('编辑商品', row, 0)" v-permissions="['business:goods:update']">编辑</el-button>
            <el-button type="text"  @click="goPriceSet(row)">供货价</el-button>
            <el-button type="text" style="color: red;" @click="deleteById(row)" v-permissions="['business:goods:delete']">删除</el-button>
            <!--              <el-button type="text" @click="$refs.operaGoodsDetailWindow.open('商品详情', row, 0)">查看详情</el-button>-->
            <!-- <el-button type="text" @click="$refs.operaGoodsDetailWindow.open('商品详情', row, 0)">查看详情</el-button>-->
          </template>
        </el-table-column>
      </el-table>
@@ -123,6 +123,7 @@
    <OperaGoodsWindow ref="operaGoodsWindow" @success="handlePageChange"/>
    <OperaGoodsDetailWindow ref="operaGoodsDetailWindow"/>
    <OperaPlatformGoodsSkuWindow ref="operaPlatformGoodsSkuWindow"/>
    <OperaShopGoodsWindow ref="OperaShopGoodsWindow" @success="priceSuccess"/>
  </TableLayout>
</template>
@@ -133,11 +134,12 @@
import OperaGoodsWindow from '@/components/business/OperaGoodsWindow'
import OperaGoodsDetailWindow from '@/components/business/OperaGoodsDetailWindow'
import OperaPlatformGoodsSkuWindow from '@/components/business/OperaPlatformGoodsSkuWindow'
import OperaShopGoodsWindow from '@/components/business/OperaShopGoodsWindow'
import { findAll as labelList } from '@/api/business/labels'
export default {
  name: 'Goods',
  extends: BaseTable,
  components: { TableLayout, Pagination, OperaGoodsWindow, OperaGoodsDetailWindow, OperaPlatformGoodsSkuWindow },
  components: { TableLayout, Pagination, OperaGoodsWindow, OperaGoodsDetailWindow, OperaPlatformGoodsSkuWindow ,OperaShopGoodsWindow},
  data () {
    return {
      activeName: 'first',
@@ -199,10 +201,18 @@
      })
  },
  methods: {
    priceSuccess(){
      this.handlePageChange()
    },
    goPriceSet(row){
      if(row.skuPrice == null){
        this.$tip.warning('请先设置商品销售价!')
        return
      }
      this.$refs.OperaShopGoodsWindow.open('设置供货价 - '+row.name, row )
    },
    handleClick (val) {
    },
    /**
     *
@@ -224,10 +234,10 @@
    statusChangeBiz (rows) {
      this.api.updateStatus(rows)
        .then(() => {
          this.search()
          this.handlePageChange()
        })
        .catch(e => {
          this.search()
          this.handlePageChange()
        })
    }
  }
server/dmmall_admin/src/main/java/com/doumee/api/business/IntegralController.java
@@ -89,7 +89,6 @@
                model.setStrType("支出");
            }
            model.setStrObjType(Constants.IntegralObjType.getName(model.getObjType()));
        }
        ExcelExporter.build(Integral.class).export(list, "用户积分明细"+ DateUtil.getNowLongTime(), response);
    }
server/dmmall_admin/src/main/java/com/doumee/api/business/MemberController.java
@@ -7,6 +7,7 @@
import com.doumee.core.model.ApiResponse;
import com.doumee.core.model.PageWrap;
import com.doumee.core.model.PageData;
import com.doumee.dao.business.model.Integral;
import com.doumee.dao.business.model.Member;
import com.doumee.dao.system.dto.MemberRechargeDTO;
import com.doumee.service.business.MemberService;
@@ -72,6 +73,20 @@
        memberService.updateById(member);
        return ApiResponse.success(null);
    }
    @ApiOperation("更换经销商")
    @PostMapping("/updateShop")
    @RequiresPermissions("business:member:update")
    public ApiResponse updateShop(@RequestBody Member member) {
        memberService.updateShop(member);
        return ApiResponse.success(null);
    }
    @ApiOperation("调整积分")
    @PostMapping("/updateIntegral")
    @RequiresPermissions("business:member:update")
    public ApiResponse updateIntegral(@RequestBody Integral param) {
        memberService.updateIntegral(param);
        return ApiResponse.success(null);
    }
    @ApiOperation("分页查询")
    @PostMapping("/page")
@@ -104,6 +119,12 @@
            ExcelExporter.build(MemberRechargeDTO.class).export(collect, "用户信息表", response);
        }
    }
    @ApiOperation("导出Excel")
    @PostMapping("/exportExcelList")
    @RequiresPermissions("business:member:exportExcel")
    public void exportExcelList (@RequestBody PageWrap<Member> pageWrap, HttpServletResponse response) {
        ExcelExporter.build(Member.class).export( memberService.findPage(pageWrap).getRecords(), "用户信息表", response);
    }
    @ApiOperation("根据ID查询")
    @GetMapping("/{id}")
server/dmmall_admin/src/main/java/com/doumee/api/business/ShopController.java
@@ -40,6 +40,13 @@
    public ApiResponse create(@RequestBody Shop shop) {
        return ApiResponse.success(shopService.create(shop));
    }
    @PreventRepeat
    @ApiOperation("设置供货价")
    @PostMapping("/setGoodsPrice")
    @RequiresPermissions("business:shop:update")
    public ApiResponse setGoodsPrice(@RequestBody Shop shop) {
        return ApiResponse.success(shopService.setGoodsPrice(shop));
    }
    @ApiOperation("根据ID删除")
    @GetMapping("/delete/{id}")
@@ -90,8 +97,8 @@
    @ApiOperation("查询所有数据")
    @PostMapping("/findAll")
    @RequiresPermissions("business:shop:query")
    public ApiResponse<List<Shop>> findAll (@RequestBody PageWrap<Shop> pageWrap) {
        return ApiResponse.success(shopService.findAll(pageWrap));
    public ApiResponse<List<Shop>> findAll (@RequestBody Shop pageWrap) {
        return ApiResponse.success(shopService.findList(pageWrap));
    }
server/dmmall_admin/src/main/java/com/doumee/api/business/UserActionController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,90 @@
package com.doumee.api.business;
import com.doumee.api.BaseController;
import com.doumee.core.annotation.excel.ExcelExporter;
import com.doumee.core.annotation.pr.PreventRepeat;
import com.doumee.core.model.ApiResponse;
import com.doumee.core.model.PageData;
import com.doumee.core.model.PageWrap;
import com.doumee.dao.business.model.UserAction;
import com.doumee.service.business.UserActionService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
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 java.util.ArrayList;
import java.util.List;
/**
 * @author æ±Ÿè¹„蹄
 * @date 2023/12/14 13:57
 */
@Api(tags = "人员操作记录日志")
@RestController
@RequestMapping("/business/userAction")
public class UserActionController extends BaseController {
    @Autowired
    private UserActionService userActionService;
    @PreventRepeat
    @ApiOperation("新建")
    @PostMapping("/create")
    @RequiresPermissions("business:useraction:create")
    public ApiResponse create(@RequestBody UserAction userAction) {
        return ApiResponse.success(userActionService.create(userAction));
    }
    @ApiOperation("根据ID删除")
    @GetMapping("/delete/{id}")
    @RequiresPermissions("business:useraction:delete")
    public ApiResponse deleteById(@PathVariable Integer id) {
        userActionService.deleteById(id);
        return ApiResponse.success(null);
    }
    @ApiOperation("批量删除")
    @GetMapping("/delete/batch")
    @RequiresPermissions("business:useraction:delete")
    public ApiResponse deleteByIdInBatch(@RequestParam String ids) {
        String [] idArray = ids.split(",");
        List<Integer> idList = new ArrayList<>();
        for (String id : idArray) {
            idList.add(Integer.valueOf(id));
        }
        userActionService.deleteByIdInBatch(idList);
        return ApiResponse.success(null);
    }
    @ApiOperation("根据ID修改")
    @PostMapping("/updateById")
    @RequiresPermissions("business:useraction:update")
    public ApiResponse updateById(@RequestBody UserAction userAction) {
        userActionService.updateById(userAction);
        return ApiResponse.success(null);
    }
    @ApiOperation("分页查询")
    @PostMapping("/page")
    @RequiresPermissions("business:useraction:query")
    public ApiResponse<PageData<UserAction>> findPage (@RequestBody PageWrap<UserAction> pageWrap) {
        return ApiResponse.success(userActionService.findPage(pageWrap));
    }
    @ApiOperation("导出Excel")
    @PostMapping("/exportExcel")
    @RequiresPermissions("business:useraction:exportExcel")
    public void exportExcel (@RequestBody PageWrap<UserAction> pageWrap, HttpServletResponse response) {
        ExcelExporter.build(UserAction.class).export(userActionService.findPage(pageWrap).getRecords(), "人员操作记录日志", response);
    }
    @ApiOperation("根据ID查询")
    @GetMapping("/{id}")
    @RequiresPermissions("business:useraction:query")
    public ApiResponse findById(@PathVariable Integer id) {
        return ApiResponse.success(userActionService.findById(id));
    }
}
server/dmmall_service/src/main/java/com/doumee/core/utils/Constants.java
@@ -871,8 +871,6 @@
        SYSTEM_RECHARGE(12,"平台充值","平台充值",0),
        SYSTEM_DEDUCT(13,"平台扣款","平台扣款",0),
        SHOP_ORDER_CANCEL(14,"积分抵扣商品退还","积分抵扣商品退还",0),
        ORDER_DONATE(15,"订单赠送积分","订单赠送积分",0),
        ORDER_DONE_AMOUNT(16,"订单结算金额","订单结算金额",0),
@@ -1158,5 +1156,52 @@
        }
    }
    public  enum UserActionType {
        CHANGE_SHOP(0, "经销商更换","由【${param1}】于【${param2}】,进行【经销商更换】" ),
        ;
        // æˆå‘˜å˜é‡
        private int key;
        private String name;
        private String info;
        // æž„造方法
        UserActionType(int key, String name,String info ) {
            this.key = key;
            this.info = info;
            this.name = name;
        }
        public static String getName(int index) {
            for (UserActionType c : UserActionType.values()) {
                if (c.getKey() == index) {
                    return c.name;
                }
            }
            return null;
        }
        public int getKey() {
            return key;
        }
        public void setKey(int key) {
            this.key = key;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getInfo() {
            return info;
        }
        public void setInfo(String info) {
            this.info = info;
        }
    }
}
server/dmmall_service/src/main/java/com/doumee/dao/business/MemberMapper.java
@@ -2,6 +2,7 @@
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.doumee.dao.business.model.Member;
import com.github.yulichang.base.MPJBaseMapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
@@ -11,7 +12,7 @@
 * @author æ±Ÿè¹„蹄
 * @date 2023/03/21 15:48
 */
public interface MemberMapper extends BaseMapper<Member> {
public interface MemberMapper extends MPJBaseMapper<Member> {
    /**
server/dmmall_service/src/main/java/com/doumee/dao/business/UserActionMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,12 @@
package com.doumee.dao.business;
import com.doumee.dao.business.model.UserAction;
import com.github.yulichang.base.MPJBaseMapper;
/**
 * @author æ±Ÿè¹„蹄
 * @date 2023/11/30 15:33
 */
public interface UserActionMapper extends MPJBaseMapper<UserAction> {
}
server/dmmall_service/src/main/java/com/doumee/dao/business/model/Goods.java
@@ -202,6 +202,12 @@
    @ApiModelProperty(value = "商品SKU规格组")
    @TableField(exist = false)
    private List<GoodsSku>  goodsSkuList;
    @ApiModelProperty(value = "供銷商数量")
    @TableField(exist = false)
    private Long shopNum;
    @ApiModelProperty(value = "已设置供銷商数量")
    @TableField(exist = false)
    private Long pricedShopNum;
}
server/dmmall_service/src/main/java/com/doumee/dao/business/model/Member.java
@@ -23,130 +23,129 @@
public class Member {
    @ApiModelProperty(value = "主键", example = "1")
    @ExcelColumn(name="主键")
   // @ExcelColumn(name="主键")
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;
    @ApiModelProperty(value = "创建人编码", example = "1")
    @ExcelColumn(name="创建人编码")
   // @ExcelColumn(name="创建人编码")
    private Integer creator;
    @ApiModelProperty(value = "创建时间")
    @ExcelColumn(name="创建时间")
    @ExcelColumn(name="创建时间",width = 10,index = 8,dateFormat = "yyyy-MM-dd HH:mm:ss")
    private Date createDate;
    @ApiModelProperty(value = "更新人编码", example = "1")
    @ExcelColumn(name="更新人编码")
   // @ExcelColumn(name="更新人编码")
    private Integer editor;
    @ApiModelProperty(value = "更新时间")
    @ExcelColumn(name="更新时间")
   // @ExcelColumn(name="更新时间")
    
    private Date editDate;
    @ApiModelProperty(value = "是否删除0否 1是", example = "1")
    @ExcelColumn(name="是否删除0否 1是")
   // @ExcelColumn(name="是否删除0否 1是")
    private Integer isdeleted;
    @ApiModelProperty(value = "备注")
    @ExcelColumn(name="备注")
   // @ExcelColumn(name="备注")
    private String remark;
    @ApiModelProperty(value = "昵称")
    @ExcelColumn(name="昵称")
    @ExcelColumn(name="昵称",width = 10,index = 2)
    private String nickname;
    @ApiModelProperty(value = "头像")
    @ExcelColumn(name="头像")
   // @ExcelColumn(name="头像")
    private String imgurl;
    @ApiModelProperty(value = "真实姓名")
    @ExcelColumn(name="真实姓名")
    @ExcelColumn(name="客户姓名",width = 10,index = 3)
    private String name;
    @ApiModelProperty(value = "手机号")
    @ExcelColumn(name="手机号")
    @ExcelColumn(name="授权手机号",width = 10,index = 4)
    private String phone;
    @ApiModelProperty(value = "身份证号")
    @ExcelColumn(name="身份证号")
   // @ExcelColumn(name="身份证号")
    private String idcard;
    @ApiModelProperty(value = "身份证正面照")
    @ExcelColumn(name="身份证正面照")
   // @ExcelColumn(name="身份证正面照")
    private String idcardImg;
    @ApiModelProperty(value = "身份证反面照")
    @ExcelColumn(name="身份证反面照")
   // @ExcelColumn(name="身份证反面照")
    private String idcardImgBack;
    @ApiModelProperty(value = "积分余额", example = "1")
    @ExcelColumn(name="积分余额")
    @ExcelColumn(name="积分余额",width = 10,index = 5)
    private BigDecimal integral;
    @ApiModelProperty(value = "积分累计", example = "1")
    @ExcelColumn(name="积分累计")
    @ExcelColumn(name="积分累计获得",width = 10,index = 6)
    private BigDecimal totalIntegral;
    @ApiModelProperty(value = "状态0正常 1异常", example = "1")
    @ExcelColumn(name="状态0正常 1异常")
    @ExcelColumn(name="状态",width = 10,index =9,valueMapping = "0=启用;1=禁用")
    private Integer status;
    @ApiModelProperty(value = "性别 0男 1女 2未知", example = "1")
    @ExcelColumn(name="性别 0男 1女 2未知")
   // @ExcelColumn(name="性别 0男 1女 2未知")
    private Integer sex;
    @ApiModelProperty(value = "定位经度", example = "1")
    @ExcelColumn(name="定位经度")
   // @ExcelColumn(name="定位经度")
    private BigDecimal longitude;
    @ApiModelProperty(value = "定位维度", example = "1")
    @ExcelColumn(name="定位维度")
   // @ExcelColumn(name="定位维度")
    private BigDecimal latitude;
    @ApiModelProperty(value = "当前所在城市编码(关联areas表)", example = "1")
    @ExcelColumn(name="当前所在城市编码(关联areas表)")
   // @ExcelColumn(name="当前所在城市编码(关联areas表)")
    private Integer cityId;
    @ApiModelProperty(value = "地址")
    @ExcelColumn(name="地址")
   // @ExcelColumn(name="地址")
    private String addr;
    @ApiModelProperty(value = "类型 0普通用户", example = "1")
    @ExcelColumn(name="类型 0普通用户")
   // @ExcelColumn(name="类型 0普通用户")
    private Integer type;
    @ApiModelProperty(value = "一句话介绍")
    @ExcelColumn(name="一句话介绍")
   // @ExcelColumn(name="一句话介绍")
    private String info;
    @ApiModelProperty(value = "数据来源 0小程序注册 1后台录入", example = "1")
    @ExcelColumn(name="数据来源 0小程序注册 1后台录入")
   // @ExcelColumn(name="数据来源 0小程序注册 1后台录入")
    private Integer origin;
    @ApiModelProperty(value = "邀请人编码(关联member表)", example = "1")
    @ExcelColumn(name="邀请人编码(关联member表)")
   // @ExcelColumn(name="邀请人编码(关联member表)")
    private Integer recId;
    @ApiModelProperty(value = "邀请奖励咖豆", example = "1")
    @ExcelColumn(name="邀请奖励咖豆")
   // @ExcelColumn(name="邀请奖励咖豆")
    private BigDecimal recIntegral;
    @ApiModelProperty(value = "注册奖励咖豆", example = "1")
    @ExcelColumn(name="注册奖励咖豆")
   // @ExcelColumn(name="注册奖励咖豆")
    private BigDecimal registerIntegral;
    @ApiModelProperty(value = "微信openId")
    @ExcelColumn(name="微信openId")
    @ExcelColumn(name="微信openId",width = 10,index = 1)
    private String openId;
    @ApiModelProperty(value = "生日")
    @ExcelColumn(name="birthday")
   // @ExcelColumn(name="birthday")
    private Date birthday;
    @ApiModelProperty(value = "微信分享码")
    @ExcelColumn(name="sharingCode")
   // @ExcelColumn(name="sharingCode")
    private String sharingCode;
    @ApiModelProperty(value = "绑定商铺主键 shop:id åˆ†é”€äºº")
@@ -162,8 +161,10 @@
    @ApiModelProperty(value = "用户所在城市")
    @TableField(exist = false)
    private String cityName;
    @ApiModelProperty(value = "经销商名称")
    @TableField(exist = false)
    @ExcelColumn(name = "关联经销商",width = 10,index = 7)
    private String shopName;
    @ApiModelProperty(value = "开始时间 ")
    @TableField(exist = false)
    private Date starttime;
server/dmmall_service/src/main/java/com/doumee/dao/business/model/Shop.java
@@ -268,6 +268,9 @@
    @ApiModelProperty(value = "优惠券:优惠券领取总数")
    @TableField(exist = false)
    private BigDecimal  couponDrawCount;
    @ApiModelProperty(value = "商品编码")
    @TableField(exist = false)
    private Integer  goodsId;
    @ApiModelProperty(value = "优惠券:优惠券使用总数(å¼ )")
    @TableField(exist = false)
@@ -276,6 +279,9 @@
    @ApiModelProperty(value = "优惠券:优惠券使用金额(元)")
    @TableField(exist = false)
    private BigDecimal  couponUserMoney;
    @ApiModelProperty(value = "某商品供货价(元)")
    @TableField(exist = false)
    private BigDecimal  goodsPrice;
    @ApiModelProperty(value = "店铺标签")
server/dmmall_service/src/main/java/com/doumee/dao/business/model/ShopGoodsRelation.java
@@ -55,6 +55,9 @@
    @ApiModelProperty(value = "商户主键(shop主键)", example = "1")
    @ExcelColumn(name="商户主键(shop主键)")
    private Integer shopId;
    @ApiModelProperty(value = "商品编码(goods主键)", example = "1")
    @ExcelColumn(name="商品编码(goods主键)")
    private Integer goodsId;
    @ApiModelProperty(value = "商品SKU ID(goods_sku主键)", example = "1")
    @ExcelColumn(name="商品SKU ID(goods_sku主键)")
server/dmmall_service/src/main/java/com/doumee/dao/business/model/UserAction.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,97 @@
package com.doumee.dao.business.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.doumee.core.annotation.excel.ExcelColumn;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
 * äººå‘˜ä¿¡æ¯è¡¨
 * @author æ±Ÿè¹„蹄
 * @date 2023/11/30 15:33
 */
@Data
@ApiModel("人员信息表")
@TableName("`user_action`")
public class UserAction  {
        @TableId(type = IdType.AUTO)
        @ApiModelProperty(value = "主键", example = "1")
        @ExcelColumn(name="主键")
        private Integer id;
        @ApiModelProperty(value = "创建人编码", example = "1")
        @ExcelColumn(name="创建人编码")
        private Integer creator;
        @ApiModelProperty(value = "创建时间")
        @ExcelColumn(name="创建时间")
        private Date createDate;
        @ApiModelProperty(value = "更新人编码", example = "1")
        @ExcelColumn(name="更新人编码")
        private Integer editor;
        @ApiModelProperty(value = "更新时间")
        @ExcelColumn(name="更新时间")
        private Date editDate;
        @ApiModelProperty(value = "是否删除0否 1是", example = "1")
        @ExcelColumn(name="是否删除0否 1是")
        private Integer isdeleted;
        @ApiModelProperty(value = "备注")
        @ExcelColumn(name="备注")
        private String remark;
        @ApiModelProperty(value = "修改详细内容")
        @ExcelColumn(name="修改详细内容")
        private String content;
        @ApiModelProperty(value = "更改前内容", example = "1")
        private String beforeInfo;
        @ApiModelProperty(value = "更改后内容", example = "1")
        private String afterInfo;
        @ApiModelProperty(value = "类型 0解冻 1冻结 2拉黑 3恢复 4设为拜访人 5取消拜访人 6设为高级审批人 7取消高级审批人 8手动离场 9删除人员 10更新人员", example = "1")
        @ExcelColumn(name="类型 0解冻 1冻结 2拉黑 3恢复 4设为拜访人 5取消拜访人 6设为高级审批人 7取消高级审批人 8手动离场 9删除人员 10更新人员")
        private Integer type;
        @ApiModelProperty(value = "人员操作记录日志")
        @ExcelColumn(name="人员操作记录日志")
        private String memberId;
        @ApiModelProperty(value = "操作前状态 0解冻 1冻结 2拉黑 3恢复 4设为拜访人 5取消拜访人 6设为高级审批人 7取消高级审批人 8手动离场 9删除", example = "1")
        @ExcelColumn(name="操作前状态 0解冻 1冻结 2拉黑 3恢复 4设为拜访人 5取消拜访人 6设为高级审批人 7取消高级审批人 8手动离场 9删除")
        private Integer beforeStatus;
        @ApiModelProperty(value = "操作人名称", example = "1")
        @TableField(exist = false)
        private String createName;
        @ApiModelProperty(value = "人员类型:0劳务访客 1普通访客  2内部人员", example = "1")
        @TableField(exist = false)
        private String memberType;
        @ApiModelProperty(value = "操作对象", example = "1")
        @TableField(exist = false)
        private String memberName;
        @ApiModelProperty(value = "类型名称", example = "1")
        @TableField(exist = false)
        private String typeName;
        @ApiModelProperty(value = "手机号", example = "1")
        @TableField(exist = false)
        private String mobile;
        @ApiModelProperty(value = "查询对象类型  0人员操作 1其他业务操作", example = "1")
        @TableField(exist = false)
        private Integer objType;
}
server/dmmall_service/src/main/java/com/doumee/service/business/MemberService.java
@@ -3,6 +3,7 @@
import com.doumee.core.model.PageData;
import com.doumee.core.model.PageWrap;
import com.doumee.dao.business.model.Areas;
import com.doumee.dao.business.model.Integral;
import com.doumee.dao.business.model.Member;
import com.doumee.dao.system.dto.MemberRechargeDTO;
import com.doumee.dao.web.dto.MemberOwnDTO;
@@ -193,4 +194,8 @@
     * @return
     */
    Integer changeMemberRechargeBatch(MemberRechargeDTO memberRechargeDTO);
    void updateShop(Member member);
    void updateIntegral(Integral param);
}
server/dmmall_service/src/main/java/com/doumee/service/business/ShopService.java
@@ -210,4 +210,6 @@
     */
    SaleReportResponse saleReport(SaleReportRequest request, String shopId);
    String setGoodsPrice(Shop shop);
}
server/dmmall_service/src/main/java/com/doumee/service/business/UserActionService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,98 @@
package com.doumee.service.business;
import com.doumee.core.model.PageData;
import com.doumee.core.model.PageWrap;
import com.doumee.dao.business.model.UserAction;
import java.util.List;
/**
 * äººå‘˜æ“ä½œè®°å½•日志Service定义
 * @author æ±Ÿè¹„蹄
 * @date 2023/12/14 13:57
 */
public interface UserActionService {
    /**
     * åˆ›å»º
     *
     * @param userAction å®žä½“对象
     * @return Integer
     */
    Integer create(UserAction userAction);
    /**
     * ä¸»é”®åˆ é™¤
     *
     * @param id ä¸»é”®
     */
    void deleteById(Integer id);
    /**
     * åˆ é™¤
     *
     * @param userAction å®žä½“对象
     */
    void delete(UserAction userAction);
    /**
     * æ‰¹é‡ä¸»é”®åˆ é™¤
     *
     * @param ids ä¸»é”®é›†
     */
    void deleteByIdInBatch(List<Integer> ids);
    /**
     * ä¸»é”®æ›´æ–°
     *
     * @param userAction å®žä½“对象
     */
    void updateById(UserAction userAction);
    /**
     * æ‰¹é‡ä¸»é”®æ›´æ–°
     *
     * @param userActions å®žä½“集
     */
    void updateByIdInBatch(List<UserAction> userActions);
    /**
     * ä¸»é”®æŸ¥è¯¢
     *
     * @param id ä¸»é”®
     * @return UserAction
     */
   UserAction findById(Integer id);
    /**
     * æ¡ä»¶æŸ¥è¯¢å•条记录
     *
     * @param userAction å®žä½“对象
     * @return UserAction
     */
   UserAction findOne(UserAction userAction);
    /**
     * æ¡ä»¶æŸ¥è¯¢
     *
     * @param userAction å®žä½“对象
     * @return List<UserAction>
     */
    List<UserAction> findList(UserAction userAction);
    /**
     * åˆ†é¡µæŸ¥è¯¢
     *
     * @param pageWrap åˆ†é¡µå¯¹è±¡
     * @return PageData<UserAction>
     */
    PageData<UserAction> findPage(PageWrap<UserAction> pageWrap);
    /**
     * æ¡ä»¶ç»Ÿè®¡
     *
     * @param userAction å®žä½“对象
     * @return long
     */
    long count(UserAction userAction);
}
server/dmmall_service/src/main/java/com/doumee/service/business/impl/GoodsServiceImpl.java
@@ -89,6 +89,8 @@
    @Autowired
    private SystemDictDataBiz systemDictDataBiz;
    @Autowired
    private ShopMapper shopMapper;
    @Autowired
    private GoodsSkuAttrJoinMapper goodsSkuAttrJoinMapper;
@@ -214,8 +216,9 @@
                    || goods.getDeductRata() == null
                    || goods.getPrice() == null
                    || goods.getSkuPrice() == null
                    || StringUtils.isBlank(goods.getImgurl())
                    || org.apache.commons.collections.CollectionUtils.isEmpty(goods.getFileList())) {
//                    || StringUtils.isBlank(goods.getImgurl())
//                    || org.apache.commons.collections.CollectionUtils.isEmpty(goods.getFileList())
            ) {
                throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), ResponseStatus.BAD_REQUEST.getMessage());
            }
@@ -730,6 +733,7 @@
        queryWrapper.leftJoin(Labels.class,Labels::getId,Goods::getParentCategoryId);
        //库存量
        queryWrapper.select("(select sum(STOCK) from goods_sku where ISDELETED=0 and GOODS_ID=t.id) as stockNum ");
        queryWrapper.select("(select count(id) from shop_goods_relation s where s.ISDELETED=0 and s.GOODS_ID=t.id) as pricedShopNum ");
        //实际销量
        queryWrapper.select("(select sum(gd.GOODS_NUM) from  goodsorder_detail gd" +
                "        inner join  goods_sku gs on gs.id=gd.GOODS_SKU_ID" +
@@ -781,9 +785,12 @@
        if (list == null || list.size() == 0) {
            return;
        }
       long shopNum = shopMapper.selectCount(new QueryWrapper<Shop>().lambda()
                .eq(Shop::getIsdeleted,Constants.ZERO));
        String path = systemDictDataBiz.queryByCode(Constants.OSS, Constants.RESOURCE_PATH).getCode()
                + systemDictDataBiz.queryByCode(Constants.OSS, Constants.GOODS_FILE).getCode();
        for (Goods goods : list) {
            goods.setShopNum(shopNum);
            goods.setResourcePath(path);
            //查询sku
            MPJLambdaWrapper<GoodsSku> queryWrapper = new MPJLambdaWrapper<GoodsSku>()
server/dmmall_service/src/main/java/com/doumee/service/business/impl/IntegralServiceImpl.java
@@ -342,6 +342,7 @@
        String path = systemDictDataBiz.queryByCode(Constants.OSS, Constants.RESOURCE_PATH).getCode() + systemDictDataBiz.queryByCode(Constants.OSS, Constants.MEMBER_FILE).getCode();
        for (Integral model : result.getRecords()) {
            model.setStrObjType(Constants.IntegralObjType.getName(model.getObjType()));
            if (StringUtils.isNotBlank(model.getImgurl())) {
                model.setImgurl(path + model.getImgurl());
            }
server/dmmall_service/src/main/java/com/doumee/service/business/impl/MemberServiceImpl.java
@@ -19,6 +19,7 @@
import com.doumee.core.utils.DateUtil;
import com.doumee.core.utils.Utils;
import com.doumee.core.wx.WxMiniConfig;
import com.doumee.dao.business.*;
import com.doumee.dao.business.MemberMapper;
import com.doumee.dao.business.ShopMapper;
import com.doumee.dao.business.SmsrecordMapper;
@@ -67,7 +68,7 @@
import java.util.stream.Collectors;
/**
 * ç”¨æˆ·ä¿¡æ¯è¡¨Service实现
 * å®¢æˆ·ä¿¡æ¯è¡¨Service实现
 * @author æ±Ÿè¹„蹄
 * @date 2023/03/21 15:48
 */
@@ -77,9 +78,13 @@
    @Autowired
    private MemberMapper memberMapper;
    @Autowired
    private IntegralMapper integralMapper;
    @Autowired
    private ShopMapper shopMapper;
    @Autowired
    private UserActionMapper userActionMapper;
    @Autowired
    private SmsrecordMapper smsrecordMapper;
@@ -139,6 +144,109 @@
        member.setEditor(user.getId());
        memberMapper.updateById(member);
    }
    @Override
    @Transactional
    public void updateShop(Member member) {
        if(member.getBindShopId()==null || member.getId()==null){
            throw new BusinessException(ResponseStatus.BAD_REQUEST);
        }
        MPJLambdaWrapper<Member> queryWrapper =new MPJLambdaWrapper<>();
        queryWrapper.selectAll(Member.class);
        queryWrapper.selectAs(Shop::getName,Member::getShopName);
        queryWrapper.leftJoin(Shop.class, Shop::getId,Member::getBindShopId);
        queryWrapper.eq(Member::getId,member.getId());
        Member model = memberMapper.selectJoinOne(Member.class,queryWrapper);
        if(model == null ||Constants.equalsObject(model.getIsdeleted(),Constants.ONE)){
            throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(),"客户信息查询无效!");
        }
        if(model.getBindShopId() == null){
            throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(),"客户尚未绑定经销商信息,无法更换!");
        }
        if(Constants.equalsInteger(model.getBindShopId() ,member.getBindShopId())){
            throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(),"请选择新的经销商!");
        }
        Shop shop = shopMapper.selectById(member.getBindShopId());
        if(shop == null ||Constants.equalsObject(shop.getIsdeleted(),Constants.ONE)){
            throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(),"经销商信息查询无效!");
        }
        LoginUserInfo user = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal();
        Date date = new Date();
        memberMapper.update(null,new UpdateWrapper<Member>().lambda()
                .eq(Member::getId,member.getId())
                .set(Member::getEditDate,date)
                .set(Member::getEditor,user.getId())
                .set(Member::getBindShopId,member.getBindShopId())
        );
        //更换日志记录
        UserActionServiceImpl.saveUserActionBiz(user,member.getId(),
                Constants.UserActionType.CHANGE_SHOP,
                userActionMapper,
                date,
                new String[]{user.getUsername(),DateUtil.getPlusTime2(date)},
                JSONObject.toJSONString(member) ,
                model.getShopName(), shop.getName());
    }
    @Override
    @Transactional
    public void updateIntegral(Integral param) {
        if(param.getMemberId()==null || param.getType()==null
                || param.getType()<0
                || param.getType()>2
                || Constants.formatBigdecimal(param.getNum()).compareTo(new BigDecimal(0))<=0){
            throw new BusinessException(ResponseStatus.BAD_REQUEST);
        }
        MPJLambdaWrapper<Member> queryWrapper =new MPJLambdaWrapper<>();
        queryWrapper.selectAll(Member.class);
        queryWrapper.selectAs(Shop::getName,Member::getShopName);
        queryWrapper.leftJoin(Shop.class, Shop::getId,Member::getBindShopId);
        queryWrapper.eq(Member::getId,param.getMemberId());
        Member model = memberMapper.selectJoinOne(Member.class,queryWrapper);
        if(model == null ||Constants.equalsObject(model.getIsdeleted(),Constants.ONE)){
            throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(),"客户信息查询无效!");
        }
        BigDecimal num = param.getNum();
        if(param.getType() == 1 &&Constants.formatBigdecimal(model.getIntegral()).compareTo(param.getNum())<0){
            //如果是减少,判断用户余额是否满足
            num = num.multiply(new BigDecimal(-1));//减少
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(),"用户账户余额不足!");
        }
        LoginUserInfo user = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal();
        Date date = new Date();
        //账户余额
        memberMapper.update(null,new UpdateWrapper<Member>().lambda()
                .eq(Member::getId,model.getId())
                .set(Member::getEditDate,date)
                .set(Member::getEditor,user.getId())
                .setSql(param.getType() == 0,"total_integral = ifnull(total_integral,0)+" + num)//累计增加
                .setSql(param.getType() == 0,"integral = ifnull(integral,0)+" + param.getNum())
                .setSql(param.getType() == 1,"integral = ifnull(integral,0)-" + param.getNum()));
        Constants.IntegralObjType integralObjType = param.getType()==0?Constants.IntegralObjType.SYSTEM_RECHARGE:Constants.IntegralObjType.SYSTEM_DEDUCT;
        Integral integral = new Integral();
        integral.setMemberId(model.getId());
        integral.setCreateDate(new Date());
        integral.setCreator(user.getId());
        integral.setIsdeleted(Constants.ZERO);
        integral.setTitle(integralObjType.getName());
        integral.setContent(integralObjType.getNoteinfo());
        integral.setObjId(model.getId());
        integral.setObjType(integralObjType.getKey());
        integral.setType(param.getType());
        integral.setRemark(param.getRemark());
        integral.setNum(param.getNum());
        integral.setTotalNum(param.getType() == 0? Constants.formatBigdecimal(model.getIntegral()).add(integral.getNum()):Constants.formatBigdecimal(model.getIntegral()).subtract(integral.getNum()));
        integral.setOrderCode(null);
        integral.setUserType(Constants.ZERO);
        integralMapper.insert(integral);
    }
    @Override
    public void updateByIdInBatch(List<Member> members) {
@@ -182,13 +290,15 @@
        MPJLambdaWrapper<Member> queryWrapper = new MPJLambdaWrapper<>();
        Utils.MP.blankToNull(pageWrap.getModel());
        queryWrapper.selectAll(Member.class);
        queryWrapper.selectAs(Shop::getName,Member::getShopName);
        queryWrapper.leftJoin(Shop.class, Shop::getId,Member::getBindShopId);
        queryWrapper.and(StringUtils.isNotBlank(pageWrap.getModel().getNickname()),ms->ms.like(Member::getNickname,pageWrap.getModel().getNickname())
                 .or().like(Member::getName,pageWrap.getModel().getNickname())
                .or().like(Member::getPhone,pageWrap.getModel().getNickname())
        );
        queryWrapper.like(StringUtils.isNotBlank(pageWrap.getModel().getShopName()),Shop::getStatus,pageWrap.getModel().getShopName());
        queryWrapper.eq(pageWrap.getModel().getStatus()!=null,Member::getStatus,pageWrap.getModel().getStatus());
        queryWrapper.eq(Member::getIsdeleted,Constants.ZERO);
        queryWrapper.ge(pageWrap.getModel().getStarttime()!=null, Member::getCreateDate,pageWrap.getModel().getStarttime());
        queryWrapper.le(pageWrap.getModel().getEndtime()!=null,Member::getCreateDate, pageWrap.getModel().getEndtime());
@@ -482,7 +592,7 @@
        Integer mId = Optional.ofNullable(userInfo)
                .map(s -> s.getMemberId())
                .orElseThrow(() -> new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "用户ID缺失"));
                .orElseThrow(() -> new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "客户ID缺失"));
        Member member = new Member();
        member.setId(mId);
        member.setEditor(userInfo.getId());
@@ -614,7 +724,7 @@
            if(phoneNums.size() != members.size()){
                List<String> collect = members.stream().map(s -> s.getPhone()).collect(Collectors.toList());
                List<String> unFindMember = phoneNums.stream().filter(s -> !collect.contains(s)).collect(Collectors.toList());
                throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(),unFindMember.toString()+"不存在该手机号码用户");
                throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(),unFindMember.toString()+"不存在该手机号码客户");
            }
            Map<String, MemberRechargeDTO> collect = dataList.stream().collect(Collectors.toMap(s -> s.getPhone(), s -> s));
            members.forEach(s->{
@@ -659,7 +769,7 @@
        Member member = memberMapper.selectById(memberRechargeDTO.getMemberId());
        //如果扣除金额大于用户拥金额 å–用户剩余金额
        //如果扣除金额大于客户拥金额 å–客户剩余金额
        BigDecimal integralNum = new BigDecimal(memberRechargeDTO.getNum());
        if (Constants.equalsInteger(memberRechargeDTO.getIntegralType(),Constants.ONE)
        && (member.getIntegral().compareTo(integralNum) == -1)
server/dmmall_service/src/main/java/com/doumee/service/business/impl/ShopServiceImpl.java
@@ -15,6 +15,7 @@
import com.doumee.dao.business.*;
import com.doumee.dao.business.join.GoodsorderJoinMapper;
import com.doumee.dao.business.join.MemberJoinMapper;
import com.doumee.dao.business.*;
import com.doumee.dao.business.join.ProductLabelJoinMapper;
import com.doumee.dao.business.model.*;
import com.doumee.dao.business.model.Labels;
@@ -63,6 +64,12 @@
    @Autowired
    private ShopMapper shopMapper;
    @Autowired
    private GoodsMapper goodsMapper;
    @Autowired
    private GoodsSkuMapper goodsSkuMapper;
    @Autowired
    private ShopGoodsRelationMapper shopGoodsRelationMapper;
    @Autowired
    private ShopCommentService shopCommentService;
@@ -338,6 +345,7 @@
    @Override
    public List<Shop> findList(Shop shop) {
        shop.setIsdeleted(Constants.ZERO);
        QueryWrapper<Shop> wrapper = new QueryWrapper<>(shop);
        return shopMapper.selectList(wrapper);
    }
@@ -349,6 +357,10 @@
        Utils.MP.blankToNull(pageWrap.getModel());
        queryWrapper.selectAll(Shop.class);
        if(pageWrap.getModel().getGoodsId()!=null){
            //查询某商品的供货价
            queryWrapper.select("(select s.price from shop_goods_relation s where s.ISDELETED=0 and s.shop_id = t.id and s.GOODS_ID="+pageWrap.getModel().getGoodsId()+") as goodsPrice ");
        }
        queryWrapper.selectAs(Labels::getName,Shop::getBigAreaName);
        queryWrapper.selectAs(Member::getNickname,Shop::getNickName);
        queryWrapper.selectAs(Member::getImgurl,Shop::getMemberImgurl);
@@ -364,7 +376,10 @@
        queryWrapper.eq(pageWrap.getModel().getSaleType()!=null, Shop::getSaleType, pageWrap.getModel().getSaleType());
        queryWrapper.eq(pageWrap.getModel().getStatus()!=null, Shop::getStatus, pageWrap.getModel().getStatus());
        queryWrapper.eq(pageWrap.getModel().getIsrec()!=null, Shop::getIsrec, pageWrap.getModel().getIsrec());
        queryWrapper.orderByDesc(Shop::getCreateDate);
        if(pageWrap.getModel().getGoodsId()!=null){
            queryWrapper.orderByAsc("goodsPrice");
        }
        queryWrapper.orderByDesc(Shop::getId);
        IPage<Shop> result = shopJoinMapper.selectJoinPage(page, Shop.class, queryWrapper);
        String path = systemDictDataBiz.queryByCode(Constants.OSS, Constants.RESOURCE_PATH).getCode()
                + systemDictDataBiz.queryByCode(Constants.OSS, Constants.SHOP_FILE).getCode();
@@ -831,4 +846,44 @@
    @Override
    @Transactional
    public  String setGoodsPrice(Shop dto){
        // æŸ¥è¯¢ç”¨æˆ·
        Shop shop = shopMapper.selectById(dto.getId());
        if (shop == null) {
            throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(),"对不起,供销商信息查询无效!");
        }
        GoodsSku queryGoodsSku=new GoodsSku();
        queryGoodsSku.setGoodsId(dto.getGoodsId());
        queryGoodsSku.setIsdeleted(Constants.ZERO);
        List<GoodsSku> goodsSkuList=goodsSkuMapper.selectList(new QueryWrapper<>(queryGoodsSku));
        if(goodsSkuList==null || goodsSkuList.size() ==0){
            throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(),"对不起,请确认商品信息有效且【销售价】已设置!");
        }
        //默认sku信息
        GoodsSku goodsSku = goodsSkuList.get(0);
        if(Constants.formatBigdecimal(goodsSku.getPrice()).compareTo(Constants.formatBigdecimal(dto.getGoodsPrice())) >=0){
            throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(),"对不起,供货价不允许大于商品销售价!");
        }
        LoginUserInfo user = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal();
        //先删除原来的数据
        shopGoodsRelationMapper.delete(new QueryWrapper<ShopGoodsRelation>().lambda()
                .eq(ShopGoodsRelation::getGoodsId,dto.getGoodsId())
                .eq(ShopGoodsRelation::getShopId,shop.getId())
         );
        ShopGoodsRelation add =new ShopGoodsRelation();
        add.setCreator(user.getId());
        add.setCreateDate(new Date());
        add.setIsdeleted(Constants.ZERO);
        add.setEditor(add.getCreator());
        add.setEditDate(add.getCreateDate());
        add.setShopId(dto.getId());
        add.setGoodsId(dto.getGoodsId());
        add.setGoodsSkuId(goodsSku.getId());
        add.setPrice(dto.getGoodsPrice());
        add.setStatus(Constants.ZERO);
        shopGoodsRelationMapper.insert(add);
        return "操作成功";
    }
}
server/dmmall_service/src/main/java/com/doumee/service/business/impl/UserActionServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,158 @@
package com.doumee.service.business.impl;
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.doumee.core.model.LoginUserInfo;
import com.doumee.core.model.PageData;
import com.doumee.core.model.PageWrap;
import com.doumee.core.utils.Constants;
import com.doumee.core.utils.Utils;
import com.doumee.dao.business.UserActionMapper;
import com.doumee.dao.business.model.Member;
import com.doumee.dao.business.model.UserAction;
import com.doumee.dao.system.model.SystemUser;
import com.doumee.service.business.UserActionService;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.Date;
import java.util.List;
import java.util.Objects;
/**
 * äººå‘˜æ“ä½œè®°å½•日志Service实现
 * @author æ±Ÿè¹„蹄
 * @date 2023/12/14 13:57
 */
@Service
public class UserActionServiceImpl implements UserActionService {
    @Autowired
    private UserActionMapper userActionMapper;
    @Override
    public Integer create(UserAction userAction) {
        userActionMapper.insert(userAction);
        return userAction.getId();
    }
    @Override
    public void deleteById(Integer id) {
        userActionMapper.deleteById(id);
    }
    @Override
    public void delete(UserAction userAction) {
        UpdateWrapper<UserAction> deleteWrapper = new UpdateWrapper<>(userAction);
        userActionMapper.delete(deleteWrapper);
    }
    @Override
    public void deleteByIdInBatch(List<Integer> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return;
        }
        userActionMapper.deleteBatchIds(ids);
    }
    @Override
    public void updateById(UserAction userAction) {
        userActionMapper.updateById(userAction);
    }
    @Override
    public void updateByIdInBatch(List<UserAction> userActions) {
        if (CollectionUtils.isEmpty(userActions)) {
            return;
        }
        for (UserAction userAction: userActions) {
            this.updateById(userAction);
        }
    }
    public static void saveUserActionBiz(LoginUserInfo user,
                                         Integer bizId,
                                         Constants.UserActionType type,
                                         UserActionMapper userActionMapper,
                                         Date date,
                                         String[] params,
                                         String modelInfo,
                                         String before,
                                         String after) {
        String info = type.getInfo();
        if(params!=null){
            for (int i = 0; i < params.length; i++) {
                info = info.replace("${param"+(i+1)+"}",params[i]);
            }
        }
       UserAction userAction=new UserAction();
        userAction.setIsdeleted(Constants.ZERO);
        userAction.setCreateDate(date);
        userAction.setCreator(user.getId());
        userAction.setBeforeStatus(Constants.ZERO);
        userAction.setType(type.getKey());
        userAction.setContent(modelInfo);
        userAction.setRemark(info);
        userAction.setBeforeInfo(before);
        userAction.setAfterInfo(after);
        userAction.setMemberId(bizId+"");
        userActionMapper.insert(userAction);
    }
    @Override
    public UserAction findById(Integer id) {
        return userActionMapper.selectById(id);
    }
    @Override
    public UserAction findOne(UserAction userAction) {
        QueryWrapper<UserAction> wrapper = new QueryWrapper<>(userAction);
        return userActionMapper.selectOne(wrapper);
    }
    @Override
    public List<UserAction> findList(UserAction userAction) {
        QueryWrapper<UserAction> wrapper = new QueryWrapper<>(userAction);
        return userActionMapper.selectList(wrapper);
    }
    @Override
    public PageData<UserAction> findPage(PageWrap<UserAction> pageWrap) {
        IPage<UserAction> page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity());
        MPJLambdaWrapper<UserAction> queryWrapper = new MPJLambdaWrapper<>();
        Utils.MP.blankToNull(pageWrap.getModel());
       UserAction queryModel =  pageWrap.getModel();
        queryWrapper.selectAll(UserAction.class)
                .leftJoin(Member.class,Member::getId,UserAction::getMemberId)
                .leftJoin(SystemUser.class,SystemUser::getId,UserAction::getCreator)
                .selectAs(SystemUser::getRealname,UserAction::getCreateName)
                .selectAs(Member::getName,UserAction::getMemberName)
                .selectAs(Member::getPhone,UserAction::getMobile)
                .like(StringUtils.isNotBlank(queryModel.getCreateName()),SystemUser::getRealname,queryModel.getCreateName())
                .like(StringUtils.isNotBlank(queryModel.getMemberName()),Member::getName,queryModel.getMemberName())
                .like(StringUtils.isNotBlank(queryModel.getMobile()),Member::getPhone,queryModel.getMobile())
                .like(StringUtils.isNotBlank(queryModel.getRemark()),Member::getPhone,queryModel.getRemark())
                .eq(!Objects.isNull(queryModel.getMemberType()),Member::getType,queryModel.getMemberType())
                .eq(!Objects.isNull(queryModel.getBeforeStatus()),UserAction::getBeforeStatus,queryModel.getBeforeStatus())
                .eq(!Objects.isNull(queryModel.getType()),UserAction::getType,queryModel.getType())
                .orderByDesc(UserAction::getCreateDate)
        ;
        IPage<UserAction> result =  userActionMapper.selectJoinPage(page,UserAction.class,queryWrapper);
        if(result!=null &&result.getRecords()!=null){
            for(UserAction model :result.getRecords()){
                model.setTypeName(Constants.UserActionType.getName(model.getType()));
            }
        }
        return PageData.from(result);
    }
    @Override
    public long count(UserAction userAction) {
        QueryWrapper<UserAction> wrapper = new QueryWrapper<>(userAction);
        return userActionMapper.selectCount(wrapper);
    }
}