Commit bb8e4f0d authored by zhangtong5@yidian-inc.com's avatar zhangtong5@yidian-inc.com

update:角色创建&&修改UI完善&&基础功能完善

parents 3ccbf34a eed478c4
# op management
op 运营管理系统
# 开发
- Node: 最新 LTS 版本即可(目前 v14.15.4 运行正常)
- PM2: 最新稳定版即可
- NPM 源:可以使用淘宝源
- Yarn: 最新稳定版
- lock 文件:大家 Node 环境不一致(目前并没有影响),防止总有冲突,暂时未同步到 git 仓库
# 项目启动
启动 Node 服务
```shell
npm run dev
```
启动 Webpack 服务
```shell
# 新版
npm run web-dev
```
\ No newline at end of file
const Koa = require('koa');
const views = require('koa-views');
const serve = require('koa-static');
const bodyParser = require('koa-bodyparser');
const path = require('path');
const router = require('./server/router');
const config = require('./server/config');
const env = process.env.NODE_ENV;
const app = new Koa();
app.use(serve(path.join(__dirname, './public')));
app.use(bodyParser());
app.use(router.routes(), router.allowedMethods());
app.listen(config.port, () => {
console.info(
'Listening on port %s in %s mode, Open up http://127.0.0.1:%s/ in your browser.',
config.port,
config.env,
config.port
);
});
npm run build
\ No newline at end of file
#!/bin/bash
#开发测试环境第二个参数传入端口号,默认3030
env=$1
port=$2
if [ ! -n "$port" ]
then
port="8055"
fi
if [ $env != "production" ]
then
name="op_management_$port"
isExist=`pm2 show $name`
if [ -n "$isExist" ]
then
echo "$name 已存在,需要先删除"
pm2 delete $name
echo "$name 删除成功"
fi
PORT=$port NODE_ENV=$env pm2 start app.js --name $name --watch --node-args="--inspect"
echo "NODE_ENV:$env"
echo "PORT:$port"
echo "PM2 App Name:$name"
fi
if [ $env == "development" ]
then
pm2 logs $name
fi
\ No newline at end of file
......@@ -2,9 +2,13 @@
"name": "op-management",
"version": "0.1.0",
"private": true,
"main": "app.js",
"scripts": {
"start": "vue-cli-service serve",
"build": "vue-cli-service build",
"dev": "sh ./bin/start.sh development",
"test": "sh ./bin/start.sh testing",
"prod": "sh ./bin/start.sh production",
"web-dev": "cross-env NODE_ENV=development vue-cli-service serve",
"web-build": "cross-env NODE_ENV=production vue-cli-service build",
"test:unit": "vue-cli-service test:unit",
"lint": "vue-cli-service lint"
},
......@@ -12,7 +16,13 @@
"axios": "^0.21.1",
"core-js": "^3.6.5",
"element-plus": "^1.0.2-beta.44",
"vue": "^3.0.0",
"koa": "^2.13.1",
"koa-bodyparser": "^4.3.0",
"koa-router": "^10.0.0",
"koa-static": "^5.0.0",
"koa-views": "^7.0.1",
"request": "^2.88.2",
"vue": "^3.0.11",
"vue-router": "^4.0.0-beta.12",
"vuex": "^4.0.0-beta.4"
},
......@@ -25,11 +35,13 @@
"@vue/eslint-config-prettier": "^6.0.0",
"@vue/test-utils": "^2.0.0-alpha.1",
"babel-eslint": "^10.1.0",
"cross-env": "^7.0.3",
"eslint": "^6.7.2",
"eslint-plugin-prettier": "^3.1.3",
"eslint-plugin-vue": "^7.0.0-alpha.0",
"less": "^3.0.4",
"less-loader": "^5.0.0",
"pm2": "2.7.0",
"prettier": "^1.19.1"
},
"browserslist": [
......
const env = process.env.NODE_ENV || 'development';
const port = process.env.PORT || 8066;
const LOGIN_URI = {
'development': "http://web-rest.int.yidian-inc.com",
'test': "http://web-rest.int.yidian-inc.com",
'production': "http://web-rest.int.yidian-inc.com"
}
module.exports = {
env: env,
port: port,
LOGIN_URI: LOGIN_URI[env],
};
const LOGIN_URI = require('../config.js').LOGIN_URI
const req = require('../utils/request').httpReq
exports.login = async (ctx, next) => {
var url = `${LOGIN_URI}/api/v1/pandora/auth`;
var opts = {
url: url,
method: 'POST',
json: true,
timeout: 8000,
body : ctx.request.body
}
ctx.body = await req(ctx, opts)
}
const Router = require('koa-router');
const system = require('./controllers/system')
// const index = require('./controllers/index');
// const about = require('./controllers/about');
// const api = require('./controllers/api/index');
// const apiPosts = require('./controllers/api/posts');
const router = Router();
router.post('/login', system.login);
module.exports = router;
const request = require('request')
exports.httpReq = (ctx, opts) => {
opts.timeout = opts.timeout || 1000
return new Promise((resolve, reject) => {
var time_start = +new Date()
request(opts, (err, res, body) => {
//console.info(`[Api] httpReq (${opts.url},${opts.headers && opts.headers.cookie}) spent: ${+new Date() - time_start}ms`)
if (!err) {
resolve(body)
} else {
reject(err)
console.error(opts.url, err)
}
})
})
}
\ No newline at end of file
<template>
<div id="app">
<layout>
<router-view />
</layout>
<!-- <layout>
</layout> -->
</div>
</template>
<script>
// Layout 为布局组件,控制页面基础布局,通过 slot 实现
import Layout from '@/layouts';
// import Layout from '@/layouts';
export default {
components: {
Layout,
},
// components: {
// Layout,
// },
};
</script>
......
<template>
<div>
<div id="pageheader">
<div class="line"></div>
<el-menu
class="el-menu-demo"
mode="horizontal"
router=true
:router="true"
@select="handleSelect"
background-color="#545c64"
text-color="#fff"
......@@ -14,11 +14,9 @@
<el-menu-item
v-for="item in menuItems"
:index="item.path"
:key="item.path"
@select="() => handleSelect(item.path)"
:key="item.name"
>
{{ item.name }}
<!-- <router-link :to="item.path" class="menu-router">{{ item.name }}</router-link> -->
</el-menu-item>
</el-menu>
</div>
......@@ -33,22 +31,22 @@ export default {
data() {
return {
menuItems,
activeMenu: "",
basicPath: "/app/op-management",
};
},
methods: {
handleSelect(path) {
this.activeMenu = path;
computed: {
activeMenu: function () {
return this.$route.path;
},
},
methods: {},
};
</script>
<style lang="less">
.menu-router {
.menu-router {
display: inline-block;
line-height: 60px;
width: 100%;
}
}
</style>
......@@ -7,5 +7,5 @@ const API_URI = {
}
export default {
API_URI: API_URI[currEnv]
API_URI: API_URI[currEnv],
}
\ No newline at end of file
......@@ -9,17 +9,17 @@
</div>
<!-- 页面公共 footer -->
<page-footer class="page-footer"></page-footer>
<!-- <page-footer class="page-footer"></page-footer> -->
</div>
</template>
<script>
import PageHeader from '@/components/PageHeader';
import PageFooter from '@/components/PageFooter';
// import PageFooter from '@/components/PageFooter';
export default {
components: {
PageHeader,
PageFooter,
// PageFooter,
},
};
</script>
......
<template>
<layout>
<div class="page-about">
<ul class="doc-list">
<li>
......@@ -24,8 +25,19 @@
</ul>
<h3><router-link to="/">返回首页</router-link></h3>
</div>
</layout>
</template>
<script>
import Layout from '@/layouts';
export default {
components: {
Layout,
},
};
</script>
<style lang="less">
.page-about {
padding-top: 100px;
......
<template>
<div class="page-home">
home
<div>
<layout>
homesssss
</layout>
</div>
</template>
<script>
export default {};
import Layout from '@/layouts';
export default {
components: {
Layout,
},
};
</script>
<style lang="less" src="./index.less">
......
<template>
<div id="login-page">
<div class="title">OP 运营管理系统</div>
<div class="form">
<el-input
v-model="userInfo.email"
placeholder="请输入邮箱"
class="form-input"
></el-input>
<el-input
v-model="userInfo.password"
type="password"
placeholder="请输入密码"
class="form-input"
></el-input>
</div>
<div class="login">
<el-button @click="login">登录</el-button>
</div>
<div class="tip">
<p>1. 请使用一点邮箱登录,登录密码为当前的邮箱密码。</p>
<p>2. 用户默认无功能权限,请联系管理员开通。</p>
</div>
</div>
</template>
<script>
import { userLogin } from "../../service/common";
export default {
name: "Login",
data() {
return {
userInfo: {
email: "",
password: "",
},
};
},
created() {},
methods: {
async login() {
const { email, password } = this.userInfo;
console.log(34333, email, password);
if (!email) {
console.error("请输入用户邮箱");
return;
}
// if (urlParams.auth && !pwdSec.value) {
// message.error("请输入二次验证码!")
// return
// }
try {
const emailAddress =
email.indexOf("@") === -1 ? email + "@yidian-inc.com" : email;
const res = await userLogin(emailAddress, password);
console.log(111111, res);
if (!res || !res.token) return;
// const storage = window.localStorage
// storage["YD_PANDORA_auth"] = JSON.stringify(res.auth || {})
// storage["YD_PANDORA_JWT_TOKEN"] = (res.type + " " + res.token) || ''
// storage["YD_PANDORA_user"] = JSON.stringify(res.userInfo || {})
// setCookie('uid', res.userInfo && res.userInfo.id, 16)
// setCookie('YD_PANDORA_UID', res.userInfo && res.userInfo.id, 16)
// setCookie('userid', res.userInfo && res.userInfo.id, 16)
// setCookie('username', res.userInfo && res.userInfo.email, 16)
// setCookie('nickname', res.userInfo && res.userInfo.displayName, 16)
// setCookie('YD_PANDORA_JWT_TOKEN', (res.type + " " + res.token) || '', 16)
// if (urlParams.callback) {
// // window.location.href = `${callback}${callback.indexOf('?') >= 0 ? '&' : '?'}token=${res.token}`
// window.location.href = `${urlParams.callback}`
// } else {
// window.location.href = `/?tid=${toolId}`
// }
} catch (e) {
console.log(e);
// message.error("登录不成功,请检查登录信息后重试!")
}
},
},
};
</script>
<style lang="less" scope>
#login-page {
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background: url("../../assets/img/banner1.jpg") center top no-repeat;
background-size: cover;
color: #fff;
.title {
font-size: 40px;
}
.form {
display: flex;
flex-direction: column;
justify-content: center;
margin-top: 32px;
.form-input {
margin-bottom: 20px;
width: 300px;
height: 50px;
font-size: 16px;
.el-input__inner {
background-color: rgba(0, 0, 0, 0.12);
height: 50px;
border: none;
color: #fff;
}
}
}
.tip {
margin-top: 20px;
font-size: 14px;
}
}
</style>
<template>
<div class="addRole">
<el-button type="primary">新增</el-button>
<el-button type="primary" @click="dialogFormVisible = true">新增</el-button>
<el-table
:row-class-name="tableRowClassName"
:data="tableData"
style="width: 100%; margin-top: 10px"
:header-cell-style="{ background: '#e1e4e5', color: '#80878f' }"
......@@ -15,12 +14,40 @@
<el-button
size="mini"
type="text"
@click="handleEdit(scope.$index, scope.row)"
@click="handleModify(scope.$index, scope.row)"
>修改</el-button
>
</template>
</el-table-column>
</el-table>
<el-dialog title="新增角色" v-model="dialogFormVisible">
<el-form>
<el-form-item label="角色名称" :label-width="formLabelWidth">
<el-input
style="width: 400px"
v-model="roleName"
autocomplete="off"
></el-input>
</el-form-item>
<el-form-item label="角色范围" :label-width="formLabelWidth">
<el-cascader
v-model="selectedOptions"
:options="options"
:props="props"
ref="cascaderAddr"
@change="parentCateChange"
filterable
clearable
></el-cascader>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="confirmRole">确 定</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script>
......@@ -28,19 +55,128 @@ export default {
data () {
return {
tableData: [{
id: '1',
name: '超级管理员',
address: '角色范围'
}, {
id: '2',
name: '普通角色',
address: '角色范围'
}, {
id: '3',
name: '超级管理员',
address: '角色范围'
}, {
id: '4',
name: '普通角色',
address: '角色范围'
}]
}],
vals: [],
dialogFormVisible: false,
roleName: '',
checkedRole: [],//已经选择的角色
roleTitle: '新增角色',
props: {
multiple: true,//设置为多选
checkStrictly: true,
value: 'name', //value值和哪个值绑定
label: 'desc',//label值和哪个值绑定
children: 'button_list'//children值和哪个值绑定
},
formLabelWidth: '120px',
selectedOptions: [],
rolePrivilege: [],
currentRolePrivilege: '',
options: [
{
"name": "用户列表",
"desc": "用户列表",
// "menu_redirect":"\/user\/user\/list",
"button_list": [
{
"name": "deleteBtn",
"desc": "删除用户"
},
{
"name": "addBtn",
"desc": "添加用户"
},
{
"name": "updateBtn",
"desc": "修改用户"
}
]
},
{
"menu_name": "企业审核列表",
// "menu_redirect": "\/aut\/user\/list",
"desc": "企业审核列表",
"button_list": [
{
"name": "addBtn",
"desc": "添加"
},
{
"name": "showBtn",
"desc": "查看"
}
]
}
]
}
},
methods: {
//修改
handleModify (index, row) {
console.log(index, row, 'index, row')
this.roleTitle = '角色修改'
this.dialogFormVisible = true
},
confirmRole () {
console.log(this.roleName, 'roleNameroleName')
this.dialogFormVisible = false
},
getCascaderObj (val, opt) {
console.log(val, opt, 'val, opt')
return val.map(function (value) {
for (var itm of opt) {
if (itm.value == value) { opt = itm.children; return itm; }
}
return null;
});
},
parentCateChange () {
this.vals = this.getCascaderObj(this.selectedOptions, this.options);
const checkedNodes = this.$refs['cascaderAddr'].getCheckedNodes()
console.log(checkedNodes[0].pathLabels, '000') // 获取由 label 组成的数
},
// getCurrentPrivilege (id) {
// get("/merchant/authority/get_role_list").then((res) => {
// if (res.status == 200) {
// this.rolePrivilege = res.data;
// res.data.forEach((item) => {
// if (item.id == id) {
// this.currentRolePrivilege = item;
// console.log(item);
// // this.getCheckedId(this.currentRolePrivilege);
// }
// });
// }
// });
// },
// getSelectedKeys (obj) {
// this.SelectedKeys = [];
// console.log(obj);
// obj.privileges.forEach((item, index) => {
// if (item.parentId != null) {
// this.selectedKeys.push([item.btn_name, item.btn_desc]);
// } else {
// this.selectedKeys.push([item.btn_name, item.btn_desc]);
// }
// });
// console.log(this.checkedId);
// },
}
}
</script>
......
import { createRouter, createWebHistory } from 'vue-router';
import Home from '../pages/Home';
import { createRouter, createWebHistory } from "vue-router";
import Home from "../pages/Home";
import Login from "../pages/Login";
import LifeNo from '../pages/Life-no/index.vue'
import LifeNoDetail from '../pages/Life-no/life-no-detail.vue'
import UserDetail from '../pages/User/user-detail.vue'
import AddRole from '../pages/Role/add-role.vue'
const routes = [
{
path: '/',
name: 'Home',
path: "/home",
name: "Home",
component: Home,
},
{
path: '/about',
name: 'About',
component: () => import(/* webpackChunkName: "about" */ '../pages/About'),
path: "/login",
name: "Login",
component: Login,
},
{
path: "/about",
name: "About",
component: () => import(/* webpackChunkName: "about" */ "../pages/About"),
},
//生活号管理
{
......@@ -41,7 +50,7 @@ const routes = [
];
const router = createRouter({
history: createWebHistory('/app/op-management'),
history: createWebHistory("/app/op-management"),
routes,
});
......
import axios from '../utils/request';
export async function userLogin(email, password) {
let res = await axios.post(`api/login`, {
email, password, authCode: ''
});
return res.data;
}
\ No newline at end of file
import Vuex from 'vuex';
import Vuex from "vuex";
export default Vuex.createStore({
state: {},
......
/**
* axios封装
*/
import axios from 'axios';
import { ElMessage } from 'element-plus';
import { setToken, formatDate } from '/@/libs/utils';
import { APP_URI } from '../config/app.config';
import config from '/@/config';
import router from '/@/router';
import md5 from 'js-md5';
import axios from "axios";
import { ElMessage } from "element-plus";
// import { APP_URI } from "../config/app.config";
/**
* show error tip
* @param mgs
*/
const showErrorMessage = (mgs) => {
const showErrorMessage = mgs => {
ElMessage({
message: mgs,
type: 'error',
type: "error",
showClose: true
});
};
......@@ -25,17 +20,16 @@ const showErrorMessage = (mgs) => {
* default axios config
*/
export const defaultConfig = {
baseURL: APP_URI,
// baseURL: APP_URI,
timeout: 10000
// baseURL: '/',
};
/**
* default params
* @returns {}
*/
const getDefaultParams = () => {};
const getDefaultHeaders = () => {};
const getDefaultParams = () => { };
const getDefaultHeaders = () => { };
/**
* axios instance
......@@ -50,13 +44,13 @@ instance.interceptors.request.use(
function (config) {
// network error
if (navigator.onLine !== undefined && navigator.onLine === false) {
return Promise.reject({ message: '网络未链接', code: -1 });
return Promise.reject({ message: "网络未链接", code: -1 });
}
/**
* merge headers
*/
config.headers = {...getDefaultHeaders(), ...config.headers}
config.headers = { ...getDefaultHeaders(), ...config.headers }
/**
* merge params
......@@ -79,50 +73,50 @@ instance.interceptors.response.use(
const { data = {} } = response;
const code = data.code ?? -1;
if (code !== 0) {
const msg = data.reason || '未定义错误';
const msg = data.reason || "未定义错误";
showErrorMessage(data.reason);
return Promise.reject({ code, msg });
}
if (data.message) {
Message({
ElMessage({
message: data.reason,
type: 'info',
type: "info",
showClose: true
});
}
return data;
},
function (error) {
if (!(error.code && error.code === -1)) error.message = '接口请求错误';
if (!(error.code && error.code === -1)) error.message = "接口请求错误";
showErrorMessage(error.message);
return Promise.reject(error);
}
);
/**
* Get
* @param {*} url
* @param {*} params
*/
export const get = (url, params) => {
return instance.request({
url,
method: 'get',
params
});
};
// /**
// * Get
// * @param {*} url
// * @param {*} params
// */
// export const get = ({url, params, headers}) => {
// return instance.request({
// url,
// method: "get",
// params
// });
// };
/**
* Post
* @param {*} url
* @param {*} params
*/
export const post = (url, data) => {
return instance.request({
url,
method: 'post',
data
});
};
// /**
// * Post
// * @param {*} url
// * @param {*} params
// */
// export const post = ({url, data, headers}) => {
// return instance.request({
// url,
// method: "post",
// data
// });
// };
export default instance;
......@@ -10,8 +10,9 @@ module.exports = {
configureWebpack: {
devServer: {
proxy: {
'/api': {
target: 'http://dev.yidian-inc.com:4000',
'/app/op-management/api': {
target: 'http://localhost:8055',
pathRewrite: { '^/app/op-management/api': '' },
changeOrigin: true,
},
},
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment