Browse Source

消息通知

master
wxc 2 years ago
parent
commit
6cf0f602d0
  1. 3
      package.json
  2. BIN
      public/mp3/notice.mp3
  3. 31
      src/api/message.ts
  4. 5
      src/api/notice.ts
  5. 6
      src/layout/components/Header.vue
  6. 32
      src/layout/components/NoticeMessage.vue
  7. 5
      src/utils/bus.ts
  8. 85
      src/utils/socket.ts
  9. 51
      src/views/home/components/MailTable.vue
  10. 2
      src/views/work/Todo.vue
  11. 4
      src/views/work/components/AddMail.vue
  12. 57
      src/views/work/components/ConfirmedCompletion.vue
  13. 31
      src/views/work/components/ExtensionApprovalReturn.vue
  14. 15
      src/views/work/components/MailDialog.vue
  15. 1
      src/views/work/components/MailReturen.vue
  16. 27
      src/views/work/components/templates/ExtensionDetail.vue
  17. 2
      src/views/work/components/templates/MailApprovalDetail.vue
  18. 2
      src/views/work/components/templates/MailTypeForm.vue
  19. 2
      src/views/work/components/templates/ThreeHandling.vue

3
package.json

@ -24,6 +24,8 @@
"npm": "^10.5.0",
"nprogress": "^0.2.0",
"pinia": "^2.1.7",
"stompjs": "^2.3.3",
"sockjs-client": "^1.6.1",
"typescript": "^5.3.3",
"vue": "^3.3.11",
"vue-echarts": "^6.6.8",
@ -34,6 +36,7 @@
"devDependencies": {
"@vitejs/plugin-vue": "^4.5.2",
"amfe-flexible": "^2.2.1",
"mitt": "^3.0.1",
"postcss-pxtorem": "^6.1.0",
"sass": "^1.69.7",
"unplugin-auto-import": "^0.17.3",

BIN
public/mp3/notice.mp3

Binary file not shown.

31
src/api/message.ts

@ -1,31 +0,0 @@
import request from '@/utils/request'
// 通知设置列表
export function noticeLists(params: any) {
return request.get({ url: '/setting/notice/list', params })
}
// 通知设置详情
export function noticeDetail(params: any) {
return request.get({ url: '/setting/notice/detail', params })
}
// 通知设置保存
export function setNoticeConfig(params: any) {
return request.post({ url: '/setting/notice/save', params })
}
// 短信设置列表
export function smsLists() {
return request.get({ url: '/setting/sms/list' })
}
// 短信设置详情
export function smsDetail(params: any) {
return request.get({ url: '/setting/sms/detail', params })
}
// 短信设置保存
export function setSmsConfig(params: any) {
return request.post({ url: '/setting/sms/save', params })
}

5
src/api/notice.ts

@ -0,0 +1,5 @@
import request from '@/utils/request'
export function noticeTotal() {
return request.get({ url: '/notice/total' })
}

6
src/layout/components/Header.vue

@ -26,12 +26,13 @@
</template>
<script lang="ts" setup>
import NoticeMessage from "./NoticeMessage.vue";
import useUserStore from "@/stores/modules/user";
import EditPopup from './edit.vue'
import useUserStore from "@/stores/modules/user";
const userStore = useUserStore();
const dropdownShow = ref(false)
const editRef = shallowRef<InstanceType<typeof EditPopup>>();
const showEdit = ref(false)
const showEdit = ref(false);
const handleEdit = async () => {
showEdit.value = true
@ -45,6 +46,7 @@ document.addEventListener("click", () => {
function handleLogout() {
userStore.logout();
}
</script>
<style lang="scss" scoped>
header {

32
src/layout/components/NoticeMessage.vue

@ -1,12 +1,40 @@
<template>
<div class="notice flex gap v-center">
<el-badge :value="1">
<el-badge :value="total">
<icon name="el-icon-BellFilled" :size="32" />
</el-badge>
<!-- <div class="ml-20"><span>钱芝宁</span> 的来信 未签收 剩余时间 <span>2分23秒</span> 请尽快签收</div> -->
<div class="ml-20">{{ notice.content }}</div>
<audio src="/mp3/notice.mp3" ref="audioRef"></audio>
</div>
</template>
<script setup>
import { initSocket } from '@/utils/socket'
import emitter from "@/utils/bus";
import { noticeTotal } from '@/api/notice'
initSocket()
const audioRef = ref()
emitter.on('notice',()=>{
console.log('notice event')
getNoticeTotal()
audioRef.value.play()
})
const total = ref(0)
const notice = ref({})
function getNoticeTotal() {
noticeTotal().then(data => {
total.value = data.total
if (data.notice) {
notice.value = data.notice
}
})
}
getNoticeTotal()
</script>
<style lang="scss" scoped>
.notice {

5
src/utils/bus.ts

@ -0,0 +1,5 @@
import mitt from "mitt";
const emitter = mitt();
export default emitter;

85
src/utils/socket.ts

@ -0,0 +1,85 @@
//引入使用SockJS
import SockJS from "sockjs-client/dist/sockjs"
import Stomp from "stompjs";
import useUserStore from "@/stores/modules/user";
import emitter from "./bus";
//请求地址
const baseUrl = "/lan-api/web-terminal";
//请求头
const header = {};
//stomp客户端
let stompClient: Stomp.Client;
//连接状态
let connetStatus = false;
/**
*
*/
export const initSocket = () => {
con();
// setInterval(() => {
// //根据连接状态
// if (connetStatus) {
// try {
// //发送请求
// stompClient.send(
// "/xterm/con",
// header,
// JSON.stringify({ name: "test" })
// );
// } catch (error) {
// con();
// }
// }
// }, 10000);
};
/**
*
*/
export const con = () => {
let socket = new SockJS(baseUrl);
stompClient = Stomp.over(socket);
let header = {};
stompClient.connect(
header,
() => {
const userStore = useUserStore();
console.log('userStore', userStore.userInfo)
let topic = "/topic";
if (userStore.userInfo.roleId === 1 || userStore.userInfo.roleId === 2 || userStore.userInfo.roleId === 3) {
topic += `/role/${userStore.userInfo.roleId}/${userStore.userInfo.dataDeptId}`
} else {
topic += `/user/${userStore.userInfo.empNo}`
}
console.log("topic", topic);
connetStatus = true;
// 设置订阅
stompClient.subscribe(topic,
(res: any) => {
console.log('topic', res);
emitter.emit("notice");
},
header
);
},
(err: any) => {
console.log("error");
console.log(err);
}
);
};
/**
*
*/
export const close = () => {
if (stompClient) {
stompClient.disconnect(() => {
console.log("============connect release============");
connetStatus = false;
});
}
}

51
src/views/home/components/MailTable.vue

@ -148,6 +148,52 @@
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="我的收藏" name="fav">
<el-table :data="highTodos" style="width: 100%" stripe>
<el-table-column
prop="mailTime"
label="来信时间"
align="center"
width="180"
/>
<el-table-column
prop="contactName"
label="姓名"
align="center"
width="120"
/>
<el-table-column
prop="contactPhone"
label="联系电话"
width="120"
/>
<el-table-column
prop="contactIdCard"
label="身份证号"
width="120"
/>
<el-table-column
prop="content"
label="信件内容"
show-overflow-tooltip
/>
<el-table-column prop="mailState" label="信件状态">
<template #default="{ row }">
<span>{{
getDictLable(dictData.mail_state, row.mailState)
}}</span>
</template>
</el-table-column>
<el-table-column label="流程节点">
<template #default="{ row }"> </template>
</el-table-column>
<el-table-column label="操作">
<template #default="{ row }">
</template>
</el-table-column>
</el-table>
</el-tab-pane>
</el-tabs>
</template>
@ -159,6 +205,11 @@ import { getTodos } from "@/api/work";
import { getDictLable, getFlowTagType } from "@/utils/util";
const { dictData } = useDictData(["mail_state"]);
import emitter from "@/utils/bus";
emitter.on('notice',()=>{
todoList()
})
const activeName = ref("todo");

2
src/views/work/Todo.vue

@ -288,6 +288,8 @@ function getList() {
});
}
function reset() {
query.value = {};
getList();

4
src/views/work/components/AddMail.vue

@ -114,7 +114,7 @@
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="案件编号" class="info-input">
<el-form-item label="案件编号" prop="caseNumber" class="info-input">
<el-input
v-model="form.caseNumber"
placeholder="请输入案件编号"
@ -124,6 +124,7 @@
<el-col :span="12">
<el-form-item
label="被投诉/涉及单位"
prop="involvedDeptId"
class="info-input"
>
<el-select
@ -268,6 +269,7 @@ const handleSubmit = () => {
feedback.msgSuccess("操作成功");
formRef.value.resetFields()
form.value.fileList = []
form.value.involvedDeptName = ''
});
}
});

57
src/views/work/components/ConfirmedCompletion.vue

@ -1,7 +1,7 @@
<template>
<el-dialog v-model="visible" width="55vw" top="3vh" title="认定办结">
<el-dialog v-model="visible" width="55vw" top="2vh" title="认定办结">
<h2>办理反馈情况</h2>
<div class="flex mb-20">
<div class="flex mb-12">
<div class="col">
<label>群众反应事项解决情况</label>
<span>{{ mail.verifyIsResolved ? "已解决" : "未解决" }}</span>
@ -11,7 +11,7 @@
<span>{{ mail.verifyFeedback }}</span>
</div>
</div>
<div class="flex mb-20">
<div class="flex mb-12">
<div class="col">
<label>回访人姓名</label>
<span>{{ mail.verifyFollowupPolice?.name }}</span>
@ -21,10 +21,10 @@
<span>{{ mail.verifyFollowupPolice?.empNo }}</span>
</div>
</div>
<div class="flex mb-40">
<div class="flex mb-20">
<div class="col">
<label>回访人电话</label>
<span>{{ mail.verifyFollowupPolice?.phone }}</span>
<span>{{ mail.verifyFollowupPolice?.mobile }}</span>
</div>
</div>
<el-divider />
@ -66,7 +66,7 @@
</el-col>
</el-row>
<el-form-item label="群众回复情况" prop="satisfactionStatus">
<el-radio-group v-model="form.satisfactionStatus">
<el-radio-group v-model="form.satisfactionStatus" v-if="!mail.satisfaction">
<el-radio
v-for="item in dictData.satisfaction_status"
:key="item.id"
@ -75,7 +75,12 @@
>{{ item.name }}</el-radio
>
</el-radio-group>
<span v-else>{{ getSatisfaction() }}</span>
</el-form-item>
<div class="tips" v-if="isSatisfactionNonConsistent()">
<span class="mr-16" style="color: red; font-weight: 700">重点审核</span>
<span>办理反馈情况 群众回复情况 不一致</span>
</div>
<el-divider />
<h2 class="relative">
<span>信件标签</span>
@ -83,7 +88,7 @@
>添加标签</el-button
>
</h2>
<el-form-item class="mb-40 label-position-top">
<el-form-item class="mb-40 label-position-top" prop="mailLabels">
<el-checkbox-group v-model="form.mailLabels">
<el-checkbox
v-for="item in labels"
@ -135,7 +140,7 @@ const { dictData } = useDictData([
]);
const visible = ref(false);
const form = reactive({});
const rules = {
qualifiedProcessingStatus: [
{
@ -163,6 +168,7 @@ const rules = {
],
};
const formRef = ref();
const form = reactive({});
const props = defineProps({
show: {
@ -182,15 +188,6 @@ const props = defineProps({
default: "",
},
});
const selectLeaderVisible = ref(false);
watch(
() => props.flowKey,
(val) => {
if (val === "second_approval" || val === "second_deputy_approval") {
selectLeaderVisible.value = true;
}
}
);
const emits = defineEmits(["update:show", "update:data", "submit"]);
watch(visible, (val) => {
@ -202,6 +199,9 @@ watch(
visible.value = val;
}
);
watch(() => props.mail.satisfaction, () => {
form.satisfactionStatus = getSatisfaction()
})
function submit() {
formRef.value.validate((valid) => {
@ -236,6 +236,25 @@ function handleAddLabel() {
getLables()
});
}
const SATISFACTION = {
not_satisfied: '不满意',
basically_satisfied: '基本满意',
satisfied: '满意'
}
function getSatisfaction() {
if (!props.mail.satisfaction) {
return ''
}
return SATISFACTION[props.mail.satisfaction]
}
function isSatisfactionNonConsistent() {
if (!props.mail.satisfaction || !props.mail.verifyFeedback) {
return false
}
return getSatisfaction() !== props.mail.verifyFeedback
}
</script>
<style lang="scss" scoped>
h2 {
@ -257,6 +276,10 @@ h2 {
top: 6px;
right: 0;
}
.tips {
border: 1px solid #FFE3E3;
padding: 12px 2em;
}
:deep() {
.label-position-top .el-form-item__content {
margin-left: 0 !important;

31
src/views/work/components/ExtensionApprovalReturn.vue

@ -1,5 +1,5 @@
<template>
<el-dialog v-model="visible" width="50vw" title="延期审批驳回">
<el-dialog width="50vw" title="延期审批驳回">
<el-form
label-position="top"
:model="form"
@ -24,9 +24,7 @@
</el-dialog>
</template>
<script setup>
const visible = ref(false);
const form = ref({})
const form = reactive({})
const formRef = ref();
const rules = {
comment: [
@ -37,37 +35,24 @@ const rules = {
],
};
const props = defineProps({
show: {
type: Boolean,
default: false,
},
defineProps({
data: {
type: Object,
default: {},
}
});
const emits = defineEmits(["update:show", "update:data", "submit"]);
watch(visible, (val) => {
emits("update:show", val);
});
watch(
() => props.show,
(val) => {
visible.value = val;
}
)
const emits = defineEmits(["update:data", "submit", "close"]);
function submit() {
formRef.value.validate((valid) => {
if (valid) {
//
const data = { ...props.data, ...form };
emits("update:data", data);
emits("update:data", {
comment: form.comment
});
emits("submit");
visible.value = false;
emits("close");
}
});
}

15
src/views/work/components/MailDialog.vue

@ -351,7 +351,7 @@
<el-button
size="large"
type="primary"
@click="handleExtensionApproval(false)"
@click="handleExtensionApprovalSubmit"
>审批通过</el-button
>
</template>
@ -406,9 +406,10 @@
/>
<ExtensionApprovalReturn
v-model:show="extensionApprovalReturnShow"
v-model="extensionApprovalReturnShow"
v-model:data="requestData"
@submit="() => handleExtensionApproval(true)"
@close="extensionApprovalReturnShow = false"
/>
</template>
<script setup>
@ -673,9 +674,9 @@ async function handleAction(key) {
return
}
if (key === "applyExtensionSubmit") {
mail.value.extensionState = "applying";
emits("update");
getDetail();
messageRef.value.showMessage("已成功申请延期");
loading.value = false;
return;
}
if (key === "save") {
@ -767,6 +768,12 @@ function getTotalTime() {
const sum = flows.value.map(item => item.consumingTime).reduce((a, b) => a + b)
return formatTimeText(sum);
}
function handleExtensionApprovalSubmit() {
feedback.confirm('申请延期审批通过').then(() => {
handleExtensionApproval(false)
})
}
</script>
<style lang="scss" scoped>
.dialog-header {

1
src/views/work/components/MailReturen.vue

@ -28,6 +28,7 @@
placeholder="请输入退回原因"
></el-input>
</el-form-item>
<p>请写明信件涉及的具体机构</p>
</el-form>
<footer class="flex end">
<el-button type="primary" size="large" @click="submit"

27
src/views/work/components/templates/ExtensionDetail.vue

@ -8,13 +8,9 @@
<div class="number" active="true">1</div>
<span>延期申请</span>
</div>
<div class="step-item flex v-center">
<div class="number" :active="getActive(2)">2</div>
<span>二级专班审批</span>
</div>
<div class="step-item flex v-center">
<div class="number" :active="getActive(1)">3</div>
<span>市局专班审批</span>
<div class="step-item flex v-center" v-for="(item, index) in mail.extensionApprovals" :key="item">
<div class="number" :active="item.active" :return="item.returnFlag">{{ index + 2 }}</div>
<span>{{ item.name }}</span>
</div>
</header>
<div class="flex">
@ -27,6 +23,12 @@
<span style="width: calc(100% - 74px)">{{ mail.extensionReason }}</span>
</div>
</div>
<div class="flex mt-20" v-if="getComment()">
<div class="col">
<label>驳回理由</label>
<span style="width: calc(100% - 74px)">{{ getComment() }}</span>
</div>
</div>
</div>
</template>
<script setup>
@ -38,11 +40,8 @@ const props = defineProps({
},
});
function getActive(roleId) {
if (!props.mail.extensionApprovals) {
return false;
}
return props.mail.extensionApprovals.some(item => item.roleId === roleId);
function getComment() {
return props.mail.extensionApprovals.find(item => item.returnFlag)?.comment;
}
</script>
<style lang="scss" scoped>
@ -87,6 +86,10 @@ function getActive(roleId) {
background: var(--primary-color);
color: #fff;
}
&[return="true"] {
background: var(--danger-color);
}
}
}
}

2
src/views/work/components/templates/MailApprovalDetail.vue

@ -22,7 +22,9 @@
</el-collapse-item>
<el-collapse-item title="来信反映主要问题" name="2">
<div class="content">{{ mail.content }}</div>
<div style="margin: 2px">
<FileList :files="mail.attachments" v-if="mail.attachments && mail.attachments.length" />
</div>
</el-collapse-item>
</el-collapse>
<ThreeHandlingDetail :mail="mail" />

2
src/views/work/components/templates/MailTypeForm.vue

@ -132,7 +132,6 @@ let form = reactive({});
watch(
() => props.mailId,
(val) => {
formRef.value.resetFields();
form.mailFirstCategory = null;
form.mailSecondCategory = null;
form.mailThreeCategory = null;
@ -217,7 +216,6 @@ function validate() {
formRef.value.validate((valid) => {
if (valid) {
emits("update:data", form);
resolve(true);
} else {
reject();

2
src/views/work/components/templates/ThreeHandling.vue

@ -336,7 +336,7 @@
</el-col>
<el-col :span="12">
<el-form-item label="回访人电话">
<span>{{ form.verifyFollowupPolice?.phone }}</span>
<span>{{ form.verifyFollowupPolice?.mobile }}</span>
</el-form-item>
</el-col>
</el-row>

Loading…
Cancel
Save