Browse Source

banner 设置

licailing 3 years ago
parent
commit
bfe58bbe5a

+ 3 - 0
src/main/java/com/izouma/nineth/domain/Banner.java

@@ -45,4 +45,7 @@ public class Banner extends BaseEntity {
 
     @ApiModelProperty("跳转内容")
     private String linkContent;
+
+    @ApiModelProperty("配置id")
+    private Long settingId;
 }

+ 33 - 0
src/main/java/com/izouma/nineth/domain/Setting.java

@@ -0,0 +1,33 @@
+package com.izouma.nineth.domain;
+
+import io.swagger.annotations.ApiModel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Entity;
+import javax.persistence.Transient;
+import java.util.ArrayList;
+import java.util.List;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@Entity
+@ApiModel("配置")
+public class Setting extends BaseEntity {
+    private int flag;
+
+    private String name;
+
+    private String pic;
+
+    private String description;
+
+    private Long parent;
+
+    @Transient
+    private List<Setting> children = new ArrayList<>();
+}

+ 22 - 0
src/main/java/com/izouma/nineth/repo/SettingRepo.java

@@ -0,0 +1,22 @@
+package com.izouma.nineth.repo;
+
+import com.izouma.nineth.domain.Setting;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+
+import javax.transaction.Transactional;
+import java.util.List;
+
+public interface SettingRepo extends JpaRepository<Setting, Long>, JpaSpecificationExecutor<Setting> {
+    @Query("update Setting t set t.del = true where t.id = ?1")
+    @Modifying
+    @Transactional
+    void softDelete(Long id);
+
+    @Query(nativeQuery = true, value = "SELECT ifnull(max(flag + 1),1) FROM setting")
+    int nextSort();
+
+    List<Setting> findAllByFlag(int flag);
+}

+ 48 - 0
src/main/java/com/izouma/nineth/service/SettingService.java

@@ -0,0 +1,48 @@
+package com.izouma.nineth.service;
+
+import com.alibaba.fastjson.JSON;
+import com.izouma.nineth.domain.Setting;
+import com.izouma.nineth.dto.PageQuery;
+import com.izouma.nineth.repo.SettingRepo;
+import com.izouma.nineth.utils.JpaUtils;
+import lombok.AllArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+
+@Service
+@AllArgsConstructor
+public class SettingService {
+
+    private SettingRepo settingRepo;
+
+    public Page<Setting> all(PageQuery pageQuery) {
+        return settingRepo.findAll(JpaUtils.toSpecification(pageQuery, Setting.class), JpaUtils.toPageRequest(pageQuery));
+    }
+
+    public List<Setting> getTree(List<Setting> list1) {
+        String s = JSON.toJSONString(list1);
+        List<Setting> list = JSON.parseArray(s, Setting.class);
+        Map<Long, Setting> dtoMap = new HashMap<>();
+        for (Setting node : list) {
+            dtoMap.put(node.getId(), node);
+        }
+
+        List<Setting> resultList = new ArrayList<>();
+        for (Map.Entry<Long, Setting> entry : dtoMap.entrySet()) {
+            Setting node = entry.getValue();
+            if (node.getParent() == null) {
+                // 如果是顶层节点,直接添加到结果集合中
+                resultList.add(node);
+            } else {
+                // 如果不是顶层节点,找其父节点,并且添加到父节点的子节点集合中
+                if (dtoMap.get(node.getParent()) != null) {
+                    dtoMap.get(node.getParent()).getChildren().add(node);
+                }
+            }
+        }
+        resultList.sort(Comparator.comparing(Setting::getId));
+        return resultList;
+    }
+}

+ 81 - 0
src/main/java/com/izouma/nineth/web/SettingController.java

