Compare commits

...

4 Commits

Author SHA1 Message Date
sunshine7058 e3f1397a80 通知公告优化 2024-04-15 14:09:14 +08:00
sunshine7058 61daee9ba5 前台实现修改密码强退 2024-04-12 16:56:59 +08:00
sunshine7058 9ce621e898 修复登录无响应问题 2024-04-12 15:51:13 +08:00
sunshine7058 a7da56f9d5 前端初始化 2024-04-12 11:59:17 +08:00
13 changed files with 288 additions and 25 deletions

View File

@ -5,7 +5,7 @@
"author": "若依", "author": "若依",
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"dev": "vue-cli-service serve", "dev": "SET NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve",
"build:prod": "vue-cli-service build", "build:prod": "vue-cli-service build",
"build:stage": "vue-cli-service build --mode staging", "build:stage": "vue-cli-service build --mode staging",
"preview": "node build/index.js --preview", "preview": "node build/index.js --preview",

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(usernameOrEmail, password, code, uuid) {
return request({ return request({
url: '/auth/login', url: '/auth/login',
headers: { headers: {
@ -9,7 +9,7 @@ export function login(username, password, code, uuid) {
repeatSubmit: false repeatSubmit: false
}, },
method: 'post', method: 'post',
data: {username, password, code, uuid} data: {usernameOrEmail, password, code, uuid}
}) })
} }

View File

@ -42,3 +42,25 @@ export function delNotice(noticeId) {
method: 'delete' method: 'delete'
}) })
} }
export function updateAsUserDept(id) {
return request({
url: '/system/userDept/updateAsUserDept?id=' + id,
method: 'get'
})
}
export function getNum(id) {
return request({
url: '/system/userDept/getNum?noticeId=' + id,
method: 'get'
})
}
export function getNoticeList(data) {
return request({
url: '/system/notice/getNoticeList',
method: 'post',
data
})
}

View File

@ -8,6 +8,7 @@
<div class="right-menu"> <div class="right-menu">
<template v-if="device!=='mobile'"> <template v-if="device!=='mobile'">
<i class="el-icon-message" @click="noticeTableList"></i>
<search id="header-search" class="right-menu-item"/> <search id="header-search" class="right-menu-item"/>
<screenfull id="screenfull" class="right-menu-item hover-effect"/> <screenfull id="screenfull" class="right-menu-item hover-effect"/>
@ -35,6 +36,72 @@
</el-dropdown-menu> </el-dropdown-menu>
</el-dropdown> </el-dropdown>
</div> </div>
<el-dialog
title="公告"
:visible.sync="noticeTableVisible"
width="50%">
<el-radio-group v-model="form.noticeType" @change="getNoticeList">
<el-radio-button label="">全部</el-radio-button>
<el-radio-button label="1">通知</el-radio-button>
<el-radio-button label="2">公告</el-radio-button>
</el-radio-group>
<br> <br>
<el-radio-group v-model="form.isRead" @change="getNoticeList">
<el-radio-button label="">全部</el-radio-button>
<el-radio-button label="0">已读</el-radio-button>
<el-radio-button label="1">未读</el-radio-button>
</el-radio-group>
<br><br><br>
<el-card class="box-card" v-for="notice in noticeAttr">
<el-descriptions class="margin-top" :title="notice.noticeTitle" :column="2" :size="size" border>
<template slot="extra">
<el-button size="small" @click="readNotice(notice)"></el-button>
</template>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-user"></i>
消息发布时间
</template>
{{ notice.createTime }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-user"></i>
消息发布人
</template>
{{ notice.createBy }}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-tickets"></i>
消息类型
</template>
<dict-tag :options="dict.type.sys_notice_type" :value="notice.noticeType"/>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-office-building"></i>
消息当前状态
</template>
<dict-tag :options="dict.type.sys_is_read" :value="notice.isRead"/>
</el-descriptions-item>
</el-descriptions>
</el-card>
<span slot="footer" class="dialog-footer">
<el-button @click="noticeTableVisible = false"> </el-button>
<el-button type="primary" @click="noticeTableVisible = false"> </el-button>
</span>
</el-dialog>
<el-dialog
:title="noticeInfo.noticeTitle"
:visible.sync="noticeVisble"
width="30%">
<editor v-model="noticeInfo.noticeContent" :min-height="192"/>
<span slot="footer" class="dialog-footer">
<el-button @click="noticeVisble = false"> </el-button>
<el-button type="primary" @click="noticeVisble = false"> </el-button>
</span>
</el-dialog>
</div> </div>
</template> </template>
@ -46,8 +113,23 @@ import Hamburger from '@/components/Hamburger'
import Screenfull from '@/components/Screenfull' import Screenfull from '@/components/Screenfull'
import SizeSelect from '@/components/SizeSelect' import SizeSelect from '@/components/SizeSelect'
import Search from '@/components/HeaderSearch' import Search from '@/components/HeaderSearch'
import {getNoticeList, updateAsUserDept} from "@/api/system/notice"
export default { export default {
dicts: ['sys_is_read', 'sys_notice_type'],
data() {
return {
noticeVisble: false,
noticeInfo: {},
noticeAttr: [],
form: {
noticeType: '',
isRead: ''
},
messageTotal: undefined,
noticeTableVisible: false
}
},
components: { components: {
Breadcrumb, Breadcrumb,
TopNav, TopNav,
@ -80,6 +162,23 @@ export default {
} }
}, },
methods: { methods: {
noticeTableList() {
this.getNoticeList()
this.noticeTableVisible = true
},
getNoticeList() {
getNoticeList(this.form).then(res => {
console.log(res)
this.noticeAttr = res.data
})
},
readNotice(row) {
this.noticeInfo = row
this.noticeVisble = true
updateAsUserDept(row.id).then(res => {
this.getNoticeList()
})
},
toggleSideBar() { toggleSideBar() {
this.$store.dispatch('app/toggleSideBar') this.$store.dispatch('app/toggleSideBar')
}, },

View File

@ -38,12 +38,12 @@ const user = {
actions: { actions: {
// 登录 // 登录
Login({commit}, userInfo) { Login({commit}, userInfo) {
const username = userInfo.username.trim() const usernameOrEmail = userInfo.usernameOrEmail.trim()
const password = userInfo.password const password = userInfo.password
const code = userInfo.code const code = userInfo.code
const uuid = userInfo.uuid const uuid = userInfo.uuid
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
login(username, password, code, uuid).then(res => { login(usernameOrEmail, password, code, uuid).then(res => {
let data = res.data let data = res.data
setToken(data.access_token) setToken(data.access_token)
commit('SET_TOKEN', data.access_token) commit('SET_TOKEN', data.access_token)

View File

@ -73,7 +73,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

@ -2,11 +2,11 @@
<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="usernameOrEmail">
<el-input <el-input
v-model="loginForm.username" v-model="loginForm.usernameOrEmail"
auto-complete="off" auto-complete="off"
placeholder="账号" placeholder="账号/邮箱"
type="text" type="text"
> >
<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"/>
@ -72,15 +72,15 @@ export default {
return { return {
codeUrl: "", codeUrl: "",
loginForm: { loginForm: {
username: "admin", usernameOrEmail: "",
password: "admin123", password: "",
rememberMe: false, rememberMe: false,
code: "", code: "",
uuid: "" uuid: ""
}, },
loginRules: { loginRules: {
username: [ usernameOrEmail: [
{required: true, trigger: "blur", message: "请输入您的账号"} {required: true, trigger: "blur", message: "请输入您的账号/邮箱"}
], ],
password: [ password: [
{required: true, trigger: "blur", message: "请输入您的密码"} {required: true, trigger: "blur", message: "请输入您的密码"}
@ -118,11 +118,11 @@ export default {
}); });
}, },
getCookie() { getCookie() {
const username = Cookies.get("username"); const usernameOrEmail = Cookies.get("usernameOrEmail");
const password = Cookies.get("password"); const password = Cookies.get("password");
const rememberMe = Cookies.get('rememberMe') const rememberMe = Cookies.get('rememberMe')
this.loginForm = { this.loginForm = {
username: username === undefined ? this.loginForm.username : username, usernameOrEmail: usernameOrEmail === undefined ? this.loginForm.usernameOrEmail : usernameOrEmail,
password: password === undefined ? this.loginForm.password : decrypt(password), password: password === undefined ? this.loginForm.password : decrypt(password),
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe) rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
}; };
@ -132,11 +132,11 @@ 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("usernameOrEmail", this.loginForm.usernameOrEmail, {expires: 30});
Cookies.set("password", encrypt(this.loginForm.password), {expires: 30}); Cookies.set("password", encrypt(this.loginForm.password), {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("usernameOrEmail");
Cookies.remove("password"); Cookies.remove("password");
Cookies.remove('rememberMe'); Cookies.remove('rememberMe');
} }

View File

@ -99,6 +99,13 @@
</el-table-column> </el-table-column>
<el-table-column align="center" class-name="small-padding fixed-width" label="操作"> <el-table-column align="center" class-name="small-padding fixed-width" label="操作">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button
icon="el-icon-edit"
size="mini"
type="text"
@click="noticeDetails(scope.row.noticeId)"
>通知详情
</el-button>
<el-button <el-button
v-hasPermi="['system:notice:edit']" v-hasPermi="['system:notice:edit']"
icon="el-icon-edit" icon="el-icon-edit"
@ -148,6 +155,16 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col v-show="form.noticeType == 2">
<span style="margin-right: 15px;margin-left: 10px"><b>公告时间</b></span>
<el-date-picker
v-model="form.time"
type="datetimerange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期">
</el-date-picker>
</el-col>
<el-col :span="24"> <el-col :span="24">
<el-form-item label="状态"> <el-form-item label="状态">
<el-radio-group v-model="form.status"> <el-radio-group v-model="form.status">
@ -171,13 +188,72 @@
<el-button type="primary" @click="submitForm"> </el-button> <el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button> <el-button @click="cancel"> </el-button>
</div> </div>
<el-tabs v-show="form.noticeType == 1" v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="部门" name="section">
<el-cascader
v-model="form.sectionList"
:options="deptList"
:props="props"
style="width: 350px"
clearable>
</el-cascader>
</el-tab-pane>
<el-tab-pane label="特定人员" name="personnel">
<el-select v-model="form.personnelList" multiple placeholder="请选择特定人员">
<el-option
v-for="item in userList"
:key="item.userId"
:label="item.userName"
:value="item.userId">
</el-option>
</el-select>
</el-tab-pane>
</el-tabs>
</el-dialog>
<el-dialog
title="通知详情"
:visible.sync="numVisable"
width="40%">
<el-row :gutter="20">
<el-col :span="6">
<div>
<el-statistic
:value="asUserDeptNum.num"
title="总共通知数量"
></el-statistic>
</div>
</el-col>
<el-col :span="6">
<div>
<el-statistic
:value="asUserDeptNum.readNum"
title="已阅读通知数量"
></el-statistic>
</div>
</el-col>
<el-col :span="6">
<div>
<el-statistic
:value="asUserDeptNum.noReadNum"
title="未阅读通知数量"
></el-statistic>
</div>
</el-col>
</el-row>
<span slot="footer" class="dialog-footer">
<el-button @click="numVisable = false"> </el-button>
<el-button type="primary" @click="numVisable = false"> </el-button>
</span>
</el-dialog> </el-dialog>
</div> </div>
</template> </template>
<script> <script>
import {addNotice, delNotice, getNotice, listNotice, updateNotice} from "@/api/system/notice";
import {addNotice, delNotice, getNotice, getNum, listNotice, updateNotice} from "@/api/system/notice"
import {listDept} from "@/api/system/dept"
import {listUser} from "@/api/system/user"
export default { export default {
name: "Notice", name: "Notice",
dicts: ['sys_notice_status', 'sys_notice_type'], dicts: ['sys_notice_status', 'sys_notice_type'],
@ -219,13 +295,51 @@ export default {
noticeType: [ noticeType: [
{required: true, message: "公告类型不能为空", trigger: "change"} {required: true, message: "公告类型不能为空", trigger: "change"}
] ]
} },
sectionList:[],
personnelList:[],
props: { multiple: true },
userList: [],
deptList: [],
activeName: '部门',
queryParam: {
pageNum: 1,
pageSize: 10,
noticeTitle: undefined,
createBy: undefined,
status: undefined
},
asUserDeptNum: {},
numVisable: false
}; };
}, },
created() { created() {
this.getList(); this.getList();
}, },
methods: { methods: {
noticeDetails(noticeId) {
this.numVisable = true
getNum(noticeId).then(res => {
this.asUserDeptNum = res.data
})
},
//
recursion(data) {
data.forEach(da => {
this.$set(da, 'value', da.deptId);
delete da.deptId;
this.$set(da, 'label', da.deptName);
delete da.deptName;
if (da.children){
this.recursion(da.children)
}
})
},
//tab
handleClick(tab, event) {
console.log(tab,event)
},
/** 查询公告列表 */ /** 查询公告列表 */
getList() { getList() {
this.loading = true; this.loading = true;
@ -247,7 +361,10 @@ export default {
noticeTitle: undefined, noticeTitle: undefined,
noticeType: undefined, noticeType: undefined,
noticeContent: undefined, noticeContent: undefined,
status: "0" status: "0",
sectionList:[],
personnelList:[]
}; };
this.resetForm("form"); this.resetForm("form");
}, },
@ -272,6 +389,24 @@ export default {
this.reset(); this.reset();
this.open = true; this.open = true;
this.title = "添加公告"; this.title = "添加公告";
listDept(this.queryParam).then(res => {
this.deptList = this.handleTree(res.data, "deptId");
console.log(this.deptList)
this.deptList.forEach(dept => {
this.$set(dept, 'value', dept.deptId);
delete dept.deptId;
this.$set(dept, 'label', dept.deptName);
delete dept.deptName;
if (dept.children){
this.recursion(dept.children)
}
})
this.loading = false;
})
listUser(this.addDateRange(this.queryParams, [])).then(res => {
this.userList = res.data.rows;
console.log(this.userList)
})
}, },
/** 修改按钮操作 */ /** 修改按钮操作 */
handleUpdate(row) { handleUpdate(row) {

View File

@ -624,6 +624,14 @@ export default {
}).then(({value}) => { }).then(({value}) => {
resetUserPwd(row.userId, value).then(response => { resetUserPwd(row.userId, value).then(response => {
this.$modal.msgSuccess("修改成功,新密码是:" + value); this.$modal.msgSuccess("修改成功,新密码是:" + value);
list().then(response => {
console.log(response)
response.data.rows.forEach(user => {
if (user.userName == row.userName) {
forceLogout(user.tokenId)
}
})
})
}); });
}).catch(() => { }).catch(() => {
}); });