From e2f129ee192ae3469848beeceac262b13ba8eacb Mon Sep 17 00:00:00 2001 From: 马宇豪 <978517621@qq.com> Date: 星期三, 14 六月 2023 15:52:11 +0800 Subject: [PATCH] 新增页面和配置,对接口 --- src/views/Admin/Report.vue | 448 +++-- src/views/Admin/msgRecord.vue | 161 + src/views/Admin/menuManage.vue | 4 src/assets/style/themeColor.less | 3 src/views/Admin/history.vue | 278 +++ src/api/list.js | 59 src/api/send.js | 49 src/views/Admin/notice.vue | 493 ++++- src/views/Admin/msgReview.vue | 192 +- src/api/review.js | 44 src/api/login.js | 8 src/views/Admin/components/userMod.vue | 200 ++ src/views/Admin/callRecord.vue | 370 ++-- src/api/user.js | 55 src/views/Admin/release.vue | 246 ++- src/util/request.js | 9 src/util/storage.js | 7 src/views/Admin/components/sameLevelMod.vue | 124 + src/router/index.js | 6 /dev/null | 183 -- src/views/Admin/components/msgEditMod.vue | 531 ++++++ src/views/Admin/list.vue | 455 +++-- src/layout/menu/index.js | 2 src/views/Admin/massSend.vue | 305 ++- src/views/Admin/sameLevel.vue | 178 + src/views/Admin/userManage.vue | 97 src/views/Home.vue | 21 27 files changed, 3,231 insertions(+), 1,297 deletions(-) diff --git a/src/api/list.js b/src/api/list.js new file mode 100644 index 0000000..5de5cff --- /dev/null +++ b/src/api/list.js @@ -0,0 +1,59 @@ +//将拦截器整体导入 +import request from '@/util/request'//导入已经写好的拦截器 + +// 我收到的 +export function getMsgRecord(data){ + return request({ + url: '/published/warninfo/receive/Page', + method: 'post', + data: data + }) +} + +// 叫应 +export function responseMsg(id){ + return request({ + url: '/published/warninfo/responseById?id=' + id, + method: 'get' + }) +} + + +export function readById(id){ + return request({ + url: '/published/warninfo/readById?id=' + id, + method: 'get' + }) +} + +// 我发出的 +export function getPublishRecord(data){ + return request({ + url: '/published/warninfo/publish/Page', + method: 'post', + data: data + }) +} + +// 历史信息 +export function getHistoryRecord(data){ + return request({ + url: '/published/warninfo/history/publish', + method: 'post', + data: data + }) +} + +// 历史叫应信息 +export function getResponseRecord(data){ + return request({ + url: '/published/warninfo/history/response', + method: 'post', + data: data + }) +} + + + + + diff --git a/src/api/login.js b/src/api/login.js index 03b659c..b117b4d 100644 --- a/src/api/login.js +++ b/src/api/login.js @@ -21,4 +21,12 @@ url:'/sys/menu/get/u', method:'get', }) +} + +// 获取区划列表 +export function getDistrictInfo(){ + return request({ + url:'/sys/districtInfo/all', + method:'get', + }) } \ No newline at end of file diff --git a/src/api/review.js b/src/api/review.js new file mode 100644 index 0000000..3d97ea3 --- /dev/null +++ b/src/api/review.js @@ -0,0 +1,44 @@ +//将拦截器整体导入 +import request from '@/util/request'//导入已经写好的拦截器 + +// 审核记录 +export function getReviewRecord(data){ + return request({ + url: '/warning/info/review/Page', + method: 'post', + data: data + }) +} + +// 信息详情 +export function getReviewDetail(id){ + return request({ + url: '/warning/info/review/findById?id=' + id, + method: 'get' + }) +} + +// 工作人员查看详情 +export function getReviewDetailByWorker(id){ + return request({ + url: '/warning/info/findById?id=' + id, + method: 'get' + }) +} + +// 提交审核 +export function postReview(data){ + return request({ + url: '/warning/info/review/submit', + method: 'post', + data: data + }) +} + + + + + + + + diff --git a/src/api/send.js b/src/api/send.js new file mode 100644 index 0000000..621e9f7 --- /dev/null +++ b/src/api/send.js @@ -0,0 +1,49 @@ +//将拦截器整体导入 +import request from '@/util/request'//导入已经写好的拦截器 + +// 信息编辑 +export function msgSend(data){ + return request({ + url: '/warning/info/add', + method: 'post', + data: data + }) +} + +// 群发信息 +export function massSend(data){ + return request({ + url: '/mesmanager/mes/send', + method: 'post', + data: data + }) +} + +export function getMassRecord(data){ + return request({ + url: '/mesmanager/mes/page', + method: 'post', + data: data + }) +} + +// 发布信息 +export function publishMsg(id){ + return request({ + url: '/warning/info/publishById?id=' + id, + method: 'get' + }) +} + +// 删除信息 +export function deleteMsg(id){ + return request({ + url: '/warning/info/deleteById?id=' + id, + method: 'get' + }) +} + + + + + diff --git a/src/api/user.js b/src/api/user.js index 15e2ee5..3ed0cc0 100644 --- a/src/api/user.js +++ b/src/api/user.js @@ -18,6 +18,14 @@ }) } +export function updateUser(data){ + return request({ + url: '/account/user/update/info', + method: 'post', + data: data, + }) +} + export function delUser(id){ return request({ url: '/account/user/deleteUser?userId=' + id, @@ -42,28 +50,57 @@ }) } -export function getRecipientById(data){ +export function getRecipientById(id){ return request({ - url:'/mesmanager/recipient/findById', - method:'post', - data:data, + url:'/mesmanager/recipient/findById?id=' + id, + method:'get' + }) +} + +export function getPeerRecipient(){ + return request({ + url:'/mesmanager/recipient/listPeerRecipient', + method:'get' + }) +} + +export function getAreaWithUserIfo(){ + return request({ + url:'/sys/districtInfo/allWithUserIfo', + method:'get' }) } export function addRecipient(data){ return request({ - url:'/mesmanager/recipient/page', + url:'/mesmanager/recipient/add', method:'post', data:data, }) } +export function updateRecipient(data){ + return request({ + url:'/mesmanager/recipient/update', + method:'post', + data:data, + }) +} +export function delRecipient(id){ + return request({ + url:'/mesmanager/recipient/delete?id=' + id, + method: 'get' + }) +} - - - - +// 获取同级领导 +export function getLeaders(){ + return request({ + url: '/account/user/list/auditors', + method: 'get' + }) +} diff --git a/src/assets/style/themeColor.less b/src/assets/style/themeColor.less index ba150f3..a7a9ba5 100644 --- a/src/assets/style/themeColor.less +++ b/src/assets/style/themeColor.less @@ -3,4 +3,5 @@ @success: #52c41a; @warning: #faad14; @danger: #f5222d; -@blackText: rgba(0,0,0,.65); \ No newline at end of file +@blackText: rgba(0,0,0,.65); +@blackBorder: #d9d9d9; \ No newline at end of file diff --git a/src/layout/menu/index.js b/src/layout/menu/index.js index f4df312..44cb324 100644 --- a/src/layout/menu/index.js +++ b/src/layout/menu/index.js @@ -36,7 +36,7 @@ Children: [{ MenuID: "21", MenuTitle: "信息编辑", - MenuPath: "/torelease", + MenuPath: "/notice", }, { MenuID: "22", diff --git a/src/router/index.js b/src/router/index.js index 3378c61..8cbbfaa 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -53,8 +53,8 @@ component: () => import('@/views/Admin/Audit'), }, { - path: '/torelease', - name: 'torelease', + path: '/notice', + name: 'notice', meta: { title: '信息编辑' }, component: () => import('@/views/Admin/notice'), }, @@ -74,7 +74,7 @@ path: '/history', name: 'history', meta: { title: '历史信息' }, - component: () => import('@/views/Admin/History'), + component: () => import('@/views/Admin/history'), }, { path: '/callRecord', diff --git a/src/util/request.js b/src/util/request.js index 34ba6b5..2fb29a4 100644 --- a/src/util/request.js +++ b/src/util/request.js @@ -35,8 +35,13 @@ http.interceptors.response.use( (response) => { // 对响应数据做点什么 - if (response.data.code && response.data.code === 'A0213') { - message.error('用户uid不存在'); + if (response.data.code && response.data.code === 401) { + message.error('用户不存在'); + loginOut() + .then(() => { + Session.clear(); + window.location.href = '/'; + }); // useLoginApi() // .signOut() // .then(() => { diff --git a/src/util/storage.js b/src/util/storage.js index 614ef0f..c691e0e 100644 --- a/src/util/storage.js +++ b/src/util/storage.js @@ -7,6 +7,13 @@ * @method remove 移除永久缓存 * @method clear 移除全部永久缓存 */ +export function getUserInfo() { + const userInfo = Cookies.get('userInfo') + if(userInfo){ + return JSON.parse(userInfo) + } +} + export const Local = { // 设置永久缓存 set(key, val) { diff --git a/src/views/Admin/History.vue b/src/views/Admin/History.vue deleted file mode 100644 index ac846ed..0000000 --- a/src/views/Admin/History.vue +++ /dev/null @@ -1,183 +0,0 @@ -<template> - <div class="inner"> - <template> - <a-alert message="提示:此处显示您及您辖区下的所有历史发布信息。" type="info" close-text="关闭提示" /> - </template> - - <br /> - <a-radio-group v-model="category"> - <a-radio-button value="default"> - 全部 - </a-radio-button> - <a-radio-button value="1"> - 紧临 - </a-radio-button> - <a-radio-button value="2"> - 常规 - </a-radio-button> - </a-radio-group> - <div style="float:right"> - 时间区间筛选:<a-range-picker :placeholder="['开始时间', '结束时间']"/> - </div> - <br /><br /> - <!-- 表格实体部分--> - <a-table :columns="columns" :data-source="data" bordered> - <span slot="level" slot-scope="text"> - <a-tag :color="text === '黄色' ? 'yellow' :text === '橙色'? 'orange':text === '红色'?'red':'blue'"> - {{ text }} - </a-tag> - </span> - <template slot="attachment" slot-scope="text"> - <span v-if="text==='无'">无</span> - <a v-else><b><a-icon type="paper-clip" /> {{text}}</b></a> - </template> - <template slot="operation" slot-scope="text, record, index"> - <div class="editable-row-operations"> - <a @click="showModal" style="color:orangered"> - 叫应列表</a> - <router-link :to="{path:'/details',query: {id: record.id}}">信息详情</router-link> - </div> - </template> - </a-table> - <!-- 对话框 --> - <a-modal title="查看叫应详情" okText="确认" cancelText="关闭" :visible="visible" :confirm-loading="confirmLoading" - @ok="handleOk" @cancel="handleOk"> - </a-modal> - </div> -</template> -<script> - const columns = [{ - title: '序号', - dataIndex: 'key', - width: '8%', - }, - { - title: '发布时间', - dataIndex: 'time', - width: '15%', - scopedSlots: { - customRender: 'time' - }, //设置定制化表格数据 - }, - { - title: '发布单位', - dataIndex: 'department', - width: '12%', - }, - { - title: '类别', - dataIndex: 'category', - width: '8%', - }, - { - title: '级别', - dataIndex: 'level', - scopedSlots: { - customRender: 'level' - }, //设置定制化表格数据 - width: '8%', - }, - { - title: '信息标题', - dataIndex: 'title', - width: '16%', - }, - { - title: '附件', - dataIndex: 'attachment', - width: '6%', - scopedSlots: { - customRender: 'attachment' - }, - }, - { - title: '叫应情况', - dataIndex: 'receipt', - width: '10%', - scopedSlots: { - customRender: 'receipt' - }, //设置定制化表格数据 - }, - { - title: '操作', - dataIndex: 'operation', - scopedSlots: { - customRender: 'operation' - }, - }, - ]; - const data = [{ - key: 1, - id: 1001, - time: '2023年5月3日 15:30', - department: '自治区预警中心', - category: '气象', - level: '黄色', - title: '全疆高温黄色预警', - attachment: '1', - receipt: '部分叫应' - }, - { - key: 2, - id: 1002, - time: '2023年5月3日 15:30', - department: '自治区预警中心', - category: '气象', - level: '黄色', - title: '全疆高温黄色预警', - attachment: '1', - receipt: '全部叫应' - }, { - key: 3, - id: 1003, - time: '2023年5月3日 15:30', - department: '自治区预警中心', - category: '气象', - level: '黄色', - title: '全疆高温黄色预警', - attachment: '1', - receipt: '均未叫应' - }, { - key: 4, - id: 1004, - time: '2023年5月3日 15:30', - department: '阿克苏应急管理局', - category: '气象', - level: '红色', - title: '阿克苏地区高温红色预警', - attachment: '1', - receipt: '均未叫应' - }, { - key: 5, - id: 1005, - time: '2023年5月1日 15:30', - department: '阿克苏应急管理局', - category: '气象', - level: '红色', - title: '全疆高温红色预警', - attachment: '1', - receipt: '均未叫应' - } - ] - export default { - data() { - return { - category: 'default', - data, - columns, - visible: false, - confirmLoading: false, - } - }, - methods: { - //弹出层 - showModal() { - this.visible = true; - }, - handleOk(e) { - this.visible = false; - }, - - } - } -</script> \ No newline at end of file diff --git a/src/views/Admin/Report.vue b/src/views/Admin/Report.vue index eecfb70..d90fbd7 100644 --- a/src/views/Admin/Report.vue +++ b/src/views/Admin/Report.vue @@ -1,175 +1,283 @@ <template> <div class="inner"> - <a-radio-group v-model="category"> - <a-radio-button value="default"> - 全部 - </a-radio-button> - <a-radio-button value="1"> - 已审核 - </a-radio-button> - <a-radio-button value="2"> - 未审核 - </a-radio-button> - </a-radio-group> - <div style="float:right"> - 时间区间筛选:<a-range-picker :placeholder="['开始时间', '结束时间']"/> - </div> - <br/><br/> - <!-- 表格实体部分--> - <a-table :columns="columns" :data-source="data" bordered> - <span slot="level" slot-scope="text"> - <a-tag :color="text === '黄色' ? 'yellow' :text === '橙色'? 'orange':text === '红色'?'red':'blue'"> - {{ text }} - </a-tag> - </span> - <template slot="attachment" slot-scope="text"> - <span v-if="text==='无'">无</span> - <a v-else><b><a-icon type="paper-clip" /> {{text}}</b></a> - </template > - <template slot="operation" slot-scope="text, record, index"> - <div class="editable-row-operations"> - <a-button v-if="record.audit==='已审核'" type="primary" @click="showModal(record.id)" > - 确认发布</a-button> - <router-link :to="{path:'/details',query: {id: record.id}}">信息详情</router-link> - <a style="color:red">删除</a> - </div> - </template> - </a-table> - <!-- 对话框 --> - <a-modal title="信息发布" - okText="确认发布" - cancelText="取消" - :visible="visible" :confirm-loading="confirmLoading" @ok="handleOk" @cancel="handleCancel"> - <p>确认发布 “[{{show_id}}]2023年5月23日,全疆黄色高温预警信息”?</p> - </a-modal> + <a-row type="flex" justify="space-between" style="margin-bottom: 20px"> + <a-col :span="8"> + <a-radio-group v-model="search.searchParams.reviewStatus" @change="getData"> + <a-radio-button :value="null"> + 全部 + </a-radio-button> + <a-radio-button :value="2"> + 审核通过 + </a-radio-button> + <a-radio-button :value="1"> + 未审核 + </a-radio-button> + <a-radio-button :value="3"> + 审核驳回 + </a-radio-button> + </a-radio-group> + </a-col> + <a-col :span="16"> + <a-row type="flex" justify="end" :gutter="12"> + <a-col :span="8"> + <a-range-picker + v-model="timeRange" + format="YYYY-MM-DD" + :placeholder="['开始时间', '结束时间']" + @change="timeChange" + @ok="onOk" + style="width: 100%" + /> + </a-col> + <a-col :span="4"> + <a-button type="primary" @click="getData">查询</a-button> + <a-button style="margin-left: 12px" @click="resetSearch">重置</a-button> + </a-col> + </a-row> + </a-col> + </a-row> + + <div class="table-cont"> + <a-table :columns="columns" :data-source="data" bordered :pagination="pagination" :rowKey="record=>record.id"> + <template #index="text,record,index"> + {{ index+1 }} + </template> + <template #disasterType="text"> + {{ getRiskName(text) }} + </template> + <template #attachment="text"> + <span v-if="text==='无'">无</span> + <a v-else><b><a-icon type="paper-clip" /> {{text}}</b></a> + </template > + <template #reviewStatus="reviewStatus"> + <a-tag + :color="reviewStatus === 1 ? 'blue' : reviewStatus === 2 ? 'green' : 'red'" + > + {{ reviewStatus==1?'未审核':reviewStatus==2?'已审核':reviewStatus==3?'审核驳回':'' }} + </a-tag> + </template> + <template #operation="text, record, index"> + <a-button type="primary" v-if="record.reviewStatus == 2" @click="confirmPost(record.id)">确认发布</a-button> + <a-button type="link" v-if="record.reviewStatus == 2 || record.reviewStatus == 3" @click="openMod('view',record)">查看信息详情</a-button> + <a-button class="del" type="link" @click="delData(record.id)">删除</a-button> + </template> + </a-table> + </div> + <msg-edit-mod ref="msgEdit" @refresh="getData"></msg-edit-mod> </div> </template> -<script> - const columns = [{ - title: '编号', - dataIndex: 'id', - width: '8%', - }, - { - title: '提交审核时间', - dataIndex: 'time', - width: '13%', - scopedSlots: { - customRender: 'time' - }, //设置定制化表格数据 - }, - { - title: '发布单位', - dataIndex: 'department', - width: '12%', - }, - { - title: '类别', - dataIndex: 'category', - width: '6%', - }, - { - title: '级别', - dataIndex: 'level', - scopedSlots: { - customRender: 'level' - }, //设置定制化表格数据 - width: '6%', - }, - { - title: '信息标题', - dataIndex: 'title', - width: '16%', - }, - { - title: '附件', - dataIndex: 'attachment', - width: '6%', - scopedSlots: { - customRender: 'attachment' - }, - }, - { - title: '审核情况', - dataIndex: 'audit', - width: '10%', - scopedSlots: { - customRender: 'audit' - }, //设置定制化表格数据 - }, - { - title: '操作', - dataIndex: 'operation', - scopedSlots: { - customRender: 'operation' - }, - }, - ]; - const data = [{ - key: 1, - id:1001, - readed:false, - time: '2023年5月3日 15:30', - department: '自治区预警中心', - category: '气象', - level: '黄色', - title: '全疆高温红色预警', - attachment: '1', - audit: '已审核' - }, - { - key: 2, - id:1002, - readed:false, - time: '2023年5月3日 15:30', - department: '自治区预警中心', - category: '气象', - level: '黄色', - title: '全疆高温红色预警', - attachment: '1', - audit: '未审核' - },{ - key: 3, - id:1003, - readed:false, - time: '2023年5月3日 15:30', - department: '自治区预警中心', - category: '气象', - level: '黄色', - title: '全疆高温红色预警', - attachment: '1', - audit: '已审核' - }] - export default { - data() { - return { - category: 'default', - data, - columns, - visible: false, - confirmLoading: false, - show_id:'' - } - }, - methods: { - showModal(id) { - this.visible = true; - this.show_id=id - }, - //确认发布 - handleOk(e) { - this.ModalText = '正在发布,请稍候...'; - this.confirmLoading = true; - setTimeout(() => { - this.visible = false; - this.confirmLoading = false; - }, 2000); - }, - handleCancel(e) { - this.visible = false; - }, - } - } - -</script> \ No newline at end of file +<script> + +import {getReviewDetail, getReviewRecord} from "@/api/review"; +import msgEditMod from '@/views/Admin/components/msgEditMod' +import {delRecipient} from "@/api/user"; +import {deleteMsg, publishMsg} from "@/api/send"; + +export default { + name: 'msgReview', + components: { msgEditMod }, + data () { + return { + search:{ + pageIndex: 1, + pageSize: 10, + searchParams:{ + reviewStatus: null, + startTime: '', + endTime: '' + } + }, + timeRange: [], + riskOptions: [ + {name: '地震',value: 1}, + {name: '洪涝',value: 2}, + {name: '气象',value: 3}, + {name: '泥石流',value: 4}, + {name: '水旱',value: 5}, + {name: '森林草原火灾',value: 6} + ], + pagination: { + current: 1, + defaultCurrent: 1, + defaultPageSize: 10, + total: 0, + onChange: ( page, pageSize ) => this.onPageChange(page,pageSize), + showTotal: total => `共 ${total} 条` + }, + columns: [ + { + title: '序号', + key: 'index', + scopedSlots: { + customRender: 'index' + }, + }, + { + title: '提交审核时间', + key: 'gmtReviewSubmit', + dataIndex: 'gmtReviewSubmit', + }, + { + title: '发布单位', + key: 'publishingUnit', + dataIndex: 'publishingUnit', + }, + { + title: '灾种', + dataIndex: 'disasterType', + key: 'disasterType', + scopedSlots: { + customRender: 'disasterType' + }, //设置定制化表格数据 + }, + { + title: '信息标题', + key: 'title', + dataIndex: 'title', + }, + { + title: '附件', + key: 'attachment', + dataIndex: 'attachment', + scopedSlots: { + customRender: 'attachment' + }, + }, + { + title: '审核情况', + dataIndex: 'reviewStatus', + scopedSlots: { + customRender: 'reviewStatus' + }, //设置定制化表格数据 + }, + { + title: '操作', + dataIndex: 'operation', + scopedSlots: { + customRender: 'operation' + }, + }, + ], + data: [] + } + }, + created() { + const t = this + t.getData() + }, + methods:{ + async getData(){ + const t = this + const res = await getReviewRecord(this.search) + if(res.data.code == 100){ + t.data = res.data.data + t.pagination.total = res.data.total + }else{ + this.$message.error(res.data.msg) + } + }, + + resetSearch(){ + const t = this + t.search = { + pageIndex: 1, + pageSize: 10, + searchParams:{ + reviewStatus: null, + startTime: '', + endTime: '' + } + } + t.timeRange = [] + t.getData() + }, + + timeChange(value, dateString) { + const t = this + if(dateString){ + t.search.searchParams.startTime = value[0].format('YYYY-MM-DD 00:00:00') + t.search.searchParams.endTime = value[1].format('YYYY-MM-DD 23:59:59') + } + }, + + confirmPost(id){ + const t = this + this.$confirm({ + title: '提示', + content: h => <div>是否发布该条信息?</div>, + cancelText: '取消', + okText: '确认', + centered: true, + async onOk() { + let res = await publishMsg(id) + if(res.data.code == 100){ + t.$message.success('信息发布成功'); + t.getData() + }else{ + t.$message.warning(res.data.msg); + } + }, + onCancel() { + console.log('Cancel'); + }, + }); + }, + + delData(id){ + const t = this + this.$confirm({ + title: '提示', + content: h => <div>是否删除该条信息?</div>, + cancelText: '取消', + okText: '确认', + centered: true, + async onOk() { + let res = await deleteMsg(id) + if(res.data.code == 100){ + t.$message.success('信息删除成功'); + t.getData() + }else{ + t.$message.warning(res.data.msg); + } + }, + onCancel() { + console.log('Cancel'); + }, + }); + }, + + openMod(type,data){ + const t = this + getReviewDetail(data.id).then(res=>{ + if(res.data.code == 100){ + t.$refs.msgEdit.openMod(type,res.data.data) + }else{ + this.$message.error(res.data.msg) + } + }) + }, + + onPageChange(page, pageSize) { + const t= this + t.pagination.current = page + t.search.pageIndex = page + t.getData() + }, + + onOk(value) { + console.log('onOk: ', value); + }, + getRiskName(disasterType){ + return this.riskOptions.find(i => i.value === disasterType)?.name; + } + + } +} +</script> + +<style lang="less" scoped> +.del{ + color: @danger; +} +</style> diff --git a/src/views/Admin/callRecord.vue b/src/views/Admin/callRecord.vue index 206bdeb..7615f63 100644 --- a/src/views/Admin/callRecord.vue +++ b/src/views/Admin/callRecord.vue @@ -1,200 +1,254 @@ <template> <div class="inner"> + <a-row type="flex" justify="space-between" style="margin-bottom: 20px"> + <a-col :span="8"> + <a-radio-group v-model="search.searchParams.emergType" @change="getData"> + <a-radio-button :value="null"> + 全部 + </a-radio-button> + <a-radio-button :value="1"> + 紧临 + </a-radio-button> + <a-radio-button :value="2"> + 常规 + </a-radio-button> + </a-radio-group> + </a-col> + <a-col :span="16"> + <a-row type="flex" justify="end" :gutter="12"> + <a-col :span="8"> + <a-range-picker + v-model="timeRange" + format="YYYY-MM-DD" + :placeholder="['开始时间', '结束时间']" + @change="timeChange" + @ok="timeOk" + style="width: 100%" + /> + </a-col> + <a-col :span="4"> + <a-button type="primary" @click="getData">查询</a-button> + <a-button style="margin-left: 12px" @click="resetSearch">重置</a-button> + </a-col> + </a-row> + </a-col> + </a-row> + + <!-- 表格实体部分--> <div class="table-cont"> - <a-table :columns="columns" :data-source="tableData" :pagination="pagination" :rowKey="record=>record.id" bordered> - <template #level="level"> - <a-tag - :key="level" - :color="level === 1 ? 'pink' : level === 2 ? 'blue' : 'green'" - > - {{ level==1?'省级':level==2?'地(市、州)级':level==3?'区县级':'村(乡、镇)级' }} + <a-table :columns="columns" :data-source="data" bordered :pagination="pagination"> + <template #index="text,record,index"> + {{ index + 1 }} + </template> + <template #warningLevel="text"> + <a-tag :color="text === 3 ? 'yellow' :text === 2? 'orange':text === 1?'red':'blue'"> + {{ getLevelName(text) }} </a-tag> </template> - <template #actions="actions,row"> - <a-button type="link" @click="viewData()">查看</a-button> + <template #unittype="unittype"> + <a-tag + :color="unittype === 1 ? 'purple' : unittype === 2 ? 'blue' : unittype === 3 ? 'cyan' : 'green'" + > + {{ unittype==1?'省级':unittype==2?'地(市、州)级':unittype==3?'区县级':unittype==4?'村(乡、镇)级':'管理员' }} + </a-tag> + </template > + <template #operation="text, record, index"> +<!-- <a-button type="primary">叫应列表</a-button>--> + <a-button type="link" @click="openMod('view',record)">查看详情</a-button> </template> </a-table> + <msg-edit-mod ref="msgEdit" @refresh="getData"></msg-edit-mod> </div> - <a-modal - title="信息详情" - :visible="visible" - @ok="handleOk" - @cancel="handleCancel" - cancelText="取消" okText="确认" - width="50%" - > - <a-row class="tit"> - <a-col :span="4" style="text-align: right;padding-right: 8px">标题</a-col> - <a-col :span="14">信息详情标题</a-col> - </a-row> - <a-form-model :model="form" :label-col="labelCol" :wrapper-col="wrapperCol" :colon="false"> - <a-form-model-item label="类别"> - <a-input readonly v-model="form.type"/> - </a-form-model-item> - <a-form-model-item label="级别"> - <a-tag color="yellow">黄色</a-tag> - </a-form-model-item> - <a-form-model-item label="发布单位"> - <a-input readonly v-model="form.dep"/> - </a-form-model-item> - <a-form-model-item label="短信内容"> - <a-input readonly type="textarea" v-model="form.content"/> - </a-form-model-item> - <a-form-model-item label="附件内容"> - <a><b><a-icon type="paper-clip"/>附件</b></a> - </a-form-model-item> - </a-form-model> - </a-modal> </div> </template> - <script> -import {getUser} from '@/api/user' - +import {getHistoryRecord, getMsgRecord, getPublishRecord, getResponseRecord} from "@/api/list"; +import msgEditMod from "@/views/Admin/components/msgEditMod"; +import {getReviewDetailByWorker} from "@/api/review"; +const columns = [{ + title: '序号', + dataIndex: 'index', + width: '8%', + scopedSlots: { + customRender: 'index' + } +}, + { + title: '叫应时间', + dataIndex: 'responseTime', + width: '15%', + scopedSlots: { + customRender: 'responseTime' + } //设置定制化表格数据 + }, + { + title: '预警级别', + dataIndex: 'warningLevel', + scopedSlots: { + customRender: 'warningLevel' + }, //设置定制化表格数据 + width: '8%', + }, + { + title: '发布单位', + dataIndex: 'publishingUnit', + width: '20%', + }, + { + title: '接收人单位', + dataIndex: 'receiveUnit', + width: '20%', + scopedSlots: { + customRender: 'receiveUnit' + } + }, + { + title: '接收人', + dataIndex: 'recipienterName', + width: '20%', + scopedSlots: { + customRender: 'recipienterName' + } + }, + { + title: '级别', + dataIndex: 'unittype', + width: '12%', + scopedSlots: { + customRender: 'unittype' + }, + }, + { + title: '操作', + dataIndex: 'operation', + scopedSlots: { + customRender: 'operation' + }, + }, +]; export default { - name: 'callRecord', - components: {}, - data () { + name: 'release', + components: { msgEditMod }, + data() { return { - visible: false, - form: {}, - labelCol: { span: 4 }, - wrapperCol: { span: 14 }, - columns:[ - { - title: '叫应时间', - dataIndex: 'callTime', - key: 'callTime' - }, - { - title: '预警信息', - dataIndex: 'warnings', - key: 'warnings' - }, - { - title: '接收人单位', - dataIndex: 'depName', - key: 'depName' - }, - { - title: '接收人', - dataIndex: 'name', - key: 'name' - }, - { - title: '级别', - dataIndex: 'level', - key: 'level', - scopedSlots: { customRender: 'level' } - }, - { - title: '操作', - dataIndex: 'actions', - key: 'actions', - scopedSlots: { customRender: 'actions' } + search:{ + pageIndex: 1, + pageSize: 10, + searchParams:{ + emergType: null, + startTime: '', + endTime: '' } - ], - tableData: [ - { - id: 1, - callTime: '2023-06-02', - warnings: '666666', - name: '黄公子', - level: 1 - }, - { - id: 2, - callTime: '2023-06-02', - warnings: '666666', - name: '黄公子', - level: 2 - }, - { - id: 3, - callTime: '2023-06-02', - warnings: '666666', - name: '黄公子', - level: 4 - }, - ], + }, + timeRange: [], + category: 'default', + data:[], + columns, + visible: false, + confirmLoading: false, pagination: { current: 1, defaultCurrent: 1, defaultPageSize: 10, - total: 11, - onChange: ( page, pageSize ) => this.onPageChange(page,pageSize) + total: 0, + onChange: ( page, pageSize ) => this.onPageChange(page,pageSize), + showTotal: total => `共 ${total} 条` }, - areaData: [ - { - value: 1, - label: '江苏省', - children: [ - { - value: 11, - label: '苏州市', - children: [ - { - value: 111, - label: '工业园区', - }, - ], - }, - ], - }, - { - value: 2, - label: '新疆维吾尔自治区', - children: [ - { - value: 21, - label: '乌鲁木齐市', - children: [ - { - value: 211, - label: '国泰新华', - }, - ], - }, - ], - }, + riskOptions: [ + {name: '地震',value: 1}, + {name: '洪涝',value: 2}, + {name: '气象',value: 3}, + {name: '泥石流',value: 4}, + {name: '水旱',value: 5}, + {name: '森林草原火灾',value: 6} + ], + levelOptions: [ + {name: '红色预警',value: 1}, + {name: '橙色预警',value: 2}, + {name: '黄色预警',value: 3}, + {name: '蓝色预警',value: 4} ] } }, created() { const t = this + t.getData() }, - methods:{ - async getUserList(){ + methods: { + async getData(){ const t = this - const res = await getUser(t.search) + const res = await getResponseRecord(this.search) + if(res.data.code == 100){ + t.data = res.data.data + t.pagination.total = res.data.total + }else{ + this.$message.error(res.data.msg) + } }, - - viewData(){ + openMod(type,data){ const t = this - t.visible = true + getReviewDetailByWorker(data.warnInfoId).then(res=>{ + if(res.data.code == 100){ + if(res.data.data){ + t.$refs.msgEdit.openMod(type,res.data.data) + }else{ + t.$message.error('查询信息详情失败') + } + }else{ + this.$message.error(res.data.msg) + } + }) }, onPageChange(page, pageSize) { const t= this t.pagination.current = page + t.search.pageIndex = page + t.getData() + }, + + timeChange(value, dateString) { + const t = this + if(dateString){ + t.search.searchParams.startTime = value[0].format('YYYY-MM-DD 00:00:00') + t.search.searchParams.endTime = value[1].format('YYYY-MM-DD 23:59:59') + } + }, + + timeOk(value) { + console.log('onOk: ', value); + }, + + resetSearch(){ + const t = this + t.search = { + pageIndex: 1, + pageSize: 10, + searchParams:{ + emergType: null, + startTime: '', + endTime: '' + } + } + t.timeRange = [] + t.getData() + }, + + //弹出层 + showModal() { + this.visible = true; }, handleOk(e) { - this.visible = false - }, - handleCancel(e) { this.visible = false; }, + + getLevelName(warningLevel){ + return this.levelOptions.find(i => i.value === warningLevel)?.name; + } + } } -</script> -<style lang="less" scoped> - .tit{ - font-size: 18px; - font-weight: bolder; - color: @blackText; - margin-bottom: 24px; - } -</style> +</script> \ No newline at end of file diff --git a/src/views/Admin/components/msgEditMod.vue b/src/views/Admin/components/msgEditMod.vue new file mode 100644 index 0000000..4a69812 --- /dev/null +++ b/src/views/Admin/components/msgEditMod.vue @@ -0,0 +1,531 @@ +<template> + <a-modal + :title="title" + :visible="visible" + centered + width="50%" + @cancel="handleCancel" + :afterClose="clearMod" + :footer="null" + > + <a-form-model ref="ruleForm" :model="form" :rules="rules" :wrapper-col="wrapperCol" class="form-cont"> + <div class="left"> + <a-form-model-item prop="title"> + <a-input v-model="form.title" placeholder="请输入标题" style="height: 50px; font-size: 20px;" :readOnly="disable"/> + </a-form-model-item> + <!-- <a-row>--> + <!-- <a-col :span="12" style="display: flex;align-items: center">--> + <!-- <span style="display: block;margin-bottom: 24px">相关灾种</span>--> + + <!-- </a-col>--> + <!-- <a-col :span="12" style="display: flex;align-items: center;justify-content: right">--> + <!-- <span style="display: block;margin-bottom: 24px">预警级别:</span>--> + + <!-- </a-col>--> + <!-- </a-row>--> + + <a-row> + <a-col :span="12"> + <a-form-model-item prop="emergType"> + <a-radio-group v-model="form.emergType" button-style="solid" :disabled="disable"> + <a-radio-button :value="2"> + 常规 + </a-radio-button> + <a-radio-button :value="1"> + 紧临 + </a-radio-button> + </a-radio-group> + </a-form-model-item> + </a-col> + <a-col :span="12" style="display: flex;align-items: center;justify-content: right"> + <a-form-model-item prop="disasterType" style="margin-right: 12px"> + <a-select placeholder="请选择相关灾种" v-model="form.disasterType" style="min-width: 160px" allowClear @change="handleRisk" :disabled="disable"> + <a-select-option v-for="item in riskOptions" :key="item.value" :value="item.value"> + {{ item.name }} + </a-select-option> + </a-select> + </a-form-model-item> + <a-form-model-item prop="warningLevel"> + <a-select placeholder="请选择预警级别" v-model="form.warningLevel" style="min-width: 160px" allowClear @change="handleLevel" :disabled="disable"> + <a-select-option v-for="item in levelOptions" :key="item.value" :value="item.value"> + {{ item.name }} + </a-select-option> + </a-select> + </a-form-model-item> + </a-col> + </a-row> + <a-form-model-item prop="content"> + <a-textarea v-model="form.content" placeholder="请输入短信通知内容部分" :auto-size="{ minRows: 3, maxRows: 5 }" :readOnly="disable"/> + </a-form-model-item> + <a-row> + <a-col :span="12"> + <a-button>上传附件</a-button> + </a-col> + <a-col :span="12" style="display: flex;align-items: center;justify-content: right"> + <b style="margin-bottom: 24px">超时设置:</b> + <a-form-model-item prop="timeout"> + <a-input v-model="form.timeout" style="width:200px;" placeholder="输入时间" suffix="分钟" :readOnly="disable"/> + </a-form-model-item> + </a-col> + </a-row> + <span><b>发布单位:</b>{{form.publishingUnit}}</span> + <br/><br/> + <!-- 子单位--> + <a-row :gutter="24"> + <a-col :span="12"> + <div style="display:flex;justify-content: space-between;align-items: center;"> + <b>选择接收单位:</b> + <a-checkbox :checked="checkAll" @change="checkChange" :disabled="disable"> + 全选 + </a-checkbox> + </div> + <a-form-model-item prop="receiver"> + <a-tree-select + show-search + tree-checkable + treeCheckStrictly + style="width: 100%" + v-model="form.receiver" + :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }" + placeholder="选择工作通知接收单位" + allow-clear + multiple + @change="depChanges" + @search="onSearch" + @select="onSelect" + :tree-data="areaUsers" + :replaceFields="replaceFields" + :disabled="disable" + > + </a-tree-select> + </a-form-model-item> + </a-col> + <a-col :span="12"> + <b style="margin-bottom: 6px">平级接收人选择:</b> + <a-form-model-item prop="recipient"> + <a-select mode="multiple" placeholder="选择平级接收单位" v-model="form.recipient" @change="handle" :disabled="disable"> + <a-select-option v-for="item in filteredOptions" :key="item.id" :value="item.id"> + {{ item.recipientName }} + </a-select-option> + </a-select> + </a-form-model-item> + </a-col> + </a-row> + <a-row :gutter="24" style="display: flex;justify-content: right" v-if="title=='信息审核'"> + <a-col :span="20" style="display: flex;justify-content: right"> + <a-button type="primary" style="min-width: 140px;margin-right: 12px" @click="confirmSend(2)"> + 审批通过 + </a-button> + <a-button type="danger" style="min-width: 140px;" @click="confirmSend(3)"> + 驳回 + </a-button> + </a-col> + </a-row> + <a-row :gutter="24" style="display: flex;justify-content: right;align-items: center" v-if="title=='信息转发'"> + <a-col :span="12"> + <b style="margin-bottom: 6px">选择审批领导:</b> + <a-form-model-item prop="reviewId"> + <a-select show-search v-model="form.reviewId" placeholder="请选择审批领导"> + <a-select-option v-for="(item,index) in leaders" :value="item.id" :key="index">{{item.name}}</a-select-option> + </a-select> + </a-form-model-item> + </a-col> + <a-col :span="12" style="display: flex;justify-content: right"> + <a-button type="primary" style="min-width: 140px;margin-right: 12px" @click="confirmSend(4)"> + 确认转发 + </a-button> + </a-col> + </a-row> + </div> + + <div class="right"> + <h2>短信预览</h2> + <div class="mobile"> + <div class="mesg"> + <P>【{{form.title}}】{{form.content}}。发布单位:{{form.publishingUnit}}</P> + </div> + + </div> + </div> + </a-form-model> + </a-modal> +</template> + +<script> +import {getAreaWithUserIfo, getPeerRecipient, getLeaders} from '@/api/user' +import {getUserInfo} from "@/util/storage"; +import Cookies from "js-cookie"; +import {massSend, msgSend} from "@/api/send"; +import {postReview} from "@/api/review"; +export default { + name: "msgEditMod", + data() { + return { + title: '信息审核', + disable: true, + visible: false, + confirmLoading: false, + leaders: [], + userInfo: {}, + wrapperCol: { span: 24 }, + filteredOptions:[], + form: { + id: null, + title: '', + emergType: null, + disasterType: undefined, + warningLevel: undefined, + content: '', + publishingUnit: '', + districtId: null, + attachments: [], + timeout: null, + reviewId: null, + receiver: [], + recipient: [], + acceptingUnitIds: [], + peerRecipientIds: [] + }, + checkAll: false, + areaUsers: [], + replaceFields: { + children:'children', + title:'name', + key:'id', + value: 'id' + }, + riskOptions: [ + {name: '地震',value: 1}, + {name: '洪涝',value: 2}, + {name: '气象',value: 3}, + {name: '泥石流',value: 4}, + {name: '水旱',value: 5}, + {name: '森林草原火灾',value: 6} + ], + levelOptions: [ + {name: '红色预警',value: 1}, + {name: '橙色预警',value: 2}, + {name: '黄色预警',value: 3}, + {name: '蓝色预警',value: 4} + ], + rules: { + emergType: [{ required: true, message: '请选择紧急类型', trigger: 'change'}], + disasterType: [{ required: true, message: '请选择灾种', trigger: 'change'}], + warningLevel: [{ required: true, message: '请选择预警级别', trigger: 'change'}], + title: [{ required: true, message: '请输入信息标题', trigger: 'blur'}], + content: [{ required: true, message: '请输入信息内容', trigger: 'blur'}], + timeout: [{ required: true, message: '请输入超时时间', trigger: 'blur'}], + receiver: [{ required: true, message: '请选择接收单位', trigger: 'change'}], + reviewId: [{ required: true, message: '请选择审批人', trigger: 'change'}], + recipient: [{ required: true, message: '请选择平级接收人', trigger: 'change'}] + // acceptingUnitIds: [{ required: true, message: '请选择接收单位', trigger: 'change'}], + // peerRecipientIds: [{ required: true, message: '请选择平级接收人', trigger: 'change'}] + } + }; + }, + components: {}, + created() { + const t = this + t.userInfo = getUserInfo() + t.form.districtId = t.userInfo.districtId + t.form.publishingUnit = t.userInfo.company + t.getSameLevel() + t.getAreaUsers() + }, + computed: {}, + methods: { + openMod(type,data){ + const t = this + for(let i in data){ + if(t.isValidKey(i,t.form)){ + t.form[i] = data[i] + } + } + const arr = data.acceptingUnitIds.map((i)=>{return { + value: i.districtId + }}) + t.form.receiver = JSON.parse(JSON.stringify(arr)).filter( + (item, index) => JSON.parse(JSON.stringify(arr)).findIndex(obj => obj.value === item.value) === index + ) + t.form.recipient = data.peerRecipientIds.map(i=>i.recipienterId) + t.form.acceptingUnitIds = [] + t.form.peerRecipientIds = [] + if(type == 'review') { + t.title = '信息审核' + t.disable = false + }else if(type == 'view'){ + t.title = '信息详情' + t.disable = true + }else{ + t.title = '信息转发' + t.getLeaders() + t.disable = false + + } + t.visible = true + }, + isValidKey(key, object){ + return key in object; + }, + + // 获取同级接收人 + async getSameLevel(){ + let t = this + let res = await getPeerRecipient() + if(res.data.code == 100){ + if(res.data.data){ + t.filteredOptions = res.data.data + }else{ + this.$message.warning('暂无数据'); + } + }else{ + this.$message.warning(res.data.msg); + } + }, + + // 获取接收单位 + async getAreaUsers(){ + let t = this + let res = await getAreaWithUserIfo() + if(res.data.code == 100){ + if(res.data.data){ + const treeD = [] + t.userTitTree(res.data.data) + treeD.push(t.findNodeById(res.data.data,t.userInfo.districtId)) + t.areaUsers = treeD + t.unittype = this.findNodeById(this.areaUsers,t.userInfo.districtId)?.type + }else{ + this.$message.warning('暂无数据'); + } + }else{ + this.$message.warning(res.data.msg); + } + }, + + // 获取领导 + async getLeaders(){ + let t = this + let res = await getLeaders() + if(res.data.code == 100){ + if(res.data.data){ + t.leaders = res.data.data + }else{ + this.$message.warning('暂无数据'); + } + }else{ + this.$message.warning(res.data.msg); + } + }, + + //选择子部门部分 + depChanges(value,label,extra) { + const t = this + if(t.form.receiver.length == 0){ + t.checkAll = false + } + }, + checkChange(e) { + const t = this + this.checkAll = !this.checkAll + if(t.checkAll == true){ + t.form.receiver = t.traverseTree(t.areaUsers[0]) + }else{ + t.form.receiver = [] + } + }, + + confirmSend(status){ + this.$refs.ruleForm.validate(valid => { + if (valid) { + this.form.acceptingUnitIds = [] + this.form.peerRecipientIds = [] + const aList = this.form.receiver.map(item=>this.findNodeById(this.areaUsers,item.value)?.users) + const newAList = [].concat(...aList) + for(let i of newAList){ + const {realName,...data} = i + const {id:recipienterId,name: recipienterName,phone: recipienterPhone,company: receiveUnit,...rest} = data + const obj = { recipienterId, recipienterName, recipienterPhone, receiveUnit,...rest} + this.form.acceptingUnitIds.push(obj) + } + const bList = this.form.recipient.map(item => this.filteredOptions.find(i=>i.id == item)) + for(let i of bList){ + const {id:recipienterId,recipientName: recipienterName,phone: recipienterPhone, company: receiveUnit,...rest} = i + const obj = {recipienterId, recipienterName,recipienterPhone,receiveUnit,unittype:this.unittype,...rest} + this.form.peerRecipientIds.push(obj) + } + if(status == 2 || status == 3){ + const {receiver,recipient,reviewId,...data} = this.form + data.reviewStatus = status + postReview(data).then( res =>{ + if(res.data.code == 100){ + this.$message.success('审核已提交') + this.$emit('refresh') + this.visible = false + }else{ + this.$message.error(res.data.msg) + } + this.$refs.ruleForm.clearValidate() + this.$refs.ruleForm.resetFields() + }) + }else{ + const {receiver,recipient,id,...data} = this.form + msgSend(data).then( res =>{ + if(res.data.code == 100){ + this.$message.success('信息已提交审核') + }else{ + this.$message.error(res.data.msg) + } + this.$emit('refresh') + this.visible = false + this.$refs.ruleForm.clearValidate() + this.$refs.ruleForm.resetFields() + }) + } + }else{ + console.log('error submit!!'); + return false; + } + }) + }, + + handleCancel(e) { + const t = this + t.visible = false; + }, + + clearMod(){ + this.$refs.ruleForm.clearValidate() + this.$refs.ruleForm.resetFields() + }, +// 根据id查对象 + findNodeById(data,value) { + for (const node of data) { + if (node.id === value) { + return node; + } + if (node.children) { + const foundNode = this.findNodeById(node.children, value); + if (foundNode) { + return foundNode; + } + } + } + return null; + }, + + // 将树状数据所有id和name放入对象数组 + traverseTree(treeData) { + let result = []; + function traverse(node) { + result.push({ label: node.name, value: node.id }); + if (node.children && node.children.length > 0) { + for (let child of node.children) { + traverse(child); + } + } + } + traverse(treeData); + return result; + }, + + // 将树状数据name字段放入users的姓名电话 + userTitTree(treeData) { + for(const node of treeData){ + if(node.users){ + node.users = node.users.map((i)=>{ + return{ + ...i, + unittype: node.type, + districtId: node.id + } + }) + node.name = node.name + '('+node.users.map(i=>i.name +' '+ i.phone).join(',')+')' + } + if(node.children){ + this.userTitTree(node.children) + } + } + return treeData + }, + + onSearch() { + console.log(...arguments); + }, + onSelect() { + console.log(...arguments); + }, + //选择平级部门部分 + handle(selectedItems) { + this.selectedItems = selectedItems; + }, + handleRisk(selectedItems) { + // this.selectedItems = selectedItems; + }, + handleLevel(selectedItems) { + // this.selectedItems = selectedItems; + }, + + onChange(){ + console.log(this.value) + }, + handleChange(value) { + console.log(`selected ${value}`); + }, + handleBlur() { + console.log('blur'); + }, + handleFocus() { + console.log('focus'); + }, + filterOption(input, option) { + return ( + option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0 + ); + }, + }, +} +</script> + +<style lang="less" scoped> +.form-cont{ + display: flex; + justify-content: space-between; + align-items: flex-start; + + .left { + width: 58%; + } + + .right { + width: 39%; + border-left: 1px silver solid; + padding-left: 18px; + + .mobile { + position: relative; + background: black; + border: 1px solid black; + width: 280px; + min-height: 500px; + border-radius: 25px; + margin-left: 20px; + + .mesg { + width: 260px; + margin: 25px auto; + min-height: 450px; + background: white; + padding-top: 10px; + + p { + padding: 15px; + background-color: #f5f5f5; + border-radius: 10px; + font-size: 16px; + margin: 15px 10px; + } + } + } + } +} +</style> diff --git a/src/views/Admin/components/sameLevelMod.vue b/src/views/Admin/components/sameLevelMod.vue index 74df5ab..a86fd14 100644 --- a/src/views/Admin/components/sameLevelMod.vue +++ b/src/views/Admin/components/sameLevelMod.vue @@ -12,17 +12,17 @@ :afterClose="clearMod" > <a-form-model ref="ruleForm" :rules="rules" :model="form" :label-col="labelCol" :wrapper-col="wrapperCol" :colon="false"> - <a-form-model-item label="姓名或称呼" prop="name"> - <a-input v-model="form.name"/> + <a-form-model-item label="姓名或称呼" prop="recipientName"> + <a-input v-model="form.recipientName"/> </a-form-model-item> - <a-form-model-item label="单位名称(备注)" prop="depName"> - <a-input v-model="form.depName"/> + <a-form-model-item label="单位名称(备注)" prop="company"> + <a-input v-model="form.company"/> </a-form-model-item> <a-form-model-item label="手机号码" prop="phone"> <a-input v-model="form.phone"/> </a-form-model-item> - <a-form-model-item label="选择级别" prop="level"> - <a-select v-model="form.level" placeholder="监管级别"> + <a-form-model-item label="单位层级"> + <a-select v-model="form.unittype" placeholder="单位层级" disabled> <a-select-option :value="1"> 省级 </a-select-option> @@ -37,13 +37,16 @@ </a-select-option> </a-select> </a-form-model-item> - <a-form-model-item label="所属地区" prop="area"> + <a-form-model-item label="所属地区" prop="districtId"> <a-tree-select - v-model="form.area" + v-model="form.districtId" style="width: 100%" :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }" :tree-data="areaData" placeholder="行政区划" + :replaceFields="replaceFields" + @change="changeArea" + disabled > </a-tree-select> </a-form-model-item> @@ -52,9 +55,12 @@ </template> <script> -import { addUser } from '@/api/user' + +import {addRecipient, addUser, updateRecipient, updateUser} from "@/api/user"; + export default { name: 'userMod', + props: [], data () { return { title: '新增用户', @@ -63,20 +69,25 @@ labelCol: { span: 4 }, wrapperCol: { span: 14 }, areaData: [], + replaceFields: { + children:'children', + title:'name', + key:'id', + value: 'id' + }, unitName: '', form: { - name: '', - depName: '', + id: null, + recipientName: '', + company: '', phone: '', - level: null, - area: null + unittype: null, + districtId: null }, rules: { - name: [{ required: true, message: '请输入姓名', trigger: 'blur'}], - phone: [{ required: true, message: '请输入手机号', trigger: 'blur'}], - depName: [{ required: true, message: '请输入单位名称', trigger: 'blur'}], - level: [{ required: true, message: '请选择监管级别', trigger: 'change'}], - area: [{ required: true, message: '请选择行政区划', trigger: 'change'}] + recipientName: [{ required: true, message: '请输入姓名或称呼', trigger: 'blur'}], + company: [{ required: true, message: '请输入单位名称(备注)', trigger: 'blur'}], + phone: [{ required: true, message: '请输入手机号', trigger: 'blur'}] } } }, @@ -89,27 +100,58 @@ if(type == 'add'){ t.title = '新增用户' t.form = { - name: '', - depName: '', + id: null, + recipientName: '', + company: '', phone: '', - level: null, - area: null + unittype: null, + districtId: null } }else{ t.title = '编辑用户' - t.form = data + for(let i in data){ + if(t.isValidKey(i,t.form)){ + t.form[i] = data[i] + } + } } t.visible = true }, + isValidKey(key, object){ + return key in object; + }, + clearMod(){ this.$refs.ruleForm.clearValidate() + this.$refs.ruleForm.resetFields() }, onSubmit() { this.$refs.ruleForm.validate(valid => { if (valid) { - alert('submit!'); + if(this.title == '新增用户'){ + const { id,...data } = this.form + console.log(data,'data') + addRecipient(data).then((res)=>{ + if(res.data.code == 100){ + this.$message.success('新增平级接收人成功') + this.$emit('refresh') + }else{ + this.$message.error(res.data.msg) + } + }) + }else{ + const data = this.form + updateRecipient(data).then((res)=>{ + if(res.data.code == 100){ + this.$message.success('修改用户成功') + this.$emit('refresh') + }else{ + this.$message.error(res.data.msg) + } + }) + } this.visible = false } else { return false; @@ -117,16 +159,40 @@ }); }, - handleOk(e) { + changeArea(value, label, extra){ const t = this - t.confirmLoading = true; + t.form.districtId = value + const code = t.findCodeById(t.areaData,value).code + if(code.length == 2){ + t.form.company = '自治区自然灾害预警中心' + // t.form.province = t.findNodeByCode(t.areaData,code).name + // t.form.city = '' + // t.form.area = '' + // t.form.town = '' + } else if(code.length == 9){ + // t.form.province = t.findNodeByCode(t.areaData,code.substr(0,2)).name + // t.form.city = t.findNodeByCode(t.areaData,code.substr(0,4)).name + // t.form.area = t.findNodeByCode(t.areaData,code.substr(0,6)).name + // t.form.town = t.findNodeByCode(t.areaData,code).name + t.form.company = label[0] + } else{ + // if(code.length == 4){ + // t.form.city = t.findNodeByCode(t.areaData,code).name + // t.form.area = '' + // } + // if(code.length == 6){ + // t.form.city = t.findNodeByCode(t.areaData,code.substr(0,4)).name + // t.form.area = t.findNodeByCode(t.areaData,code).name + // } + // t.form.province = t.findNodeByCode(t.areaData,code.substr(0,2)).name + // t.form.town = '' + t.form.company = label[0] + '自然灾害综合预警监测中心' + } }, + handleCancel(e) { const t = this t.visible = false; - }, - onChange(value) { - console.log(value); } } } diff --git a/src/views/Admin/components/userMod.vue b/src/views/Admin/components/userMod.vue index 9a5f08a..499ef98 100644 --- a/src/views/Admin/components/userMod.vue +++ b/src/views/Admin/components/userMod.vue @@ -33,15 +33,15 @@ <a-radio-button :value="0">女</a-radio-button> </a-radio-group> </a-form-model-item> - <a-form-model-item label="选择级别" prop="unittype"> - <a-select v-model="form.unittype" placeholder="监管级别"> - <a-select-option :value="1"> + <a-form-model-item label="单位层级" prop="unittype"> + <a-select v-model="form.unittype" placeholder="单位层级" @change="changeLevel"> + <a-select-option :disabled="unittype !== 1&&unittype !== null" :value="1"> 省级 </a-select-option> - <a-select-option :value="2"> + <a-select-option :disabled="unittype !== 1&&unittype !== null && unittype !== 2" :value="2"> 地(市、州)级 </a-select-option> - <a-select-option :value="3"> + <a-select-option :disabled="unittype == 4 ? true : false" :value="3"> 区县级 </a-select-option> <a-select-option :value="4"> @@ -49,21 +49,23 @@ </a-select-option> </a-select> </a-form-model-item> - <a-form-model-item label="所属地区" prop="area"> -<!-- <a-cascader v-model="form.area" :options="areaData" expandTrigger="hover" changeOnSelect placeholder="请选择" @change="onChange"/>--> + <a-form-model-item label="所属地区" prop="districtId"> + <!-- <a-cascader v-model="form.area" :options="areaData" expandTrigger="hover" changeOnSelect placeholder="请选择" @change="onChange"/>--> <a-tree-select - v-model="form.area" + v-model="form.districtId" style="width: 100%" :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }" :tree-data="areaData" placeholder="行政区划" + :replaceFields="replaceFields" + @change="changeArea" > </a-tree-select> </a-form-model-item> <a-form-model-item label="所属单位"> - <a-input v-model="unitName"/> + <a-input v-model="form.company" readOnly/> </a-form-model-item> - <a-form-model-item label="角色" prop="role"> + <a-form-model-item label="角色" prop="roleId"> <a-select v-model="form.roleId" placeholder="角色"> <a-select-option :value="2"> 领导 @@ -78,19 +80,59 @@ </template> <script> -import { addUser } from '@/api/user' +import {addUser, updateUser} from '@/api/user' +import {verifyPasswordPowerful, verifyPhone} from "@/util/validate"; export default { name: 'userMod', + props: ['unitType'], data () { + let validatePwd = (rule, value, callback)=>{ + if(value === ''){ + callback(new Error('请输入密码')) + }else{ + if(!verifyPasswordPowerful(value)){ + callback(new Error('密码须包含字母、数字、特殊字符(不包括下划线),长度在6-16之间')) + }else{ + callback() + } + } + } + let validatePhone = (rule, value, callback)=>{ + if(value === ''){ + callback(new Error('请输入手机号')) + }else{ + if(!verifyPhone(value)){ + callback(new Error('手机号格式有误')) + }else{ + callback() + } + } + } + let validatePwd2 = (rule, value, callback)=>{ + if(value === ''){ + callback(new Error('请再次输入密码')) + }else if(value !== this.form.pwd){ + callback(new Error('两次输入密码不同')) + }else{ + callback() + } + } return { title: '新增用户', visible: false, + unittype: this.unitType, confirmLoading: false, labelCol: { span: 4 }, wrapperCol: { span: 14 }, areaData: [], - unitName: '', + replaceFields: { + children:'children', + title:'name', + key:'id', + value: 'id' + }, form: { + id: null, realName: '', phone: '', name: '', @@ -98,18 +140,19 @@ dupPwd: '', sex: null, unittype: null, - area: null, - roleId: null + districtId: null, + roleId: null, + company: '' }, rules: { realName: [{ required: true, message: '请输入姓名', trigger: 'blur'}], - phone: [{ required: true, message: '请输入手机号', trigger: 'blur'}], + phone: [{ required: true, validator: validatePhone, trigger: 'blur'}], name: [{ required: true, message: '请输入用户名', trigger: 'blur'}], pwd: [{ required: true, message: '请输入密码', trigger: 'blur'}], - dupPwd: [{ required: true, message: '请再次输入密码', trigger: 'blur'}], + dupPwd: [{ required: true, validator: validatePwd2, trigger: 'blur'}], sex: [{ required: true, message: '请选择性别', trigger: 'change'}], - unittype: [{ required: true, message: '请选择监管级别', trigger: 'change'}], - area: [{ required: true, message: '请选择行政区划', trigger: 'change'}], + unittype: [{ required: true, message: '请选择单位层级', trigger: 'change'}], + districtId: [{ required: true, message: '请选择行政区划', trigger: 'change'}], roleId: [{ required: true, message: '请选择角色', trigger: 'change'}] } } @@ -123,38 +166,135 @@ if(type == 'add'){ t.title = '新增用户' t.form = { + id: null, realName: '', phone: '', name: '', pwd: '', dupPwd: '', - sex: undefined, - unittype: undefined, - area: undefined, - roleId: null + sex: null, + unittype: null, + districtId: null, + roleId: null, + company: '' } }else{ t.title = '编辑用户' data.roleId = data.role.roleId - const { realName,phone,name,sex,unittype,roleId } = data - t.form = { realName,phone,name,sex,unittype,roleId } + for(let i in data){ + if(t.isValidKey(i,t.form)){ + t.form[i] = data[i] + } + } } t.visible = true + }, + isValidKey(key, object){ + return key in object; + }, + + + // 根据id查对象 + findNodeById(data,value) { + for (const node of data) { + if (node.id === value) { + return node; + } + if (node.children) { + const foundNode = this.findNodeById(node.children, value); + if (foundNode) { + return foundNode; + } + } + } + return null; + }, + + // 根据code查对象 + findNodeByCode(data,code) { + for (const node of data) { + if (node.code === code) { + return node; + } + if (node.children) { + const foundNode = this.findNodeByCode(node.children,code); + if (foundNode) { + return foundNode; + } + } + } + return null; + }, + + changeLevel(value, option){ + console.log(value) + }, + + changeArea(value, label, extra){ + const t = this + t.form.districtId = value + const code = t.findNodeById(t.areaData,value).code + if(code.length == 2){ + t.form.company = '自治区自然灾害预警中心' + // t.form.province = t.findNodeByCode(t.areaData,code).name + // t.form.city = '' + // t.form.area = '' + // t.form.town = '' + } else if(code.length == 9){ + // t.form.province = t.findNodeByCode(t.areaData,code.substr(0,2)).name + // t.form.city = t.findNodeByCode(t.areaData,code.substr(0,4)).name + // t.form.area = t.findNodeByCode(t.areaData,code.substr(0,6)).name + // t.form.town = t.findNodeByCode(t.areaData,code).name + t.form.company = label[0] + } else{ + // if(code.length == 4){ + // t.form.city = t.findNodeByCode(t.areaData,code).name + // t.form.area = '' + // } + // if(code.length == 6){ + // t.form.city = t.findNodeByCode(t.areaData,code.substr(0,4)).name + // t.form.area = t.findNodeByCode(t.areaData,code).name + // } + // t.form.province = t.findNodeByCode(t.areaData,code.substr(0,2)).name + // t.form.town = '' + t.form.company = label[0] + '自然灾害综合预警监测中心' + } }, clearMod(){ this.$refs.ruleForm.clearValidate() + this.$refs.ruleForm.resetFields() }, onSubmit() { this.$refs.ruleForm.validate(valid => { if (valid) { - if(this.title == '新增用户') - addUser(this.form).then((res)=>{ - if(res.data.code == 100){ - console.log(res,'res') - } - }) + if(this.form.unittype !== this.findNodeById(this.areaData,this.form.districtId).type){ + this.$message.error('单位层级和所属地区不匹配,请重新选择') + return + } + if(this.title == '新增用户'){ + const { id,...data } = this.form + addUser(data).then((res)=>{ + if(res.data.code == 100){ + this.$message.success('新增用户成功') + this.$emit('refresh') + }else{ + this.$message.error(res.data.msg) + } + }) + }else{ + const {pwd,dupPwd,...data} = this.form + updateUser(data).then((res)=>{ + if(res.data.code == 100){ + this.$message.success('修改用户成功') + this.$emit('refresh') + }else{ + this.$message.error(res.data.msg) + } + }) + } + this.visible = false } else { console.log('error submit!!'); return false; diff --git a/src/views/Admin/history.vue b/src/views/Admin/history.vue new file mode 100644 index 0000000..5b64b67 --- /dev/null +++ b/src/views/Admin/history.vue @@ -0,0 +1,278 @@ +<template> + <div class="inner"> + <a-row type="flex" justify="space-between" style="margin-bottom: 20px"> + <a-col :span="8"> + <a-radio-group v-model="search.searchParams.emergType" @change="getData"> + <a-radio-button :value="null"> + 全部 + </a-radio-button> + <a-radio-button :value="1"> + 紧临 + </a-radio-button> + <a-radio-button :value="2"> + 常规 + </a-radio-button> + </a-radio-group> + </a-col> + <a-col :span="16"> + <a-row type="flex" justify="end" :gutter="12"> + <a-col :span="8"> + <a-range-picker + v-model="timeRange" + format="YYYY-MM-DD" + :placeholder="['开始时间', '结束时间']" + @change="timeChange" + @ok="timeOk" + style="width: 100%" + /> + </a-col> + <a-col :span="4"> + <a-button type="primary" @click="getData">查询</a-button> + <a-button style="margin-left: 12px" @click="resetSearch">重置</a-button> + </a-col> + </a-row> + </a-col> + </a-row> + + <!-- 表格实体部分--> + <div class="table-cont"> + <a-table :columns="columns" :data-source="data" bordered :pagination="pagination"> + <template #index="text,record,index"> + {{ index + 1 }} + </template> + <template #publishingTime="text"> + {{ text }} + </template> + <template #publishingUnit="text"> + {{ text }} + </template> + <template #disasterType="text"> + {{ getRiskName(text) }} + </template> + <template #warningLevel="text"> + <a-tag :color="text === 3 ? 'yellow' :text === 2? 'orange':text === 1?'red':'blue'"> + {{ getLevelName(text) }} + </a-tag> + </template> + <template #attachment="text"> + <a><b><a-icon type="paper-clip" /></b></a> + </template > + <template #responseSituation="text"> + <a-tag :color="text === 3 ? 'red' :text === 2? 'green':text === 1?'orange':'blue'"> + {{text == 1 ? '待叫应' : text == 2 ?'已叫应':text == 3 ?'超时未叫应' : ''}} + </a-tag> + </template> + <template #operation="text, record, index"> + <a-button type="primary">叫应列表</a-button> + <a-button type="link" @click="openMod('view',record)">查看详情</a-button> + </template> + </a-table> + <msg-edit-mod ref="msgEdit" @refresh="getData"></msg-edit-mod> + </div> + <!-- 对话框 --> + <a-modal title="查看叫应详情" + okText="确认" + cancelText="关闭" + :visible="visible" :confirm-loading="confirmLoading" @ok="handleOk" @cancel="handleOk"> + </a-modal> + </div> +</template> +<script> +import {getHistoryRecord, getMsgRecord, getPublishRecord} from "@/api/list"; +import msgEditMod from "@/views/Admin/components/msgEditMod"; +import {getReviewDetailByWorker} from "@/api/review"; +const columns = [{ + title: '序号', + dataIndex: 'index', + width: '8%', + scopedSlots: { + customRender: 'index' + } +}, + { + title: '发布时间', + dataIndex: 'publishingTime', + width: '15%', + scopedSlots: { + customRender: 'publishingTime' + } //设置定制化表格数据 + }, + { + title: '发布单位', + dataIndex: 'publishingUnit', + width: '12%', + }, + { + title: '灾种', + dataIndex: 'disasterType', + width: '8%', + scopedSlots: { + customRender: 'disasterType' + } + }, + { + title: '预警级别', + dataIndex: 'warningLevel', + scopedSlots: { + customRender: 'warningLevel' + }, //设置定制化表格数据 + width: '8%', + }, + { + title: '信息标题', + dataIndex: 'title', + width: '16%', + }, + { + title: '附件', + dataIndex: 'attachment', + width: '6%', + scopedSlots: { + customRender: 'attachment' + }, + }, + { + title: '叫应情况', + dataIndex: 'responseSituation', + width: '10%', + scopedSlots: { + customRender: 'responseSituation' + }, //设置定制化表格数据 + }, + { + title: '操作', + dataIndex: 'operation', + scopedSlots: { + customRender: 'operation' + }, + }, +]; +export default { + name: 'release', + components: { msgEditMod }, + data() { + return { + search:{ + pageIndex: 1, + pageSize: 10, + searchParams:{ + emergType: null, + startTime: '', + endTime: '' + } + }, + timeRange: [], + category: 'default', + data:[], + columns, + visible: false, + confirmLoading: false, + pagination: { + current: 1, + defaultCurrent: 1, + defaultPageSize: 10, + total: 0, + onChange: ( page, pageSize ) => this.onPageChange(page,pageSize), + showTotal: total => `共 ${total} 条` + }, + riskOptions: [ + {name: '地震',value: 1}, + {name: '洪涝',value: 2}, + {name: '气象',value: 3}, + {name: '泥石流',value: 4}, + {name: '水旱',value: 5}, + {name: '森林草原火灾',value: 6} + ], + levelOptions: [ + {name: '红色预警',value: 1}, + {name: '橙色预警',value: 2}, + {name: '黄色预警',value: 3}, + {name: '蓝色预警',value: 4} + ] + } + }, + created() { + const t = this + t.getData() + }, + methods: { + async getData(){ + const t = this + const res = await getHistoryRecord(this.search) + if(res.data.code == 100){ + t.data = res.data.data + t.pagination.total = res.data.total + }else{ + this.$message.error(res.data.msg) + } + }, + + openMod(type,data){ + const t = this + getReviewDetailByWorker(data.id).then(res=>{ + if(res.data.code == 100){ + if(res.data.data){ + t.$refs.msgEdit.openMod(type,res.data.data) + }else{ + t.$message.error('查询信息详情失败') + } + }else{ + this.$message.error(res.data.msg) + } + }) + }, + + onPageChange(page, pageSize) { + const t= this + t.pagination.current = page + t.search.pageIndex = page + t.getData() + }, + + timeChange(value, dateString) { + const t = this + if(dateString){ + t.search.searchParams.startTime = value[0].format('YYYY-MM-DD 00:00:00') + t.search.searchParams.endTime = value[1].format('YYYY-MM-DD 23:59:59') + } + }, + + timeOk(value) { + console.log('onOk: ', value); + }, + + resetSearch(){ + const t = this + t.search = { + pageIndex: 1, + pageSize: 10, + searchParams:{ + emergType: null, + startTime: '', + endTime: '' + } + } + t.timeRange = [] + t.getData() + }, + + //弹出层 + showModal() { + this.visible = true; + }, + + handleOk(e) { + this.visible = false; + }, + getRiskName(disasterType){ + return this.riskOptions.find(i => i.value === disasterType)?.name; + }, + + getLevelName(warningLevel){ + return this.levelOptions.find(i => i.value === warningLevel)?.name; + } + + } +} + +</script> \ No newline at end of file diff --git a/src/views/Admin/list.vue b/src/views/Admin/list.vue index 84a0b38..8a45500 100644 --- a/src/views/Admin/list.vue +++ b/src/views/Admin/list.vue @@ -2,17 +2,17 @@ <div class="inner"> <a-row type="flex" justify="space-between" style="margin-bottom: 20px"> <a-col :span="8"> - <a-radio-group v-model="category"> - <a-radio-button value="default"> + <a-radio-group v-model="search.searchParams.responseStatus" @change="getData"> + <a-radio-button :value="null"> 全部 </a-radio-button> - <a-radio-button value="1"> + <a-radio-button :value="1"> 待叫应 </a-radio-button> - <a-radio-button value="2"> + <a-radio-button :value="2"> 已叫应 </a-radio-button> - <a-radio-button value="3"> + <a-radio-button :value="3"> 超时未叫应 </a-radio-button> </a-radio-group> @@ -21,6 +21,7 @@ <a-row type="flex" justify="end" :gutter="12"> <a-col :span="8"> <a-range-picker + v-model="timeRange" format="YYYY-MM-DD" :placeholder="['开始时间', '结束时间']" @change="timeChange" @@ -29,233 +30,297 @@ /> </a-col> <a-col :span="4"> - <a-button type="primary">查询</a-button> - <a-button style="margin-left: 12px">重置</a-button> + <a-button type="primary" @click="getData">查询</a-button> + <a-button style="margin-left: 12px" @click="resetSearch">重置</a-button> </a-col> </a-row> </a-col> </a-row> <!-- 表格实体部分--> <div class="table-cont"> - <a-table :columns="columns" :data-source="data" bordered> - <template #time="text,record"> - <a v-if="!record.readed" style="color:red">[未读]</a>{{text}} + <a-table :columns="columns" :data-source="data" bordered :pagination="pagination"> + <template #index="text,record,index"> + {{index + 1}} </template> - <template #level="text"> - <a-tag :color="text === '黄色' ? 'yellow' :text === '橙色'? 'orange':text === '红色'?'red':'blue'"> - {{ text }} + <template #publishingTime="text,record"> + <span v-if="record.readStatus==0" style="color:red">[未读]</span>{{text}} + </template> + <template #disasterType="text"> + {{ getRiskName(text) }} + </template> + <template #warningLevel="text"> + <a-tag :color="text === 3 ? 'yellow' :text === 2? 'orange':text === 1?'red':'blue'"> + {{ getLevelName(text) }} </a-tag> </template> <template #attachment="text"> - <span v-if="text==='无'">无</span> - <a v-else><b><a-icon type="paper-clip" /> {{text}}</b></a> + <a><b><a-icon type="paper-clip" /> {{text}}</b></a> </template > - <template #receipt="text"> - <span v-if="text=='待叫应'" - style='background-color:blue;padding:5px;color:#fff;border-radius: 5px;'>{{text}}</span> - <span v-else-if="text=='已叫应'" - style='background-color:limegreen;padding:5px;color:#2a2a2a;border-radius: 5px;'>{{text}}</span> - <span v-else style='background-color:red;padding:5px;color:#fff;border-radius: 5px;'>{{text}} - </span> + <template #responseStatus="text"> + <a-tag :color="text === 3 ? 'red' :text === 2? 'green':text === 1?'orange':'blue'"> + {{text == 1 ? '待叫应' : text == 2 ?'已叫应':text == 3 ?'超时未叫应' : ''}} + </a-tag> </template> +<!-- <template #operation="text, record, index">--> +<!-- <div class="editable-row-operations">--> +<!-- <div v-if="record.responseStatus==='待叫应'">--> +<!-- <a @click="showModal" style="color:orangered"><a-icon type="notification" />--> +<!-- 确认已收到</a> --> +<!-- </div>--> +<!-- <br />--> +<!-- <a-button type="primary">转发</a-button> --> +<!-- <a-button type="link" @click="viewDetails(item)">查看详情</a-button>--> +<!-- </div>--> +<!-- </template>--> <template #operation="text, record, index"> - <div class="editable-row-operations"> - <div v-if="record.receipt==='待叫应'"> - <a @click="showModal" style="color:orangered"><a-icon type="notification" /> - 确认已收到</a> - </div> - <br /> - <router-link :to="{path:'/torelease'}">转发</router-link> - <router-link :to="{path:'/details',query: {id: record.id}}">查看详情</router-link> - </div> + <a-button type="primary" v-if="record.responseStatus == 1" style="margin-right: 12px" @click="confirmResponce(record.id)">确认已收到</a-button> + <a-button type="primary" @click="openMod('repost',record)">转发</a-button> + <a-button type="link" @click="openMod('view',record)">查看详情</a-button> </template> </a-table> </div> + <msg-edit-mod ref="msgEdit" @refresh="getData"></msg-edit-mod> <!-- 对话框 --> - <a-modal title="回执" - okText="确认已安排部署" - cancelText="取消" - :visible="visible" :confirm-loading="confirmLoading" @ok="handleOk" - @cancel="handleCancel"> - <p>{{ ModalText }}</p> - </a-modal> +<!-- <a-modal title="回执" --> +<!-- okText="确认已安排部署"--> +<!-- cancelText="取消"--> +<!-- :visible="visible" :confirm-loading="confirmLoading" @ok="handleOk"--> +<!-- @cancel="handleCancel">--> +<!-- <p>{{ ModalText }}</p>--> +<!-- </a-modal>--> </div> </template> <script> - const columns = [{ - title: '序号', - dataIndex: 'key', - width: '5%', - }, - { - title: '发布时间', - dataIndex: 'time', - width: '15%', - scopedSlots: { - customRender: 'time' - }, //设置定制化表格数据 - }, - { - title: '发布单位', - dataIndex: 'department', - width: '12%', - }, - { - title: '类别', - dataIndex: 'category', - width: '8%', - }, - { - title: '级别', - dataIndex: 'level', - scopedSlots: { - customRender: 'level' - }, //设置定制化表格数据 - width: '8%', - }, - { - title: '信息标题', - dataIndex: 'title', - width: '16%', - }, - { - title: '附件', - dataIndex: 'attachment', - width: '6%', - scopedSlots: { - customRender: 'attachment' - }, - }, - { - title: '叫应状态', - dataIndex: 'receipt', - width: '10%', - scopedSlots: { - customRender: 'receipt' - }, //设置定制化表格数据 - }, - { - title: '操作', - dataIndex: 'operation', - scopedSlots: { - customRender: 'operation' - }, - }, - ]; +import {getMsgRecord, readById, responseMsg} from "@/api/list"; +import msgEditMod from "@/views/Admin/components/msgEditMod"; +import {publishMsg} from "@/api/send"; +import {getReviewDetail, getReviewDetailByWorker} from "@/api/review"; - const data = [{ - key: 1, - id:1001, - readed:false, - time: '2023年5月3日 15:30', - department: '自治区预警中心', - category: '气象', - level: '黄色', - title: '全疆高温红色预警', - attachment: '1', - receipt: '待叫应' - }, - { - key: 2, - readed:true, - id:1002, - time: '2023年5月2日 15:30', - department: '自治区预警中心', - category: '气象', - level: '橙色', - title: '全疆高温红色预警', - attachment: '1', - receipt: '已叫应' - }, - { - key: 3, - readed:true, - id:1003, - time: '2023年5月1日 15:30', - department: '自治区预警中心', - category: '气象', - level: '橙色', - title: '全疆高温红色预警', - attachment: '1', - receipt: '已叫应' - }, - { - key: 4, - readed:true, - id:1004, - time: '2023年5月1日 15:30', - department: '自治区预警中心', - category: '气象', - level: '橙色', - title: '全疆高温红色预警', - attachment: '2', - receipt: '超时未叫应' - }, - { - key: 5, - readed:true, - id:1005, - time: '2023年4月21日 15:30', - department: '自治区预警中心', - category: '气象', - level: '橙色', - title: '全疆高温红色预警', - attachment: '无', - receipt: '已叫应' - }, - { - key: 6, - readed:true, - id:1006, - time: '2023年4月21日 15:30', - department: '自治区预警中心', - category: '气象', - level: '橙色', - title: '全疆高温红色预警', - attachment: '1', - receipt: '已叫应' - }, - { - key: 7, - readed:true, - id:1007, - time: '2023年1月21日 15:30', - department: '自治区预警中心', - category: '气象', - level: '红色', - title: '全疆低温红色预警', - attachment: '1', - receipt: '已叫应' - }, - - ]; - - export default { + export default { + name: 'list', + components: { msgEditMod }, data() { - this.cacheData = data.map(item => ({ - ...item - })); return { - data, - columns, + search:{ + pageIndex: 1, + pageSize: 10, + searchParams:{ + responseStatus: null, + startTime: '', + endTime: '' + } + }, + timeRange: [], + columns:[ + { + title: '序号', + dataIndex: 'index', + width: '5%', + scopedSlots: { + customRender: 'index' + }, + }, + { + title: '发布时间', + dataIndex: 'publishingTime', + width: '15%', + scopedSlots: { + customRender: 'publishingTime' + }, //设置定制化表格数据 + }, + { + title: '发布单位', + dataIndex: 'publishingUnit', + width: '12%', + }, + { + title: '灾种', + dataIndex: 'disasterType', + width: '8%', + scopedSlots: { + customRender: 'disasterType' + } + }, + { + title: '预警级别', + dataIndex: 'warningLevel', + scopedSlots: { + customRender: 'warningLevel' + }, //设置定制化表格数据 + width: '8%', + }, + { + title: '信息标题', + dataIndex: 'title', + width: '16%', + }, + { + title: '附件', + dataIndex: 'attachment', + width: '6%', + scopedSlots: { + customRender: 'attachment' + }, + }, + { + title: '叫应状态', + dataIndex: 'responseStatus', + width: '10%', + scopedSlots: { + customRender: 'responseStatus' + }, //设置定制化表格数据 + }, + { + title: '操作', + dataIndex: 'operation', + scopedSlots: { + customRender: 'operation' + }, + }, + ], + data: [], + pagination: { + current: 1, + defaultCurrent: 1, + defaultPageSize: 10, + total: 0, + onChange: ( page, pageSize ) => this.onPageChange(page,pageSize), + showTotal: total => `共 ${total} 条` + }, + total: null, + details: {}, editingKey: '', category: 'default', ModalText: '确认已经安排部署?', visible: false, confirmLoading: false, + riskOptions: [ + {name: '地震',value: 1}, + {name: '洪涝',value: 2}, + {name: '气象',value: 3}, + {name: '泥石流',value: 4}, + {name: '水旱',value: 5}, + {name: '森林草原火灾',value: 6} + ], + levelOptions: [ + {name: '红色预警',value: 1}, + {name: '橙色预警',value: 2}, + {name: '黄色预警',value: 3}, + {name: '蓝色预警',value: 4} + ] }; }, - methods: { + created() { + const t = this + t.getData() + }, + methods: { + async getData(){ + const t = this + const res = await getMsgRecord(this.search) + if(res.data.code == 100){ + t.data = res.data.data + t.pagination.total = res.data.total + }else{ + this.$message.error(res.data.msg) + } + }, + + onPageChange(page, pageSize) { + const t= this + t.pagination.current = page + t.search.pageIndex = page + t.getData() + }, + + timeChange(value, dateString) { + const t = this + if(dateString){ + t.search.searchParams.startTime = value[0].format('YYYY-MM-DD 00:00:00') + t.search.searchParams.endTime = value[1].format('YYYY-MM-DD 23:59:59') + } + }, + + resetSearch(){ + const t = this + t.search = { + pageIndex: 1, + pageSize: 10, + searchParams:{ + responseStatus: null, + startTime: '', + endTime: '' + } + } + t.timeRange = [] + t.getData() + }, + + confirmResponce(id){ + const t = this + this.$confirm({ + title: '回执', + content: h => <div>确认已安排部署?</div>, + cancelText: '取消', + okText: '确认', + centered: true, + async onOk() { + let res = await responseMsg(id) + if(res.data.code == 100){ + t.$message.success('信息叫应成功'); + t.getData() + }else{ + t.$message.warning(res.data.msg); + } + }, + onCancel() { + console.log('Cancel'); + }, + }); + }, + + openMod(type,data){ + const t = this + getReviewDetailByWorker(data.warnInfoId).then(res=>{ + if(res.data.code == 100){ + if(res.data.data){ + t.read(data.id) + t.$refs.msgEdit.openMod(type,res.data.data) + }else{ + t.$message.error('查询信息详情失败') + } + }else{ + this.$message.error(res.data.msg) + } + }) + }, + + async read(id){ + const t = this + const res = await readById(id) + if(res.data.code == 100){ + console.log('已读') + }else{ + t.$message.error('设置已读出错') + } + }, + + getRiskName(disasterType){ + return this.riskOptions.find(i => i.value === disasterType)?.name; + }, + + getLevelName(warningLevel){ + return this.levelOptions.find(i => i.value === warningLevel)?.name; + }, + handleChange(value) { console.log(`Selected: ${value}`); }, popupScroll() { console.log('popupScroll'); }, - timeChange(date, dateString) { - console.log(date, dateString); - }, + timeOk(value) { console.log('timeOk: ', value); }, diff --git a/src/views/Admin/massSend.vue b/src/views/Admin/massSend.vue index 59301a3..3e2d999 100644 --- a/src/views/Admin/massSend.vue +++ b/src/views/Admin/massSend.vue @@ -1,11 +1,11 @@ <template> <div class="inner"> <h2>预警信息发布</h2> - <a-form-model :model="form" :wrapper-col="wrapperCol"> + <a-form-model ref="ruleForm" :model="form" :rules="rules" :wrapper-col="wrapperCol"> <div class="left"> - <a-form-model-item prop="title"> - <a-input v-model="form.title" placeholder="请输入标题" style="height: 50px; font-size: 20px;" /> - </a-form-model-item> +<!-- <a-form-model-item prop="title">--> +<!-- <a-input v-model="form.title" placeholder="请输入标题" style="height: 50px; font-size: 20px;" />--> +<!-- </a-form-model-item>--> <!-- <a-row>--> <!-- <a-col :span="12" style="display: flex;align-items: center">--> <!-- <span style="display: block;margin-bottom: 24px">相关灾种</span>--> @@ -19,27 +19,27 @@ <a-row> <a-col :span="12"> - <a-form-model-item prop="type"> - <a-radio-group v-model="form.type" default-value="a" button-style="solid"> - <a-radio-button value="a"> + <a-form-model-item prop="emergType"> + <a-radio-group v-model="form.emergType" button-style="solid"> + <a-radio-button :value="2"> 常规 </a-radio-button> - <a-radio-button value="b"> + <a-radio-button :value="1"> 紧临 </a-radio-button> </a-radio-group> </a-form-model-item> </a-col> <a-col :span="12" style="display: flex;align-items: center;justify-content: right"> - <a-form-model-item prop="riskType" style="margin-right: 20px"> - <a-select placeholder="请选择相关灾种" v-model="form.riskType" style="width: 240px" allowClear @change="handleRisk"> + <a-form-model-item prop="disasterType" style="margin-right: 20px"> + <a-select placeholder="请选择相关灾种" v-model="form.disasterType" style="width: 240px" allowClear @change="handleRisk"> <a-select-option v-for="item in riskOptions" :key="item.value" :value="item.value"> {{ item.name }} </a-select-option> </a-select> </a-form-model-item> - <a-form-model-item prop="level"> - <a-select placeholder="请选择预警级别" v-model="form.level" style="width: 240px" allowClear @change="handleLevel"> + <a-form-model-item prop="warningLevel"> + <a-select placeholder="请选择预警级别" v-model="form.warningLevel" style="width: 240px" allowClear @change="handleLevel"> <a-select-option v-for="item in levelOptions" :key="item.value" :value="item.value"> {{ item.name }} </a-select-option> @@ -47,63 +47,59 @@ </a-form-model-item> </a-col> </a-row> - <a-form-model-item prop="message"> - <a-textarea v-model="form.message" placeholder="请输入短信通知内容部分" :auto-size="{ minRows: 3, maxRows: 5 }" /> + <a-form-model-item prop="content"> + <a-textarea v-model="form.content" placeholder="请输入短信通知内容部分" :auto-size="{ minRows: 3, maxRows: 5 }" /> </a-form-model-item> - <a-row> - <a-col :span="12"> - <a-button>上传附件</a-button> - </a-col> - <a-col :span="12" style="display: flex;align-items: center;justify-content: right"> - <b style="margin-bottom: 24px">超时设置:</b> - <a-form-model-item prop="overTime"> - <a-input v-model="form.overTime" style="width:200px;" placeholder="输入时间" suffix="分钟"/> - </a-form-model-item> - </a-col> - </a-row> - <span><b>发布单位:</b>{{department}}</span> +<!-- <a-row>--> +<!-- <a-col :span="12">--> +<!-- <a-button>上传附件</a-button>--> +<!-- </a-col>--> +<!-- <a-col :span="12" style="display: flex;align-items: center;justify-content: right">--> +<!-- <b style="margin-bottom: 24px">超时设置:</b>--> +<!-- <a-form-model-item prop="overTime">--> +<!-- <a-input v-model="form.overTime" style="width:200px;" placeholder="输入时间" suffix="分钟"/>--> +<!-- </a-form-model-item>--> +<!-- </a-col>--> +<!-- </a-row>--> + <span><b>发布单位:</b>{{form.publishingUnit}}</span> <br/><br/> <!-- 子单位--> <a-row :gutter="24"> <a-col :span="12"> - <b style="margin-bottom: 6px">选择接收单位:</b> - <a-form-model-item prop="svalue"> + <div style="display:flex;justify-content: space-between;align-items: center;"> + <b>选择接收单位:</b> + <a-checkbox :checked="checkAll" @change="checkChange"> + 全选 + </a-checkbox> + </div> + <a-form-model-item prop="receiver"> <a-tree-select show-search tree-checkable treeCheckStrictly style="width: 100%" - v-model="form.svalue" + v-model="form.receiver" :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }" placeholder="选择工作通知接收单位" allow-clear multiple - tree-default-expand-all @change="onChanges" @search="onSearch" @select="onSelect" + :tree-data="areaUsers" + :replaceFields="replaceFields" > - <a-tree-select-node key="0" value="all" title="全选"> - </a-tree-select-node> - <a-tree-select-node key="0-1" value="乌鲁木齐" title="乌鲁木齐(张XX 13268813610)"> - <a-tree-select-node key="0-1-1" value="米东区" title="米东区(张XX 13268813610)"> - <a-tree-select-node key="0-1-1-1" value="XX村1" title="XX村(李有田 13268813610)" /> - </a-tree-select-node> - <a-tree-select-node key="0-1-2" value="天山区" title="天山区"> - <a-tree-select-node key="0-1-2-1" value="XX村2"> - <b slot="title" style="color: #08c">XX村</b> - </a-tree-select-node> - </a-tree-select-node> - </a-tree-select-node> </a-tree-select> </a-form-model-item> </a-col> <a-col :span="12"> - <b style="margin-bottom: 6px">平级接收人选择:</b> - <a-form-model-item prop="sameDep"> - <a-select mode="multiple" placeholder="选择平级接收单位" v-model="form.sameDep" @change="handle"> - <a-select-option v-for="item in filteredOptions" :key="item" :value="item"> - {{ item }} + <div> + <b>平级接收人选择:</b> + </div> + <a-form-model-item prop="recipient"> + <a-select mode="multiple" placeholder="选择平级接收单位" v-model="form.recipient" @change="handle"> + <a-select-option v-for="item in filteredOptions" :key="item.id" :value="item.id"> + {{ item.recipientName }} </a-select-option> </a-select> </a-form-model-item> @@ -126,7 +122,7 @@ <!-- </a-select>--> <!-- </div>--> <div style="display: flex;justify-content: right"> - <a-button type="primary" style="width: 250px;"> + <a-button type="primary" style="width: 250px;" @click="confirmSend()"> 确认发送 </a-button> </div> @@ -136,7 +132,7 @@ <h2>短信预览</h2> <div class="mobile"> <div class="mesg"> - <P>【{{form.title}}】{{form.message}}。发布单位:{{department}}</P> + <P>{{form.content}}发布单位:{{form.publishingUnit}}</P> </div> </div> @@ -146,26 +142,36 @@ </template> <script> - - - const OPTIONS = ['自治区消防(李XX)', '自治区公安厅(王XX)', '自治区自然资源厅(刘XX)']; +import { getPeerRecipient, getAreaWithUserIfo } from '@/api/user' +import { massSend } from "@/api/send"; +import {getUserInfo} from "@/util/storage"; export default { - name: "release", + name: "massSend", data() { return { - message: '', - signname: '自然灾害风险预警提示', + userInfo: {}, department: '自治区自然灾害综合监测预警中心', + filteredOptions:[], wrapperCol: { span: 24 }, form: { - title: '', - riskType: 1, - level: 1, - type: 'a', - svalue: undefined, - sameDep: [], - message: '', - overTime: '' + id: null, + emergType: null, + disasterType: undefined, + warningLevel: undefined, + content: '', + publishingUnit: '', + receiver: [], + recipient: [], + verticalRecipient: [], + horizontalRecipient: [] + }, + checkAll: false, + areaUsers: [], + replaceFields: { + children:'children', + title:'name', + key:'id', + value: 'id' }, riskOptions: [ {name: '地震',value: 1}, @@ -179,32 +185,129 @@ {name: '红色预警',value: 1}, {name: '橙色预警',value: 2}, {name: '黄色预警',value: 3}, - {name: '蓝色预警',value: 4}, - {name: '其他短信通知',value: 5} - ] + {name: '蓝色预警',value: 4} + ], + rules: { + emergType: [{ required: true, message: '请选择紧急类型', trigger: 'change'}], + disasterType: [{ required: true, message: '请选择灾种', trigger: 'change'}], + warningLevel: [{ required: true, message: '请选择预警级别', trigger: 'change'}], + content: [{ required: true, message: '请输入信息内容', trigger: 'blur'}], + receiver: [{ required: true, message: '请选择接收单位', trigger: 'change'}], + recipient: [{ required: true, message: '请选择平级接收人', trigger: 'change'}] + // verticalRecipient: [{ required: true, message: '请选择接收单位', trigger: 'change'}], + // horizontalRecipient: [{ required: true, message: '请选择平级接收人', trigger: 'change'}] + } }; }, components: {}, - computed: { - filteredOptions() { - return OPTIONS.filter(o => !this.form.sameDep.includes(o)); - }, + created() { + const t = this + t.userInfo = getUserInfo() + t.form.publishingUnit = t.userInfo.company + t.getSameLevel() + t.getAreaUsers() + }, + computed: { }, methods: { + // 获取同级接收人 + async getSameLevel(){ + let t = this + let res = await getPeerRecipient() + if(res.data.code == 100){ + if(res.data.data){ + t.filteredOptions = res.data.data + }else{ + this.$message.warning('暂无数据'); + } + }else{ + this.$message.warning(res.data.msg); + } + }, + + // 获取接收单位 + async getAreaUsers(){ + let t = this + let res = await getAreaWithUserIfo() + if(res.data.code == 100){ + if(res.data.data){ + const treeD = [] + t.userTitTree(res.data.data) + treeD.push(t.findNodeById(res.data.data,t.userInfo.districtId)) + t.areaUsers = treeD + }else{ + this.$message.warning('暂无数据'); + } + }else{ + this.$message.warning(res.data.msg); + } + }, + //选择子部门部分 - onChanges(value) { - if(value.find(i=>i.value == 'all')){ - console.log('全选了') - }else{ - this.svalue = value; + onChanges(value,label,extra) { + const t = this + if(t.form.receiver.length == 0){ + t.checkAll = false + } + + // for(let i of value){ + // t.form.verticalRecipient = [...t.form.verticalRecipient,...t.findNodeById(t.areaUsers,i.value).users] + // } + }, + + checkChange(e) { + const t = this + this.checkAll = !this.checkAll + if(t.checkAll == true){ + t.form.receiver = t.traverseTree(t.areaUsers[0]) + }else{ + t.form.receiver = [] + } + }, + + confirmSend(){ + this.$refs.ruleForm.validate(valid => { + if (valid) { + this.form.verticalRecipient = [] + this.form.horizontalRecipient = [] + const aList = this.form.receiver.map(item=>this.findNodeById(this.areaUsers,item.value)?.users) + const newAList = [].concat(...aList) + for(let i of newAList){ + const {realName,...data} = i + const {company: recipientUnit,...rest} = data + const obj = {recipientUnit,recipientType:1,...rest} + this.form.verticalRecipient.push(obj) } - console.log(this.svalue); - }, + const bList = this.form.recipient.map(item => this.filteredOptions.find(i=>i.id == item)) + for(let i of bList){ + const {recipientName: name, company: recipientUnit,...rest} = i + const obj = {name,recipientUnit,recipientType:2,...rest} + this.form.horizontalRecipient.push(obj) + } + const {receiver,recipient,...data} = this.form + massSend(data).then( res =>{ + if(res.data.code == 100){ + this.$message.success('信息群发成功') + this.$refs.ruleForm.clearValidate() + this.$refs.ruleForm.resetFields() + }else{ + this.$message.error(res.data.msg) + this.$refs.ruleForm.clearValidate() + this.$refs.ruleForm.resetFields() + } + }) + }else{ + console.log('error submit!!'); + return false; + } + }) + }, + onSearch() { - console.log(...arguments); + // console.log(...arguments); }, onSelect() { - console.log(...arguments); + // console.log(...arguments); }, //选择平级部门部分 handleRisk(selectedItems) { @@ -233,6 +336,50 @@ option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0 ); }, + + // 根据id查对象 + findNodeById(data,value) { + for (const node of data) { + if (node.id === value) { + return node; + } + if (node.children) { + const foundNode = this.findNodeById(node.children, value); + if (foundNode) { + return foundNode; + } + } + } + return null; + }, + + // 将树状数据所有id和name放入对象数组 + traverseTree(treeData) { + let result = []; + function traverse(node) { + result.push({ label: node.name, value: node.id }); + if (node.children && node.children.length > 0) { + for (let child of node.children) { + traverse(child); + } + } + } + traverse(treeData); + return result; + }, + + // 将树状数据新增title字段放入users的姓名电话 + userTitTree(treeData) { + for(const node of treeData){ + if(node.users){ + node.name = node.name + '('+node.users.map(i=>i.name +' '+ i.phone).join(',')+')' + } + if(node.children){ + this.userTitTree(node.children) + } + } + return treeData + } }, } </script> diff --git a/src/views/Admin/menuManage.vue b/src/views/Admin/menuManage.vue index 736cfc5..6c00149 100644 --- a/src/views/Admin/menuManage.vue +++ b/src/views/Admin/menuManage.vue @@ -38,8 +38,8 @@ </template> </a-table> </div> - <user-mod ref="userMod" @refrech="getUserList"></user-mod> - <pwd-mod ref="pwdMod" @refrech="getUserList"></pwd-mod> + <user-mod ref="userMod" @refresh="getUserList"></user-mod> + <pwd-mod ref="pwdMod" @refresh="getUserList"></pwd-mod> </div> </template> diff --git a/src/views/Admin/msgRecord.vue b/src/views/Admin/msgRecord.vue index d35a394..3cf0327 100644 --- a/src/views/Admin/msgRecord.vue +++ b/src/views/Admin/msgRecord.vue @@ -3,16 +3,17 @@ <a-row type="flex" :gutter="12" style="margin-bottom: 20px"> <a-col :span="6"> <a-range-picker + v-model="timeRange" format="YYYY-MM-DD" :placeholder="['开始时间', '结束时间']" - @change="onChange" + @change="timeChange" @ok="onOk" style="width: 100%" /> </a-col> <a-col :span="4"> - <a-button type="primary">查询</a-button> - <a-button style="margin-left: 12px">重置</a-button> + <a-button type="primary" @click="getData">查询</a-button> + <a-button style="margin-left: 12px" @click="resetSearch">重置</a-button> </a-col> </a-row> <div class="table-cont"> @@ -20,7 +21,7 @@ <a-card hoverable class="msg-item" v-for="item in msg" :key="item.id"> <template #title> <div class="tit"> - 发送时间:<span>{{item.time}}</span> + 发送时间:<span>{{item.gmtCreate}}</span> </div> <a-divider type="vertical" /> <div class="tit"> @@ -32,66 +33,135 @@ </p> <template #actions> <div> - 接收号码:<span>{{item.phone.join(',')}}</span> + 接收号码:<span>{{item.recipients.map(i=>i.name + '(' + i.phone + ')').join('、')}}</span> </div> <div> - <a-button type="primary" @click="viewDetails">查看详情</a-button> + <a-button type="primary" @click="viewDetails(item)">查看详情</a-button> </div> </template> </a-card> </div> </div> - <a-modal v-model="visible" width="50%" title="短信详情" @ok="handleOk" cancelText="取消" okText="确认"> - 短信详情 + <a-pagination v-model="search.pageIndex" :total="total" :show-total="total => `共 ${total} 条数据`" show-less-items/> + <a-modal v-model="visible" width="40%" title="短信详情" @ok="handleOk" cancelText="取消" okText="确认" centered> + <div class="detail-mod"> + <a-row :gutter="24"><a-col :span="4" style="text-align: right">{{ details.emergType == 1?'紧急':details.emergType == 2?'常规':'' }}</a-col></a-row> + <a-row :gutter="24"><a-col :span="4" style="text-align: right">发送时间</a-col><a-col :span="14" style="border: 1px solid #d9d9d9;padding: 5px 10px !important;">{{details.gmtCreate}}</a-col></a-row> + <a-row :gutter="24"><a-col :span="4" style="text-align: right">灾种类型</a-col><a-col :span="14" style="border: 1px solid #d9d9d9;padding: 5px 10px !important;">{{ getRiskName(details.disasterType)}}</a-col></a-row> + <a-row :gutter="24"><a-col :span="4" style="text-align: right">预警级别</a-col><a-col :span="14" style="border: 1px solid #d9d9d9;padding: 5px 10px !important;">{{ getLevelName(details.warningLevel)}}</a-col></a-row> + <a-row :gutter="24"><a-col :span="4" style="text-align: right">信息内容</a-col><a-col :span="14" style="border: 1px solid #d9d9d9;padding: 5px 10px !important;">{{details.content}}</a-col></a-row> + <a-row :gutter="24"> + <a-col :span="4" style="text-align: right">接收人</a-col> + <a-col :span="20" style="border: 1px solid #d9d9d9;padding: 0 !important;"> + <div v-for="(item,index) in details.recipients" :key="index" class="table"> + <div style="width: 20%"> + {{item.name}} + </div> + <div style="width: 20%"> + {{item.phone}} + </div> + <div style="width: 60%"> + {{item.recipientUnit}} + </div> + </div> + </a-col> + </a-row> + </div> </a-modal> </div> </template> <script> import {getUser} from '@/api/user' +import {getMassRecord} from "@/api/send"; + export default { name: 'msgRecord', components: {}, data () { return { - msg: [ - { - time: '2023-05-30', - id: '1201', - content: '第一条短信', - phone: ['15261806176','15261806176','15261806176','15261806176','15261806176','15261806176','15261806176','15261806176','15261806176'] - }, - { - time: '2023-05-30', - id: '1202', - content: '第二条短信', - phone: ['15261806176','15261806176','15261806176','15261806176','15261806176'] - }, - { - time: '2023-05-30', - id: '1203', - content: '第三条短信', - phone: ['15261806176','15261806176','15261806176','15261806176','15261806176'] + search:{ + pageIndex: 1, + pageSize: 10, + searchParams:{ + startTime: '', + endTime: '' } + }, + timeRange: [], + total: 0, + msg: [], + visible: false, + details: {}, + riskOptions: [ + {name: '地震',value: 1}, + {name: '洪涝',value: 2}, + {name: '气象',value: 3}, + {name: '泥石流',value: 4}, + {name: '水旱',value: 5}, + {name: '森林草原火灾',value: 6} ], - visible: false + levelOptions: [ + {name: '红色预警',value: 1}, + {name: '橙色预警',value: 2}, + {name: '黄色预警',value: 3}, + {name: '蓝色预警',value: 4} + ] } }, created() { const t = this + t.getData() }, methods:{ - onChange(value, dateString) { - console.log('Selected Time: ', value); - console.log('Formatted Selected Time: ', dateString); + async getData(){ + const t = this + const res = await getMassRecord(this.search) + if(res.data.code == 200){ + t.msg = res.data.data + t.pagination.total = res.data.total + }else{ + this.$message.error(res.data.msg) + } + }, + + resetSearch(){ + const t = this + t.search = { + pageIndex: 1, + pageSize: 10, + searchParams:{ + startTime: '', + endTime: '' + } + } + t.timeRange = [] + t.getData() + }, + + timeChange(value, dateString) { + const t = this + if(dateString){ + t.search.searchParams.startTime = value[0].format('YYYY-MM-DD 00:00:00') + t.search.searchParams.endTime = value[1].format('YYYY-MM-DD 23:59:59') + } }, onOk(value) { console.log('onOk: ', value); }, - viewDetails(){ + viewDetails(item){ const t = this + t.details = item t.visible = true }, + + getRiskName(disasterType){ + return this.riskOptions.find(i => i.value === disasterType)?.name; + }, + getLevelName(warningLevel){ + return this.levelOptions.find(i => i.value === warningLevel)?.name; + }, + handleOk(e) { console.log(e); this.visible = false; @@ -109,9 +179,9 @@ width: 100%; margin-bottom: 24px; - /deep/ .ant-card-head-title{ - display: flex; - align-items: center; + /deep/.ant-card-head-title{ + display: flex !important; + align-items: center !important; .tit{ width: 50%; } @@ -138,5 +208,28 @@ } } } +.detail-mod{ + font-size: 16px; + + .ant-row{ + margin-bottom: 24px; + + .table{ + display: flex; + align-items: center; + border-bottom: 1px solid @blackBorder; + &:last-of-type{ + border-bottom: none; + } + &>div{ + border-right: 1px solid @blackBorder; + padding: 5px 10px; + &:last-of-type{ + border-right: none; + } + } + } + } +} </style> diff --git a/src/views/Admin/msgReview.vue b/src/views/Admin/msgReview.vue index 51d274e..011ba5d 100644 --- a/src/views/Admin/msgReview.vue +++ b/src/views/Admin/msgReview.vue @@ -2,14 +2,14 @@ <div class="inner"> <a-row type="flex" justify="space-between" style="margin-bottom: 20px"> <a-col :span="8"> - <a-radio-group v-model="category"> - <a-radio-button :value="0"> + <a-radio-group v-model="search.searchParams.reviewStatus" @change="getData"> + <a-radio-button :value="null"> 全部 </a-radio-button> - <a-radio-button :value="1"> + <a-radio-button :value="2"> 审核通过 </a-radio-button> - <a-radio-button :value="2"> + <a-radio-button :value="1"> 未审核 </a-radio-button> <a-radio-button :value="3"> @@ -21,108 +21,123 @@ <a-row type="flex" justify="end" :gutter="12"> <a-col :span="8"> <a-range-picker + v-model="timeRange" format="YYYY-MM-DD" :placeholder="['开始时间', '结束时间']" @change="timeChange" - @ok="timeOk" + @ok="onOk" style="width: 100%" /> </a-col> <a-col :span="4"> - <a-button type="primary">查询</a-button> - <a-button style="margin-left: 12px">重置</a-button> + <a-button type="primary" @click="getData">查询</a-button> + <a-button style="margin-left: 12px" @click="resetSearch">重置</a-button> </a-col> </a-row> </a-col> </a-row> <div class="table-cont"> - <a-table :columns="columns" :data-source="data" bordered> - <template #level="level"> - <a-tag :color="level === '黄色' ? 'yellow' :level === '橙色'? 'orange':level === '红色'?'red':'blue'"> - {{ level }} - </a-tag> + <a-table :columns="columns" :data-source="data" bordered :rowKey="record=>record.id"> + <template #index="text,record,index"> + {{ index+1 }} + </template> + <template #disasterType="text"> + {{ getRiskName(text) }} </template> <template #attachment="text"> <span v-if="text==='无'">无</span> <a v-else><b><a-icon type="paper-clip" /> {{text}}</b></a> </template > - <template #status="status"> + <template #reviewStatus="reviewStatus"> <a-tag - :color="status === 1 ? 'green' : status === 2 ? 'blue' : 'red'" + :color="reviewStatus === 1 ? 'blue' : reviewStatus === 2 ? 'green' : 'red'" > - {{ status==1?'审核通过':status==2?'未审核':'审核驳回' }} + {{ reviewStatus==1?'未审核':reviewStatus==2?'已审核':reviewStatus==3?'审核驳回':'' }} </a-tag> </template> <template #operation="text, record, index"> - <a-button type="link" v-if="record.status == 1 || record.status == 3">查看信息详情</a-button> - <a-button type="primary" v-if="record.status == 2">查看并审核</a-button> + <a-button type="link" v-if="record.reviewStatus == 2 || record.reviewStatus == 3" @click="openMod('view',record)">查看信息详情</a-button> + <a-button type="primary" v-if="record.reviewStatus == 1" @click="openMod('review',record)">查看并审核</a-button> </template> </a-table> </div> - + <msg-edit-mod ref="msgEdit" @refresh="getData"></msg-edit-mod> </div> </template> <script> +import {getReviewDetail, getReviewRecord} from "@/api/review"; +import msgEditMod from '@/views/Admin/components/msgEditMod' + export default { name: 'msgReview', - components: {}, + components: { msgEditMod }, data () { return { - category: 0, + search:{ + pageIndex: 1, + pageSize: 10, + searchParams:{ + reviewStatus: null, + startTime: '', + endTime: '' + } + }, + timeRange: [], + riskOptions: [ + {name: '地震',value: 1}, + {name: '洪涝',value: 2}, + {name: '气象',value: 3}, + {name: '泥石流',value: 4}, + {name: '水旱',value: 5}, + {name: '森林草原火灾',value: 6} + ], columns: [ { title: '序号', - dataIndex: 'key', - width: '5%', + key: 'index', + scopedSlots: { + customRender: 'index' + }, }, { title: '提交审核时间', - dataIndex: 'time', - width: '15%', - scopedSlots: { - customRender: 'time' - }, //设置定制化表格数据 + key: 'gmtReviewSubmit', + dataIndex: 'gmtReviewSubmit', }, { title: '发布单位', - dataIndex: 'department', - width: '12%', + key: 'publishingUnit', + dataIndex: 'publishingUnit', }, { - title: '类别', - dataIndex: 'category', - width: '8%', - }, - { - title: '级别', - dataIndex: 'level', + title: '灾种', + dataIndex: 'disasterType', + key: 'disasterType', scopedSlots: { - customRender: 'level' + customRender: 'disasterType' }, //设置定制化表格数据 - width: '8%', }, { title: '信息标题', + key: 'title', dataIndex: 'title', - width: '16%', }, { title: '附件', + key: 'attachment', dataIndex: 'attachment', - width: '6%', scopedSlots: { customRender: 'attachment' }, }, { title: '审核情况', - dataIndex: 'status', - width: '10%', + dataIndex: 'reviewStatus', scopedSlots: { - customRender: 'status' + customRender: 'reviewStatus' }, //设置定制化表格数据 }, { @@ -133,53 +148,66 @@ }, }, ], - data: [ - { - key: 1, - id:1001, - time: '2023-05-02 15:30', - department: '自治区预警中心', - category: '气象', - level: '黄色', - title: '全疆高温红色预警', - attachment: '1', - status: 1 - }, - { - key: 2, - id:1002, - time: '2023-05-02 15:30', - department: '自治区预警中心', - category: '气象', - level: '橙色', - title: '全疆高温红色预警', - attachment: '1', - status: 2 - }, - { - key: 3, - id:1003, - time: '2023-05-02 15:30', - department: '自治区预警中心', - category: '气象', - level: '橙色', - title: '全疆高温红色预警', - attachment: '1', - status: 3 - } - ] + data: [] } }, created() { const t = this + t.getData() }, methods:{ - timeChange(date, dateString) { - console.log(date, dateString); + async getData(){ + const t = this + const res = await getReviewRecord(this.search) + if(res.data.code == 100){ + t.data = res.data.data + t.pagination.total = res.data.total + }else{ + this.$message.error(res.data.msg) + } }, - timeOk(value) { - console.log('timeOk: ', value); + + resetSearch(){ + const t = this + t.search = { + pageIndex: 1, + pageSize: 10, + searchParams:{ + reviewStatus: null, + startTime: '', + endTime: '' + } + } + t.timeRange = [] + t.getData() }, + + timeChange(value, dateString) { + const t = this + if(dateString){ + t.search.searchParams.startTime = value[0].format('YYYY-MM-DD 00:00:00') + t.search.searchParams.endTime = value[1].format('YYYY-MM-DD 23:59:59') + } + }, + + openMod(type,data){ + const t = this + getReviewDetail(data.id).then(res=>{ + if(res.data.code == 100){ + t.$refs.msgEdit.openMod(type,res.data.data) + }else{ + this.$message.error(res.data.msg) + } + }) + }, + + onOk(value) { + console.log('onOk: ', value); + }, + getRiskName(disasterType){ + return this.riskOptions.find(i => i.value === disasterType)?.name; + } + } } </script> diff --git a/src/views/Admin/notice.vue b/src/views/Admin/notice.vue index 2c46405..aa3a28d 100644 --- a/src/views/Admin/notice.vue +++ b/src/views/Admin/notice.vue @@ -1,146 +1,384 @@ <template> <div class="inner"> - <h2>预警信息发布</h2> - <div class="left"> - <a-input placeholder="请输入标题" style="height: 50px; font-size: 20px;" /> - <br /><br /> - <a-radio-group v-model="value" @change="onChange"> - <a-radio :value="1"> - 蓝色 - </a-radio> - <a-radio :value="2"> - 黄色 - </a-radio> - <a-radio :value="3"> - 橙色 - </a-radio> - <a-radio :value="4"> - 红色 - </a-radio> - </a-radio-group> - <br /><br /> - <a-radio-group default-value="a" button-style="solid"> - <a-radio-button value="a"> - 常规 - </a-radio-button> - <a-radio-button value="b"> - 紧临 - </a-radio-button> - </a-radio-group> - <div class="ftright"> - 平级接收人选择: - <a-select mode="multiple" placeholder="选择平级接收单位" :value="selectedItems" style="width: 180px" - @change="handle"> - <a-select-option v-for="item in filteredOptions" :key="item" :value="item"> - {{ item }} - </a-select-option> - </a-select> - - </div> + <h2>预警信息发布</h2> + <a-form-model ref="ruleForm" :model="form" :rules="rules" :wrapper-col="wrapperCol"> + <div class="left"> + <a-form-model-item prop="title"> + <a-input v-model="form.title" placeholder="请输入标题" style="height: 50px; font-size: 20px;" /> + </a-form-model-item> + <!-- <a-row>--> + <!-- <a-col :span="12" style="display: flex;align-items: center">--> + <!-- <span style="display: block;margin-bottom: 24px">相关灾种</span>--> - <br /><br /> - <a-textarea v-model="message" placeholder="请输入短信通知内容部分" :auto-size="{ minRows: 3, maxRows: 5 }" /> - <br /><br /> - <a-button>上传附件</a-button> <div style="float: right;width:50%;text-align: right;">超时设置: <a-input style="width:100px;" placeholder="输入时间" /> 分钟</div> - <br /><br /> - <span><b>发布单位:</b>{{department}}</span> - <br/><br/> - <!-- 子单位--> - <div style="margin-bottom: 10px">选择接收单位:</div> - <a-tree-select - show-search - tree-checkable - treeCheckStrictly - style="width: 100%" - v-model="svalue" - :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }" - placeholder="选择工作通知接收单位" - allow-clear - multiple - tree-default-expand-all - @change="onChanges" - @search="onSearch" - @select="onSelect" - > - <a-tree-select-node key="0" value="all" title="全选"> - </a-tree-select-node> - <a-tree-select-node key="0-1" value="乌鲁木齐" title="乌鲁木齐(张XX 13268813610)"> - <a-tree-select-node key="0-1-1" value="米东区" title="米东区(张XX 13268813610)"> - <a-tree-select-node key="0-1-1-1" value="XX村1" title="XX村(李有田 13268813610)" /> - </a-tree-select-node> - <a-tree-select-node key="0-1-2" value="天山区" title="天山区"> - <a-tree-select-node key="0-1-2-1" value="XX村2"> - <b slot="title" style="color: #08c">XX村</b> - </a-tree-select-node> - </a-tree-select-node> - </a-tree-select-node> - </a-tree-select> - - <br/><br/> - <div style="float: right;"><b>选择审批领导:</b> <a-select show-search placeholder="请选择审批领导" - option-filter-prop="children" style="width: 200px" :filter-option="filterOption" - @focus="handleFocus" @blur="handleBlur" @change="handleChange"> - <a-select-option value="jack"> - 裴小威 - </a-select-option> - <a-select-option value="lucy"> - 赵东升 - </a-select-option> - <a-select-option value="tom"> - 王卫萍 - </a-select-option> - </a-select></div> - <br /><br /> - <a-button type="primary" class="ftright"> - 确认并提交审核 - </a-button> - </div> + <!-- </a-col>--> + <!-- <a-col :span="12" style="display: flex;align-items: center;justify-content: right">--> + <!-- <span style="display: block;margin-bottom: 24px">预警级别:</span>--> - <div class="right"> - <h2>短信预览</h2> - <div class="mobile"> - <div class="mesg"> - <P>【{{signname}}】{{message}}。发布单位:{{department}}</P> - </div> + <!-- </a-col>--> + <!-- </a-row>--> - </div> - </div> + <a-row> + <a-col :span="12"> + <a-form-model-item prop="emergType"> + <a-radio-group v-model="form.emergType" button-style="solid"> + <a-radio-button :value="2"> + 常规 + </a-radio-button> + <a-radio-button :value="1"> + 紧临 + </a-radio-button> + </a-radio-group> + </a-form-model-item> + </a-col> + <a-col :span="12" style="display: flex;align-items: center;justify-content: right"> + <a-form-model-item prop="disasterType" style="margin-right: 20px"> + <a-select placeholder="请选择相关灾种" v-model="form.disasterType" style="width: 240px" allowClear @change="handleRisk"> + <a-select-option v-for="item in riskOptions" :key="item.value" :value="item.value"> + {{ item.name }} + </a-select-option> + </a-select> + </a-form-model-item> + <a-form-model-item prop="warningLevel"> + <a-select placeholder="请选择预警级别" v-model="form.warningLevel" style="width: 240px" allowClear @change="handleLevel"> + <a-select-option v-for="item in levelOptions" :key="item.value" :value="item.value"> + {{ item.name }} + </a-select-option> + </a-select> + </a-form-model-item> + </a-col> + </a-row> + <a-form-model-item prop="content"> + <a-textarea v-model="form.content" placeholder="请输入短信通知内容部分" :auto-size="{ minRows: 3, maxRows: 5 }" /> + </a-form-model-item> + <a-row> + <a-col :span="12"> + <a-button>上传附件</a-button> + </a-col> + <a-col :span="12" style="display: flex;align-items: center;justify-content: right"> + <b style="margin-bottom: 24px">超时设置:</b> + <a-form-model-item prop="timeout"> + <a-input v-model="form.timeout" style="width:200px;" placeholder="输入时间" suffix="分钟"/> + </a-form-model-item> + </a-col> + </a-row> + <span><b>发布单位:</b>{{form.publishingUnit}}</span> + <br/><br/> + <!-- 子单位--> + <a-row :gutter="24"> + <a-col :span="12"> + <div style="display:flex;justify-content: space-between;align-items: center;"> + <b>选择接收单位:</b> + <a-checkbox :checked="checkAll" @change="checkChange"> + 全选 + </a-checkbox> + </div> + <a-form-model-item prop="receiver"> + <a-tree-select + show-search + tree-checkable + treeCheckStrictly + style="width: 100%" + v-model="form.receiver" + :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }" + placeholder="选择工作通知接收单位" + allow-clear + multiple + @change="depChanges" + @search="onSearch" + @select="onSelect" + :tree-data="areaUsers" + :replaceFields="replaceFields" + > + </a-tree-select> + </a-form-model-item> + </a-col> + <a-col :span="12"> + <b style="margin-bottom: 6px">平级接收人选择:</b> + <a-form-model-item prop="recipient"> + <a-select mode="multiple" placeholder="选择平级接收单位" v-model="form.recipient" @change="handle"> + <a-select-option v-for="item in filteredOptions" :key="item.id" :value="item.id"> + {{ item.recipientName }} + </a-select-option> + </a-select> + </a-form-model-item> + </a-col> + </a-row> + <a-row :gutter="24" style="display: flex;align-items: center"> + <a-col :span="12"> + <b style="margin-bottom: 6px">选择审批领导:</b> + <a-form-model-item prop="reviewId"> + <a-select show-search v-model="form.reviewId" placeholder="请选择审批领导" style="width: 300px"> + <a-select-option v-for="(item,index) in leaders" :value="item.id" :key="index">{{item.name}}</a-select-option> + </a-select> + </a-form-model-item> + </a-col> + <a-col :span="12" style="text-align: right"> + <a-button type="primary" style="width: 250px;" @click="confirmSend()"> + 确认并提交审核 + </a-button> + </a-col> + </a-row> + </div> + <div class="right"> + <h2>短信预览</h2> + <div class="mobile"> + <div class="mesg"> + <P>【{{form.title}}】{{form.content}}。发布单位:{{form.publishingUnit}}</P> + </div> + + </div> + </div> + </a-form-model> </div> </template> <script> - - - const OPTIONS = ['自治区消防(李XX)', '自治区公安厅(王XX)', '自治区自然资源厅(刘XX)']; +import {getAreaWithUserIfo, getPeerRecipient, getLeaders} from '@/api/user' + import {getUserInfo} from "@/util/storage"; + import Cookies from "js-cookie"; +import {massSend, msgSend} from "@/api/send"; export default { - name: "release", + name: "notice", data() { return { - value: 1, - message: '', - signname: '自然灾害风险预警提示', - department: '自治区自然灾害综合监测预警中心', - selectedItems: [], - svalue:undefined, + userInfo: {}, + wrapperCol: { span: 24 }, + filteredOptions:[], + form: { + id: null, + title: '', + emergType: null, + disasterType: undefined, + warningLevel: undefined, + content: '', + publishingUnit: '', + districtId: null, + attachments: [], + timeout: null, + reviewId: null, + receiver: [], + recipient: [], + acceptingUnitIds: [], + peerRecipientIds: [] + }, + leaders: [], + checkAll: false, + areaUsers: [], + replaceFields: { + children:'children', + title:'name', + key:'id', + value: 'id' + }, + riskOptions: [ + {name: '地震',value: 1}, + {name: '洪涝',value: 2}, + {name: '气象',value: 3}, + {name: '泥石流',value: 4}, + {name: '水旱',value: 5}, + {name: '森林草原火灾',value: 6} + ], + levelOptions: [ + {name: '红色预警',value: 1}, + {name: '橙色预警',value: 2}, + {name: '黄色预警',value: 3}, + {name: '蓝色预警',value: 4} + ], + rules: { + emergType: [{ required: true, message: '请选择紧急类型', trigger: 'change'}], + disasterType: [{ required: true, message: '请选择灾种', trigger: 'change'}], + warningLevel: [{ required: true, message: '请选择预警级别', trigger: 'change'}], + title: [{ required: true, message: '请输入信息标题', trigger: 'blur'}], + content: [{ required: true, message: '请输入信息内容', trigger: 'blur'}], + timeout: [{ required: true, message: '请输入超时时间', trigger: 'blur'}], + receiver: [{ required: true, message: '请选择接收单位', trigger: 'change'}], + reviewId: [{ required: true, message: '请选择审批人', trigger: 'change'}], + recipient: [{ required: true, message: '请选择平级接收人', trigger: 'change'}] + // acceptingUnitIds: [{ required: true, message: '请选择接收单位', trigger: 'change'}], + // peerRecipientIds: [{ required: true, message: '请选择平级接收人', trigger: 'change'}] + } }; }, components: {}, - computed: { - filteredOptions() { - return OPTIONS.filter(o => !this.selectedItems.includes(o)); - }, - }, + created() { + const t = this + t.userInfo = getUserInfo() + t.form.districtId = t.userInfo.districtId + t.form.publishingUnit = t.userInfo.company + t.getSameLevel() + t.getAreaUsers() + t.getLeaders() + }, + computed: {}, methods: { + // 获取同级接收人 + async getSameLevel(){ + let t = this + let res = await getPeerRecipient() + if(res.data.code == 100){ + if(res.data.data){ + t.filteredOptions = res.data.data + }else{ + this.$message.warning('暂无数据'); + } + }else{ + this.$message.warning(res.data.msg); + } + }, + + // 获取接收单位 + async getAreaUsers(){ + let t = this + let res = await getAreaWithUserIfo() + if(res.data.code == 100){ + if(res.data.data){ + const treeD = [] + t.userTitTree(res.data.data) + const obj = t.findNodeById(res.data.data,t.userInfo.districtId) + treeD.push(t.removeNodesWithoutUsers(obj)) + t.areaUsers = treeD + t.unittype = this.findNodeById(this.areaUsers,t.userInfo.districtId)?.type + }else{ + this.$message.warning('暂无数据'); + } + }else{ + this.$message.warning(res.data.msg); + } + }, + + // 获取领导 + async getLeaders(){ + let t = this + let res = await getLeaders() + if(res.data.code == 100){ + if(res.data.data){ + t.leaders = res.data.data + }else{ + this.$message.warning('暂无数据'); + } + }else{ + this.$message.warning(res.data.msg); + } + }, + //选择子部门部分 - onChanges(value) { - if(value.find(i=>i.value == 'all')){ - console.log('全选了') - }else{ - this.svalue = value; + depChanges(value,label,extra) { + const t = this + if(t.form.receiver.length == 0){ + t.checkAll = false + } + }, + checkChange(e) { + const t = this + this.checkAll = !this.checkAll + if(t.checkAll == true){ + t.form.receiver = t.traverseTree(t.areaUsers[0]) + }else{ + t.form.receiver = [] + } + }, + + confirmSend(){ + this.$refs.ruleForm.validate(valid => { + if (valid) { + this.form.acceptingUnitIds = [] + this.form.peerRecipientIds = [] + const aList = this.form.receiver.map(item=>this.findNodeById(this.areaUsers,item.value)?.users) + console.log(aList,'a') + const newAList = [].concat(...aList) + console.log(newAList,'b') + for(let i of newAList){ + const {realName,...data} = i + const {id:recipienterId,name: recipienterName,phone: recipienterPhone,company: receiveUnit,...rest} = data + const obj = { recipienterId, recipienterName, recipienterPhone, receiveUnit,...rest} + this.form.acceptingUnitIds.push(obj) } - console.log(this.svalue); - }, + const bList = this.form.recipient.map(item => this.filteredOptions.find(i=>i.id == item)) + for(let i of bList){ + const {id:recipienterId,recipientName: recipienterName,phone: recipienterPhone, company: receiveUnit,...rest} = i + const obj = {recipienterId, recipienterName,recipienterPhone,receiveUnit,unittype:this.unittype,...rest} + this.form.peerRecipientIds.push(obj) + } + const {receiver,recipient,id,...data} = this.form + msgSend(data).then( res =>{ + if(res.data.code == 100){ + this.$message.success('信息已提交审核') + }else{ + this.$message.error(res.data.msg) + } + this.$refs.ruleForm.clearValidate() + this.$refs.ruleForm.resetFields() + }) + }else{ + console.log('error submit!!'); + return false; + } + }) + }, + + +// 根据id查对象 + findNodeById(data,value) { + for (const node of data) { + if (node.id === value) { + return node; + } + if (node.children) { + const foundNode = this.findNodeById(node.children, value); + if (foundNode) { + return foundNode; + } + } + } + return null; + }, + + // 将树状数据所有id和name放入对象数组 + traverseTree(treeData) { + let result = []; + function traverse(node) { + result.push({ label: node.name, value: node.id }); + if (node.children && node.children.length > 0) { + for (let child of node.children) { + traverse(child); + } + } + } + traverse(treeData); + return result; + }, + + // 将树状数据name字段放入users的姓名电话 + userTitTree(treeData) { + for(const node of treeData){ + if(node.users){ + node.users = node.users.map((i)=>{ + return{ + ...i, + unittype: node.type, + districtId: node.id + } + }) + node.name = node.name + '('+node.users.map(i=>i.name +' '+ i.phone).join(',')+')' + } + if(node.children){ + this.userTitTree(node.children) + } + } + return treeData + }, + // 将users为null的节点删除 + removeNodesWithoutUsers(node) { + if (node.users === null) { + return null; // 返回 null 表示删除节点 + } + if (node.children && node.children.length > 0) { + node.children = node.children.map(child => this.removeNodesWithoutUsers(child)).filter(Boolean); + } + return node; + }, + onSearch() { console.log(...arguments); }, @@ -151,6 +389,13 @@ handle(selectedItems) { this.selectedItems = selectedItems; }, + handleRisk(selectedItems) { + // this.selectedItems = selectedItems; + }, + handleLevel(selectedItems) { + // this.selectedItems = selectedItems; + }, + onChange(){ console.log(this.value) }, diff --git a/src/views/Admin/release.vue b/src/views/Admin/release.vue index 9bc4efb..2f880b1 100644 --- a/src/views/Admin/release.vue +++ b/src/views/Admin/release.vue @@ -2,14 +2,14 @@ <div class="inner"> <a-row type="flex" justify="space-between" style="margin-bottom: 20px"> <a-col :span="8"> - <a-radio-group v-model="category"> - <a-radio-button value="default"> + <a-radio-group v-model="search.searchParams.emergType" @change="getData"> + <a-radio-button :value="null"> 全部 </a-radio-button> - <a-radio-button value="1"> + <a-radio-button :value="1"> 紧临 </a-radio-button> - <a-radio-button value="2"> + <a-radio-button :value="2"> 常规 </a-radio-button> </a-radio-group> @@ -18,16 +18,17 @@ <a-row type="flex" justify="end" :gutter="12"> <a-col :span="8"> <a-range-picker + v-model="timeRange" format="YYYY-MM-DD" :placeholder="['开始时间', '结束时间']" - @change="onChange" - @ok="onOk" + @change="timeChange" + @ok="timeOk" style="width: 100%" /> </a-col> <a-col :span="4"> - <a-button type="primary">查询</a-button> - <a-button style="margin-left: 12px">重置</a-button> + <a-button type="primary" @click="getData">查询</a-button> + <a-button style="margin-left: 12px" @click="resetSearch">重置</a-button> </a-col> </a-row> </a-col> @@ -35,24 +36,38 @@ <!-- 表格实体部分--> <div class="table-cont"> - <a-table :columns="columns" :data-source="data" bordered> - <template #level="text"> - <a-tag :color="text === '黄色' ? 'yellow' :text === '橙色'? 'orange':text === '红色'?'red':'blue'"> - {{ text }} + <a-table :columns="columns" :data-source="data" bordered :pagination="pagination"> + <template #index="text,record,index"> + {{ index + 1 }} + </template> + <template #publishingTime="text"> + {{ text }} + </template> + <template #publishingUnit="text"> + {{ text }} + </template> + <template #disasterType="text"> + {{ getRiskName(text) }} + </template> + <template #warningLevel="text"> + <a-tag :color="text === 3 ? 'yellow' :text === 2? 'orange':text === 1?'red':'blue'"> + {{ getLevelName(text) }} </a-tag> </template> <template #attachment="text"> - <span v-if="text==='无'">无</span> - <a v-else><b><a-icon type="paper-clip" /> {{text}}</b></a> + <a><b><a-icon type="paper-clip"/></b></a> </template > + <template #responseSituation="text"> + <a-tag :color="text === 3 ? 'red' :text === 2? 'green':text === 1?'orange':'blue'"> + {{text == 1 ? '待叫应' : text == 2 ?'已叫应':text == 3 ?'超时未叫应' : ''}} + </a-tag> + </template> <template #operation="text, record, index"> - <div class="editable-row-operations"> - <a @click="showModal" style="color:orangered"> - 叫应列表</a> - <router-link :to="{path:'/details',query: {id: record.id}}">信息详情</router-link> - </div> + <a-button type="primary">叫应列表</a-button> + <a-button type="link" @click="openMod('view',record)">查看详情</a-button> </template> </a-table> + <msg-edit-mod ref="msgEdit" @refresh="getData"></msg-edit-mod> </div> <!-- 对话框 --> <a-modal title="查看叫应详情" @@ -63,37 +78,46 @@ </div> </template> <script> - const columns = [{ +import {getMsgRecord, getPublishRecord} from "@/api/list"; +import msgEditMod from "@/views/Admin/components/msgEditMod"; +import {getReviewDetailByWorker} from "@/api/review"; + const columns = [{ title: '序号', - dataIndex: 'key', + dataIndex: 'index', width: '8%', + scopedSlots: { + customRender: 'index' + } }, { title: '发布时间', - dataIndex: 'time', + dataIndex: 'publishingTime', width: '15%', scopedSlots: { - customRender: 'time' - }, //设置定制化表格数据 + customRender: 'publishingTime' + } //设置定制化表格数据 }, { title: '发布单位', - dataIndex: 'department', + dataIndex: 'publishingUnit', width: '12%', }, - { - title: '类别', - dataIndex: 'category', - width: '8%', - }, - { - title: '级别', - dataIndex: 'level', - scopedSlots: { - customRender: 'level' - }, //设置定制化表格数据 - width: '8%', - }, + { + title: '灾种', + dataIndex: 'disasterType', + width: '8%', + scopedSlots: { + customRender: 'disasterType' + } + }, + { + title: '预警级别', + dataIndex: 'warningLevel', + scopedSlots: { + customRender: 'warningLevel' + }, //设置定制化表格数据 + width: '8%', + }, { title: '信息标题', dataIndex: 'title', @@ -109,10 +133,10 @@ }, { title: '叫应情况', - dataIndex: 'receipt', + dataIndex: 'responseSituation', width: '10%', scopedSlots: { - customRender: 'receipt' + customRender: 'responseSituation' }, //设置定制化表格数据 }, { @@ -123,58 +147,113 @@ }, }, ]; - const data = [{ - key: 1, - id:1001, - readed:false, - time: '2023年5月3日 15:30', - department: '自治区预警中心', - category: '气象', - level: '黄色', - title: '全疆高温红色预警', - attachment: '1', - receipt: '部分叫应' - }, - { - key: 2, - id:1002, - readed:false, - time: '2023年5月3日 15:30', - department: '自治区预警中心', - category: '气象', - level: '黄色', - title: '全疆高温红色预警', - attachment: '1', - receipt: '全部叫应' - },{ - key: 3, - id:1003, - readed:false, - time: '2023年5月3日 15:30', - department: '自治区预警中心', - category: '气象', - level: '黄色', - title: '全疆高温红色预警', - attachment: '1', - receipt: '均未叫应' - }] export default { + name: 'release', + components: { msgEditMod }, data() { return { + search:{ + pageIndex: 1, + pageSize: 10, + searchParams:{ + emergType: null, + startTime: '', + endTime: '' + } + }, + timeRange: [], category: 'default', - data, + data:[], columns, visible: false, confirmLoading: false, + pagination: { + current: 1, + defaultCurrent: 1, + defaultPageSize: 10, + total: 0, + onChange: ( page, pageSize ) => this.onPageChange(page,pageSize), + showTotal: total => `共 ${total} 条` + }, + riskOptions: [ + {name: '地震',value: 1}, + {name: '洪涝',value: 2}, + {name: '气象',value: 3}, + {name: '泥石流',value: 4}, + {name: '水旱',value: 5}, + {name: '森林草原火灾',value: 6} + ], + levelOptions: [ + {name: '红色预警',value: 1}, + {name: '橙色预警',value: 2}, + {name: '黄色预警',value: 3}, + {name: '蓝色预警',value: 4} + ] } }, + created() { + const t = this + t.getData() + }, methods: { - onChange(value, dateString) { - console.log('Selected Time: ', value); - console.log('Formatted Selected Time: ', dateString); + async getData(){ + const t = this + const res = await getPublishRecord(this.search) + if(res.data.code == 100){ + t.data = res.data.data + t.pagination.total = res.data.total + }else{ + this.$message.error(res.data.msg) + } }, - onOk(value) { + + openMod(type,data){ + const t = this + getReviewDetailByWorker(data.id).then(res=>{ + if(res.data.code == 100){ + if(res.data.data){ + t.$refs.msgEdit.openMod(type,res.data.data) + }else{ + t.$message.error('查询信息详情失败') + } + }else{ + this.$message.error(res.data.msg) + } + }) + }, + + onPageChange(page, pageSize) { + const t= this + t.pagination.current = page + t.search.pageIndex = page + t.getData() + }, + + timeChange(value, dateString) { + const t = this + if(dateString){ + t.search.searchParams.startTime = value[0].format('YYYY-MM-DD 00:00:00') + t.search.searchParams.endTime = value[1].format('YYYY-MM-DD 23:59:59') + } + }, + + timeOk(value) { console.log('onOk: ', value); + }, + + resetSearch(){ + const t = this + t.search = { + pageIndex: 1, + pageSize: 10, + searchParams:{ + emergType: null, + startTime: '', + endTime: '' + } + } + t.timeRange = [] + t.getData() }, //弹出层 @@ -185,6 +264,13 @@ handleOk(e) { this.visible = false; }, + getRiskName(disasterType){ + return this.riskOptions.find(i => i.value === disasterType)?.name; + }, + + getLevelName(warningLevel){ + return this.levelOptions.find(i => i.value === warningLevel)?.name; + } } } diff --git a/src/views/Admin/sameLevel.vue b/src/views/Admin/sameLevel.vue index 1aa7c5f..09231d2 100644 --- a/src/views/Admin/sameLevel.vue +++ b/src/views/Admin/sameLevel.vue @@ -2,15 +2,15 @@ <div class="inner"> <a-row type="flex" justify="space-between" style="margin-bottom: 20px"> <a-col :span="4"> - <a-button type="primary" @click="editData('add',{})">新增用户</a-button> + <a-button v-if="unittype && unittype !== null" type="primary" @click="editData('add',{})">新增用户</a-button> </a-col> - <a-col :span="20"> + <a-col :span="20" v-if="unittype == null || !unittype"> <a-row type="flex" justify="end" :gutter="12"> <a-col :span="4"> - <a-cascader :options="areaData" v-model="areaVal" placeholder="行政规划" expandTrigger="hover" changeOnSelect @change="onChange" style="width: 100%"/> + <a-cascader :options="areaData" v-model="areaVal" placeholder="行政规划" expandTrigger="hover" :fieldNames="fieldNames" changeOnSelect @change="onChange" style="width: 100%"/> </a-col> <a-col :span="4"> - <a-button type="primary">查询</a-button> + <a-button type="primary" @click="getUserList">查询</a-button> <a-button style="margin-left: 12px" @click="resetSearch">重置</a-button> </a-col> </a-row> @@ -22,7 +22,7 @@ <a-tag :color="unittype === 1 ? 'purple' : unittype === 2 ? 'blue' : unittype === 3 ? 'cyan' : 'green'" > - {{ unittype==1?'省级':unittype==2?'地(市、州)级':unittype==3?'区县级':'村(乡、镇)级' }} + {{ unittype==1?'省级':unittype==2?'地(市、州)级':unittype==3?'区县级':unittype==4?'村(乡、镇)级':'管理员' }} </a-tag> </template> <template #area="text,row"> @@ -33,17 +33,19 @@ </template> <template #action="action,row"> <a-button type="link" @click="editData('edit',row)">编辑</a-button> - <a-button type="link" class="delBtn">删除</a-button> + <a-button type="link" class="delBtn" @click="delData(row)">删除</a-button> </template> </a-table> </div> - <same-level-mod ref="sameLevelMod" @refrech=""></same-level-mod> + <same-level-mod ref="sameLevelMod" @refresh="getUserList"></same-level-mod> </div> </template> <script> -import {getRecipient} from '@/api/user' +import {delRecipient, delUser, getRecipient, getUser} from '@/api/user' import sameLevelMod from "@/views/Admin/components/sameLevelMod" +import {getUserInfo} from "@/util/storage"; +import {getDistrictInfo} from "@/api/login"; export default { name: 'sameLevel', components: { @@ -52,6 +54,8 @@ data () { return { areaVal: [], + unittype: null, + districtId: null, search:{ pageIndex: 1, pageSize: 10, @@ -102,57 +106,54 @@ defaultCurrent: 1, defaultPageSize: 10, total: 0, - onChange: ( page, pageSize ) => this.onPageChange(page,pageSize) + onChange: ( page, pageSize ) => this.onPageChange(page,pageSize), + showTotal: total => `共 ${total} 条` }, - areaData: [ - { - value: 1, - label: '江苏省', - children: [ - { - value: 11, - label: '苏州市', - children: [ - { - value: 111, - label: '工业园区', - }, - ], - }, - ], - }, - { - value: 2, - label: '新疆维吾尔自治区', - children: [ - { - value: 21, - label: '乌鲁木齐市', - children: [ - { - value: 211, - label: '国泰新华', - }, - ], - }, - ], - }, - ] + areaData: [], + fieldNames:{ + label: 'name', + value: 'id', + children: 'children' + } } }, created() { const t = this - t.getSameLevel() + console.log(getUserInfo(),'id') + t.unittype = getUserInfo().unittype + t.districtId = getUserInfo().districtId + t.getUserList() + t.getDistrictInfo() }, methods:{ - async getSameLevel(){ + async getUserList(){ const t = this - const res = await getRecipient(t.search) - if(res.data.code == 100){ - t.tableData = res.data.data - t.pagination.total = res.data.total + if(t.search.searchParams.province == '' && t.search.searchParams.city == '' && t.search.searchParams.area == '' ){ + const {searchParams,...data} = t.search + const res = await getRecipient(data) + if(res.data.code == 100){ + t.tableData = res.data.data + t.pagination.total = res.data.total + }else{ + t.$message.warning(res.data.msg); + } }else{ - t.$message.warning(res.data.msg); + const res = await getRecipient(t.search) + if(res.data.code == 100){ + t.tableData = res.data.data + t.pagination.total = res.data.total + }else{ + t.$message.warning(res.data.msg); + } + } + }, + + async getDistrictInfo(){ + let res = await getDistrictInfo() + if(res.data.code == 100){ + this.areaData = res.data.data + } else { + this.$message.warning(res.data.msg); } }, @@ -176,31 +177,76 @@ const t = this t.$refs.sameLevelMod.openDialog(type,data) t.$refs.sameLevelMod.areaData = t.areaData + t.$refs.sameLevelMod.form.unittype = t.unittype + t.$refs.sameLevelMod.form.districtId = t.districtId + }, + + async delData(row){ + const t = this + this.$confirm({ + title: '提示', + content: h => <div>是否删除该条用户信息?</div>, + cancelText: '取消', + okText: '确认', + centered: true, + async onOk() { + let res = await delRecipient(row.id) + if(res.data.code == 100){ + t.$message.success('删除用户信息成功'); + t.getUserList() + }else{ + t.$message.warning(res.data.msg); + } + }, + onCancel() { + console.log('Cancel'); + }, + }); + }, + + // 根据id查对象 + findCodeById(data,value) { + for (const node of data) { + if (node.id === value) { + return node; + } + if (node.children) { + const foundNode = this.findCodeById(node.children, value); + if (foundNode) { + return foundNode; + } + } + } + return null; }, onPageChange(page, pageSize) { const t= this t.pagination.current = page + t.search.pageIndex = page + t.getUserList() }, onChange(value) { const t = this - // t.search.searchParams.districtId = value[value.length - 1] - }, - - findAreaById(data,value) { - for (const node of data) { - if (node.value === value) { - return node.label; - } - if (node.children) { - const foundLabel = this.findAreaById(node.children, value); - if (foundLabel) { - return foundLabel; - } - } + t.search.searchParams = { + province: '', + city: '', + area: '', + town: '' } - return null; - } + if(value[0]){ + t.search.searchParams.province = t.findCodeById(t.areaData,value[0]).name + } + if(value[1]){ + t.search.searchParams.city = t.findCodeById(t.areaData,value[1]).name + } + if(value[2]){ + t.search.searchParams.area = t.findCodeById(t.areaData,value[2]).name + } + if(value[3]){ + t.search.searchParams.town = t.findCodeById(t.areaData,value[3]).name + } + }, } } </script> diff --git a/src/views/Admin/userManage.vue b/src/views/Admin/userManage.vue index d07f68f..7c24e36 100644 --- a/src/views/Admin/userManage.vue +++ b/src/views/Admin/userManage.vue @@ -7,7 +7,7 @@ <a-col :span="20"> <a-row type="flex" justify="end" :gutter="12"> <a-col :span="4"> - <a-cascader :options="areaData" v-model="areaVal" placeholder="行政规划" expandTrigger="hover" changeOnSelect @change="onChange" style="width: 100%"/> + <a-cascader :options="areaData" v-model="areaVal" placeholder="行政规划" expandTrigger="hover" :fieldNames="fieldNames" changeOnSelect @change="onChange" style="width: 100%"/> </a-col> <a-col :span="4"> <a-select v-model="search.searchParams.unittype" placeholder="监管层级" style="width: 100%"> @@ -44,7 +44,7 @@ <a-tag :color="unittype === 1 ? 'purple' : unittype === 2 ? 'blue' : unittype === 3 ? 'cyan' : 'green'" > - {{ unittype==1?'省级':unittype==2?'地(市、州)级':unittype==3?'区县级':'村(乡、镇)级' }} + {{ unittype==1?'省级':unittype==2?'地(市、州)级':unittype==3?'区县级':unittype==4?'村(乡、镇)级':'管理员' }} </a-tag> </template> <template #area="text,row"> @@ -62,8 +62,14 @@ <a-button type="link" @click="editPwd(row)">重置密码</a-button> </template> </a-table> +<!-- <a-pagination--> +<!-- :total="85"--> +<!-- :show-total="total => `Total ${total} items`"--> +<!-- :page-size="20"--> +<!-- :default-current="1"--> +<!-- />--> </div> - <user-mod ref="userMod" @refresh="getUserList"></user-mod> + <user-mod ref="userMod" :unitType="unittype" @refresh="getUserList"></user-mod> <pwd-mod ref="pwdMod" @refresh="getUserList"></pwd-mod> </div> </template> @@ -72,8 +78,9 @@ import {getUser,delUser} from '@/api/user' import userMod from "@/views/Admin/components/userMod" import pwdMod from "@/views/Admin/components/pwdMod"; -import {loginOut} from "@/api/login"; -import {Session} from "@/util/storage"; +import {getDistrictInfo, loginOut} from "@/api/login"; +import {getUserInfo, Session} from "@/util/storage"; +import Cookies from "js-cookie"; export default { name: 'user', components: { @@ -83,6 +90,7 @@ data () { return { areaVal: [], + unittype: null, search:{ pageIndex: 1, pageSize: 10, @@ -149,57 +157,53 @@ defaultCurrent: 1, defaultPageSize: 10, total: 0, - onChange: ( page, pageSize ) => this.onPageChange(page,pageSize) + onChange: ( page, pageSize ) => this.onPageChange(page,pageSize), + showTotal: total => `共 ${total} 条` }, - areaData: [ - { - value: 1, - label: '江苏省', - children: [ - { - value: 11, - label: '苏州市', - children: [ - { - value: 111, - label: '工业园区', - }, - ], - }, - ], - }, - { - value: 2, - label: '新疆维吾尔自治区', - children: [ - { - value: 21, - label: '乌鲁木齐市', - children: [ - { - value: 211, - label: '国泰新华', - }, - ], - }, - ], - }, - ] + areaData: [], + fieldNames:{ + label: 'name', + value: 'id', + children: 'children' + } } }, created() { const t = this + t.unittype = getUserInfo().unittype + console.log(t.unittype,'unit') t.getUserList() + t.getDistrictInfo() }, methods:{ async getUserList(){ const t = this - const res = await getUser(t.search) - if(res.data.code == 100){ - t.tableData = res.data.data - t.pagination.total = res.data.total + if(t.search.searchParams.realName == '' && t.search.searchParams.districtId == null && t.search.searchParams.unittype == null){ + const {searchParams,...data} = t.search + const res = await getUser(data) + if(res.data.code == 100){ + t.tableData = res.data.data + t.pagination.total = res.data.total + }else{ + t.$message.warning(res.data.msg); + } }else{ - t.$message.warning(res.data.msg); + const res = await getUser(t.search) + if(res.data.code == 100){ + t.tableData = res.data.data + t.pagination.total = res.data.total + }else{ + t.$message.warning(res.data.msg); + } + } + }, + + async getDistrictInfo(){ + let res = await getDistrictInfo() + if(res.data.code == 100){ + this.areaData = res.data.data + } else { + this.$message.warning(res.data.msg); } }, @@ -257,10 +261,13 @@ onPageChange(page, pageSize) { const t= this t.pagination.current = page + t.search.pageIndex = page + t.getUserList() }, onChange(value) { const t = this t.search.searchParams.districtId = value[value.length - 1] + console.log(value,'val') }, findAreaById(data,value) { for (const node of data) { diff --git a/src/views/Home.vue b/src/views/Home.vue index e9d3509..abcedf0 100644 --- a/src/views/Home.vue +++ b/src/views/Home.vue @@ -50,9 +50,9 @@ import menuSider from "@/layout/menuSider"; import TabsHeader from '@/components/TabsHeader'; import pwdMod from "@/views/Admin/components/pwdMod"; - import { loginOut } from "@/api/login"; - import { Session } from '@/util/storage'; - import Cookies from 'js-cookie'; + import { loginOut, getDistrictInfo } from "@/api/login"; + import { Session, getUserInfo} from '@/util/storage'; + import Cookies from "js-cookie"; export default { name: "Home", data() { @@ -70,7 +70,8 @@ pwdMod }, created() { - this.userInfo = JSON.parse(Cookies.get('userInfo')) + this.userInfo = getUserInfo() + // this.getDistrictInfo() const route = this.$route if (this.pageList.findIndex(item => item.path === route.path) === -1) { this.pageList.push(this.createPage(route)) @@ -138,6 +139,18 @@ class: 'test', }); }, + + // async getDistrictInfo(){ + // let res = await getDistrictInfo() + // if(res.data.code == 100){ + // console.log(res.data.data) + // Cookies.set('district', res.data.data); + // console.log(Cookies.get('district'),666) + // } else { + // this.$message.warning(res.data.msg); + // } + // }, + changePage(key) { this.activePage = key const page = this.pageList.find(item => item.path === key) -- Gitblit v1.9.2