feat(mall): 增加会员等级和分销等级设置功能
- 新增会员等级和分销等级设置页面
- 实现会员等级和分销等级的更新逻辑
- 优化会员列表页面,增加相关筛选条件
- 调整数据库查询以支持新的筛选条件
7 files modified
1 files added
284 ■■■■ changed files
src/main/java/cc/mrbird/febs/mall/controller/member/AdminMallMemberController.java 13 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/controller/member/ViewMallMemberController.java 15 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/impl/AdminMemberLevelServiceImpl.java 4 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallMemberServiceImpl.java 3 ●●●●● patch | view | raw | blame | history
src/main/resources/mapper/modules/MallMemberMapper.xml 31 ●●●● patch | view | raw | blame | history
src/main/resources/templates/febs/views/modules/mallMember/mallMemberList.html 112 ●●●● patch | view | raw | blame | history
src/main/resources/templates/febs/views/modules/mallMember/sale-level-setting.html 92 ●●●●● patch | view | raw | blame | history
src/main/resources/templates/febs/views/modules/mallMember/vip-level-setting.html 14 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/controller/member/AdminMallMemberController.java
@@ -631,8 +631,17 @@
    @PostMapping("vipLevelSetUpdate")
    public FebsResponse vipLevelSetUpdate(MallMember member) {
        member.setVipLevelTime(new Date());
        mallMemberService.updateById(member);
        MallMember mallMember = mallMemberService.getBaseMapper().selectById(member.getId());
        mallMember.setDirector(member.getDirector());
        mallMemberService.updateById(mallMember);
        return new FebsResponse().success().message("操作成功");
    }
    @PostMapping("saleLevelSetUpdate")
    public FebsResponse saleLevelSetUpdate(MallMember member) {
        MallMember mallMember = mallMemberService.getBaseMapper().selectById(member.getId());
        mallMember.setStoreMaster(member.getStoreMaster());
        mallMemberService.updateById(mallMember);
        return new FebsResponse().success().message("操作成功");
    }
