Kaynağa Gözat

任务系统

lrf402788946 4 yıl önce
ebeveyn
işleme
8b74b698d0
3 değiştirilmiş dosya ile 196 ekleme ve 10 silme
  1. 143 0
      components/mission-icon.vue
  2. 9 10
      layout/admin/navBar.vue
  3. 44 0
      store/mission.js

+ 143 - 0
components/mission-icon.vue

@@ -0,0 +1,143 @@
+<template>
+  <div id="mission-icon">
+    <el-tooltip class="item" effect="light" placement="bottom-end">
+      <el-badge class="icon" :value="list.length">
+        <i class="el-icon-bell icon"></i>
+      </el-badge>
+      <template #content>
+        <!-- <el-row type="flex" align="middle" v-for="(i, index) in list" :key="`mission-${index}`">
+          <el-col :span="14" class="out">{{ i.title }}</el-col>
+          <el-col :span="4">{{ getProgress(i) }}</el-col>
+          <el-col :span="6" style="text-align:right;width:80px;">
+            <el-link type="primary" size="mini" @click="noDot(i)">[不再提示]</el-link>
+          </el-col>
+        </el-row> -->
+        <el-table :data="list" size="mini" border :show-header="false" max-height="200px">
+          <el-table-column align="center" prop="title" show-overflow-tooltip min-width="200px"></el-table-column>
+          <el-table-column align="center">
+            <template v-slot="{ row }">
+              {{ getProgress(row) }}
+            </template>
+          </el-table-column>
+          <el-table-column align="center">
+            <template v-slot="{ row }">
+              <el-button type="text" icon="el-icon-close-notification" @click="noDot(row)"></el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+      </template>
+    </el-tooltip>
+  </div>
+</template>
+
+<script>
+// import Vue from 'vue';\
+const _ = require('lodash');
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: mission } = createNamespacedHelpers('mission');
+export default {
+  name: 'mission-icon',
+  props: {},
+  components: {},
+  data: function() {
+    return {
+      list: [],
+    };
+  },
+  created() {
+    this.search();
+  },
+  mounted() {
+    this.channel();
+  },
+  methods: {
+    ...mission(['query', 'update']),
+    async search() {
+      const res = await this.query({ dot: true });
+      if (this.$checkRes(res)) {
+        let newData = _.cloneDeep(res.data);
+        const oldData = _.cloneDeep(this.list);
+        if (oldData.length !== 0) {
+          // 非初始化提示,初始化不提示
+          for (const nd of newData) {
+            const sr = oldData.find(f => nd.id === f.id && nd.status === '2' && f.status === '1');
+            let ntitle, type, message;
+            if (sr) {
+              const { title } = sr;
+              ntitle = title;
+              type = 'success';
+              message = '已完成,请在 菜单-待办事项 中查看结果';
+            }
+            const er = oldData.find(f => nd.id === f.id && nd.status === '3' && f.status === '1');
+            if (er) {
+              const { title } = er;
+              ntitle = title;
+              type = 'error';
+              message = '任务失败,请在 菜单-待办事项 中重新执行任务.若多次执行仍错误,请联系开发人员!';
+            }
+            if (ntitle && message && type) {
+              this.$notify({
+                title: ntitle,
+                message,
+                type,
+              });
+            }
+          }
+        }
+        this.$set(this, `list`, newData);
+      }
+    },
+    async noDot(data) {
+      data.dot = false;
+      const res = await this.update(data);
+      if (this.$checkRes(res, '已取消提示', res.errmsg || '取消提示失败')) {
+        this.search();
+      }
+    },
+    getProgress(data) {
+      const { status } = data;
+      if (!status) return '';
+      if (status === '0') return '未开始';
+      if (status === '2') return '已完成';
+      if (status === '3') return '失败';
+      if (status === '1') return `${data.progress || 0}%`;
+    },
+    channel() {
+      this.$stomp({
+        [`/exchange/mission/remind`]: this.onMessage,
+      });
+    },
+    onMessage(message) {
+      this.search();
+      console.log('receive a message: ', message.body);
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.icon {
+  display: inline-block;
+  font-size: 1.25rem;
+  text-align: center;
+  z-index: 100;
+}
+.out {
+  white-space: nowrap;
+  text-overflow: ellipsis;
+  overflow: hidden;
+  word-break: break-all;
+  width: 150px;
+  font-size: 16px;
+  padding: 5px 0;
+}
+</style>

+ 9 - 10
layout/admin/navBar.vue

@@ -3,15 +3,13 @@
     <el-menu class="navbar" mode="horizontal">
       <div class="user-profile-container">
         <div class="user-profile-content">
-          <!-- <div class="menu-icons">
-          <span class="menu-icon"><i class="el-icon-search icon"></i></span>
-          <span class="menu-icon"><i class="el-icon-message icon"></i></span>
-          <span class="menu-icon">
-            <el-badge is-dot class="item">
-              <i class="el-icon-bell icon"></i>
-            </el-badge>
-          </span>
-        </div> -->
+          <div class="menu-icons">
+            <!-- <span class="menu-icon"><i class="el-icon-search icon"></i></span>
+            <span class="menu-icon"><i class="el-icon-message icon"></i></span> -->
+            <span class="menu-icon">
+              <mission v-if="user.type === '0'"></mission>
+            </span>
+          </div>
           <el-dropdown @command="handleCommand" style="z-index:99">
             <div class="user-profile-body">
               <img class="user-avatar" src="https://img.alicdn.com/tfs/TB1ONhloamWBuNjy1XaXXXCbXXa-200-200.png" />
@@ -48,6 +46,7 @@
 </template>
 
 <script>
+import mission from '@frame/components/mission-icon.vue';
 import Vue from 'vue';
 import defSel from '@frame/layout/admin/navBar/default-select.vue';
 import '@frame/plugins/setting';
@@ -59,7 +58,7 @@ const { mapActions } = createNamespacedHelpers('login');
 export default {
   name: 'navBar',
   props: {},
-  components: { dataForm, qrcode, defSel },
+  components: { dataForm, qrcode, defSel, mission },
   data: () => ({
     weixin: require('@frame/assets/wechat.png'),
     dataUrl: '',

+ 44 - 0
store/mission.js

@@ -0,0 +1,44 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import _ from 'lodash';
+import axios from 'axios';
+Vue.use(Vuex);
+const api = {
+  interface: `/api/mission`,
+  start: id => `/api/mission/start/${id}`,
+};
+const state = () => ({});
+const mutations = {};
+
+const actions = {
+  async query({ commit }, { skip = 0, limit, ...info } = {}) {
+    const res = await this.$axios.$get(`${api.interface}`, { skip, limit, ...info });
+    return res;
+  },
+  async create({ commit }, payload) {
+    const res = await this.$axios.$post(`${api.interface}`, payload);
+    return res;
+  },
+  async fetch({ commit }, payload) {
+    const res = await this.$axios.$get(`${api.interface}/${payload}`);
+    return res;
+  },
+  async update({ commit }, { id, ...data }) {
+    const res = await this.$axios.$post(`${api.interface}/update/${id}`, data);
+    return res;
+  },
+  async delete({ commit }, payload) {
+    const res = await this.$axios.$delete(`${api.interface}/${payload}`);
+    return res;
+  },
+  async start({ commit }, { id }) {
+    const res = await this.$axios.$post(`${api.start(id)}`);
+    return res;
+  },
+};
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions,
+};