change - add车间查看通知

master
yinq 4 months ago
parent 2332ff1642
commit 001b6e7e33

@ -1,6 +1,8 @@
package com.hw.system.controller;
import java.util.List;
import com.hw.system.domain.SysUserNotice;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
@ -89,4 +91,28 @@ public class SysNoticeController extends BaseController
{
return toAjax(noticeService.deleteNoticeByIds(noticeIds));
}
/**
* List
* @param notice
* @return
*/
@GetMapping("/workshopNoticeList")
public AjaxResult workshopNoticeList(SysNotice notice)
{
List<SysNotice> list = noticeService.workshopNoticeList(notice);
return success(list);
}
/**
*
* @param userNotice
* @return
*/
@Log(title = "通知公告", businessType = BusinessType.UPDATE)
@PostMapping("/updateUserNotice")
public AjaxResult updateUserNotice( @RequestBody SysUserNotice userNotice)
{
return toAjax(noticeService.updateUserNotice(userNotice));
}
}

@ -78,6 +78,25 @@ public class SysNotice extends BaseEntity {
*/
private List<Long> userNoticeList;
private Long userId;
private String checkStatus;
public String getCheckStatus() {
return checkStatus;
}
public void setCheckStatus(String checkStatus) {
this.checkStatus = checkStatus;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public List<Long> getUserNoticeList() {
return userNoticeList;
}

@ -82,4 +82,19 @@ public interface SysNoticeMapper
* @return
*/
public int deleteSysUserNoticeByNoticeId(Long noticeId);
/**
* List
* @param notice
* @return
*/
List<SysNotice> workshopNoticeList(SysNotice notice);
/**
*
* @param userNotice
* @return
*/
public int updateSysUserNotice(SysUserNotice userNotice);
}

@ -2,6 +2,7 @@ package com.hw.system.service;
import java.util.List;
import com.hw.system.domain.SysNotice;
import com.hw.system.domain.SysUserNotice;
/**
*
@ -57,4 +58,18 @@ public interface ISysNoticeService
* @return
*/
public int deleteNoticeByIds(Long[] noticeIds);
/**
* List
* @param notice
* @return
*/
List<SysNotice> workshopNoticeList(SysNotice notice);
/**
*
* @param userNotice
* @return
*/
public int updateUserNotice(SysUserNotice userNotice);
}

@ -2,8 +2,11 @@ package com.hw.system.service.impl;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import com.hw.common.core.utils.DateUtils;
import com.hw.common.core.utils.StringUtils;
import com.hw.common.security.utils.SecurityUtils;
import com.hw.system.common.mapper.SysPointRouterMapper;
import com.hw.system.domain.SysUserNotice;
import org.springframework.beans.factory.annotation.Autowired;
@ -133,4 +136,26 @@ public class SysNoticeServiceImpl implements ISysNoticeService
}
}
/**
* List
* @param notice
* @return
*/
@Override
public List<SysNotice> workshopNoticeList(SysNotice notice) {
Long userId = SecurityUtils.getUserId();
notice.setUserId(userId);
return noticeMapper.workshopNoticeList(notice);
}
/**
*
* @param userNotice
* @return
*/
@Override
public int updateUserNotice(SysUserNotice userNotice) {
return noticeMapper.updateSysUserNotice(userNotice);
}
}

