Merge remote-tracking branch 'origin/dev' into dev

# Conflicts:
#	src/api/monitor/job.js
dev
chentaisen 2024-09-26 20:32:46 +08:00
commit 5eb9c4cc27
19 changed files with 783 additions and 36 deletions

View File

@ -13,6 +13,9 @@ npm install
# 建议不要直接使用 cnpm 安装依赖,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题 # 建议不要直接使用 cnpm 安装依赖,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题
npm install --registry=https://registry.npmmirror.com npm install --registry=https://registry.npmmirror.com
# 更新启动配置
set NODE_OPTIONS=--openssl-legacy-provider
# 启动服务 # 启动服务
npm run dev npm run dev
``` ```

View File

@ -41,7 +41,7 @@
"clipboard": "2.0.8", "clipboard": "2.0.8",
"core-js": "3.25.3", "core-js": "3.25.3",
"echarts": "5.4.0", "echarts": "5.4.0",
"element-ui": "2.15.14", "element-ui": "2.15.13",
"file-saver": "2.0.5", "file-saver": "2.0.5",
"fuse.js": "6.4.3", "fuse.js": "6.4.3",
"highlight.js": "9.18.5", "highlight.js": "9.18.5",
@ -51,6 +51,7 @@
"nprogress": "0.2.0", "nprogress": "0.2.0",
"quill": "1.3.7", "quill": "1.3.7",
"screenfull": "5.0.2", "screenfull": "5.0.2",
"skywalking-client-js": "^0.11.0",
"sortablejs": "1.10.2", "sortablejs": "1.10.2",
"vue": "2.6.12", "vue": "2.6.12",
"vue-count-to": "1.0.13", "vue-count-to": "1.0.13",
@ -67,7 +68,7 @@
"babel-eslint": "10.1.0", "babel-eslint": "10.1.0",
"babel-plugin-dynamic-import-node": "2.3.3", "babel-plugin-dynamic-import-node": "2.3.3",
"chalk": "4.1.0", "chalk": "4.1.0",
"compression-webpack-plugin": "6.1.2", "compression-webpack-plugin": "5.0.2",
"connect": "3.6.6", "connect": "3.6.6",
"eslint": "7.15.0", "eslint": "7.15.0",
"eslint-plugin-vue": "7.2.0", "eslint-plugin-vue": "7.2.0",

View File

@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询企业基础信息列表
export function listFirmInfo(query) {
return request({
url: '/system/firmInfo/list',
method: 'get',
params: query
})
}
// 查询企业基础信息详细
export function getFirmInfo(id) {
return request({
url: '/system/firmInfo/' + id,
method: 'get'
})
}
// 新增企业基础信息
export function addFirmInfo(data) {
return request({
url: '/system/firmInfo',
method: 'post',
data: data
})
}
// 修改企业基础信息
export function updateFirmInfo(data) {
return request({
url: '/system/firmInfo',
method: 'put',
data: data
})
}
// 删除企业基础信息
export function delFirmInfo(id) {
return request({
url: '/system/firmInfo/' + id,
method: 'delete'
})
}

View File