@@ -0,0 +1,81 @@
+package com.izouma.nineth.web;
+
+import cn.hutool.core.collection.CollUtil;
+import com.izouma.nineth.domain.Setting;
+import com.izouma.nineth.service.SettingService;
+import com.izouma.nineth.dto.PageQuery;
+import com.izouma.nineth.exception.BusinessException;
+import com.izouma.nineth.repo.SettingRepo;
+import com.izouma.nineth.utils.ObjUtils;
+import com.izouma.nineth.utils.excel.ExcelUtils;
+import lombok.AllArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.List;
+
+@RestController
+@RequestMapping("/setting")
+@AllArgsConstructor
+public class SettingController extends BaseController {
+    private SettingService settingService;
+    private SettingRepo    settingRepo;
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/save")
+    public Setting save(@RequestBody Setting record) {
+        if (record.getId() != null) {
+            Setting orig = settingRepo.findById(record.getId()).orElseThrow(new BusinessException("无记录"));
+            ObjUtils.merge(orig, record);
+            return settingRepo.save(orig);
+        }
+
+        if (record.getParent() == null) {
+            record.setFlag(settingRepo.nextSort());
+        }
+        return settingRepo.save(record);
+    }
+
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/all")
+    public Page<Setting> all(@RequestBody PageQuery pageQuery) {
+        return settingService.all(pageQuery);
+    }
+
+    @GetMapping("/get/{id}")
+    public Setting get(@PathVariable Long id) {
+        return settingRepo.findById(id).orElseThrow(new BusinessException("无记录"));
+    }
+
+    @PostMapping("/del/{id}")
+    public void del(@PathVariable Long id) {
+        settingRepo.softDelete(id);
+    }
+
+    @GetMapping("/excel")
+    @ResponseBody
+    public void excel(HttpServletResponse response, PageQuery pageQuery) throws IOException {
+        List<Setting> data = all(pageQuery).getContent();
+        ExcelUtils.export(response, data);
+    }
+
+    @PostMapping("/allList")
+    public List<Setting> allList() {
+        return settingService.getTree(settingRepo.findAll());
+    }
+
+    @PostMapping("/byFlag")
+    public List<Setting> byFlag(int flag) {
+        List<Setting> tree = settingService.getTree(settingRepo.findAllByFlag(flag));
+        if (CollUtil.isEmpty(tree)) {
+            return null;
+        }
+        return tree.get(0).getChildren();
+    }
+
+}
+

+ 1 - 0
src/main/resources/genjson/Setting.json

@@ -0,0 +1 @@
+{"tableName":"Setting","className":"Setting","remark":"其他配置","genTable":true,"genClass":true,"genList":false,"genForm":false,"genRouter":false,"javaPath":"/Users/qiufangchao/Desktop/project/raex_back/src/main/java/com/izouma/nineth","viewPath":"/Users/qiufangchao/Desktop/project/raex_back/src/main/vue/src/views","routerPath":"/Users/qiufangchao/Desktop/project/raex_back/src/main/vue/src","resourcesPath":"/Users/qiufangchao/Desktop/project/raex_back/src/main/resources","dataBaseType":"Mysql","fields":[{"name":"name","modelName":"name","remark":"名称","showInList":true,"showInForm":true,"formType":"singleLineText"},{"name":"pic","modelName":"pic","remark":"图片","showInList":true,"showInForm":true,"formType":"singleLineText"},{"name":"description","modelName":"description","remark":"描述","showInList":true,"showInForm":true,"formType":"singleLineText"}],"readTable":false,"dataSourceCode":"dataSource","genJson":"","subtables":[],"update":false,"basePackage":"com.izouma.nineth","tablePackage":"com.izouma.nineth.domain.Setting"}

+ 39 - 28
src/main/vue/src/router.js