@ -62,8 +62,26 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
AND create_by like concat('%', #{createBy}, '%')
</if>
</where>
order by create_time desc
</select>
<select id="workshopNoticeList" parameterType="SysNotice" resultMap="SysNoticeSysUserNoticeResult">
select a.notice_id, a.notice_title, a.notice_type, a.notice_content, a.status, a.station_id, a.user_group_id, a.attach_path, a.create_by, a.create_time, a.update_by, a.update_time, a.remark,
b.notice_id as sub_notice_id, b.user_id as sub_user_id, b.check_status as sub_check_status, b.check_time as sub_check_time, b.download_status as sub_download_status, b.download_time as sub_download_time
from sys_notice a
left join sys_user_notice b on b.notice_id = a.notice_id
<where>
<if test="noticeType != null and noticeType != ''">
AND a.notice_type = #{noticeType}
</if>
<if test="userId != null">
AND b.user_id = #{userId}
</if>
<if test="userId != null">
AND b.check_status = #{checkStatus}
</if>
</where>
order by a.create_time desc
</select>
<insert id="insertNotice" parameterType="SysNotice" useGeneratedKeys="true" keyProperty="noticeId">
insert into sys_notice (
<if test="noticeTitle != null and noticeTitle != '' ">notice_title, </if>
@ -135,4 +153,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</foreach>
</insert>
<update id="updateSysUserNotice" parameterType="SysUserNotice">
update sys_user_notice
<set>
<if test="checkStatus != null and checkStatus != ''">check_status = #{checkStatus}, </if>
<if test="checkTime != null">check_time = #{checkTime}, </if>
<if test="downloadStatus != null and downloadStatus != ''">download_status = #{downloadStatus}, </if>
<if test="downloadTime != null">download_time = #{downloadTime}, </if>
</set>
where notice_id = #{noticeId} and user_id = #{userId}
</update>
</mapper>

@ -42,3 +42,21 @@ export function delNotice(noticeId) {
method: 'delete'
})
}
// 车间获取通知公告List
export function workshopNoticeList(query) {
return request({
url: '/system/notice/workshopNoticeList',
method: 'get',
params: query
})
}
// 更新用户通知公告
export function updateUserNotice(data) {
return request({
url: '/system/notice/updateUserNotice',
method: 'post',
data: data
})
}

@ -0,0 +1,190 @@
<template>
<div class="upload-file">
<!-- 文件列表 -->
<transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
<li :key="file.url" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in fileList">
<el-link :href="file.url" :underline="false" target="_blank" @click.native="handleClick(file.name)">
<span class="el-icon-document"> {{ getFileName(file.name) }} </span>
</el-link>
</li>
</transition-group>
</div>
</template>
<script>
import { getToken } from "@/utils/auth";
export default {
name: "FileUpload",
props: {
//
value: [String, Object, Array],
//
limit: {
type: Number,
default: 5,
},
// (MB)
fileSize: {
type: Number,
default: 5,
},
// , ['png', 'jpg', 'jpeg']
fileType: {
type: Array,
default: () => ["doc", "xls", "ppt", "txt", "pdf"],
},
//
isShowTip: {
type: Boolean,
default: true
}
},
data() {
return {
number: 0,
uploadList: [],
uploadFileUrl: process.env.VUE_APP_BASE_API + "/file/upload", //
headers: {
Authorization: "Bearer " + getToken(),
},
fileList: [],
};
},
watch: {
value: {
handler(val) {
if (val) {
let temp = 1;
//
const list = Array.isArray(val) ? val : this.value.split(',');
//
this.fileList = list.map(item => {
if (typeof item === "string") {
item = { name: item, url: item };
}
item.uid = item.uid || new Date().getTime() + temp++;
return item;
});
} else {
this.fileList = [];
return [];
}
},
deep: true,
immediate: true
}
},
computed: {
//
showTip() {
return this.isShowTip && (this.fileType || this.fileSize);
},
},
methods: {
//
handleBeforeUpload(file) {
//
if (this.fileType) {
const fileName = file.name.split('.');
const fileExt = fileName[fileName.length - 1];
const isTypeOk = this.fileType.indexOf(fileExt) >= 0;
if (!isTypeOk) {
this.$modal.msgError(`文件格式不正确, 请上传${this.fileType.join("/")}格式文件!`);
return false;
}
}
//
if (this.fileSize) {
const isLt = file.size / 1024 / 1024 < this.fileSize;
if (!isLt) {
this.$modal.msgError(`上传文件大小不能超过 ${this.fileSize} MB!`);
return false;
}
}
this.$modal.loading("正在上传文件,请稍候...");
this.number++;
return true;
},
//
handleExceed() {
this.$modal.msgError(`上传文件数量不能超过 ${this.limit} 个!`);
},
//
handleUploadError(err) {
this.$modal.msgError("上传文件失败,请重试");
this.$modal.closeLoading()
},
//
handleUploadSuccess(res, file) {
if (res.code === 200) {
this.uploadList.push({ name: res.data.url, url: res.data.url });
this.uploadedSuccessfully();
} else {
this.number--;
this.$modal.closeLoading();
this.$modal.msgError(res.msg);
this.$refs.fileUpload.handleRemove(file);
this.uploadedSuccessfully();
}
},
//
handleDelete(index) {
this.fileList.splice(index, 1);
this.$emit("input", this.listToString(this.fileList));
},
//
uploadedSuccessfully() {
if (this.number > 0 && this.uploadList.length === this.number) {
this.fileList = this.fileList.concat(this.uploadList);
this.uploadList = [];
this.number = 0;
this.$emit("input", this.listToString(this.fileList));
this.$modal.closeLoading();
}
},
//
getFileName(name) {
// url
if (name.lastIndexOf("/") > -1) {
return name.slice(name.lastIndexOf("/") + 1);
} else {
return name;
}
},
//
listToString(list, separator) {
let strs = "";
separator = separator || ",";
for (let i in list) {
strs += list[i].url + separator;
}
return strs != '' ? strs.substr(0, strs.length - 1) : '';
},
handleClick(fileName) {
this.$emit('file-clicked', this.getFileName(fileName)); //
}
}
};
</script>
<style scoped lang="scss">
.upload-file-uploader {
margin-bottom: 5px;
}
.upload-file-list .el-upload-list__item {
border: 1px solid #e4e7ed;
line-height: 2;
margin-bottom: 10px;
position: relative;
}
.upload-file-list .ele-upload-list__item-content {
display: flex;
justify-content: space-between;
align-items: center;
color: inherit;
}
.ele-upload-list__item-content-action .el-link {
margin-right: 10px;
}
</style>

