notificationMsg.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. <template>
  2. <!-- 消息通知 -->
  3. <div>
  4. <el-popover
  5. placement="bottom"
  6. width="443"
  7. trigger="click" v-model="visible">
  8. <div class="notifation-wrap">
  9. <!-- 防止tabs在popover前渲染,会导致tab选中状态不正确 -->
  10. <el-tabs v-model="activeName" v-if="visible" @tab-click="getMsgList">
  11. <!-- 研报审批 -->
  12. <el-tab-pane v-if="tabsShow.first" :label="`${$t('AprrovalPage.research_approval_btn')}${activeName==='first'?'('+UnreadTotal+')':''}`" name="first"></el-tab-pane>
  13. <!-- bi看板审批 -->
  14. <el-tab-pane v-if="tabsShow.second" :label="`${$t('SystemManage.BaseConfig.bIDashboard_approval')}${activeName==='second'?'('+UnreadTotal+')':''}`" name="second"></el-tab-pane>
  15. <!-- 资产数据 -->
  16. <el-tab-pane v-if="tabsShow.third" :label="`${$t('SystemManage.OperateAuth.label_notice_title')}${activeName==='third'?'('+UnreadTotal+')':''}`" name="third"></el-tab-pane>
  17. </el-tabs>
  18. <div class="massage-list" v-if="visible">
  19. <div class="message-item" :class="{'IsRead':item.IsRead}" v-for="item in msgList" :key="item.Id" @click="readMsg(item)">
  20. <span class="icon">
  21. <img :src="require(`@/assets/img/approve_m/${approveState[item.ApproveState]||'process'}-msg.svg`)" alt="">
  22. </span>
  23. <div class="info">
  24. <div class="head">
  25. <span class="title">{{item.Content}}</span>
  26. <span class="time">{{item.CreateTime}}</span>
  27. </div>
  28. <!-- 审批内容 -->
  29. <div class="content" v-if="activeName==='first'">{{item.Remark||''}}&nbsp;</div>
  30. <!-- 看板审批 内容部分-->
  31. <div class="content" v-else-if="activeName==='second'">{{item.Remark||''}}&nbsp;</div>
  32. <!-- 权限内容 -->
  33. <div class="content" v-else>
  34. {{item.Remark||''}}
  35. <span>,点击<el-button type="text" @click="openAuthDetail(item)">查看详情</el-button>!</span>
  36. </div>
  37. </div>
  38. </div>
  39. <tableNoData v-if="!msgList.length" :text="$t('AprrovalPage.no_news_yet')"></tableNoData>
  40. </div>
  41. <el-button type="text" class="close-btn" @click="visible=false">{{$t('AprrovalPage.close_btn')}}</el-button>
  42. </div>
  43. <span slot="reference" @click="visible = !visible" class="msg-btn">
  44. <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
  45. <path d="M16.7344 15.4904L15.2941 12.9564V7.84847C15.2941 5.89142 13.8231 3.77337 11.6786 2.99732C11.5741 1.96012 10.8811 1.20374 9.97287 1.20374C9.06595 1.20374 8.37036 1.96014 8.26717 2.99732C6.12392 3.77337 4.65292 5.8914 4.65292 7.84847V12.9564L3.14258 15.6146C3.04183 15.7903 3.04429 16.0054 3.14504 16.1799C3.24581 16.3544 3.43263 16.4601 3.63415 16.4601H7.22871C7.49293 17.7357 8.62233 18.6967 9.97289 18.6967C11.3247 18.6967 12.4541 17.7357 12.7171 16.4601H16.3116C16.3215 16.4601 16.3288 16.4601 16.3374 16.4601C16.6508 16.4601 16.904 16.2082 16.904 15.8948C16.904 15.7362 16.8401 15.5925 16.7344 15.4904ZM9.97287 2.33803C10.1769 2.33803 10.3415 2.49286 10.4472 2.7239C10.2899 2.70792 10.1375 2.67106 9.97287 2.67106C9.8082 2.67106 9.65583 2.70792 9.49851 2.7239C9.60422 2.49284 9.76889 2.33803 9.97287 2.33803ZM9.97287 17.5636C9.25396 17.5636 8.65303 17.1016 8.41951 16.4601H11.5262C11.2927 17.1015 10.693 17.5636 9.97287 17.5636ZM4.60745 15.3282L5.71102 13.3853C5.76015 13.3017 5.78719 13.2034 5.78719 13.1051V7.84847C5.78719 5.93934 7.57648 3.80413 9.97287 3.80413C12.3692 3.80413 14.161 5.93934 14.161 7.84847V13.1051C14.161 13.2034 14.1868 13.3017 14.2347 13.3853L15.3395 15.3282H4.60745Z" fill="currentColor"/>
  46. </svg>
  47. <div class="unread" v-if="allUnreadTotal">{{allUnreadTotal>99?'99+':allUnreadTotal}}</div>
  48. </span>
  49. </el-popover>
  50. <m-dialog
  51. :show.sync="isOpenAuthDia"
  52. width="800px"
  53. title="权限变更详情"
  54. @close="isOpenAuthDia = false"
  55. >
  56. <div class="notice-auth-box">
  57. <div class="main">
  58. <div class="left" v-if="!detailInfo.isAuthSet">
  59. <el-radio-group v-model="detailInfo.Source" @input="changeSource" style="margin-bottom:10px;">
  60. <el-radio-button
  61. v-for="item in tabs"
  62. :key="item.key"
  63. :label="item.key"
  64. >{{item.label}}</el-radio-button>
  65. </el-radio-group>
  66. <ul class="data-types" v-if="detailInfo.Source===6">
  67. <li
  68. v-for="item in subTabs"
  69. :key="item.key"
  70. :class="item.key===detailInfo.SubSource&&'act'"
  71. @click="changeSubSource(item)"
  72. >{{item.label}}</li>
  73. </ul>
  74. </div>
  75. <div class="right">
  76. <label v-if="detailInfo.isAuthSet">{{tabs.find(_ => _.key===detailInfo.Source).label}}</label>
  77. <el-table
  78. :data="tableData"
  79. ref="table"
  80. element-loading-text="加载中..."
  81. v-loading="tableLoading"
  82. border
  83. style="margin:20px 0"
  84. max-height="400"
  85. >
  86. <el-table-column
  87. v-for="item in tableColums"
  88. :key="item.label"
  89. :label="item.label"
  90. :prop="item.key"
  91. :width="item.widthsty"
  92. :min-width="item.minwidthsty"
  93. align="center"
  94. >
  95. <template slot-scope="{row}">
  96. <span>{{ row[item.key] }}</span>
  97. </template>
  98. </el-table-column>
  99. <div slot="empty" style="padding: 20px 0">
  100. <tableNoData :text="$t('Table.prompt_slogan')" size="mini"/>
  101. </div>
  102. </el-table>
  103. </div>
  104. </div>
  105. <div class="dia-bot">
  106. <el-button type="primary" plain @click="isOpenAuthDia = false"
  107. >{{$t('Dialog.known')}}</el-button
  108. >
  109. </div>
  110. </div>
  111. </m-dialog>
  112. </div>
  113. </template>
  114. <script>
  115. import {approveInterence} from '@/api/modules/approve.js';
  116. import { operateAuthInterface } from '@/api/modules/setApi';
  117. import {etaBaseConfigInterence} from '@/api/modules/etaBaseConfigApi.js';
  118. import mDialog from './mDialog.vue';
  119. const tabNames = ['first','second','third'];
  120. export default {
  121. components: { mDialog },
  122. data() {
  123. this.approveState=['','process','passed','reject','return',]
  124. return {
  125. activeName:'',
  126. visible:false,
  127. msgList:[],
  128. UnreadTotal:0,
  129. allUnreadTotal: 0,
  130. //详情弹窗
  131. isOpenAuthDia: false,
  132. tableData: [],
  133. page_no: 1,
  134. haveMore: false,
  135. detailInfo: {
  136. MessageId: 0,
  137. isAuthSet: false,//true权限设置 false资产转移
  138. Source: 1,
  139. SubSource: 0,
  140. },
  141. tabsShow:{
  142. first:false, //研报
  143. second:false, //BI
  144. third:true, //资产
  145. },
  146. };
  147. },
  148. computed: {
  149. tabs(){
  150. const tabs = [
  151. { label: this.$t('SystemManage.OperateAuth.tab01'), key: 1 },
  152. { label: this.$t('SystemManage.OperateAuth.tab02'), key: 2 },
  153. { label: this.$t('SystemManage.OperateAuth.tab03'), key: 3 },
  154. { label: this.$t('SystemManage.OperateAuth.tab04'), key: 4 },
  155. { label: this.$t('SystemManage.OperateAuth.tab05'), key: 5 },
  156. { label: this.$t('SystemManage.OperateAuth.tab06'), key: 6 },
  157. ]
  158. return tabs
  159. },
  160. subTabs() {
  161. const subTabs = [
  162. { label: /* '自定义分析' */this.$t('SystemManage.OperateAuth.tab_sub_sheet1'), key: 4 },
  163. { label:/* '时间序列表格' */this.$t('SystemManage.OperateAuth.tab_sub_sheet2'), key: 2 },
  164. { label: /* '混合表格' */this.$t('SystemManage.OperateAuth.tab_sub_sheet3'), key: 3 },
  165. ]
  166. return subTabs
  167. },
  168. tableColums() {
  169. const clomusMap = {
  170. 5: [
  171. { label: this.$t('SystemManage.OperateAuth.table_col_name01'),key: 'DataName' },
  172. { label: '操作时间',key: 'CreateTime' },
  173. ],
  174. 6: [
  175. { label: this.$t('SystemManage.OperateAuth.table_col_sheet_name'),key: 'DataName' },
  176. { label: '操作时间',key: 'CreateTime' },
  177. ],
  178. }
  179. return clomusMap[this.detailInfo.Source] ? clomusMap[this.detailInfo.Source]
  180. : [
  181. { label: this.$t('SystemManage.OperateAuth.table_col_name05'),key: 'DataName' },
  182. { label: '操作时间',key: 'CreateTime' },
  183. ]
  184. },
  185. },
  186. watch:{
  187. async visible(val){
  188. if(val){
  189. await this.handleTabs()
  190. this.getMsgList()
  191. }
  192. },
  193. isOpenAuthDia(nval) {
  194. if(!nval){
  195. this.$refs.table.bodyWrapper.removeEventListener('scroll',this.handleScroll)
  196. return
  197. }
  198. this.getAuthMsgDetail()
  199. this.$nextTick(() => {
  200. this.$refs.table.bodyWrapper.addEventListener('scroll',this.handleScroll)
  201. })
  202. }
  203. },
  204. methods:{
  205. async handleTabs(){
  206. return new Promise(async resolve=>{
  207. const res = await etaBaseConfigInterence.getBaseConfig()
  208. if(res.Ret != 200) return;
  209. const {IsReportApprove='',ReportApproveType='',IsBIApprove=''} = res.Data
  210. let isETAApprove = (IsReportApprove==='true'?true:false) && ReportApproveType==='eta'
  211. let IsBIApprove_v = IsBIApprove==='true'?true:false
  212. if(isETAApprove) this.tabsShow.first = true;
  213. if(IsBIApprove_v) this.tabsShow.second = true;
  214. if(!tabNames.includes(this.activeName)){//默认选中第一个显示的tab
  215. this.activeName = Object.entries(this.tabsShow).filter(_=>_[1])[0][0] || 'third';
  216. }
  217. resolve()
  218. })
  219. },
  220. async readMsg(msg){
  221. const res = this.activeName === 'first'
  222. ? await approveInterence.readApproveMsg({MessageId:msg.Id})
  223. : this.activeName === 'second' ? await approveInterence.readBiApproveMsg({MessageId:msg.Id})
  224. : await operateAuthInterface.redMessage({ MessageId: msg.DataPermissionMessageId })
  225. if(res.Ret!==200) return
  226. this.getMsgList()
  227. this.getUnreadNum()
  228. if(this.activeName === 'first' || this.activeName === 'second'){
  229. const type = msg.ApproveState===1?'approve':msg.ApproveState===4?'detail':'myself'
  230. this.$router.push({
  231. path:'/approveDetail',
  232. query:{
  233. mainType:this.activeName === 'first' ? 'report' :'bi',
  234. type,
  235. approveId:this.activeName === 'first' ? msg.ReportApproveId :msg.BiApproveId,
  236. }
  237. })
  238. }
  239. },
  240. async getMsgList(){
  241. const res = this.activeName === 'first'
  242. ? await approveInterence.getApproveMsgList({
  243. CurrentIndex:1,
  244. PageSize:1000
  245. })
  246. : (
  247. this.activeName === 'second' ?
  248. await approveInterence.getBiApproveMsgList({
  249. CurrentIndex:1,
  250. PageSize:1000
  251. })
  252. : await operateAuthInterface.getNoticeList({
  253. CurrentIndex:1,
  254. PageSize:1000
  255. })
  256. )
  257. if(res.Ret!==200) return
  258. this.msgList = res.Data.List||[]
  259. this.UnreadTotal = res.Data.UnreadTotal||0
  260. },
  261. async getUnreadNum() {
  262. const res = await operateAuthInterface.getAllUnread()
  263. if(res.Ret !== 200) return
  264. this.allUnreadTotal = res.Data
  265. },
  266. openAuthDetail(item) {
  267. this.detailInfo.MessageId = item.DataPermissionMessageId;
  268. this.detailInfo.isAuthSet = [3,4].includes(item.OpType);
  269. this.detailInfo.Source = item.Source;
  270. this.detailInfo.SubSource = item.SubSource;
  271. this.isOpenAuthDia = true
  272. },
  273. changeSource() {
  274. this.page_no = 1;
  275. this.detailInfo.SubSource = this.detailInfo.Source===6?4:0;
  276. this.getAuthMsgDetail()
  277. },
  278. changeSubSource({key}) {
  279. this.page_no = 1;
  280. this.detailInfo.SubSource = key;
  281. this.getAuthMsgDetail()
  282. },
  283. async getAuthMsgDetail() {
  284. const { MessageId,Source,SubSource } = this.detailInfo;
  285. const res = await operateAuthInterface.getNoticeDetail({
  286. MessageId,
  287. Source,
  288. SubSource,
  289. CurrentIndex: this.page_no
  290. })
  291. if(res.Ret !== 200) return
  292. let arr = res.Data.List||[]
  293. this.haveMore = res.Data.Paging.Pages > this.page_no
  294. this.tableData = this.page_no ===1 ? arr : [...this.tableData,...arr];
  295. },
  296. /* 滚动事件 */
  297. handleScroll:_.throttle(function(){
  298. const {scrollTop,clientHeight,scrollHeight} = this.$refs.table.bodyWrapper
  299. if(scrollTop + clientHeight >= scrollHeight-10 && this.haveMore){
  300. this.page_no++;
  301. this.getAuthMsgDetail();
  302. }
  303. },300),
  304. },
  305. mounted() {
  306. this.getUnreadNum()
  307. }
  308. };
  309. </script>
  310. <style lang="scss">
  311. .notifation-wrap{
  312. position:relative;
  313. .massage-list{
  314. padding: 0 10px;
  315. max-height: 320px;
  316. overflow-y: auto;
  317. .message-item{
  318. cursor: pointer;
  319. display: flex;
  320. padding: 5px 0;
  321. border-bottom: 1px solid #E4E7ED;
  322. color:#333;
  323. &.IsRead{
  324. color:#999;
  325. }
  326. .icon{
  327. width:40px;
  328. display: flex;
  329. align-items: flex-start;
  330. justify-content: center;
  331. }
  332. .info{
  333. flex:1;
  334. .head{
  335. display: flex;
  336. justify-content: space-between;
  337. }
  338. }
  339. }
  340. }
  341. .close-btn{
  342. position:absolute;
  343. top:0;
  344. right:0;
  345. box-sizing: border-box;
  346. }
  347. }
  348. .msg-btn{
  349. cursor: pointer;
  350. display: inline-block;
  351. width: 50px;
  352. text-align: center;
  353. position: relative;
  354. .unread{
  355. position: absolute;
  356. width:23px;
  357. height:14px;
  358. color:#fff;
  359. background-color:#AD352F;
  360. border-radius: 40px;
  361. top:-4px;
  362. right:4px;
  363. font-size: 12px;
  364. }
  365. }
  366. .notice-auth-box {
  367. .main {
  368. //display: flex;
  369. .left {
  370. flex-shrink: 0;
  371. margin-right: 15px;
  372. .data-types {
  373. display: flex;
  374. gap: 15px;
  375. li {
  376. padding: 5px 0;
  377. border-bottom: 2px solid transparent;
  378. &.act {
  379. border-color: #0052D9;
  380. }
  381. }
  382. }
  383. }
  384. .right {
  385. flex: 1;
  386. }
  387. }
  388. .dia-bot {
  389. display: flex;
  390. justify-content: center;
  391. margin-top: 30px;
  392. }
  393. }
  394. </style>