src/main/java/cc/mrbird/febs/mall/controller/member/ViewMallMemberController.java
@@ -403,16 +403,29 @@
    }
    @GetMapping("vipLevelSetting/{id}")
    @RequiresPermissions("updateMemberLevel:update")
    public String vipLevelSetting(@PathVariable(value = "id") String id, Model model) {
        MallMember mallMember = mallMemberMapper.selectById(id);
        Map<String, Object> data = new HashMap<>();
        data.put("id", mallMember.getId());
        data.put("level", mallMember.getLevel());
        data.put("director", mallMember.getDirector());
        model.addAttribute("vipLevelSet", data);
        return FebsUtil.view("modules/mallMember/vip-level-setting");
    }
    @GetMapping("saleLevelSetting/{id}")
    @RequiresPermissions("updateSaleLevel:update")
    public String updateSaleLevel(@PathVariable(value = "id") String id, Model model) {
        MallMember mallMember = mallMemberMapper.selectById(id);
        Map<String, Object> data = new HashMap<>();
        data.put("id", mallMember.getId());
        data.put("storeMaster", mallMember.getStoreMaster());
        model.addAttribute("saleLevelSet", data);
        return FebsUtil.view("modules/mallMember/sale-level-setting");
    }
    @GetMapping("addCoupon/{id}")
    public String addCoupon(@PathVariable long id, Model model) {
//        AdminAgentLevelSetInfoVo data = mallMemberService.getAgentLevelSetInfoByMemberId(id);
src/main/java/cc/mrbird/febs/mall/service/impl/AdminMemberLevelServiceImpl.java
@@ -64,7 +64,7 @@
    public FebsResponse levelAll() {
        List<HappyMemberLevel> happyMemberLevels = happyMemberLevelMapper.selectList(
                new LambdaQueryWrapper<HappyMemberLevel>()
                        .select(HappyMemberLevel::getId, HappyMemberLevel::getName)
                        .select(HappyMemberLevel::getCode, HappyMemberLevel::getName)
                        .orderByAsc(HappyMemberLevel::getId)
        );
        return new FebsResponse().success().data(happyMemberLevels);
@@ -102,7 +102,7 @@
    public FebsResponse saleLevelAll() {
        List<HappySaleLevel> happySaleLevels = happySaleLevelMapper.selectList(
                new LambdaQueryWrapper<HappySaleLevel>()
                        .select(HappySaleLevel::getId, HappySaleLevel::getName)
                        .select(HappySaleLevel::getCode, HappySaleLevel::getName)
                        .orderByAsc(HappySaleLevel::getId)
        );
        return new FebsResponse().success().data(happySaleLevels);
src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallMemberServiceImpl.java
@@ -678,6 +678,9 @@
                    wallet.setMemberId(mallMember.getId());
                    mallMemberWalletMapper.insert(wallet);
                } else {
                    if (MallMember.ACCOUNT_STATUS_DISABLED.equals(mallMember.getAccountStatus())) {
                        throw new FebsException("账号已停用");
                    }
                    mallMember.setSessionKey(sessionKey);
                    this.baseMapper.updateById(mallMember);
                }
src/main/resources/mapper/modules/MallMemberMapper.xml
@@ -53,34 +53,35 @@
        <where>
            <if test="record != null" >
                <if test="record.birthdayQuery!=null">
                    and date_format(m.birthday, '%m-%d') = date_format(#{record.birthdayQuery}, '%m-%d')
                    and date_format(a.birthday, '%m-%d') = date_format(#{record.birthdayQuery}, '%m-%d')
                </if>
                <if test="record.name!=null and record.name!=''">
                    and m.name like concat('%',  #{record.name},'%')
                    and a.name like concat('%',  #{record.name},'%')
                </if>
                <if test="record.account!=null and record.account!=''">
                    and (
                    m.phone like concat('%',  #{record.account},'%')
                    or m.email like concat('%',  #{record.account},'%')
                    or m.bind_phone like concat('%',  #{record.account},'%')
                    or m.invite_id like concat('%',  #{record.account},'%')
                    )
                <if test="record.phone!=null and record.phone!=''">
                    and a.phone like concat('%',  #{record.phone},'%')
                </if>
                <if test="record.accountStatus!=null">
                    and m.account_status = #{record.accountStatus}
                    and a.account_status = #{record.accountStatus}
                </if>
                <if test="record.director!=null">
                    and a.director = #{record.director}
                </if>
                <if test="record.storeMaster!=null">
                    and a.store_master = #{record.storeMaster}
                </if>
                <if test="record.accountType != null" >
                    and m.account_type = #{record.accountType}
                    and a.account_type = #{record.accountType}
                </if>
                <if test="record.level!=null and record.level!=''">
                    and m.level=#{record.level}
                    and a.level=#{record.level}
                </if>
                <if test="record.isSale!=null and record.isSale!=''">
                    and m.is_sale=#{record.isSale}
                <if test="record.checkOrder!=null">
                    and a.check_order=#{record.checkOrder}
                </if>
            </if>
        </where>
        GROUP BY m.id order by m.CREATED_TIME desc
        GROUP BY a.id order by a.CREATED_TIME desc
    </select>
    <select id="getMallMemberInfoById" resultType="cc.mrbird.febs.mall.vo.MallMemberVo">
src/main/resources/templates/febs/views/modules/mallMember/mallMemberList.html
@@ -8,15 +8,43 @@
                            <div class="layui-col-md10">
                                <div class="layui-form-item">
                                    <div class="layui-inline">
                                        <label class="layui-form-label layui-form-label-sm">用户昵称</label>
                                        <label class="layui-form-label layui-form-label-sm">用户名</label>
                                        <div class="layui-input-inline">
                                            <input type="text" placeholder="用户昵称" name="name" autocomplete="off" class="layui-input">
                                            <input type="text" placeholder="用户名" name="name" autocomplete="off" class="layui-input">
                                        </div>
                                    </div>
                                    <div class="layui-inline">
                                        <label class="layui-form-label layui-form-label-sm">手机号码</label>
                                        <label class="layui-form-label layui-form-label-sm">联系方式</label>
                                        <div class="layui-input-inline">
                                            <input type="text" placeholder="手机号码" name="phone" autocomplete="off" class="layui-input">
                                            <input type="text" placeholder="联系方式" name="phone" autocomplete="off" class="layui-input">
                                        </div>
                                    </div>
                                    <div class="layui-inline">
                                        <label class="layui-form-label layui-form-label-sm">会员等级</label>
                                        <div class="layui-input-inline">
                                            <select name="director" class="director-type">
                                                <option value="">请选择</option>
                                            </select>
                                        </div>
                                    </div>
                                    <div class="layui-inline">
                                        <label class="layui-form-label layui-form-label-sm">分销等级</label>
                                        <div class="layui-input-inline">
                                            <select name="storeMaster" class="storeMaster-type">
                                                <option value="">请选择</option>
                                            </select>
                                        </div>
                                    </div>
                                    <div class="layui-inline">
                                        <label class="layui-form-label layui-form-label-sm">状态</label>
                                        <div class="layui-input-inline">
                                            <select name="accountStatus">
                                                <option value="">请选择</option>
                                                <option value="1">启用</option>
                                                <option value="2">停用</option>
                                            </select>
                                        </div>
                                    </div>
                                    <div class="layui-inline">
@@ -61,11 +89,11 @@
    <a lay-event="edit" shiro:hasPermission="user:update"><i
            class="layui-icon febs-edit-area febs-blue">&#xe7a5;</i></a>
</script>
<script type="text/html" id="switchStatus">
<script type="text/html" id="accountStatusSwitch">
    {{# if(d.accountStatus === 1) { }}
    <input type="checkbox" value={{d.id}} lay-text="正常|禁用" checked lay-skin="switch" lay-filter="switchStatus">
    <input type="checkbox" value={{d.id}} lay-text="启用|停用" checked lay-skin="switch" lay-filter="accountStatusSwitch">
    {{# } else { }}
    <input type="checkbox" value={{d.id}} lay-text="正常|禁用" lay-skin="switch" lay-filter="switchStatus">
    <input type="checkbox" value={{d.id}} lay-text="启用|停用" lay-skin="switch" lay-filter="accountStatusSwitch">
    {{# } }}
</script>
<script type="text/html" id="switchStoreMaster">
@@ -111,10 +139,11 @@
        background-color: #5FB878 !important;
    }
</style>
<script type="text/html" id="toolbar">
<script type="text/html" id="memberToolbar">
    <div class="layui-btn-container">
<!--        <button class="layui-btn layui-btn-normal layui-btn-sm" type="button" lay-event="updateReferer">修改推荐人</button>-->
<!--        <button class="layui-btn layui-btn-normal layui-btn-sm" type="button" lay-event="updateVipLevel">修改会员等级</button>-->
        <button class="layui-btn layui-btn-normal layui-btn-sm" type="button" shiro:hasPermission="updateMemberLevel:update" lay-event="updateMemberLevel">修改会员等级</button>
        <button class="layui-btn layui-btn-normal layui-btn-sm" type="button" shiro:hasPermission="updateSaleLevel:update" lay-event="updateSaleLevel">修改分销等级</button>
<!--        <button class="layui-btn layui-btn-normal layui-btn-sm" type="button" lay-event="addCoupon">优惠券派送</button>-->
    </div>
</script>
@@ -144,9 +173,33 @@
            elem: '#febs-member-benefits-list-birthday-start',
            format:'MM-dd'
        });
        //(下拉框)
        $.get(ctx + 'admin/level/levelAll', function (res) {
            var data = res.data;
            for (let k in data)
            {
                $(".director-type").append("<option value='" + data[k].code + "'>" + data[k].name + "</option>");
            }
            layui.use('form', function () {
                var form = layui.form;
                form.render();
            });
        });
        //(下拉框)
        $.get(ctx + 'admin/level/saleLevelAll', function (res) {
            var data = res.data;
            for (let k in data)
            {
                $(".storeMaster-type").append("<option value='" + data[k].code + "'>" + data[k].name + "</option>");
            }
            layui.use('form', function () {
                var form = layui.form;
                form.render();
            });
        });
        // 表格初始化
        initTable();
        initMemberListTable();
        // 初始化表格操作栏各个按钮功能
        table.on('tool(userTable)', function (obj) {
@@ -223,13 +276,13 @@
        }
        function closeAccount(id) {
            febs.get(ctx + 'admin/mallMember/closeAccount/' + id, null, function () {
                febs.alert.success('禁用成功');
                febs.alert.success('操作成功');
                $query.click();
            });
        }
        function openAccount(id) {
            febs.get(ctx + 'admin/mallMember/openAccount/' + id, null, function () {
                febs.alert.success('开启成功');
                febs.alert.success('操作成功');
                $query.click();
            });
        }
@@ -318,12 +371,12 @@
            tableIns.reload({where: getQueryParams(), page: {curr: 1}, initSort: sortObject});
        });
        function initTable() {
        function initMemberListTable() {
            tableIns = febs.table.init({
                elem: $view.find('table'),
                id: 'userTable',
                url: ctx + 'admin/mallMember/getMallMemberList',
                toolbar:"#toolbar",
                toolbar:"#memberToolbar",
                defaultToolbar:[],
                cols: [[
                    {type: 'checkbox'},
@@ -332,7 +385,10 @@
                    {field: 'name', title: '用户名', minWidth: 100,align:'left'},
                    {field: 'realName', title: '真实姓名', minWidth: 100,align:'left'},
                    {field: 'phone', title: '联系方式', minWidth: 150,align:'left'},
                    {field: 'directorName', title: '会员等级', minWidth: 150,align:'left'},
                    {field: 'storeMasterName', title: '分销等级', minWidth: 150,align:'left'},
                    {field: 'inviteId', title: '邀请码', minWidth: 100,align:'left'},
                    {field: 'checkOrder', title: '状态', templet: '#accountStatusSwitch', minWidth: 100,align:'center'},
                    {field: 'checkOrder', title: '核销员', templet: '#checkOrderSwitch', minWidth: 100,align:'center'},
                    {field: 'createdTime', title: '注册时间', minWidth: 180,align:'center'},
                ]]
@@ -379,16 +435,29 @@
                });
            }
            if (layEvent === 'updateVipLevel') {
            if (layEvent === 'updateSaleLevel') {
                var checkData = table.checkStatus('userTable').data;
                if (checkData.length > 1) {
                    febs.alert.warn('每次只能修改一个用户');
                    return;
                }
                // var idList = [];
                // for (var i = 0; i < checkData.length; i++) {
                //     idList.push(checkData[i].id);
                // }
                febs.modal.open('设置分销等级', 'modules/mallMember/saleLevelSetting/' + checkData[0].id, {
                    btn: ['确认', '取消'],
                    yes: function (index, layero) {
                        $('#sale-level-set').find('#submit').trigger('click');
                    },
                    btn2: function () {
                        layer.closeAll();
                    }
                });
            }
            if (layEvent === 'updateMemberLevel') {
                var checkData = table.checkStatus('userTable').data;
                if (checkData.length > 1) {
                    febs.alert.warn('每次只能修改一个用户');
                    return;
                }
                febs.modal.open('设置会员等级', 'modules/mallMember/vipLevelSetting/' + checkData[0].id, {
                    btn: ['确认', '取消'],
                    yes: function (index, layero) {
@@ -485,10 +554,13 @@
                name: $searchForm.find('input[name="name"]').val().trim(),
                phone: $searchForm.find('input[name="phone"]').val().trim(),
                checkOrder: $searchForm.find("select[name='checkOrder']").val(),
                accountStatus: $searchForm.find("select[name='accountStatus']").val(),
                director: $searchForm.find("select[name='director']").val(),
                storeMaster: $searchForm.find("select[name='storeMaster']").val(),
            };
        }
        form.on('switch(switchStatus)', function (data) {
        form.on('switch(accountStatusSwitch)', function (data) {
            if (data.elem.checked) {
                openAccount(data.value);
            } else {
src/main/resources/templates/febs/views/modules/mallMember/sale-level-setting.html
New file
@@ -0,0 +1,92 @@
<style>
    #sale-level-set {
        padding: 20px 25px 25px 0;
    }
    #sale-level-set .layui-treeSelect .ztree li a, .ztree li span {
        margin: 0 0 2px 3px !important;
    }
    #sale-level-set #data-permission-tree-block {
        border: 1px solid #eee;
        border-radius: 2px;
        padding: 3px 0;
    }
    #sale-level-set .layui-treeSelect .ztree li span.button.switch {
        top: 1px;
        left: 3px;
    }
</style>
<div class="layui-fluid" id="sale-level-set">
    <form class="layui-form" action="" lay-filter="sale-level-set-form">
        <div class="layui-form-item febs-hide">
            <label class="layui-form-label febs-form-item-require">id:</label>
            <div class="layui-input-block">
                <input type="text" name="id">
            </div>
        </div>
        <div class="layui-form-item">
            <div class="layui-inline">
                <label class="layui-form-label">分销等级:</label>
                <div class="layui-input-inline">
                    <select lay-verify="required" name="storeMaster" class="sale-level-set-level" id="saleLevelSet">
                        <option value="">请选择</option>
                    </select>
                </div>
            </div>
        </div>
        <div class="layui-form-item febs-hide">
            <button class="layui-btn" lay-submit="" lay-filter="sale-level-set-form-submit" id="submit"></button>
        </div>
    </form>
</div>
<script data-th-inline="javascript">
    layui.use(['febs', 'form', 'formSelects', 'validate', 'treeSelect', 'eleTree'], function () {
        var $ = layui.jquery,
            febs = layui.febs,
            layer = layui.layer,
            formSelects = layui.formSelects,
            treeSelect = layui.treeSelect,
            form = layui.form,
            eleTree = layui.eleTree,
            saleLevelSet = [[${saleLevelSet}]],
            $view = $('#sale-level-set'),
            validate = layui.validate,
            _deptTree;
        form.render();
        initMemberLevel();
        function initMemberLevel() {
            form.val("sale-level-set-form", {
                "id": saleLevelSet.id,
                "storeMaster": saleLevelSet.storeMaster
            });
        }
        //(下拉框)
        $.get(ctx + 'admin/level/saleLevelAll', function (res) {
            var data = res.data;
            for (var k in data)
            {
                $(".sale-level-set-level").append("<option value='" + data[k].code + "'>" + data[k].name + "</option>");
            }
            layui.use('form', function () {
                var form = layui.form;
                $("#saleLevelSet").val(saleLevelSet.storeMaster)
                form.render();
            });
        });
        form.on('submit(sale-level-set-form-submit)', function (data) {
            febs.post(ctx + 'admin/mallMember/saleLevelSetUpdate', data.field, function () {
                layer.closeAll();
                febs.alert.success('操作成功');
                $('#febs-member-list').find('#query').click();
            });
            return false;
        });
    });
</script>
src/main/resources/templates/febs/views/modules/mallMember/vip-level-setting.html
@@ -29,7 +29,7 @@
            <div class="layui-inline">
                <label class="layui-form-label">会员等级:</label>
                <div class="layui-input-inline">
                    <select lay-verify="required" name="level" class="vip-level-set-level" id="levelSet">
                    <select lay-verify="required" name="director" class="vip-level-set-level" id="levelSet">
                        <option value="">请选择</option>
                    </select>
                </div>
@@ -57,17 +57,17 @@
        form.render();
        initUserValue();
        initMemberLevel();
        function initUserValue() {
        function initMemberLevel() {
            form.val("vip-level-set-form", {
                "id": vipLevelSet.id,
                "level": vipLevelSet.level
                "director": vipLevelSet.director
            });
        }
        //(下拉框)
        $.get(ctx + 'admin/vip/config/allList', function (res) {
        $.get(ctx + 'admin/level/levelAll', function (res) {
            var data = res.data;
            for (var k in data)
            {
@@ -75,7 +75,7 @@
            }
            layui.use('form', function () {
                var form = layui.form;
                $("#levelSet").val(vipLevelSet.level)
                $("#levelSet").val(vipLevelSet.director)
                form.render();
            });
        });
@@ -84,7 +84,7 @@
            febs.post(ctx + 'admin/mallMember/vipLevelSetUpdate', data.field, function () {
                layer.closeAll();
                febs.alert.success('操作成功');
                $('#febs-member-list').find('#reset').click();
                $('#febs-member-list').find('#query').click();
            });
            return false;
        });