@ -0,0 +1,299 @@
<template>
<div>
<el-upload
:action="uploadUrl"
:before-upload="handleBeforeUpload"
:on-success="handleUploadSuccess"
:on-error="handleUploadError"
name="file"
:show-file-list="false"
:headers="headers"
style="display: none"
ref="upload"
v-if="this.type == 'url'"
>
</el-upload>
<div class="editor" ref="editor" :style="styles"></div>
</div>
</template>
<script>
import Quill from "quill";
import "quill/dist/quill.core.css";
import "quill/dist/quill.snow.css";
import "quill/dist/quill.bubble.css";
import {getToken} from "@/utils/auth";
export default {
name: "ReadOnlyEditor",
props: {
/* 编辑器的内容 */
value: {
type: String,
default: "",
},
/* 高度 */
height: {
type: Number,
default: null,
},
/* 最小高度 */
minHeight: {
type: Number,
default: null,
},
/* 只读 */
readOnly: {
type: Boolean,
default: true,
},
/* 上传文件大小限制(MB) */
fileSize: {
type: Number,
default: 5,
},
/* 类型base64格式、url格式 */
type: {
type: String,
default: "url",
}
},
data() {
return {
uploadUrl: process.env.VUE_APP_BASE_API + "/file/upload", //
headers: {
Authorization: "Bearer " + getToken()
},
Quill: null,
currentValue: "",
options: {
theme: "snow",
bounds: document.body,
debug: "warn",
modules: {
//
toolbar: [
// ["bold", "italic", "underline", "strike"], // 线 线
// ["blockquote", "code-block"], //
// [{ list: "ordered" }, { list: "bullet" }], //
// [{ indent: "-1" }, { indent: "+1" }], //
// [{ size: ["small", false, "large", "huge"] }], //
// [{ header: [1, 2, 3, 4, 5, 6, false] }], //
// [{ color: [] }, { background: [] }], //
// [{ align: [] }], //
// ["clean"], //
// ["link", "image", "video"] //
],
},
placeholder: "请输入内容",
readOnly: this.readOnly,
},
fileList: [],
};
},
computed: {
styles() {
let style = {};
if (this.minHeight) {
style.minHeight = `${this.minHeight}px`;
}
if (this.height) {
style.height = `${this.height}px`;
}
return style;
},
},
watch: {
value: {
handler(val) {
console.log(22,val)
if (val !== this.currentValue) {
this.currentValue = val === null ? "" : val;
if (this.Quill) {
this.Quill.pasteHTML(this.currentValue);
}
}
},
immediate: true,
},
},
mounted() {
this.init();
},
beforeDestroy() {
this.Quill = null;
},
methods: {
init() {
const editor = this.$refs.editor;
this.Quill = new Quill(editor, this.options);
//
// const toolbar = editor.previousElementSibling;
// if (toolbar && toolbar.classList.contains('ql-toolbar')) {
// toolbar.style.display = 'none';
// }
//
if (this.type == 'url') {
let toolbar = this.Quill.getModule("toolbar");
toolbar.addHandler("image", (value) => {
if (value) {
this.$refs.upload.$children[0].$refs.input.click();
} else {
this.quill.format("image", false);
}
});
}
this.Quill.pasteHTML(this.currentValue);
this.Quill.on("text-change", (delta, oldDelta, source) => {
const html = this.$refs.editor.children[0].innerHTML;
const text = this.Quill.getText();
const quill = this.Quill;
this.currentValue = html;
this.$emit("input", html);
this.$emit("on-change", {html, text, quill});
});
this.Quill.on("text-change", (delta, oldDelta, source) => {
this.$emit("on-text-change", delta, oldDelta, source);
});
this.Quill.on("selection-change", (range, oldRange, source) => {
this.$emit("on-selection-change", range, oldRange, source);
});
this.Quill.on("editor-change", (eventName, ...args) => {
this.$emit("on-editor-change", eventName, ...args);
});
},
//
handleBeforeUpload(file) {
const type = ["image/jpeg", "image/jpg", "image/png", "image/svg"];
const isJPG = type.includes(file.type);
//
if (!isJPG) {
this.$message.error(`图片格式错误!`);
return false;
}
//
if (this.fileSize) {
const isLt = file.size / 1024 / 1024 < this.fileSize;
if (!isLt) {
this.$message.error(`上传文件大小不能超过 ${this.fileSize} MB!`);
return false;
}
}
return true;
},
handleUploadSuccess(res, file) {
//
if (res.code == 200) {
//
let quill = this.Quill;
//
let length = quill.getSelection().index;
// res.url
quill.insertEmbed(length, "image", res.data.url);
//
quill.setSelection(length + 1);
} else {
this.$message.error("图片插入失败");
}
},
handleUploadError() {
this.$message.error("图片插入失败");
},
},
};
</script>
<style>
.editor, .ql-toolbar {
white-space: pre-wrap !important;
line-height: normal !important;
}
.quill-img {
display: none;
}
.ql-snow .ql-tooltip[data-mode="link"]::before {
content: "请输入链接地址:";
}
.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
border-right: 0px;
content: "保存";
padding-right: 0px;
}
.ql-snow .ql-tooltip[data-mode="video"]::before {
content: "请输入视频地址:";
}
.ql-snow .ql-picker.ql-size .ql-picker-label::before,
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
content: "14px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
content: "10px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
content: "18px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
content: "32px";
}
.ql-snow .ql-picker.ql-header .ql-picker-label::before,
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
content: "文本";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
content: "标题1";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
content: "标题2";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
content: "标题3";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
content: "标题4";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
content: "标题5";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
content: "标题6";
}
.ql-snow .ql-picker.ql-font .ql-picker-label::before,
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
content: "标准字体";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
content: "衬线字体";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
content: "等宽字体";
}
</style>