@@ -444,72 +444,75 @@ const router = new Router({
                     name: 'MintActivityEdit',
                     component: () => import(/* webpackChunkName: "mintActivityEdit" */ '@/views/MintActivityEdit.vue'),
                     meta: {
-                       title: '铸造活动编辑',
-                    },
+                        title: '铸造活动编辑'
+                    }
                 },
                 {
                     path: '/mintActivityList',
                     name: 'MintActivityList',
                     component: () => import(/* webpackChunkName: "mintActivityList" */ '@/views/MintActivityList.vue'),
                     meta: {
-                       title: '铸造活动',
-                    },
-               },
+                        title: '铸造活动'
+                    }
+                },
                 {
                     path: '/mintOrderEdit',
                     name: 'MintOrderEdit',
                     component: () => import(/* webpackChunkName: "mintOrderEdit" */ '@/views/MintOrderEdit.vue'),
                     meta: {
-                       title: '铸造订单编辑',
-                    },
+                        title: '铸造订单编辑'
+                    }
                 },
                 {
                     path: '/mintOrderList',
                     name: 'MintOrderList',
                     component: () => import(/* webpackChunkName: "mintOrderList" */ '@/views/MintOrderList.vue'),
                     meta: {
-                       title: '铸造订单',
-                    },
-               },
+                        title: '铸造订单'
+                    }
+                },
                 {
                     path: '/purchaseLevelEdit',
                     name: 'PurchaseLevelEdit',
-                    component: () => import(/* webpackChunkName: "purchaseLevelEdit" */ '@/views/PurchaseLevelEdit.vue'),
+                    component: () =>
+                        import(/* webpackChunkName: "purchaseLevelEdit" */ '@/views/PurchaseLevelEdit.vue'),
                     meta: {
-                       title: '会员等级编辑',
-                    },
+                        title: '会员等级编辑'
+                    }
                 },
                 {
                     path: '/purchaseLevelList',
                     name: 'PurchaseLevelList',
-                    component: () => import(/* webpackChunkName: "purchaseLevelList" */ '@/views/PurchaseLevelList.vue'),
+                    component: () =>
+                        import(/* webpackChunkName: "purchaseLevelList" */ '@/views/PurchaseLevelList.vue'),
                     meta: {
-                       title: '会员等级',
-                    },
-               },
+                        title: '会员等级'
+                    }
+                },
                 {
                     path: '/newsEdit',
                     name: 'NewsEdit',
                     component: () => import(/* webpackChunkName: "newsEdit" */ '@/views/NewsEdit.vue'),
                     meta: {
-                       title: '新闻管理编辑',
-                    },
+                        title: '新闻管理编辑'
+                    }
                 },
                 {
                     path: '/newsList',
                     name: 'NewsList',
                     component: () => import(/* webpackChunkName: "newsList" */ '@/views/NewsList.vue'),
                     meta: {
-                       title: '新闻管理',
-                    },
-               },
+                        title: '新闻管理'
+                    }
+                },
                 {
                     path: '/adapayMerchantEdit',
                     name: 'AdapayMerchantEdit',
-                    component: () => import(/* webpackChunkName: "adapayMerchantEdit" */ '@/views/AdapayMerchantEdit.vue'),
+                    component: () =>
+                        import(/* webpackChunkName: "adapayMerchantEdit" */ '@/views/AdapayMerchantEdit.vue'),
                     meta: {
-                        title: 'ada编辑',
-                    },
+                        title: 'ada编辑'
+                    }
                 },
                 {
                     path: '/adapayMerchantList',
@@ -534,15 +537,23 @@ const router = new Router({
                     component: () => import(/* webpackChunkName: "showroomList" */ '@/views/ShowroomList.vue'),
                     meta: {
                         title: '展厅'
-                    },
+                    }
                 },
                 {
                     path: '/querySettle',
                     name: 'QuerySettle',
                     component: () => import(/* webpackChunkName: "querySettle" */ '@/views/QuerySettle.vue'),
                     meta: {
-                        title: '结算查询',
-                    },
+                        title: '结算查询'
+                    }
+                },
+                {
+                    path: '/settings',
+                    name: 'Settings',
+                    component: () => import(/* webpackChunkName: "settings" */ '@/views/Settings.vue'),
+                    meta: {
+                        title: '结算查询'
+                    }
                 }
                 /**INSERT_LOCATION**/
             ]

+ 26 - 3
src/main/vue/src/views/BannerEdit.vue

@@ -39,6 +39,11 @@
                             </el-option>
                         </el-select>
                     </el-form-item>
+                    <el-form-item prop="settingId" label="分类" v-if="formData.type == 'MARKET'">
+                        <el-select v-model="formData.settingId">
+                            <el-option v-for="item in settings" :key="item.id" :label="item.name" :value="item.id"></el-option>
+                        </el-select>
+                    </el-form-item>
                     <el-form-item prop="link" label="跳转">
                         <el-switch v-model="formData.link"></el-switch>
                     </el-form-item>
@@ -53,8 +58,16 @@
                         </el-select>
                     </el-form-item>
                     <el-form-item prop="linkContent" label="跳转内容" v-if="formData.link">
-                        <el-input v-if="formData.linkType === 'collections'" v-model="formData.linkContent" placeholder="输入藏品名称"></el-input>
-                        <el-input v-else-if="formData.linkType === 'hyperlink'" v-model="formData.linkContent" placeholder="输入链接"></el-input>
+                        <el-input
+                            v-if="formData.linkType === 'collections'"
+                            v-model="formData.linkContent"
+                            placeholder="输入藏品名称"
+                        ></el-input>
+                        <el-input
+                            v-else-if="formData.linkType === 'hyperlink'"
+                            v-model="formData.linkContent"
+                            placeholder="输入链接"
+                        ></el-input>
                         <el-input v-else v-model="formData.linkContent" placeholder="输入ID"></el-input>
                     </el-form-item>
                     <el-form-item class="form-submit">
@@ -84,6 +97,15 @@ export default {
                     this.$message.error(e.error);
                 });
         }