@ -1,7 +1,7 @@
import request from '@/utils/request' import request from '@/utils/request'
// 登录方法 // 登录方法
export function login(username, password, code, uuid) { export function login(firmCode, username, password, code, uuid) {
return request({ return request({
url: '/auth/login', url: '/auth/login',
headers: { headers: {
@ -9,10 +9,11 @@ export function login(username, password, code, uuid) {
repeatSubmit: false repeatSubmit: false
}, },
method: 'post', method: 'post',
data: {username, password, code, uuid} data: {firmCode, username, password, code, uuid}
}) })
} }
// 注册方法 // 注册方法
export function register(data) { export function register(data) {
return request({ return request({

View File

@ -68,4 +68,4 @@ export function runJob(jobId, jobGroup) {
method: 'put', method: 'put',
data: data data: data
}) })
} }

View File

@ -21,7 +21,7 @@ export function getUser(userId) {
// 新增用户 // 新增用户
export function addUser(data) { export function addUser(data) {
return request({ return request({
url: '/system/user', url: '/saas/user',
method: 'post', method: 'post',
data: data data: data
}) })

View File

@ -63,6 +63,41 @@ Vue.use(plugins)
Vue.use(VueMeta) Vue.use(VueMeta)
DictData.install() DictData.install()
//skywalking监控系统
import ClientMonitor from 'skywalking-client-js';
//注册skywalking
ClientMonitor.register({
service: 'muyu::cloud-ui',//应用名称
serviceVersion:'2.0.1',//应用版本号
traceSDKInternal:true,//追踪sdk
pagePath: location.href,//当前路由地址
useFmp: true,
vue:Vue,//vue实例
});
// Vue 报错上报到skywalking。
Vue.config.errorHandler = (error) => {
console.error(error);
reportFrameErrors(error);
}
//监听ajax报错
window.addEventListener('error', error=>{
console.log("error--->",error)
reportFrameErrors(error);
}, true);
//上报错误信息方法
function reportFrameErrors(error){
ClientMonitor.reportFrameErrors({
service: 'muyu::cloud-ui',//应用名称
serviceVersion:'2.0.1',//应用版本号
pagePath: location.href,
vue:Vue,
}, error);
}
/** /**
* If you don't want to use mock-server * If you don't want to use mock-server
* you want to use MockJs for mock api * you want to use MockJs for mock api

View File

@ -5,12 +5,20 @@ import NProgress from 'nprogress'
import 'nprogress/nprogress.css' import 'nprogress/nprogress.css'
import {getToken} from '@/utils/auth' import {getToken} from '@/utils/auth'
import {isRelogin} from '@/utils/request' import {isRelogin} from '@/utils/request'
import Vue from 'vue'
NProgress.configure({showSpinner: false}) NProgress.configure({showSpinner: false})
const whiteList = ['/login', '/register'] const whiteList = ['/login','/platform/login', '/register']
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
//路由上报到skywalking
//因为有些参数已经在ClientMonitor.register中注册过了所以不用填加了。
ClientMonitor.setPerformance({
pagePath: location.href,//当前路由地址。
useFmp: true,
vue:Vue,
});
NProgress.start() NProgress.start()
if (getToken()) { if (getToken()) {
to.meta.title && store.dispatch('settings/setTitle', to.meta.title) to.meta.title && store.dispatch('settings/setTitle', to.meta.title)

View File

@ -44,6 +44,10 @@ export const constantRoutes = [
path: '/login', path: '/login',
component: () => import('@/views/login'), component: () => import('@/views/login'),
hidden: true hidden: true
},{
path: '/platform/login',
component: () => import('@/views/login'),
hidden: true
}, },
{ {
path: '/register', path: '/register',

View File

@ -1,9 +1,10 @@
import {getInfo, login, logout, refreshToken} from '@/api/login' import {getInfo, login, logout, firmLogin, refreshToken} from '@/api/login'
import {getToken, removeToken, setExpiresIn, setToken} from '@/utils/auth' import {getEntCode, getToken, removeEntCode, removeToken, setEntCode, setExpiresIn, setToken} from '@/utils/auth'
const user = { const user = {
state: { state: {
token: getToken(), token: getToken(),
ent_code: getEntCode(),
id: '', id: '',
name: '', name: '',
avatar: '', avatar: '',
@ -15,6 +16,9 @@ const user = {
SET_TOKEN: (state, token) => { SET_TOKEN: (state, token) => {
state.token = token state.token = token
}, },
SET_ENT_CODE: (state, ent_code) => {
state.ent_code = ent_code
},
SET_EXPIRES_IN: (state, time) => { SET_EXPIRES_IN: (state, time) => {
state.expires_in = time state.expires_in = time
}, },
@ -55,6 +59,29 @@ const user = {
}) })
}) })
}, },
// 企业登录
firmLogin({commit}, userInfo) {
const firmCode = userInfo.firmCode.trim()
const firmUser = userInfo.firmUser.trim()
const firmPassword = userInfo.firmPassword.trim()
const rememberMe = userInfo.rememberMe
const code = userInfo.code
const uuid = userInfo.uuid
return new Promise((resolve, reject) => {
login(firmCode,firmUser,firmPassword, rememberMe, code, uuid).then(res => {
let data = res.data
setToken(data.access_token)
setEntCode(data.ent_code)
commit('SET_TOKEN', data.access_token)
commit('SET_ENT_CODE', data.ent_code)
commit('SET_EXPIRES_IN', data.expires_in)
setExpiresIn(data.expires_in)
resolve()
}).catch(error => {
reject(error)
})
})
},
// 获取用户信息 // 获取用户信息
GetInfo({commit, state}) { GetInfo({commit, state}) {
@ -96,9 +123,11 @@ const user = {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
logout(state.token).then(() => { logout(state.token).then(() => {
commit('SET_TOKEN', '') commit('SET_TOKEN', '')
commit('SET_ENT_CODE', '')
commit('SET_ROLES', []) commit('SET_ROLES', [])
commit('SET_PERMISSIONS', []) commit('SET_PERMISSIONS', [])
removeToken() removeToken()
removeEntCode()
resolve() resolve()
}).catch(error => { }).catch(error => {
reject(error) reject(error)
@ -110,7 +139,9 @@ const user = {
FedLogOut({commit}) { FedLogOut({commit}) {
return new Promise(resolve => { return new Promise(resolve => {
commit('SET_TOKEN', '') commit('SET_TOKEN', '')
commit('SET_ENT_CODE', '')
removeToken() removeToken()
removeEntCode()
resolve() resolve()
}) })
} }

View File

@ -2,6 +2,8 @@ import Cookies from 'js-cookie'
const TokenKey = 'Admin-Token' const TokenKey = 'Admin-Token'
const EntCode = 'ent-code'
const ExpiresInKey = 'Admin-Expires-In' const ExpiresInKey = 'Admin-Expires-In'
export function getToken() { export function getToken() {
@ -16,6 +18,18 @@ export function removeToken() {
return Cookies.remove(TokenKey) return Cookies.remove(TokenKey)
} }
export function getEntCode() {
return Cookies.get(EntCode)
}
export function setEntCode(entCode) {
return Cookies.set(EntCode, entCode)
}
export function removeEntCode() {
return Cookies.remove(EntCode)
}
export function getExpiresIn() { export function getExpiresIn() {
return Cookies.get(ExpiresInKey) || -1 return Cookies.get(ExpiresInKey) || -1
} }

View File

@ -1,7 +1,7 @@
import axios from 'axios' import axios from 'axios'
import {Loading, Message, MessageBox, Notification} from 'element-ui' import {Loading, Message, MessageBox, Notification} from 'element-ui'
import store from '@/store' import store from '@/store'
import {getToken} from '@/utils/auth' import {getEntCode, getToken} from '@/utils/auth'
import errorCode from '@/utils/errorCode' import errorCode from '@/utils/errorCode'
import {blobValidate, tansParams} from "@/utils/muyu"; import {blobValidate, tansParams} from "@/utils/muyu";
import cache from '@/plugins/cache' import cache from '@/plugins/cache'
@ -17,7 +17,7 @@ const service = axios.create({
// axios中请求配置有baseURL选项表示请求URL公共部分 // axios中请求配置有baseURL选项表示请求URL公共部分
baseURL: process.env.VUE_APP_BASE_API, baseURL: process.env.VUE_APP_BASE_API,
// 超时 // 超时
timeout: 10000 timeout: 20000
}) })
// request拦截器 // request拦截器
@ -29,6 +29,9 @@ service.interceptors.request.use(config => {
if (getToken() && !isToken) { if (getToken() && !isToken) {
config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改 config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
} }
if (getEntCode() && !isToken) {
config.headers['ent-code'] = getEntCode() // 让每个请求携带自定义token 请根据实际情况自行修改
}
// get请求映射params参数 // get请求映射params参数
if (config.method === 'get' && config.params) { if (config.method === 'get' && config.params) {
let url = config.url + '?' + tansParams(config.params); let url = config.url + '?' + tansParams(config.params);
@ -73,7 +76,6 @@ service.interceptors.request.use(config => {
// 响应拦截器 // 响应拦截器
service.interceptors.response.use(res => { service.interceptors.response.use(res => {
debugger
// 未设置状态码则默认成功状态 // 未设置状态码则默认成功状态
const code = res.data.code || 200; const code = res.data.code || 200;
// 获取错误信息 // 获取错误信息

View File

@ -0,0 +1,310 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="企业名称" prop="firmName">
<el-input
v-model="queryParams.firmName"
placeholder="请输入企业名称"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="启用状态" prop="state">
<el-select v-model="queryParams.state" placeholder="请选择启用状态" clearable>
<el-option
v-for="dict in dict.type.sys_firm_start"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery"></el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery"></el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['firm:firmInfo:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['firm:firmInfo:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['firm:firmInfo:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
v-hasPermi="['firm:firmInfo:export']"
>导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="firmInfoList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="自增主键" align="center" prop="id" />
<el-table-column label="统一社会信用代码" align="center" prop="firmCreditCode" />
<el-table-column label="企业编码" align="center" prop="firmCode" />
<el-table-column label="企业名称" align="center" prop="firmName" />
<el-table-column label="企业logs" align="center" prop="firmLogs" width="100">
<template slot-scope="scope">
<image-preview :src="scope.row.firmLogs" :width="50" :height="50"/>
</template>
</el-table-column>
<el-table-column label="企业登录名" align="center" prop="firmUser" />
<el-table-column label="企业登录密码" align="center" prop="firmPassword" />
<el-table-column label="启用状态" align="center" prop="state">
<template slot-scope="scope">
<dict-tag :options="dict.type.sys_firm_start" :value="scope.row.state"/>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['firm:firmInfo:edit']"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['firm:firmInfo:remove']"
>删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改企业基础信息对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="统一社会信用代码" prop="firmCreditCode">
<el-input v-model="form.firmCreditCode" placeholder="请输入统一社会信用代码" />
</el-form-item>
<el-form-item label="企业编码" prop="firmCode">
<el-input v-model="form.firmCode" placeholder="请输入企业编码" />
</el-form-item>
<el-form-item label="企业名称" prop="firmName">
<el-input v-model="form.firmName" placeholder="请输入企业名称" />
</el-form-item>
<el-form-item label="企业logs" prop="firmLogs">
<image-upload v-model="form.firmLogs"/>
</el-form-item>
<el-form-item label="企业登录名" prop="firmUser">
<el-input v-model="form.firmUser" placeholder="请输入企业登录名" />
</el-form-item>
<el-form-item label="企业登录密码" prop="firmPassword">
<el-input v-model="form.firmPassword" placeholder="请输入企业登录密码" />
</el-form-item>
<el-form-item label="启用状态" prop="state">
<el-select v-model="form.state" placeholder="请选择启用状态">
<el-option
v-for="dict in dict.type.sys_firm_start"
:key="dict.value"
:label="dict.label"
:value="dict.value"
></el-option>
</el-select>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listFirmInfo, getFirmInfo, delFirmInfo, addFirmInfo, updateFirmInfo } from "/src/api/firm/firmInfo";
export default {
name: "FirmInfo",
dicts: ['sys_firm_start'],
data() {
return {
//
loading: true,
//
ids: [],
//
single: true,
//
multiple: true,
//
showSearch: true,
//
total: 0,
//
firmInfoList: [],
//
title: "",
//
open: false,
//
queryParams: {
pageNum: 1,
pageSize: 10,
firmName: null,
state: null,
},
//
form: {},
//
rules: {
firmCreditCode: [
{ required: true, message: "统一社会信用代码不能为空", trigger: "blur" }
],
}
};
},
created() {
this.getList();
},
methods: {
/** 查询企业基础信息列表 */
getList() {
this.loading = true;
listFirmInfo(this.queryParams).then(response => {
this.firmInfoList = response.data.rows;
this.total = response.data.total;
this.loading = false;
});
},
//
cancel() {
this.open = false;
this.reset();
},
//
reset() {
this.form = {
id: null,
firmCreditCode: null,
firmCode: null,
firmName: null,
firmLogs: null,
firmUser: null,
firmPassword: null,
state: null,
createBy: null,
createTime: null,
updateBy: null,
updateTime: null,
remark: null
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
//
handleSelectionChange(selection) {
this.ids = selection.map(item => item.id)
this.single = selection.length!==1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加企业基础信息";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const id = row.id || this.ids
getFirmInfo(id).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改企业基础信息";
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.id != null) {
updateFirmInfo(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
addFirmInfo(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const ids = row.id || this.ids;
this.$modal.confirm('是否确认删除企业基础信息编号为"' + ids + '"的数据项?').then(function() {
return delFirmInfo(ids);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
this.download('firm/firmInfo/export', {
...this.queryParams
}, `firmInfo_${new Date().getTime()}.xlsx`)
}
}
};
</script>

View File

@ -2,9 +2,19 @@
<div class="login"> <div class="login">
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form"> <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
<h3 class="title">若依后台管理系统</h3> <h3 class="title">若依后台管理系统</h3>
<el-form-item prop="username"> <el-form-item prop="firmCode">
<el-input <el-input
v-model="loginForm.username" v-model="loginForm.firmCode"
auto-complete="off"
placeholder="企业编码"
type="text"
>
<svg-icon slot="prefix" class="el-input__icon input-icon" icon-class="tool"/>
</el-input>
</el-form-item>
<el-form-item prop="firmUser">
<el-input
v-model="loginForm.firmUser"
auto-complete="off" auto-complete="off"
placeholder="账号" placeholder="账号"
type="text" type="text"
@ -12,9 +22,9 @@
<svg-icon slot="prefix" class="el-input__icon input-icon" icon-class="user"/> <svg-icon slot="prefix" class="el-input__icon input-icon" icon-class="user"/>
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item prop="password"> <el-form-item prop="firmPassword">
<el-input <el-input
v-model="loginForm.password" v-model="loginForm.firmPassword"
auto-complete="off" auto-complete="off"
placeholder="密码" placeholder="密码"
type="password" type="password"
@ -72,24 +82,28 @@ export default {
return { return {
codeUrl: "", codeUrl: "",
loginForm: { loginForm: {
username: "admin", firmCode: "FIRM",
password: "admin123", firmUser: "admin",
firmPassword: "admin123",
rememberMe: false, rememberMe: false,
code: "", code: "",
uuid: "" uuid: ""
}, },
loginRules: { loginRules: {
username: [ firmCode: [
{required: true, trigger: "blur", message: "请输入您的企业编码"}
],
firmUser: [
{required: true, trigger: "blur", message: "请输入您的账号"} {required: true, trigger: "blur", message: "请输入您的账号"}
], ],
password: [ firmPassword: [
{required: true, trigger: "blur", message: "请输入您的密码"} {required: true, trigger: "blur", message: "请输入您的密码"}
], ],
code: [{required: true, trigger: "change", message: "请输入验证码"}] code: [{required: true, trigger: "change", message: "请输入验证码"}]
}, },
loading: false, loading: false,
// //
captchaEnabled: true, captchaEnabled: false,
// //
register: false, register: false,
redirect: undefined redirect: undefined
@ -118,12 +132,14 @@ export default {
}); });
}, },
getCookie() { getCookie() {
const username = Cookies.get("username"); const firmCode = Cookies.get("firmCode");
const password = Cookies.get("password"); const firmUser = Cookies.get("firmUser");
const firmPassword = Cookies.get("firmPassword");
const rememberMe = Cookies.get('rememberMe') const rememberMe = Cookies.get('rememberMe')
this.loginForm = { this.loginForm = {
username: username === undefined ? this.loginForm.username : username, firmCode: firmCode === undefined ? this.loginForm.firmCode : firmCode,
password: password === undefined ? this.loginForm.password : decrypt(password), firmUser: firmUser === undefined ? this.loginForm.firmUser : firmUser,
firmPassword: firmPassword === undefined ? this.loginForm.firmPassword : decrypt(firmPassword),
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe) rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
}; };
}, },
@ -132,15 +148,17 @@ export default {
if (valid) { if (valid) {
this.loading = true; this.loading = true;
if (this.loginForm.rememberMe) { if (this.loginForm.rememberMe) {
Cookies.set("username", this.loginForm.username, {expires: 30}); Cookies.set("firmCode", this.loginForm.firmCode, {expires: 30});
Cookies.set("password", encrypt(this.loginForm.password), {expires: 30}); Cookies.set("firmUser", this.loginForm.firmUser, {expires: 30});
Cookies.set("firmPassword", encrypt(this.loginForm.firmPassword), {expires: 30});
Cookies.set('rememberMe', this.loginForm.rememberMe, {expires: 30}); Cookies.set('rememberMe', this.loginForm.rememberMe, {expires: 30});
} else { } else {
Cookies.remove("username"); Cookies.remove("firmCode");
Cookies.remove("password"); Cookies.remove("firmUser");
Cookies.remove("firmPassword");
Cookies.remove('rememberMe'); Cookies.remove('rememberMe');
} }
this.$store.dispatch("Login", this.loginForm).then(() => { this.$store.dispatch("firmLogin", this.loginForm).then(() => {
this.$router.push({path: this.redirect || "/"}).catch(() => { this.$router.push({path: this.redirect || "/"}).catch(() => {
}); });
}).catch(() => { }).catch(() => {

View File

@ -0,0 +1,229 @@
<template>
<div class="login">
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
<h3 class="title">若依后台管理系统</h3>
<el-form-item prop="username">
<el-input
v-model="loginForm.username"
auto-complete="off"
placeholder="账号"
type="text"
>
<svg-icon slot="prefix" class="el-input__icon input-icon" icon-class="user"/>
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
v-model="loginForm.password"
auto-complete="off"
placeholder="密码"
type="password"
@keyup.enter.native="handleLogin"
>
<svg-icon slot="prefix" class="el-input__icon input-icon" icon-class="password"/>
</el-input>
</el-form-item>
<el-form-item v-if="captchaEnabled" prop="code">
<el-input
v-model="loginForm.code"
auto-complete="off"
placeholder="验证码"
style="width: 63%"
@keyup.enter.native="handleLogin"
>
<svg-icon slot="prefix" class="el-input__icon input-icon" icon-class="validCode"/>
</el-input>
<div class="login-code">
<img :src="codeUrl" class="login-code-img" @click="getCode"/>
</div>
</el-form-item>
<el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;"></el-checkbox>
<el-form-item style="width:100%;">
<el-button
:loading="loading"
size="medium"
style="width:100%;"
type="primary"
@click.native.prevent="handleLogin"
>
<span v-if="!loading"> </span>
<span v-else> ...</span>
</el-button>
<div v-if="register" style="float: right;">
<router-link :to="'/register'" class="link-type">立即注册</router-link>
</div>
</el-form-item>
</el-form>
<!-- 底部 -->
<div class="el-login-footer">
<span>Copyright © 2018-2023 muyu.vip All Rights Reserved.</span>
</div>
</div>
</template>
<script>
import {getCodeImg} from "@/api/login";
import Cookies from "js-cookie";
import {decrypt, encrypt} from '@/utils/jsencrypt'
export default {
name: "Login",
data() {
return {
codeUrl: "",
loginForm: {
username: "admin",
password: "admin123",
rememberMe: false,
code: "",
uuid: ""
},
loginRules: {
username: [
{required: true, trigger: "blur", message: "请输入您的账号"}
],
password: [
{required: true, trigger: "blur", message: "请输入您的密码"}
],
code: [{required: true, trigger: "change", message: "请输入验证码"}]
},
loading: false,
//
captchaEnabled: false,
//
register: false,
redirect: undefined
};
},
watch: {
$route: {
handler: function (route) {
this.redirect = route.query && route.query.redirect;
},
immediate: true
}
},
created() {
this.getCode();
this.getCookie();
},
methods: {
getCode() {
getCodeImg().then(res => {
this.captchaEnabled = res.data.captchaEnabled === undefined ? true : res.data.captchaEnabled;
if (this.captchaEnabled) {
this.codeUrl = "data:image/gif;base64," + res.data.img;
this.loginForm.uuid = res.data.uuid;
}
});
},
getCookie() {
const username = Cookies.get("username");
const password = Cookies.get("password");
const rememberMe = Cookies.get('rememberMe')
this.loginForm = {
username: username === undefined ? this.loginForm.username : username,
password: password === undefined ? this.loginForm.password : decrypt(password),
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
};
},
handleLogin() {
this.$refs.loginForm.validate(valid => {
if (valid) {
this.loading = true;
if (this.loginForm.rememberMe) {
Cookies.set("username", this.loginForm.username, {expires: 30});
Cookies.set("password", encrypt(this.loginForm.password), {expires: 30});
Cookies.set('rememberMe', this.loginForm.rememberMe, {expires: 30});
} else {
Cookies.remove("username");
Cookies.remove("password");
Cookies.remove('rememberMe');
}
this.$store.dispatch("Login", this.loginForm).then(() => {
this.$router.push({path: this.redirect || "/"}).catch(() => {
});
}).catch(() => {
this.loading = false;
if (this.captchaEnabled) {
this.getCode();
}
});
}
});
}
}
};
</script>
<style lang="scss" rel="stylesheet/scss">
.login {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
background-image: url("../assets/images/login-background.jpg");
background-size: cover;
}
.title {
margin: 0px auto 30px auto;
text-align: center;
color: #707070;
}
.login-form {
border-radius: 6px;
background: #ffffff;
width: 400px;
padding: 25px 25px 5px 25px;
.el-input {
height: 38px;
input {
height: 38px;
}
}
.input-icon {
height: 39px;
width: 14px;
margin-left: 2px;
}
}
.login-tip {
font-size: 13px;
text-align: center;
color: #bfbfbf;
}
.login-code {
width: 33%;
height: 38px;
float: right;
img {
cursor: pointer;
vertical-align: middle;
}
}
.el-login-footer {
height: 40px;
line-height: 40px;
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
color: #fff;
font-family: Arial;
font-size: 12px;
letter-spacing: 1px;
}
.login-code-img {
height: 38px;
}
</style>

View File

@ -105,6 +105,7 @@
<el-table-column align="center" type="selection" width="55"/> <el-table-column align="center" type="selection" width="55"/>
<el-table-column label="角色编号" prop="roleId" width="120"/> <el-table-column label="角色编号" prop="roleId" width="120"/>
<el-table-column :show-overflow-tooltip="true" label="角色名称" prop="roleName" width="150"/> <el-table-column :show-overflow-tooltip="true" label="角色名称" prop="roleName" width="150"/>
<el-table-column v-show="getEntCode() === 'FIRM'" align="center" label="租户编码" prop="firmCode"/>
<el-table-column :show-overflow-tooltip="true" label="权限字符" prop="roleKey" width="150"/> <el-table-column :show-overflow-tooltip="true" label="权限字符" prop="roleKey" width="150"/>
<el-table-column label="显示顺序" prop="roleSort" width="100"/> <el-table-column label="显示顺序" prop="roleSort" width="100"/>
<el-table-column align="center" label="状态" width="100"> <el-table-column align="center" label="状态" width="100">
@ -277,6 +278,7 @@ import {
updateRole updateRole
} from "@/api/system/role"; } from "@/api/system/role";
import {roleMenuTreeselect, treeselect as menuTreeselect} from "@/api/system/menu"; import {roleMenuTreeselect, treeselect as menuTreeselect} from "@/api/system/menu";
import {getEntCode} from "@/utils/auth";
export default { export default {
name: "Role", name: "Role",
@ -368,6 +370,7 @@ export default {
this.getList(); this.getList();
}, },
methods: { methods: {
getEntCode,
/** 查询角色列表 */ /** 查询角色列表 */
getList() { getList() {
this.loading = true; this.loading = true;

View File

@ -26,6 +26,7 @@
</el-table-column> </el-table-column>
<el-table-column :reserve-selection="true" type="selection" width="55"></el-table-column> <el-table-column :reserve-selection="true" type="selection" width="55"></el-table-column>
<el-table-column align="center" label="角色编号" prop="roleId"/> <el-table-column align="center" label="角色编号" prop="roleId"/>
<el-table-column v-show="getEntCode() === 'FIRM'" align="center" label="租户编码" prop="firmCode"/>
<el-table-column align="center" label="角色名称" prop="roleName"/> <el-table-column align="center" label="角色名称" prop="roleName"/>
<el-table-column align="center" label="权限字符" prop="roleKey"/> <el-table-column align="center" label="权限字符" prop="roleKey"/>
<el-table-column align="center" label="创建时间" prop="createTime" width="180"> <el-table-column align="center" label="创建时间" prop="createTime" width="180">
@ -48,6 +49,7 @@
<script> <script>
import {getAuthRole, updateAuthRole} from "@/api/system/user"; import {getAuthRole, updateAuthRole} from "@/api/system/user";
import {getEntCode} from "@/utils/auth";
export default { export default {
name: "AuthRole", name: "AuthRole",
@ -87,6 +89,7 @@ export default {
} }
}, },
methods: { methods: {
getEntCode,
/** 单击选中行数据 */ /** 单击选中行数据 */
clickRow(row) { clickRow(row) {
this.$refs.table.toggleRowSelection(row); this.$refs.table.toggleRowSelection(row);

View File

@ -151,6 +151,7 @@
prop="nickName"/> prop="nickName"/>
<el-table-column v-if="columns[3].visible" key="deptName" :show-overflow-tooltip="true" align="center" label="部门" <el-table-column v-if="columns[3].visible" key="deptName" :show-overflow-tooltip="true" align="center" label="部门"
prop="dept.deptName"/> prop="dept.deptName"/>
<el-table-column v-show="getEntCode() === 'FIRM'" align="center" label="租户编码" prop="firmCode"/>
<el-table-column v-if="columns[4].visible" key="phonenumber" align="center" label="手机号码" <el-table-column v-if="columns[4].visible" key="phonenumber" align="center" label="手机号码"
prop="phonenumber" width="120"/> prop="phonenumber" width="120"/>
<el-table-column v-if="columns[5].visible" key="status" align="center" label="状态"> <el-table-column v-if="columns[5].visible" key="status" align="center" label="状态">
@ -228,7 +229,10 @@
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="归属部门" prop="deptId"> <el-form-item label="归属部门" prop="deptId">
<treeselect v-model="form.deptId" :options="deptOptions" :show-count="true" placeholder="请选择归属部门"/> <treeselect v-model="form.deptId" :options="deptOptions"
:show-count="true"
placeholder="请选择归属部门"
@input="checkRole"/>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@ -371,9 +375,10 @@ import {
resetUserPwd, resetUserPwd,
updateUser updateUser
} from "@/api/system/user"; } from "@/api/system/user";
import {getToken} from "@/utils/auth"; import {getEntCode, getToken, setEntCode} from "@/utils/auth";
import Treeselect from "@riophae/vue-treeselect"; import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css"; import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import {listDept} from "@/api/system/dept";
export default { export default {
name: "User", name: "User",
@ -409,8 +414,11 @@ export default {
dateRange: [], dateRange: [],
// //
postOptions: [], postOptions: [],
//
deptListAll: [],
// //
roleOptions: [], roleOptions: [],
roleListAll: [],
// //
form: {}, form: {},
defaultProps: { defaultProps: {
@ -495,6 +503,7 @@ export default {
}); });
}, },
methods: { methods: {
getEntCode,
/** 查询用户列表 */ /** 查询用户列表 */
getList() { getList() {
this.loading = true; this.loading = true;
@ -507,8 +516,19 @@ export default {
}, },
/** 查询部门下拉树结构 */ /** 查询部门下拉树结构 */
getDeptTree() { getDeptTree() {
deptTreeSelect().then(response => { listDept(this.queryParams).then(response => {
this.deptOptions = response.data; this.deptListAll = response.data
const deptList = response.data.map(dept => {
return {
id: dept.deptId,
label: dept.deptName,
firmCode: dept.firmCode,
parentId: dept.parentId,
children: null
}
})
this.deptOptions = this.handleTree(deptList)
console.log(this.deptOptions)
}); });
}, },
// //
@ -555,6 +575,18 @@ export default {
}; };
this.resetForm("form"); this.resetForm("form");
}, },
//
checkRole(vuler) {
let firmCode = ''
this.deptListAll.forEach(item => {
if (item.deptId == vuler){
firmCode = item.firmCode
}
})
this.roleOptions = this.roleListAll.filter(item => item.firmCode === firmCode);
console.log(firmCode)
console.log(this.roleOptions)
},
/** 搜索按钮操作 */ /** 搜索按钮操作 */
handleQuery() { handleQuery() {
this.queryParams.pageNum = 1; this.queryParams.pageNum = 1;
@ -592,7 +624,8 @@ export default {
this.reset(); this.reset();
getUser().then(response => { getUser().then(response => {
this.postOptions = response.data.posts; this.postOptions = response.data.posts;
this.roleOptions = response.data.roles; this.roleOptions = response.data.roles.filter(item => item.firmCode === getEntCode());
this.roleListAll = response.data.roles;
this.open = true; this.open = true;
this.title = "添加用户"; this.title = "添加用户";
this.form.password = this.initPassword; this.form.password = this.initPassword;

View File

@ -40,7 +40,15 @@ module.exports = {
pathRewrite: { pathRewrite: {
['^' + process.env.VUE_APP_BASE_API]: '' ['^' + process.env.VUE_APP_BASE_API]: ''
} }
} },
// '/browser': {
// target:'http://192.168.138.130:12800',//这里是路由和报错报告的代理
// changeOrigin: true
// },
// '/v3':{
// target:'http://192.168.138.130:12800',
// changeOrigin: true//这里是追踪报告的代理
// }
}, },
disableHostCheck: true disableHostCheck: true
}, },