@ -0,0 +1,70 @@
<template>
<el-dialog :visible.sync="visible" title="通知" width="50%">
<el-form ref="form" :model="noticeListData" label-width="100px">
<el-row>
<el-col :span="12">
<el-form-item label="公告标题:" prop="noticeTitle">
<span>{{ noticeListData.noticeTitle }}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="公告类型" prop="noticeType">
<el-select v-model="noticeListData.noticeType" placeholder="请选择公告类型" disabled>
<el-option
v-for="dict in dict.type.sys_notice_type"
:key="dict.value"
:label="dict.label"
:value="dict.value"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="内容">
<ReadOnlyEditor v-model="noticeListData.noticeContent" :min-height="192"/>
<DownloadFile v-model="noticeListData.attachPath" @file-clicked="handleFileClick"/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="visible = false">关闭</el-button>
</span>
</el-dialog>
</template>
<script>
import ReadOnlyEditor from "@/components/ReadOnlyEditor/index.vue";
import DownloadFile from "@/components/DownloadFile/index.vue";
import {updateUserNotice} from "@/api/system/notice";
import {parseTime} from "@/utils/ruoyi";
export default {
dicts: ['sys_notice_status', 'sys_notice_type'],
components: {
ReadOnlyEditor,
DownloadFile
},
props: {
visible: {
type: Boolean,
default: false,
},
noticeListData: {
type: Object,
default: () => [],
},
},
methods: {
handleFileClick(fileUrl) {
console.log('已下载文件:', fileUrl);
let userNotice = this.noticeListData.sysUserNoticeList[0];
userNotice.downloadStatus = '1'
userNotice.downloadTime = parseTime(new Date());
userNotice.checkTime = null;
updateUserNotice(userNotice).then(res => {
})
}
}
};
</script>