+        this.$http
+            .post('/setting/byFlag', { flag: 1 })
+            .then(res => {
+                this.settings = res;
+            })
+            .catch(e => {
+                console.log(e);
+                this.$message.error(e.error);
+            });
     },
     data() {
         return {
@@ -144,7 +166,8 @@ export default {
                 { label: '活动', value: 'activity' },
                 { label: '多个藏品', value: 'collections' },
                 { label: '指定链接', value: 'hyperlink' }
-            ]
+            ],
+            settings: []
         };
     },
     methods: {

+ 386 - 0
src/main/vue/src/views/Settings.vue

@@ -0,0 +1,386 @@
+<template>
+    <div>
+        <el-row :gutter="20">
+            <el-col :span="12">
+                <div class="menu-tree">
+                    <el-tree
+                        :data="menus"
+                        :render-content="renderContent"
+                        :highlight-current="true"
+                        :expand-on-click-node="true"
+                        node-key="id"
+                        v-loading="loading"
+                        accordion
+                        @node-click="nodeClick"
+                        :default-expanded-keys="expandKeys"
+                        :default-checked-keys="expandKeys"
+                    >
+                    </el-tree>
+                    <el-button type="text" @click="addRootMenu" style="margin-left: 24px;">添加 </el-button>
+                </div>
+            </el-col>
+            <transition name="el-fade-in">
+                <el-col :span="12" v-if="dialogVisible">
+                    <div class="menu-tree">
+                        <div style="font-weight:bold;padding:10px 0">{{ menu.id ? '编辑' : '新增' }}</div>
+                        <el-form :model="menu" ref="form" label-position="top">
+                            <el-form-item
+                                label="名称"
+                                prop="name"
+                                :rules="[{ required: true, message: '请填写名称', trigger: 'blur' }]"
+                            >
+                                <el-input v-model="menu.name"></el-input>
+                            </el-form-item>
+                            <el-form-item label="图片" prop="pic" v-if="menu.parent">
+                                <single-upload v-model="menu.pic"></single-upload>
+                            </el-form-item>
+                            <el-form-item label="备注" prop="description">
+                                <el-input v-model="menu.description"></el-input>
+                            </el-form-item>
+                        </el-form>
+                        <div slot="footer">
+                            <el-button @click="dialogVisible = false">取消 </el-button>
+                            <el-button type="primary" @click="addMenu" :loading="loading">保存 </el-button>
+                        </div>
+                    </div>
+                </el-col>
+            </transition>
+        </el-row>
+    </div>
+</template>
+<script>
+import SingleUpload from '../components/SingleUpload.vue';
+export default {
+    created() {
+        this.getData()
+    },
+    data() {
+        return {
+            dialogVisible: false,
+            curr: null,
+            loading: false,
+            menus: [],
+            menu: {
+                name: '',
+                pic: '',
+                description: ''
+            },
+            parent: null,
+            currentRef: null,
+            edit: false,
+            expandKeys: [],
+            authorities: []
+        };
+    },
+    methods: {
+        addRootMenu() {
+            this.menu = {
+                name: '',
+                pic: '',
+                description: ''
+            };
+            this.parent = null;
+            this.icon = 'bars';
+            this.dialogVisible = true;
+            setTimeout(() => {
+                this.showIcon('bars');
+            }, 100);
+        },
+        showAddDialog(node, data) {
+            this.edit = false;
+            this.parent = node.data;
+            this.menu = {
+                parent: node.data.id,
+                flag: node.data.flag,
+                name: '',
+                pic: '',
+                description: ''
+            };
+            this.dialogVisible = true;
+        },
+        showEditDialog(node, data) {
+            this.edit = true;
+            this.currentRef = node.data;
+            this.menu = {
+                ...data
+            };
+            this.dialogVisible = true;
+        },
+        addMenu() {
+            this.$refs.form.validate(valid => {
+                if (valid) {
+                    this.loading = true;
+                    let menu = { ...this.menu };
+                    delete menu.children;
+                    this.$http
+                        .post('/setting/save', menu, { body: 'json' })
+                        .then(res => {
+                            this.loading = false;
+                            this.$message.success('添加成功');
+                            this.dialogVisible = false;
+                            this.getData();
+                        })
+                        .catch(e => {
+                            console.log(e);
+                            this.loading = false;
+                            this.$message.error(e.error);
+                        });
+                }
+            });
+        },
+        remove(node, data) {
+            console.log(node);
+            this.$confirm('确定删除菜单?', '提示', {
+                confirmButtonText: '确定',
+                cancelButtonText: '取消',
+                type: 'error'
+            })
+                .then(() => {
+                    return this.$http.post(
+                        '/setting/save',
+                        {
+                            ...data,
+                            del: true,
+                            children: null
+                        },
+                        { body: 'json' }
+                    );
+                })
+                .then(res => {
+                    this.$message.success('删除成功');
+                    this.getData();
+                })
+                .catch(e => {
+                    this.loading = false;
+                    if (e !== 'cancel') {
+                        console.log(e);
+                        this.$message.error(e.error);
+                    }
+                });
+        },
+        moveUp(node, data) {
+            if (node.previousSibling) {
+                this.loading = true;
+                let sort0 = node.previousSibling.data.sort,
+                    sort1 = node.data.sort;
+                Promise.all([
+                    this.$http.post(
+                        '/setting/save',
+                        {
+                            ...node.data,
+                            children: null,
+                            sort: sort0
+                        },
+                        { body: 'json' }
+                    ),
+                    this.$http.post(
+                        '/setting/save',
+                        {
+                            ...node.previousSibling.data,
+                            children: null,
+                            sort: sort1
+                        },
+                        { body: 'json' }
+                    )
+                ])
+                    .then(_ => {
+                        this.loading = false;
+                        this.getData();
+                    })
+                    .catch(e => {
+                        console.log(e);
+                        this.loading = false;
+                        this.$message.error(e.error);
+                    });
+            }
+        },
+        moveDown(node, data) {
+            if (node.nextSibling) {
+                this.loading = true;
+                let sort0 = node.data.sort,
+                    sort1 = node.nextSibling.data.sort;
+                Promise.all([
+                    this.$http.post(
+                        '/setting/save',
+                        {
+                            ...node.data,
+                            children: null,
+                            sort: sort1
+                        },
+                        { body: 'json' }
+                    ),
+                    this.$http.post(
+                        '/setting/save',
+                        {
+                            ...node.nextSibling.data,
+                            children: null,
+                            sort: sort0
+                        },
+                        { body: 'json' }
+                    )
+                ])
+                    .then(_ => {
+                        this.loading = false;
+                        this.getData();
+                    })
+                    .catch(e => {
+                        console.log(e);
+                        this.loading = false;
+                        this.$message.error(e.error);
+                    });
+            }
+        },
+        getData() {
+            this.$http
+                .post('/setting/allList')
+                .then(res => {
+                    this.menus = res;
+                })
+                .catch(e => {
+                    console.log(e);
+                    this.$message.error(e.error);
+                });
+        },
+        renderContent(h, { node, data, store }) {
+            return (
+                <span
+                    class={
+                        this.menu.id == data.id || (this.menu.parent == data.id && !this.menu.id)
+                            ? 'custom-tree-node selected'
+                            : 'custom-tree-node'
+                    }
+                >
+                    <span>{data.name}</span>
+                    <span class="url">{data.description}</span>
+                    <span class="opt">
+                        <el-button
+                            type="text"
+                            on-click={e => {
+                                this.showEditDialog(node, data), e.stopPropagation();
+                            }}
+                            icon="el-icon-edit"
+                        >
+                            编辑
+                        </el-button>
+                        <el-button
+                            type="text"
+                            on-click={e => {
+                                this.showAddDialog(node, data), e.stopPropagation();
+                            }}
+                            icon="el-icon-plus"
+                        >
+                            添加
+                        </el-button>
+                        <el-button
+                            type="text"
+                            on-click={e => {
+                                this.remove(node, data), e.stopPropagation();
+                            }}
+                            icon="el-icon-delete"
+                        >
+                            删除
+                        </el-button>
+                    </span>
+                </span>
+            );
+        },
+        showIcon(val) {
+            if (!this.$refs.iconContainer) return;
+            if (FontAwesome.icon({ prefix: 'fas', iconName: val })) {
+                this.$refs.iconContainer.innerHTML = '';
+                let i = document.createElement('i');
+                i.className = 'fas fa-' + val;
+                this.$refs.iconContainer.append(i);
+                FontAwesome.dom.i2svg();
+                this.menu.icon = 'fas fa-' + val;
+            } else if (FontAwesome.icon({ prefix: 'fab', iconName: val })) {
+                this.$refs.iconContainer.innerHTML = '';
+                let i = document.createElement('i');
+                i.className = 'fab fa-' + val;
+                this.$refs.iconContainer.append(i);
+                FontAwesome.dom.i2svg();
+                this.menu.icon = 'fab fa-' + val;
+            } else {
+                this.$refs.iconContainer.innerHTML = '';
+                let i = document.createElement('i');
+                i.className = 'fab fa-' + val;
+                this.$refs.iconContainer.append(i);
+                FontAwesome.dom.i2svg();
+                this.menu.icon = '';
+            }
+        },
+        nodeClick(data, node, el) {
+            if (this.expandKeys[0] != data.id) {
+                this.expandKeys = [data.id];
+            }
+        }
+    },
+    watch: {
+        icon(val) {
+            this.showIcon(val);
+        },
+        category() {
+            this.getData();
+        }
+    }
+};
+</script>
+<style lang="less" scoped>
+.menu-tree {
+    border-radius: 4px;
+    background: white;
+    margin-top: 20px;
+    padding: 10px;
+}
+</style>
+<style lang="less">
+.menu-tree {
+    .el-tree-node__content {
+        height: 40px;
+        line-height: 40px;
+    }
+}
+.custom-tree-node {
+    flex: 1;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    font-size: 14px;
+    padding-right: 8px;
+    line-height: 40px;
+    height: 40px;
+    .url {
+        flex-grow: 1;
+        text-align: right;
+        margin-right: 20px;
+        color: #999;
+    }
+    .opt {
+        opacity: 0;
+    }
+    &.selected {
+        border: 2px solid #409eff;
+        border-radius: 4px;
+        padding: 0 10px;
+        box-sizing: border-box;
+        .opt {
+            opacity: 1;
+        }
+    }
+}
+
+.custom-tree-node:hover {
+    .opt {
+        opacity: 1;
+    }
+}
+
+.available-icons {
+    color: #409eff;
+    text-decoration: none;
+    &:hover {
+        color: #409eff;
+        text-decoration: none;
+    }
+}
+</style>