Zory 2 weken geleden
bovenliggende
commit
c1b0036b19

+ 2 - 2
src/api/model/auth.js

@@ -3,14 +3,14 @@ import http from "@/utils/request"
 
 export default {
     login: {
-        url: `${config.API_URL}/upload/data`,
+        url: `${config.API_URL}/login/user`,
         name: "-",
         post: async function(data, config={}){
             return await http.post(this.url, data, config);
         }
     },
     user: {
-        url: `${config.API_URL}/system/dic/get`,
+        url: `${config.API_URL}/login/profile`,
         name: "-",
         get: async function(params){
             return await http.get(this.url, params);

+ 19 - 0
src/api/model/menu.js

@@ -0,0 +1,19 @@
+import config from "@/config"
+import http from "@/utils/request"
+
+export default {
+    list: {
+        url: `${config.API_URL}/menu/list`,
+        name: "-",
+        get: async function(data={}){
+            return await http.get(this.url, data);
+        }
+    },
+    save: {
+        url: `${config.API_URL}/menu/save`,
+        name: "-",
+        post: async function(data={}){
+            return await http.post(this.url, data);
+        }
+    }
+}

+ 1 - 0
src/layout/components/userbar.vue

@@ -67,6 +67,7 @@ export default {
 	},
 	created() {
 		var userInfo = this.$TOOL.data.get("USER_INFO");
+		console.log("userInfo",userInfo)
 		this.userName = userInfo.truename;
 		this.userNameF = this.userName.substring(0, 1);
 		var baseData = this.$TOOL.data.get("SERVICE");

+ 2 - 2
src/router/systemRouter.js

@@ -2,7 +2,7 @@ import config from "@/config"
 import tool from "@/utils/tool";
 
 
-var dashboard = "/";
+var dashboard = "/dashboard";
 
 //系统路由
 const routes = [
@@ -10,7 +10,7 @@ const routes = [
 		name: "layout",
 		path: "/",
 		component: () => import(/* webpackChunkName: "layout" */ '@/layout'),
-		redirect: config.DASHBOARD_URL || dashboard,
+		redirect: config.DASHBOARD_URL,
 		children: []
 	},
 	{

+ 1 - 10
src/views/dashboard/index.vue

@@ -1,15 +1,6 @@
 <template>
 	<div class="router-err">
-		<div class="router-err__icon">
-			<img src="img/404.png" />
-		</div>
-		<div class="router-err__content">
-			<h2>无权限或找不到页面</h2>
-			<p>当前页面无权限访问或者打开了一个不存在的链接,请检查当前账户权限和链接的可访问性。</p>
-			<el-button type="primary" plain round @click="gohome">返回首页</el-button>
-			<el-button type="primary" plain round @click="gologin">重新登录</el-button>
-			<el-button type="primary" round @click="goback">返回上一页</el-button>
-		</div>
+		
 	</div>
 </template>
 

+ 0 - 19
src/views/login/components/passwd.vue

@@ -15,25 +15,10 @@
 				</template>
 			</el-input>
         </el-form-item>
-        <el-form-item prop="privacy">
-            <el-checkbox :label="$t('login.rememberMe')" v-model="form.privacy">
-                <template #default>
-                    <div class="privacy">我已阅读并同意<span @click="showPrivacy">《用户协议》</span></div>
-                </template>
-            </el-checkbox>
-        </el-form-item>
         <el-form-item>
             <el-button type="primary" size="large" style="width: 100%;" :loading="islogin" @click="onSuccess">{{ $t('login.signIn') }}</el-button>
         </el-form-item>
     </el-form>
-	<el-dialog title="用户协议" v-model="visible" :width="680" destroy-on-close :close-on-click-modal="false" :show-close="false">
-		<div class="showPrivacy">
-			<div v-html="baseData.privacy"></div>
-		</div>
-		<template #footer>
-			<el-button type="primary" @click="showPrivacyState">我已阅读并同意</el-button>
-		</template>
-	</el-dialog>
 </template>
 <script>
 export default {
@@ -54,9 +39,6 @@ export default {
 				],
 				code: [
 					{ required: true, message: this.$t('login.codeErr'), trigger: 'blur' }
-				],
-				privacy: [
-					{ required: true, message: this.$t('login.privacy'), trigger: 'change' }
 				]
 			},
         }
@@ -126,7 +108,6 @@ export default {
 				this.$message.warning(menu.message)
 				return false
 			}
-			var userType = userData.data.type;
 			this.$emit("success");
 			this.$message.success(user.msg)
 			this.$router.replace({

+ 268 - 0
src/views/setting/index/index.vue

@@ -0,0 +1,268 @@
+<template>
+    <el-container>
+        <el-main>
+            <el-card shadow="never" header="系统设置" class="borderNone mt10">
+                <el-tabs v-model="activeName" class="demo-tabs" @tab-change="handleClick">
+                    <el-tab-pane label="基础设置" name="service" v-loading="isLoading">
+                        <el-form :model="sys" :rules="rules" ref="form" label-position="top" @keyup.enter="saveForm">
+                            <el-form-item label="系统名称" prop="title" class="label-item">
+                                <el-input v-model="sys.title" placeholder="请输入" clearable />
+                                <div class="el-form-item-msg"></div>
+                            </el-form-item>
+                            <el-form-item label="客服联系电话" prop="tel" class="label-item">
+                                <el-input v-model="sys.tel" placeholder="请输入" clearable />
+                                <div class="el-form-item-msg"></div>
+                            </el-form-item>
+                            <el-form-item label="系统Logo" prop="logo">
+                                <sc-upload v-model="sys.logo"></sc-upload>
+                            </el-form-item>
+                            <el-form-item label="营业执照" prop="license">
+                                <sc-upload v-model="sys.license"></sc-upload>
+                                <div class="el-form-item-msg">小程序端资质展示使用</div>
+                            </el-form-item>
+                            <el-form-item label="备案号" prop="miitbeian" class="label-item">
+                                <el-input v-model="sys.miitbeian" placeholder="请输入" clearable />
+                                <div class="el-form-item-msg">支持Html格式</div>
+                            </el-form-item>
+                            <el-form-item label="版权信息" prop="copyright" class="label-item">
+                                <el-input v-model="sys.copyright" placeholder="请输入" clearable />
+                                <div class="el-form-item-msg"></div>
+                            </el-form-item>
+                            <el-form-item label="隐私协议" prop="privacy" class="label-item">
+                                <sc-editor v-model="sys.privacy" placeholder="请输入" :height="400"></sc-editor>
+                                <div class="el-form-item-msg"></div>
+                            </el-form-item>
+                            <el-form-item label="服务协议" prop="agreements" class="label-item">
+                                <sc-editor v-model="sys.agreements" placeholder="请输入" :height="400"></sc-editor>
+                                <div class="el-form-item-msg"></div>
+                            </el-form-item>
+                        </el-form>
+                    </el-tab-pane>
+                    <el-tab-pane label="抖音设置" name="wechat" v-loading="isLoading">
+                        <el-form :model="sys" :rules="rules2" ref="form" label-position="top" @keyup.enter="saveForm" v-if="activeName=='wechat'">
+                            <el-row :gutter="15">
+                                <el-col :span="this.$store.state.global.ismobile?24:12">
+                                    <fieldset>
+                                        <legend><el-tag>小程序配置</el-tag></legend>
+                                        <el-form-item label="AppId(小程序 APPID)" prop="mini_appid">
+                                            <el-input v-model="sys.mini_appid" clearable placeholder="请输入"></el-input>
+                                            <div class="el-form-item-msg">小程序后台获取</div>
+                                        </el-form-item>
+                                        <el-form-item label="AppSecret(小程序密钥)" prop="mini_secret">
+                                            <el-input v-model="sys.mini_secret" show-password clearable placeholder="请输入"></el-input>
+                                            <div class="el-form-item-msg">小程序后台获取</div>
+                                        </el-form-item>
+                                        <el-form-item label="应用公钥" prop="mini_public_key">
+                                            <el-input v-model="sys.mini_public_key" type="textarea" rows="10" show-password clearable placeholder="请输入"></el-input>
+                                            <div class="el-form-item-msg"></div>
+                                        </el-form-item>
+                                        <el-form-item label="应用私钥" prop="min_private_key">
+                                            <el-input v-model="sys.min_private_key" type="textarea" rows="10" show-password clearable placeholder="请输入"></el-input>
+                                            <div class="el-form-item-msg"></div>
+                                        </el-form-item>
+                                    </fieldset>
+                                </el-col>
+                                <el-col :span="this.$store.state.global.ismobile?24:12">
+                                    <fieldset>
+                                        <legend><el-tag>支付配置</el-tag></legend>
+                                        <el-form-item label="MCH_ID(商户账号)" prop="mch_id">
+                                            <el-input v-model="sys.mch_id" clearable placeholder="请输入"></el-input>
+                                            <div class="el-form-item-msg">微信商户账号,需要在微信商户平台获取,MCH_ID 与 APPID 匹配</div>
+                                        </el-form-item>
+                                        <el-form-item label="Token(支付令牌)" prop="mch_token">
+                                            <el-input v-model="sys.mch_token" show-password clearable placeholder="请输入"></el-input>
+                                            <div class="el-form-item-msg"></div>
+                                        </el-form-item>
+                                        <el-form-item label="Salt(支付盐)" prop="mch_salt">
+                                            <el-input v-model="sys.mch_salt" show-password clearable placeholder="请输入"></el-input>
+                                            <div class="el-form-item-msg"></div>
+                                        </el-form-item>
+                                        <el-form-item label="应用公钥" prop="app_public_key">
+                                            <el-input v-model="sys.app_public_key" type="textarea" rows="10" show-password clearable placeholder="请输入"></el-input>
+                                            <div class="el-form-item-msg"></div>
+                                        </el-form-item>
+                                        <el-form-item label="平台公钥" prop="public_key">
+                                            <el-input v-model="sys.public_key" type="textarea" rows="10" show-password clearable placeholder="请输入"></el-input>
+                                            <div class="el-form-item-msg"></div>
+                                        </el-form-item>
+                                    </fieldset>
+                                </el-col>
+                                <el-col :span="this.$store.state.global.ismobile?24:12">
+                                    <fieldset>
+                                        <legend><el-tag>商家应用权限</el-tag></legend>
+                                        <el-form-item label="应用名称" prop="name">
+                                            <el-input v-model="sys.name" clearable placeholder="请输入"></el-input>
+                                            <div class="el-form-item-msg">应用名称</div>
+                                        </el-form-item>
+                                        <el-form-item label="商家ID" prop="shop_id">
+                                            <el-input v-model="sys.shop_id" clearable placeholder="请输入"></el-input>
+                                            <div class="el-form-item-msg">来客商家ID</div>
+                                        </el-form-item>
+                                        <el-form-item label="AppId(应用 APPID)" prop="appid">
+                                            <el-input v-model="sys.appid" show-password clearable placeholder="请输入"></el-input>
+                                            <div class="el-form-item-msg"></div>
+                                        </el-form-item>
+                                        <el-form-item label="AppSecret(应用 Secret)" prop="secret">
+                                            <el-input v-model="sys.secret" show-password clearable placeholder="请输入"></el-input>
+                                            <div class="el-form-item-msg"></div>
+                                        </el-form-item>
+                                    </fieldset>
+                                </el-col>
+                                <el-col :span="this.$store.state.global.ismobile?24:12">
+                                    <fieldset>
+                                        <legend><el-tag>其他</el-tag></legend>
+                                        <el-form-item label="云打印机AppId" prop="ex_appid">
+                                            <el-input v-model="sys.ex_appid" show-password clearable placeholder="请输入"></el-input>
+                                            <div class="el-form-item-msg"></div>
+                                        </el-form-item>
+                                        <el-form-item label="云打印机密钥" prop="ex_secret">
+                                            <el-input v-model="sys.ex_secret" show-password clearable placeholder="请输入"></el-input>
+                                            <div class="el-form-item-msg"></div>
+                                        </el-form-item>
+                                        <el-form-item label="云打印机模版ID" prop="ex_print">
+                                            <el-input v-model="sys.ex_print" clearable placeholder="请输入"></el-input>
+                                            <div class="el-form-item-msg"></div>
+                                        </el-form-item>
+                                        <el-form-item label="快递AppKey" prop="kd_appkey">
+                                            <el-input v-model="sys.kd_appkey" clearable placeholder="请输入"></el-input>
+                                            <div class="el-form-item-msg"></div>
+                                        </el-form-item>
+                                        <el-form-item label="快递AppSecret" prop="kd_secret">
+                                            <el-input v-model="sys.kd_secret" show-password clearable placeholder="请输入"></el-input>
+                                            <div class="el-form-item-msg"></div>
+                                        </el-form-item>
+                                        <el-form-item label="快递AppCode" prop="kd_code">
+                                            <el-input v-model="sys.kd_code" show-password clearable placeholder="请输入"></el-input>
+                                            <div class="el-form-item-msg"></div>
+                                        </el-form-item>
+                                    </fieldset>
+                                </el-col>
+                            </el-row>
+                        </el-form>
+                    </el-tab-pane>
+                    
+                </el-tabs>
+            </el-card>
+        </el-main>
+        <el-footer>
+            <el-button type="primary" size="large" :loading="isSaveing" @click="saveForm">保存</el-button>
+        </el-footer>
+    </el-container>
+</template>
+<script>
+import { defineAsyncComponent } from 'vue';
+const scEditor = defineAsyncComponent(() => import('@/components/scEditor'));
+export default {
+    components: {
+        scEditor
+    },
+    data(){
+        return {
+            activeName:"service",
+            isSaveing: false,
+            sys: {},
+            smsRegion:[],
+            rules2:{
+                name: [
+                    { required: true, message: '请输入' }
+                ],
+                shop_id: [
+                    { required: true, message: '请输入' }
+                ],
+                appid: [
+                    { required: true, message: '请输入' }
+                ],
+                secret: [
+                    { required: true, message: '请输入' }
+                ],
+                mch_id: [
+                    { required: true, message: '请输入' }
+                ],
+                mch_token: [
+                    { required: true, message: '请输入' }
+                ],
+                mch_salt: [
+                    { required: true, message: '请输入' }
+                ],
+                mini_secret: [
+                    { required: true, message: '请输入' }
+                ],
+                mini_public_key: [
+                    { required: true, message: '请输入' }
+                ],
+                min_private_key: [
+                    { required: true, message: '请输入' }
+                ],
+            },
+            rules: {
+                title: [
+                    { required: true, message: '请输入' }
+                ],
+                tel: [
+                    { required: true, message: '请输入' }
+                ],
+                logo: [
+                    { required: true, message: '请选择', trigger:"change" }
+                ],
+                miitbeian: [
+                    { required: true, message: '请输入' }
+                ],
+                beian: [
+                    { required: true, message: '请输入' }
+                ],
+                copyright: [
+                    { required: true, message: '请输入' }
+                ],
+                license: [
+                    { required: true, message: '请上传' }
+                ],
+            },
+            isLoading:false
+        }
+    },
+    created() {
+        this.getConfig();
+    },
+    methods: {
+        handleClick(event){
+            this.activeName = event;
+            this.getConfig();
+        },
+        saveForm() {
+            this.isSaveing = true;
+            this.$refs.form.validate(async (valid) => {
+                console.log(valid)
+                if (valid) {
+                    var result = await this.$API.setting.configSave.post({type:this.activeName,data: this.sys });
+                    this.isSaveing = false;
+                    if(result.code == 0)
+                    {
+                        this.$message.error(result.msg);
+                        return false;
+                    }
+                    if (this.activeName == "service") {
+                        this.$TOOL.data.set("SERVICE", this.sys)
+                    }
+                    this.$message.success(result.msg);
+                } else {
+                    this.isSaveing = false;
+                    return false;
+                }
+            })
+        },
+        async getConfig() {
+            this.isLoading = true;
+            var result = await this.$API.setting.config.get({ type: this.activeName });
+            this.isLoading = false;
+            if (result.code == 0) {
+                this.$message.error(result.msg);
+                return;
+            }
+            if (this.activeName == "sms") {
+                this.smsRegion = result.data.channel
+            }
+            this.sys = result.data;
+        },
+    }
+}
+</script>

+ 167 - 0
src/views/setting/menu/index.vue

@@ -0,0 +1,167 @@
+<template>
+    <el-container>
+		<el-aside width="300px" v-loading="menuloading">
+			<el-container>
+				<el-header>
+					<el-input placeholder="输入关键字进行过滤" v-model="menuFilterText" clearable></el-input>
+				</el-header>
+				<el-main class="nopadding">
+					<el-tree ref="menu" class="menu" node-key="id" :data="menuList" :props="menuProps" draggable highlight-current :expand-on-click-node="false" check-strictly :filter-node-method="menuFilterNode" @node-click="menuClick" @node-drop="nodeDrop">
+						<template #default="{node, data}">
+							<span class="custom-tree-node">
+								<span class="label">
+									{{ node.label }}
+								</span>
+								<span class="do">
+									<el-button icon="el-icon-plus" size="small" @click.stop="add(node, data)"></el-button>
+								</span>
+							</span>
+						</template>
+					</el-tree>
+				</el-main>
+				<el-footer style="height:51px;">
+					<el-button type="primary" size="small" icon="el-icon-plus" @click="add()"></el-button>
+					<el-button type="danger" size="small" plain icon="el-icon-delete" @click="delMenu"></el-button>
+				</el-footer>
+			</el-container>
+		</el-aside>
+		<el-container>
+			<el-main class="nopadding" style="padding:20px;" ref="main">
+				<save ref="save" @success="getMenu" :type="activeName" :menu="menuList"></save>
+			</el-main>
+		</el-container>
+	</el-container>
+</template>
+
+<script>
+let newMenuIndex = 1;
+import save from './save'
+export default {
+    name: 'settingMenu',
+    components: {
+        save
+    },
+    data() {
+        return {
+            activeName:1,
+            menuloading: false,
+            menuList: [],
+            menuProps: {
+                label: (data)=>{
+                    return data.meta.title
+                }
+            },
+            menuFilterText: ""
+        }
+    },
+    watch: {
+        menuFilterText(val){
+            this.$refs.menu.filter(val);
+        }
+    },
+    mounted() {
+        this.getMenu();
+    },
+    methods: {
+        handleClick(e){
+            this.activeName = e;
+            this.getMenu();
+        },
+        //加载树数据
+        async getMenu(){
+            this.menuloading = true
+            var res = await this.$API.menu.list.get({"form":this.activeName,"type":2});
+            this.menuloading = false
+            if(res.code == 1)
+            {
+                this.menuList = res.data;
+            }
+        },
+        //树点击
+        menuClick(data, node){
+            var pid = node.level==1?undefined:node.parent.data.id;
+            this.$refs.save.setData(data, pid)
+            this.$refs.main.$el.scrollTop = 0
+        },
+        //树过滤
+        menuFilterNode(value, data){
+            if (!value) return true;
+            var targetText = data.meta.title;
+            return targetText.indexOf(value) !== -1;
+        },
+        //树拖拽
+        nodeDrop(draggingNode, dropNode, dropType){
+            this.$refs.save.setData({})
+            this.$message(`拖拽对象:${draggingNode.data.meta.title}, 释放对象:${dropNode.data.meta.title}, 释放对象的位置:${dropType}`)
+        },
+        //增加
+        async add(node, data){
+            var newMenuName = "未命名" + newMenuIndex++;
+            var newMenuData = {
+                pid: data ? data.id : 0,
+                title: newMenuName,
+                from:this.activeName,
+                path: "",
+                component: "",
+                type: "menu"
+            }
+            this.menuloading = true
+            var res = await this.$API.menu.save.post(newMenuData)
+            this.menuloading = false
+            if(res.code !== 1){
+                this.$message.warning(res.msg);
+                return ;
+            }
+            this.getMenu();
+        },
+        //删除菜单
+        async delMenu(){
+            var CheckedNodes = this.$refs.menu.getCheckedNodes()
+            if(CheckedNodes.length == 0){
+                this.$message.warning("请选择需要删除的项")
+                return false;
+            }
+
+            var confirm = await this.$confirm('确认删除已选择的菜单吗?','提示', {
+                type: 'warning',
+                confirmButtonText: '删除',
+                confirmButtonClass: 'el-button--danger'
+            }).catch(() => {})
+            if(confirm != 'confirm'){
+                return false
+            }
+
+            this.menuloading = true
+            var reqData = {
+                ids: CheckedNodes.map(item => item.id)
+            }
+            var res = await this.$API.demo.post.post(reqData)
+            this.menuloading = false
+
+            if(res.code == 200){
+                CheckedNodes.forEach(item => {
+                    var node = this.$refs.menu.getNode(item)
+                    if(node.isCurrent){
+                        this.$refs.save.setData({})
+                    }
+                    this.$refs.menu.remove(item)
+                })
+            }else{
+                this.$message.warning(res.message)
+            }
+        }
+    }
+}
+</script>
+<style scoped>
+	.menu:deep(.el-tree-node__label) {display: flex;flex: 1;height:100%;}
+	.custom-tree-node {display: flex;flex: 1;align-items: center;justify-content: space-between;font-size: 14px;height:100%;padding-right:24px;}
+	.custom-tree-node .label {display: flex;align-items: center;;height: 100%;}
+	.custom-tree-node .label .el-tag {margin-left: 5px;}
+	.custom-tree-node .do {display: none;}
+	.custom-tree-node .do i {margin-left:5px;color: #999;}
+	.custom-tree-node .do i:hover {color: #333;}
+
+	.custom-tree-node:hover .do {display: inline-block;}
+    .tabs{padding: 0 10px;}
+</style>

+ 160 - 0
src/views/setting/menu/save.vue

@@ -0,0 +1,160 @@
+<template>
+	<el-row :gutter="40">
+		<el-col v-if="!form.id">
+			<el-empty description="请选择左侧菜单后操作" :image-size="100"></el-empty>
+		</el-col>
+		<template v-else>
+			<el-col :lg="12">
+				<h2>{{form.meta.title || "新增菜单"}}</h2>
+				<el-form :model="form" :rules="rules" ref="dialogForm" label-width="80px" label-position="left">
+					<el-form-item label="显示名称" prop="form.title">
+						<el-input v-model="form.title" clearable placeholder="菜单显示名字"></el-input>
+					</el-form-item>
+					<el-form-item label="上级菜单" prop="pid">
+						<el-cascader v-model="form.pid" :options="menuOptions" :props="menuProps" :show-all-levels="false" placeholder="顶级菜单" clearable disabled></el-cascader>
+					</el-form-item>
+					<el-form-item label="类型" prop="form.type">
+						<el-radio-group v-model="form.type">
+							<el-radio-button label="menu">菜单</el-radio-button>
+							<el-radio-button label="iframe">Iframe</el-radio-button>
+							<el-radio-button label="link">外链</el-radio-button>
+							<el-radio-button label="button">按钮</el-radio-button>
+						</el-radio-group>
+					</el-form-item>
+					<el-form-item label="类型" prop="form.hide">
+						<el-radio-group v-model="form.hide">
+							<el-radio-button :label="1">显示</el-radio-button>
+							<el-radio-button :label="2">隐藏</el-radio-button>
+						</el-radio-group>
+					</el-form-item>
+					<el-form-item label="别名" prop="name">
+						<el-input v-model="form.name" clearable placeholder="菜单别名"></el-input>
+						<div class="el-form-item-msg">系统唯一且与内置组件名一致,否则导致缓存失效。如类型为Iframe的菜单,别名将代替源地址显示在地址栏</div>
+					</el-form-item>
+					<el-form-item label="菜单图标" prop="meta.icon">
+						<sc-icon-select v-model="form.icon" clearable></sc-icon-select>
+					</el-form-item>
+					<el-form-item label="路由地址" prop="path">
+						<el-input v-model="form.path" clearable placeholder=""></el-input>
+					</el-form-item>
+					<el-form-item label="视图" prop="component">
+						<el-input v-model="form.component" clearable placeholder="">
+							<template #prepend>views/</template>
+						</el-input>
+						<div class="el-form-item-msg">如父节点、链接或Iframe等没有视图的菜单不需要填写</div>
+					</el-form-item>
+					<el-form-item label="排序" prop="sort">
+						<el-input v-model="form.sort" clearable placeholder=""></el-input>
+					</el-form-item>
+					<el-form-item>
+						<el-button type="primary" size="large" @click="save" :loading="loading">保 存</el-button>
+					</el-form-item>
+				</el-form>
+
+			</el-col>
+		</template>
+	</el-row>
+
+</template>
+
+<script>
+	import scIconSelect from '@/components/scIconSelect'
+
+	export default {
+		components: {
+			scIconSelect
+		},
+        emits: ['success'],
+		props: {
+			menu: { type: Object, default: () => {} },
+			type: { type: String, default: "" },
+		},
+		data(){
+			return {
+				form: {
+					id: "",
+					pid: "",
+					name: "",
+					path: "",
+					component: "",
+					redirect: "",
+					apiList: []
+				},
+				menuOptions: [],
+				menuProps: {
+					value: 'id',
+					label: 'title',
+					checkStrictly: true
+				},
+				predefineColors: [
+					'#ff4500',
+					'#ff8c00',
+					'#ffd700',
+					'#67C23A',
+					'#00ced1',
+					'#409EFF',
+					'#c71585'
+				],
+				rules: [],
+				apiListAddTemplate: {
+					code: "",
+					url: ""
+				},
+				loading: false
+			}
+		},
+		watch: {
+			menu: {
+				handler(){
+					this.menuOptions = this.treeToMap(this.menu)
+				},
+				deep: true
+			}
+		},
+		mounted() {
+
+		},
+		methods: {
+			//简单化菜单
+			treeToMap(tree){
+				const map = []
+				tree.forEach(item => {
+					var obj = {
+						id: item.id,
+						parentId: item.parentId,
+						title: item.meta.title,
+						children: item.children&&item.children.length>0 ? this.treeToMap(item.children) : null
+					}
+					map.push(obj)
+				})
+				return map
+			},
+			//保存
+			async save(){
+				this.loading = true
+				var res = await this.$API.menu.save.post(this.form)
+				this.loading = false
+				if(res.code == 1){
+                    this.$emit('success')
+					this.$message.success(res.msg)
+				}else{
+					this.$message.warning(res.msg)
+				}
+			},
+			//表单注入数据
+			setData(data, pid){
+				this.form = data
+				this.form.apiList = data.apiList || []
+				this.form.parentId = pid
+			}
+		}
+	}
+</script>
+
+<style scoped>
+	h2 {font-size: 17px;color: #3c4a54;padding:0 0 30px 0;}
+	.apilist {border-left: 1px solid #eee;}
+
+	[data-theme="dark"] h2 {color: #fff;}
+	[data-theme="dark"] .apilist {border-color: #434343;}
+</style>

+ 6 - 0
src/views/setting/role/index.vue

@@ -0,0 +1,6 @@
+<template>
+
+</template>
+<script>
+
+</script>

+ 312 - 0
src/views/setting/storage/index.vue

@@ -0,0 +1,312 @@
+<template>
+    <el-container>
+        <el-main>
+            <el-card shadow="never" header="存储配置" class="borderNone">
+                <el-form :model="sys" :rules="rules" ref="form" label-position="top">
+                    <div class="tip-container">
+                        <el-alert title="文件将存储在本地服务器,默认保存在 public/upload 目录,文件以 HASH 命名。" show-icon description="文件存储的目录需要有读写权限,有足够的存储空间。特别注意,本地存储暂不支持图片压缩!" type="info" :closable="false" v-if="typeChange == 'public'" />
+                        <el-alert title="文件将上传到 七牛云 存储" description="对象存储需要配置为公开访问的 Bucket 空间" show-icon type="info" :closable="false" v-if="typeChange == 'qiniu'" />
+                        <el-alert title="文件将上传到 阿里云 OSS 存储,需要配置 OSS 公开访问及跨域策略" description="配置跨域访问 CORS 规则,设置:来源 Origin 为 *,允许 Methods 为 POST,允许 Headers 为 *" show-icon type="info" :closable="false" v-if="typeChange == 'oss'" />
+                        <el-alert title="文件将上传到 腾讯云 COS 存储,需要配置 COS 公有读私有写访问权限及跨域策略" description="配置跨域访问 CORS 规则,设置来源 Origin 为 *,允许 Methods 为 POST,允许 Headers 为 *" show-icon type="info" :closable="false" v-if="typeChange == 'cos'" />
+                    </div>
+                    <el-form-item label="默认上传方式:" prop="type" class="label-item">
+                        <el-col :span="11" :xs="24">
+                            <el-radio-group v-model="sys.type" @change="checkType">
+                                <el-radio label="public" border>本地 (不推荐)</el-radio>
+                                <el-radio label="qiniu" border>七牛云</el-radio>
+                                <el-radio label="oss" border>阿里云</el-radio>
+                                <el-radio label="cos" border>腾讯云</el-radio>
+                            </el-radio-group>
+                        </el-col>
+                    </el-form-item>
+                    <el-form-item label="允许类型:" prop="allow_exts" class="label-item">
+                        <el-col :span="11" :xs="24">
+                            <el-input v-model="sys.allow_exts" placeholder="请输入允许类型"></el-input>
+                        </el-col>
+                        <div class="el-form-item-msg">设置系统允许上传文件的后缀,多个以英文逗号隔开如:png,jpg,rar,doc,未设置允许上传的后缀</div>
+                    </el-form-item>
+                    <div v-if="typeChange == 'public'">
+                    </div>
+                    <div v-if="typeChange == 'qiniu'">
+                        <el-form-item label="访问协议:" prop="qiniu_http_protocol" class="label-item">
+                            <el-col :span="11" :xs="24">
+                                <el-radio-group v-model="sys.qiniu_http_protocol">
+                                    <el-radio label="http" border>HTTP</el-radio>
+                                    <el-radio label="https" border>HTTPS</el-radio>
+                                    <el-radio label="auto" border>AUTO</el-radio>
+                                </el-radio-group>
+                            </el-col>
+                            <div class="el-form-item-msg">七牛云存储访问协议,其中 HTTPS 需要配置证书才能使用( AUTO 为相对协议 )</div>
+                        </el-form-item>
+                        <el-form-item label="存储区域:" prop="qiniu_region" class="label-item">
+                            <el-col :span="11" :xs="24">
+                                <el-select v-model="sys.qiniu_region" style="width: 100%;" placeholder="请选择存储区域" size="large">
+                                    <el-option
+                                        v-for="(item, index) in qiniuRegin"
+                                        :key="index"
+                                        :label="item"
+                                        :value="index"
+                                    />
+                                </el-select>
+                            </el-col>
+                            <div class="el-form-item-msg">七牛云存储空间所在区域,需要严格对应储存所在区域才能上传文件</div>
+                        </el-form-item>
+                        <el-form-item label="空间名称:" prop="qiniu_bucket" class="label-item">
+                            <el-col :span="11" :xs="24">
+                                <el-input v-model="sys.qiniu_bucket" placeholder="请输入空间名称"></el-input>
+                            </el-col>
+                            <div class="el-form-item-msg">填写七牛云存储空间名称,如:static</div>
+                        </el-form-item>
+                        <el-form-item label="访问域名:" prop="qiniu_http_domain" class="label-item">
+                            <el-col :span="11" :xs="24">
+                                <el-input v-model="sys.qiniu_http_domain" placeholder="请输入访问域名"></el-input>
+                            </el-col>
+                            <div class="el-form-item-msg">填写七牛云存储访问域名,如:static.qiniu.tempfood.cn</div>
+                        </el-form-item>
+                        <el-form-item label="访问密钥:" prop="qiniu_access_key" class="label-item">
+                            <el-col :span="11" :xs="24">
+                                <el-input v-model="sys.qiniu_access_key" placeholder="请输入访问密钥"></el-input>
+                            </el-col>
+                            <div class="el-form-item-msg">可以在 [ 七牛云 > 个人中心 ] 设置并获取到访问密钥</div>
+                        </el-form-item>
+                        <el-form-item label="安全密钥:" prop="qiniu_secret_key" class="label-item">
+                            <el-col :span="11" :xs="24">
+                                <el-input v-model="sys.qiniu_secret_key" placeholder="请输入安全密钥"></el-input>
+                            </el-col>
+                            <div class="el-form-item-msg">可以在 [ 七牛云 > 个人中心 ] 设置并获取到安全密钥</div>
+                        </el-form-item>
+                    </div>
+                    <div v-if="typeChange == 'oss'">
+                        <el-form-item label="访问协议:" prop="oss_http_protocol" class="label-item">
+                            <el-col :span="11" :xs="24">
+                                <el-radio-group v-model="sys.oss_http_protocol">
+                                    <el-radio label="http" size="large">HTTP</el-radio>
+                                    <el-radio label="https" size="large">HTTPS</el-radio>
+                                    <el-radio label="auto" size="large">AUTO</el-radio>
+                                </el-radio-group>
+                            </el-col>
+                            <div class="el-form-item-msg">阿里云OSS存储访问协议,其中 HTTPS 需要配置证书才能使用(AUTO 为相对协议)</div>
+                        </el-form-item>
+                        <el-form-item label="存储区域:" prop="oss_region" class="label-item">
+                            <el-col :span="11" :xs="24">
+                                <el-select v-model="sys.oss_region" style="width: 100%;" placeholder="请选择存储区域" size="large">
+                                    <el-option
+                                        v-for="(item, index) in ossRegin"
+                                        :key="index"
+                                        :label="item"
+                                        :value="index"
+                                    />
+                                </el-select>
+                            </el-col>
+                            <div class="el-form-item-msg">阿里云存储空间所在区域,需要严格对应储存所在区域才能上传文件</div>
+                        </el-form-item>
+                        <el-form-item label="空间名称:" prop="oss_bucket" class="label-item">
+                            <el-col :span="11" :xs="24">
+                                <el-input v-model="sys.oss_bucket" placeholder="请输入空间名称"></el-input>
+                            </el-col>
+                            <div class="el-form-item-msg">填写阿里云存储空间名称,如:static</div>
+                        </el-form-item>
+                        <el-form-item label="访问域名:" prop="oss_http_domain" class="label-item">
+                            <el-col :span="11" :xs="24">
+                                <el-input v-model="sys.oss_http_domain" placeholder="请输入访问域名"></el-input>
+                            </el-col>
+                            <div class="el-form-item-msg">填写阿里云存储访问域名,如:static.qiniu.tempfood.cn</div>
+                        </el-form-item>
+                        <el-form-item label="访问密钥:" prop="oss_access_key" class="label-item">
+                            <el-col :span="11" :xs="24">
+                                <el-input v-model="sys.oss_access_key" placeholder="请输入访问密钥"></el-input>
+                            </el-col>
+                            <div class="el-form-item-msg">可以在 [ 阿里云 > 个人中心 ] 设置并获取到访问密钥</div>
+                        </el-form-item>
+                        <el-form-item label="安全密钥:" prop="oss_secret_key" class="label-item">
+                            <el-col :span="11" :xs="24">
+                                <el-input v-model="sys.oss_secret_key" placeholder="请输入安全密钥"></el-input>
+                            </el-col>
+                            <div class="el-form-item-msg">可以在 [ 阿里云 > 个人中心 ] 设置并获取到安全密钥</div>
+                        </el-form-item>
+                    </div>
+                    <div v-if="typeChange == 'cos'">
+                        <el-form-item label="访问协议:" prop="cos_http_protocol" class="label-item">
+                            <el-col :span="11" :xs="24">
+                                <el-radio-group v-model="sys.cos_http_protocol">
+                                    <el-radio label="http" size="large">HTTP</el-radio>
+                                    <el-radio label="https" size="large">HTTPS</el-radio>
+                                    <el-radio label="auto" size="large">AUTO</el-radio>
+                                </el-radio-group>
+                            </el-col>
+                            <div class="el-form-item-msg">阿里云OSS存储访问协议,其中 HTTPS 需要配置证书才能使用(AUTO 为相对协议)</div>
+                        </el-form-item>
+                        <el-form-item label="存储区域:" prop="cos_region" class="label-item">
+                            <el-col :span="11" :xs="24">
+                                <el-select v-model="sys.cos_region" style="width: 100%;" placeholder="请选择存储区域" size="large">
+                                    <el-option
+                                        v-for="(item, index) in cosRegin"
+                                        :key="index"
+                                        :label="item"
+                                        :value="index"
+                                    />
+                                </el-select>
+                            </el-col>
+                            <div class="el-form-item-msg">腾讯云存储空间所在区域,需要严格对应储存所在区域才能上传文件</div>
+                        </el-form-item>
+                        <el-form-item label="空间名称:" prop="cos_bucket" class="label-item">
+                            <el-col :span="11" :xs="24">
+                                <el-input v-model="sys.cos_bucket" placeholder="请输入空间名称"></el-input>
+                            </el-col>
+                            <div class="el-form-item-msg">填写腾讯云存储空间名称,如:static</div>
+                        </el-form-item>
+                        <el-form-item label="访问域名:" prop="cos_http_domain" class="label-item">
+                            <el-col :span="11" :xs="24">
+                                <el-input v-model="sys.cos_http_domain" placeholder="请输入访问域名"></el-input>
+                            </el-col>
+                            <div class="el-form-item-msg">填写腾讯云存储访问域名,如:static.tempfood.cn</div>
+                        </el-form-item>
+                        <el-form-item label="访问密钥:" prop="cos_access_key" class="label-item">
+                            <el-col :span="11" :xs="24">
+                                <el-input v-model="sys.cos_access_key" placeholder="请输入访问密钥"></el-input>
+                            </el-col>
+                            <div class="el-form-item-msg">可以在 [ 腾讯云 > 个人中心 ] 设置并获取到访问密钥</div>
+                        </el-form-item>
+                        <el-form-item label="安全密钥:" prop="cos_secret_key" class="label-item">
+                            <el-col :span="11" :xs="24">
+                                <el-input v-model="sys.cos_secret_key" placeholder="请输入安全密钥"></el-input>
+                            </el-col>
+                            <div class="el-form-item-msg">可以在 [ 腾讯云 > 个人中心 ] 设置并获取到安全密钥</div>
+                        </el-form-item>
+                    </div>
+                </el-form>
+            </el-card>
+        </el-main>
+        <el-footer>
+            <el-button type="primary" size="large" :loading="isSaveing" @click="saveForm">保存</el-button>
+        </el-footer>
+    </el-container>
+</template>
+
+<script>
+
+export default {
+    data() {
+        return {
+            isSaveing: false,
+            sys: {},
+            configList: [],
+            rules: {
+                type: [
+                    { required: true, message: '请选择上传方式', trigger: 'change' }
+                ],
+                allow_exts: [
+                    { required: true, message: '请输入允许类型', trigger: 'blur' }
+                ],
+                qiniu_http_protocol: [
+                    { required: true, message: '请选择访问协议', trigger: 'change' }
+                ],
+                oss_http_protocol: [
+                    { required: true, message: '请选择访问协议', trigger: 'change' }
+                ],
+                cos_http_protocol: [
+                    { required: true, message: '请选择访问协议', trigger: 'change' }
+                ],
+                qiniu_region: [
+                    { required: true, message: '请选择存储区域', trigger: 'change' }
+                ],
+                oss_region: [
+                    { required: true, message: '请选择存储区域', trigger: 'change' }
+                ],
+                cos_region: [
+                    { required: true, message: '请选择存储区域', trigger: 'change' }
+                ],
+                qiniu_bucket: [
+                    { required: true, message: '请输入空间名称', trigger: 'blur' }
+                ],
+                oss_bucket: [
+                    { required: true, message: '请输入空间名称', trigger: 'blur' }
+                ],
+                cos_bucket: [
+                    { required: true, message: '请输入空间名称', trigger: 'blur' }
+                ],
+                qiniu_http_domain: [
+                    { required: true, message: '请输入访问域名', trigger: 'blur' }
+                ],
+                oss_http_domain: [
+                    { required: true, message: '请输入访问域名', trigger: 'blur' }
+                ],
+                cos_http_domain: [
+                    { required: true, message: '请输入访问域名', trigger: 'blur' }
+                ],
+                qiniu_access_key: [
+                    { required: true, message: '请输入访问密钥', trigger: 'blur' }
+                ],
+                oss_access_key: [
+                    { required: true, message: '请输入访问密钥', trigger: 'blur' }
+                ],
+                cos_access_key: [
+                    { required: true, message: '请输入访问密钥', trigger: 'blur' }
+                ],
+                qiniu_secret_key: [
+                    { required: true, message: '请输入安全密钥', trigger: 'blur' }
+                ],
+                oss_secret_key: [
+                    { required: true, message: '请输入安全密钥', trigger: 'blur' }
+                ],
+                cos_secret_key: [
+                    { required: true, message: '请输入安全密钥', trigger: 'blur' }
+                ],
+            },
+            typeChange:"public",
+            ossRegin:[],
+            cosRegin:[],
+            qiniuRegin: [],
+        }
+    },
+    created() {
+        this.getConfig();
+        this.getRegin();
+    },
+    methods: {
+        checkType(val){
+            this.typeChange = val;
+        },
+        saveForm() {
+            this.isSaveing = true;
+            this.$refs.form.validate(async (valid) => {
+                if (valid) {
+                    var result = await this.$API.setting.configSave.post({type:"storage",data: this.sys });
+                    this.isSaveing = false;
+                    if(result.code == 0)
+                    {
+                        this.$message.error(result.msg);
+                        return false;
+                    }
+                    this.$message.success(result.msg);
+                } else {
+                    this.isSaveing = false;
+                    return false;
+                }
+            })
+        },
+        async getConfig() {
+            var result = await this.$API.setting.config.get({ type: "storage" });
+            if (result.code == 0) {
+                this.$message.error(result.msg);
+                return;
+            }
+            this.typeChange = result.data.type;
+            this.sys = result.data;
+        },
+        async getRegin() {
+            var result = await this.$API.setting.regin.get();
+            if (result.code == 0) {
+                this.$message.error(result.msg);
+                return;
+            }
+            this.ossRegin = result.data.oss;
+            this.cosRegin = result.data.cos;
+            this.qiniuRegin = result.data.qiniu;
+        }
+    }
+}
+
+</script>
+<style>
+</style>

+ 6 - 0
src/views/setting/user/index.vue

@@ -0,0 +1,6 @@
+<template>
+
+</template>
+<script>
+
+</script>