@ -0,0 +1,58 @@
import {updateUserNotice, workshopNoticeList} from "@/api/system/notice";
import {parseTime} from "@/utils/ruoyi";
export const noticeData = {
data() {
return {
showTableDialog: false,
//用户下的通知公告List
noticeList: [],
//当前显示的通知公告
noticeListData: {},
notificationInstance: null // 保存通知实例
};
},
mounted() {
setInterval(() => {
workshopNoticeList({noticeType: '1', checkStatus: '0'}).then(res => {
this.noticeList = res.data;
if (this.noticeList.length > 0) {
this.notificationInstance = this.$notify.info({
title: '通知',
position: 'bottom-right',
duration: 0,
message: this.$createElement(
"div",
{
on: {
click: () => {
this.handleNotificationClick();
},
},
},
[this.$createElement("el-button", {}, ["点击查看"])]
),
});
}
});
}, 60 * 1000)
},
methods: {
handleNotificationClick() {
this.noticeListData = this.noticeList[0];
let userNotice = this.noticeListData.sysUserNoticeList[0];
userNotice.checkStatus = '1'
userNotice.checkTime = parseTime(new Date());
//更新用户公告查看状态
updateUserNotice(userNotice).then(res => {
this.showTableDialog = true;
})
if (this.notificationInstance) {
this.notificationInstance.close(); // 手动关闭通知
}
},
}
};

@ -544,6 +544,9 @@
/>
</el-dialog>
<div id="workshopNotice">
<WorkshopNotice :visible.sync="showTableDialog" :noticeListData="noticeListData"></WorkshopNotice>
</div>
</div>
</template>
@ -551,6 +554,8 @@
import Chart from '@/components/board/Chart'
import PrintPage from '@/views/mes/barcode/endProductIndex'
import {monitorSerialData} from "@/utils/serial"
import WorkshopNotice from "@/components/workshopNotice/index.vue";
import {noticeData} from "@/utils/notice"
import * as echarts from 'echarts'
import {
getStockTotal,
@ -574,9 +579,10 @@ export default {
dicts: ['mes_plan_detail_status', 'wms_raw_return_task_type',"mes_safe_flag"],
components: {
Chart,
PrintPage
PrintPage,
WorkshopNotice
},
mixins: [monitorSerialData],
mixins: [monitorSerialData, noticeData],
data() {
return {
info: {},

Loading…
Cancel
Save