kuaifan %!s(int64=5) %!d(string=hai) anos
pai
achega
3f8bdb8e7e

+ 4 - 1
app/Http/Controllers/Api/ChatController.php

@@ -52,8 +52,11 @@ class ChatController extends Controller
         }
         foreach ($lists AS $key => $item) {
             $lists[$key] = array_merge($item, Users::username2basic($item['user1'] == $user['username'] ? $item['user2'] : $item['user1']));
-            $lists[$key]['unread'] = $item['user1'] == $user['username'] ? $item['unread1'] : $item['unread2'];
             $lists[$key]['lastdate'] = $item['lastdate'] ?: $item['indate'];
+            $unread = 0;
+            if ($item['user1'] == $user['username']) $unread+= $item['unread1'];
+            if ($item['user2'] == $user['username']) $unread+= $item['unread2'];
+            $lists[$key]['unread'] = $unread;
         }
         return Base::retSuccess('success', $lists);
     }

+ 70 - 1
app/Http/Controllers/Api/ProjectController.php

@@ -1008,7 +1008,7 @@ class ProjectController extends Controller
      * - 已超期
      * - 已完成
      * @apiParam {Number} [createuser]          是否仅获取自己创建的项目(1:是;赋值时projectid和username不强制)
-     * @apiParam {Number} [attention]           是否仅获取关注数据(1:是)
+     * @apiParam {Number} [attention]           是否仅获取关注数据(1:是;赋值时projectid和username不强制
      * @apiParam {Number} [statistics]          是否获取统计数据(1:获取)
      * @apiParam {String} [startdate]           任务开始时间,格式:YYYY-MM-DD
      * @apiParam {String} [enddate]             任务结束时间,格式:YYYY-MM-DD
@@ -1078,6 +1078,14 @@ class ProjectController extends Controller
             if (trim(Request::input('username'))) {
                 $whereArray[] = ['project_task.username', '=', trim(Request::input('username'))];
             }
+        } else if (intval(Request::input('attention')) === 1) {
+            if ($projectid > 0) {
+                $whereArray[] = ['project_lists.id', '=', $projectid];
+                $whereArray[] = ['project_lists.delete', '=', 0];
+            }
+            if (trim(Request::input('username'))) {
+                $whereArray[] = ['project_task.username', '=', trim(Request::input('username'))];
+            }
         } else {
             if ($projectid > 0) {
                 $whereArray[] = ['project_lists.id', '=', $projectid];
@@ -1770,6 +1778,67 @@ class ProjectController extends Controller
     }
 
     /**
+     * 项目任务-待推送日志
+     *
+     * @apiParam {Number} taskid                任务ID
+     * @apiParam {Number} [page]                当前页,默认:1
+     * @apiParam {Number} [pagesize]            每页显示数量,默认:20,最大:100
+     * @throws \Throwable
+     */
+    public function task__pushlog()
+    {
+        $user = Users::authE();
+        if (Base::isError($user)) {
+            return $user;
+        } else {
+            $user = $user['data'];
+        }
+        //
+        return DB::transaction(function () {
+            $taskid = intval(Request::input('taskid'));
+            $task = Base::DBC2A(DB::table('project_task')
+                ->select(['pushlid', 'follower', 'username'])
+                ->where([
+                    ['delete', '=', 0],
+                    ['id', '=', $taskid],
+                ])
+                ->lockForUpdate()
+                ->first());
+            if (empty($task)) {
+                return Base::retError('任务不存在!');
+            }
+            $task['follower'] = Base::string2array($task['follower']);
+            $task['follower'][] = $task['username'];
+            //
+            $pushlid = $task['pushlid'];
+            $lists = DB::table('project_log')
+                ->select(['id', 'username', 'indate', 'detail', 'other'])
+                ->where([
+                    ['id', '>', $pushlid],
+                    ['taskid', '=', $taskid],
+                    ['indate', '>', Base::time() - 60]
+                ])
+                ->orderBy('id')->paginate(Min(Max(Base::nullShow(Request::input('pagesize'), 10), 1), 100));
+            $lists = Base::getPageList($lists, false);
+            if (count($lists['lists']) == 0) {
+                return Base::retError('no lists');
+            }
+            foreach ($lists['lists'] AS $key => $item) {
+                $item = array_merge($item, Users::username2basic($item['username']));
+                $item['other'] = Base::string2array($item['other'], ['type' => '']);
+                $lists['lists'][$key] = $item;
+                $pushlid = $item['id'];
+            }
+            if ($pushlid != $task['pushlid']) {
+                DB::table('project_task')->where('id', $taskid)->update([
+                    'pushlid' => $pushlid
+                ]);
+            }
+            return Base::retSuccess('success', array_merge($lists, $task));
+        });
+    }
+
+    /**
      * 项目文件-列表
      *
      * @apiParam {Number} [projectid]           项目ID

+ 4 - 1
app/Module/Chat.php

@@ -95,7 +95,7 @@ class Chat
             $dialog = $dialog['data'];
         }
         //
-        $indate = abs($message['indate'] - time()) > 30 ? time() : $message['indate'];
+        $indate = abs($message['indate'] - time()) > 60 ? time() : $message['indate'];
         if (isset($message['id'])) unset($message['id']);
         if (isset($message['username'])) unset($message['username']);
         if (isset($message['userimg'])) unset($message['userimg']);
@@ -115,6 +115,9 @@ class Chat
             case 'image':
                 $lastText = '[图片]';
                 break;
+            case 'taskB':
+                $lastText = $message['detail'] . " [来自关注任务]";
+                break;
             default:
                 $lastText = '[未知类型]';
                 break;

+ 7 - 3
app/Services/WebSocketService.php

@@ -126,9 +126,13 @@ class WebSocketService implements WebSocketHandlerInterface
                     $dialog = Chat::openDialog(self::fd2name($frame->fd), $data['target']);
                     if (!Base::isError($dialog)) {
                         $dialog = $dialog['data'];
-                        $upArray = [
-                            ($dialog['recField'] == 1 ? 'unread2' : 'unread1') => 0,
-                        ];
+                        $upArray = [];
+                        if ($dialog['user1'] == $dialog['user2']) {
+                            $upArray['unread1'] = 0;
+                            $upArray['unread2'] = 0;
+                        } else {
+                            $upArray[($dialog['recField'] == 1 ? 'unread2' : 'unread1')] = 0;
+                        }
                         DB::table('chat_dialog')->where('id', $dialog['id'])->update($upArray);
                     }
                 }

+ 1 - 1
resources/assets/js/main/App.vue

@@ -161,7 +161,7 @@
                             return;
                         }
                         let content = $A.jsonParse(msgDetail.content)
-                        if (content.type == 'task') {
+                        if (content.type == 'taskA') {
                             $A.triggerTaskInfoListener(content.act, content.taskDetail, false);
                         }
                     }).connection(force);

+ 3 - 0
resources/assets/js/main/app.js

@@ -27,6 +27,9 @@ Vue.component('WLoading', WLoading);
 import TaskDetail from './components/project/task/detail'
 Vue.prototype.taskDetail = TaskDetail;
 
+import ReportDetail from './components/report/detail'
+Vue.prototype.reportDetail = ReportDetail;
+
 const router = new VueRouter({routes});
 
 //进度条配置

+ 2 - 2
resources/assets/js/main/components/WContent.vue

@@ -35,9 +35,9 @@
         mounted() {
             this.userInfo = $A.getUserInfo((res) => {
                 this.userInfo = res;
-                this.bgid = this.userInfo.bgid;
+                this.bgid = $A.runNum(this.userInfo.bgid);
             }, false);
-            this.bgid = this.userInfo.bgid;
+            this.bgid = $A.runNum(this.userInfo.bgid);
         },
         methods: {
             getBgUrl(id, thumb) {

+ 12 - 2
resources/assets/js/main/components/chat/Index.vue

@@ -671,27 +671,37 @@
                 }
                 //
                 let data = $A.jsonParse(msgDetail.content);
+                if (['taskA'].indexOf(data.type) !== -1) {
+                    return;
+                }
                 let lasttext;
                 switch (data.type) {
                     case 'text':
-                        lasttext = data['text'];
+                        lasttext = data.text;
                         break;
                     case 'image':
                         lasttext = '[图片]';
                         break;
+                    case 'taskB':
+                        lasttext = data.detail + " [来自关注任务]";
+                        break;
                     default:
                         lasttext = '[未知类型]';
                         break;
                 }
+                let plusUnread = msgDetail.sender != this.dialogTarget.username || !this.openWindow;
                 this.addDialog({
                     username: data.username,
                     userimg: data.userimg,
                     lasttext: lasttext,
                     lastdate: data.indate
-                }, msgDetail.sender != this.dialogTarget.username || !this.openWindow);
+                }, plusUnread);
                 if (msgDetail.sender == this.dialogTarget.username) {
                     this.addMessageData(data, true);
                 }
+                if (!plusUnread) {
+                    $A.WS.sendTo('read', data.username);
+                }
                 if (!this.openWindow) {
                     this.$Notice.close('chat-notice');
                     this.$Notice.open({

+ 38 - 4
resources/assets/js/main/components/chat/message.vue

@@ -1,7 +1,8 @@
 <template>
     <div :data-id="info.id">
-        <!--文本-->
-        <div v-if="info.type==='text'">
+
+        <!--文本、任务-->
+        <div v-if="info.type==='text' || info.type==='taskB'">
             <div v-if="info.self===true" class="list-right">
                 <div v-if="info.error" class="item-error" @click="clickError(info.error)">
                     <Icon type="md-alert" />
@@ -12,8 +13,12 @@
                         <em v-if="info.indate" class="item-date">{{formatCDate(info.indate)}}</em>
                     </div>
                     <div class="item-text">
-                        <div class="item-text-view" v-html="textMsg(info.text)"></div>
+                        <div class="item-text-view" v-html="textMsg(info[info.type==='text'?'text':'detail'])"></div>
                     </div>
+                    <template v-if="info.type==='taskB'">
+                        <div v-if="info.other.type==='task'" class="item-link" @click="taskDetail(info.other.id)">来自关注任务:<a href="javascript:void(0)">{{info.other.title}}</a></div>
+                        <div v-if="info.other.type==='file'" class="item-link">来自关注任务:<a target="_blank" :href="fileDownUrl(info.other.id)">{{info.other.name}}</a></div>
+                    </template>
                 </div>
                 <img class="item-userimg" @click="clickUser" :src="info.userimg" onerror="this.src=window.location.origin+'/images/other/avatar.png'"/>
             </div>
@@ -26,8 +31,12 @@
                         <em v-if="info.indate" class="item-date">{{formatCDate(info.indate)}}</em>
                     </div>
                     <div class="item-text">
-                        <div class="item-text-view" v-html="textMsg(info.text)"></div>
+                        <div class="item-text-view" v-html="textMsg(info[info.type==='text'?'text':'detail'])"></div>
                     </div>
+                    <template v-if="info.type==='taskB'">
+                        <div v-if="info.other.type==='task'" class="item-link" @click="taskDetail(info.other.id)">来自关注任务:<a href="javascript:void(0)">{{info.other.title}}</a></div>
+                        <div v-if="info.other.type==='file'" class="item-link">来自关注任务:<a target="_blank" :href="fileDownUrl(info.other.id)">{{info.other.name}}</a></div>
+                    </template>
                 </div>
             </div>
         </div>
@@ -68,6 +77,7 @@
         <div v-else-if="info.type==='notice'">
             <div class="item-notice">{{info.notice}}</div>
         </div>
+
     </div>
 </template>
 
@@ -164,6 +174,26 @@
         }
     }
 
+    /*信息底标*/
+    .item-link {
+        display: block;
+        font-size: 12px;
+        color: #ffffff;
+        background-color: #cacaca;
+        margin-top: 6px;
+        margin-bottom: -2px;
+        height: 20px;
+        line-height: 20px;
+        padding: 0 5px;
+        border-radius: 4px;
+        transform: scale(0.96);
+        transform-origin: 0 0;
+        > a {
+            color: #3D90E2;
+            padding-left: 3px;
+        }
+    }
+
     /*图片*/
     .item-image {
         display: inline-block;
@@ -228,6 +258,10 @@
             clickUser(e) {
                 this.$emit('clickUser', this.info, e);
             },
+
+            fileDownUrl(id) {
+                return $A.aUrl('project/files/download?fileid=' + id);
+            }
         }
     }
 </script>

+ 1 - 0
resources/assets/js/main/components/project/archived.vue

@@ -134,6 +134,7 @@
                                                     if (res.ret === 1) {
                                                         this.$Message.success(res.msg);
                                                         $A.triggerTaskInfoListener('unarchived', res.data);
+                                                        $A.triggerTaskInfoChange(params.row.id);
                                                     } else {
                                                         this.$Modal.error({title: this.$L('温馨提示'), content: res.msg});
                                                     }

+ 1 - 0
resources/assets/js/main/components/project/header/archived.vue

@@ -131,6 +131,7 @@
                                                     if (res.ret === 1) {
                                                         this.$Message.success(res.msg);
                                                         $A.triggerTaskInfoListener('unarchived', res.data);
+                                                        $A.triggerTaskInfoChange(params.row.id);
                                                     } else {
                                                         this.$Modal.error({title: this.$L('温馨提示'), content: res.msg});
                                                     }

+ 2 - 0
resources/assets/js/main/components/project/task/detail/detail.vue

@@ -371,6 +371,7 @@
                         }
                         if (eve == 'add' || eve == 'delete') {
                             this.logType == '日志' && this.$refs.log.getLists(true, true);
+                            $A.triggerTaskInfoChange(ajaxData.taskid);
                         }
                         return;
 
@@ -556,6 +557,7 @@
                                 this.$Message.success(res.msg);
                             }
                             $A.triggerTaskInfoListener(ajaxData.act, res.data);
+                            $A.triggerTaskInfoChange(ajaxData.taskid);
                         } else {
                             ajaxCallback(0);
                             this.$Modal.error({title: this.$L('温馨提示'), content: res.msg});

+ 1 - 1
resources/assets/js/main/components/report/add.vue

@@ -12,7 +12,7 @@
             </div>
             <t-editor class="add-edit" v-model="dataDetail.content" height="100%"></t-editor>
             <div class="add-input">
-                <userid-input v-model="dataDetail.ccuser" :placeholder="$L('输入关键词搜索')" multiple><span slot="prepend">{{$L('抄送人')}}</span></userid-input>
+                <user-input v-model="dataDetail.ccuser" :placeholder="$L('输入关键词搜索')" multiple><span slot="prepend">{{$L('抄送人')}}</span></user-input>
             </div>
             <div class="add-footer">
                 <Button :loading="loadIng > 0" type="primary" @click="handleSubmit" style="margin-right:6px">{{$L('保存')}}</Button>

+ 3 - 0
resources/assets/js/main/components/report/content.vue

@@ -41,6 +41,9 @@
         },
         methods: {
             setContent(val) {
+                if (!this.$el.contentWindow) {
+                    return;
+                }
                 let $d = this.$el.contentWindow.document;
                 $A("body", $d).html('<link type="text/css" rel="stylesheet" href="' + window.location.origin + '/js/build/skins/ui/oxide/content.min.css"><style>html,body{padding:0;margin:0}</style><div id="content">' + val + '</div>');
                 this.$nextTick(() => {

+ 64 - 0
resources/assets/js/main/components/report/detail/detail.vue

@@ -0,0 +1,64 @@
+<template>
+    <Modal
+        v-model="contentShow"
+        :title="contentTitle"
+        class="report-detail-window"
+        width="80%"
+        :styles="{top: '35px', paddingBottom: '35px'}"
+        footerHide>
+        <report-content :content="contentText"></report-content>
+    </Modal>
+</template>
+
+<script>
+    import ReportContent from "../content";
+    export default {
+        components: {ReportContent},
+        data() {
+            return {
+                reportid: 0,
+                reporttitle: '',
+
+                contentShow: false,
+                contentTitle: '',
+                contentText: '',
+            }
+        },
+        beforeCreate() {
+            let doms = document.querySelectorAll('.report-detail-window');
+            for (let i = 0; i < doms.length; ++i) {
+                if (doms[i].parentNode != null) doms[i].parentNode.removeChild(doms[i]);
+            }
+        },
+        mounted() {
+            this.getDetail();
+        },
+        watch: {
+            reportid() {
+                this.getDetail();
+            }
+        },
+        methods: {
+            getDetail() {
+                this.contentShow = true;
+                this.contentTitle = this.reporttitle;
+                this.contentText = this.$L('详细内容加载中.....');
+                $A.aAjax({
+                    url: 'report/content?id=' + this.reportid,
+                    error: () => {
+                        alert(this.$L('网络繁忙,请稍后再试!'));
+                        this.contentShow = false;
+                    },
+                    success: (res) => {
+                        if (res.ret === 1) {
+                            this.contentText = res.data.content;
+                        } else {
+                            this.contentShow = false;
+                            this.$Modal.error({title: this.$L('温馨提示'), content: res.msg});
+                        }
+                    }
+                });
+            },
+        }
+    }
+</script>

+ 21 - 0
resources/assets/js/main/components/report/detail/index.js

@@ -0,0 +1,21 @@
+import Vue from 'vue';
+import component from './detail.vue'
+
+const detailElement = (reportid, reporttitle) => {
+    return new Promise(() => {
+        let custom = Vue.extend(component);
+
+        let instance = new custom({
+            data: {
+                reportid: reportid,
+                reporttitle: reporttitle
+            }
+        });
+
+        instance.$mount();
+        document.body.appendChild(instance.$el);
+    })
+};
+
+export default detailElement
+

+ 12 - 42
resources/assets/js/main/components/report/my.vue

@@ -31,17 +31,9 @@
             <!-- 分页 -->
             <Page class="pageBox" :total="listTotal" :current="listPage" :disabled="loadIng > 0" @on-change="setPage" @on-page-size-change="setPageSize" :page-size-opts="[10,20,30,50,100]" placement="top" show-elevator show-sizer show-total transfer></Page>
         </div>
-        <WDrawer v-model="addDrawerShow" maxWidth="1000">
+        <WDrawer v-model="addDrawerShow" maxWidth="900">
             <report-add :canload="addDrawerShow" :id="addDrawerId" @on-success="addDrawerSuccess"></report-add>
         </WDrawer>
-        <Modal
-            v-model="contentShow"
-            :title="contentTitle"
-            width="80%"
-            :styles="{top: '35px', paddingBottom: '35px'}"
-            footerHide>
-            <report-content :content="contentText"></report-content>
-        </Modal>
     </drawer-tabs-container>
 </template>
 
@@ -89,10 +81,6 @@
 
                 addDrawerId: 0,
                 addDrawerShow: false,
-
-                contentShow: false,
-                contentTitle: '',
-                contentText: '',
             }
         },
         created() {
@@ -132,7 +120,7 @@
                     if (!params.row.id) {
                         return null;
                     }
-                    return h('div', [
+                    let arr = [
                         h('Tooltip', {
                             props: { content: this.$L('查看'), transfer: true, delay: 600 },
                             style: { position: 'relative' },
@@ -141,7 +129,7 @@
                             style: { margin: '0 3px', cursor: 'pointer' },
                             on: {
                                 click: () => {
-                                    this.contentReport(params.row);
+                                    this.reportDetail(params.row.id, params.row.title);
                                 }
                             }
                         })]),
@@ -156,8 +144,10 @@
                                     this.addDrawerShow = true
                                 }
                             }
-                        })]),
-                        h('Tooltip', {
+                        })])
+                    ];
+                    if (params.row.status !== '已发送') {
+                        arr.push(h('Tooltip', {
                             props: { content: this.$L('发送'), transfer: true, delay: 600 }
                         }, [h('Icon', {
                             props: { type: 'md-send', size: 16 },
@@ -167,8 +157,8 @@
                                     this.sendReport(params.row);
                                 }
                             }
-                        })]),
-                        h('Tooltip', {
+                        })]));
+                        arr.push(h('Tooltip', {
                             props: { content: this.$L('删除'), transfer: true, delay: 600 }
                         }, [h('Icon', {
                             props: { type: 'md-trash', size: 16 },
@@ -178,8 +168,9 @@
                                     this.deleteReport(params.row);
                                 }
                             }
-                        })]),
-                    ]);
+                        })]));
+                    }
+                    return h('div', arr);
                 },
             }];
         },
@@ -262,27 +253,6 @@
                 this.getLists(true);
             },
 
-            contentReport(row) {
-                this.contentShow = true;
-                this.contentTitle = row.title;
-                this.contentText = this.$L('详细内容加载中.....');
-                $A.aAjax({
-                    url: 'report/content?id=' + row.id,
-                    error: () => {
-                        alert(this.$L('网络繁忙,请稍后再试!'));
-                        this.contentShow = false;
-                    },
-                    success: (res) => {
-                        if (res.ret === 1) {
-                            this.contentText = res.data.content;
-                        } else {
-                            this.contentShow = false;
-                            this.$Modal.error({title: this.$L('温馨提示'), content: res.msg});
-                        }
-                    }
-                });
-            },
-
             sendReport(row) {
                 this.$Modal.confirm({
                     title: this.$L('发送汇报'),

+ 2 - 36
resources/assets/js/main/components/report/receive.vue

@@ -33,14 +33,6 @@
             <!-- 分页 -->
             <Page class="pageBox" :total="listTotal" :current="listPage" :disabled="loadIng > 0" @on-change="setPage" @on-page-size-change="setPageSize" :page-size-opts="[10,20,30,50,100]" placement="top" show-elevator show-sizer show-total transfer></Page>
         </div>
-        <Modal
-            v-model="contentShow"
-            :title="contentTitle"
-            width="80%"
-            :styles="{top: '35px', paddingBottom: '35px'}"
-            footerHide>
-            <report-content :content="contentText"></report-content>
-        </Modal>
     </drawer-tabs-container>
 </template>
 <style lang="scss" scoped>
@@ -54,14 +46,13 @@
 
 <script>
     import DrawerTabsContainer from "../DrawerTabsContainer";
-    import ReportContent from "./content";
 
     /**
      * 收到的汇报
      */
     export default {
         name: 'ReportReceive',
-        components: {ReportContent, DrawerTabsContainer},
+        components: {DrawerTabsContainer},
         props: {
             canload: {
                 type: Boolean,
@@ -86,10 +77,6 @@
                 listPage: 1,
                 listTotal: 0,
                 noDataText: "",
-
-                contentShow: false,
-                contentTitle: '',
-                contentText: '',
             }
         },
 
@@ -144,7 +131,7 @@
                             style: { margin: '0 3px', cursor: 'pointer' },
                             on: {
                                 click: () => {
-                                    this.contentReport(params.row);
+                                    this.reportDetail(params.row.id, params.row.title);
                                 }
                             }
                         })]),
@@ -226,27 +213,6 @@
                     }
                 });
             },
-
-            contentReport(row) {
-                this.contentShow = true;
-                this.contentTitle = row.title;
-                this.contentText = this.$L('详细内容加载中.....');
-                $A.aAjax({
-                    url: 'report/content?id=' + row.id,
-                    error: () => {
-                        alert(this.$L('网络繁忙,请稍后再试!'));
-                        this.contentShow = false;
-                    },
-                    success: (res) => {
-                        if (res.ret === 1) {
-                            this.contentText = res.data.content;
-                        } else {
-                            this.contentShow = false;
-                            this.$Modal.error({title: this.$L('温馨提示'), content: res.msg});
-                        }
-                    }
-                });
-            },
         }
     }
 </script>

+ 47 - 11
resources/assets/js/main/main.js

@@ -271,7 +271,7 @@ import '../../sass/main.scss';
             }
             if (sendToWS === true) {
                 $A.WS.sendTo('team', null, {
-                    type: "task",
+                    type: "taskA",
                     act: act,
                     taskDetail: taskDetail
                 });
@@ -279,6 +279,38 @@ import '../../sass/main.scss';
         },
         __taskInfoListenerObject: {},
 
+        /**
+         * 获取待推送的日志并推送
+         * @param taskid
+         */
+        triggerTaskInfoChange(taskid) {
+            $A.aAjax({
+                url: 'project/task/pushlog',
+                data: {
+                    taskid: taskid,
+                    pagesize: 20
+                },
+                success: (res) => {
+                    if (res.ret === 1) {
+                        res.data.lists.forEach((item) => {
+                            let msgData = {
+                                type: 'taskB',
+                                username: item.username,
+                                userimg: item.userimg,
+                                indate: item.indate,
+                                detail: item.detail,
+                                other: item.other
+                            };
+                            res.data.follower.forEach((username) => {
+                                if (username != msgData.username) {
+                                    $A.WS.sendTo('user', username, msgData);
+                                }
+                            });
+                        });
+                    }
+                }
+            });
+        }
     });
 
     /**
@@ -294,10 +326,10 @@ import '../../sass/main.scss';
             __autoLine() {
                 let tempId = $A.randomString(16);
                 this.__autoId = tempId;
-                // console.log("[WS] Connection auto 30s ...");
+                console.log("[WS] Connection auto 30s ...");
                 setTimeout(() => {
                     if (this.__autoId === tempId) {
-                        // console.log("[WS] Connection auto ...");
+                        console.log("[WS] Connection auto ...");
                         this.connection();
                     }
                 }, 30 * 1000);
@@ -310,14 +342,17 @@ import '../../sass/main.scss';
                 let url = $A.getObject(window.webSocketConfig, 'URL');
                 url += ($A.strExists(url, "?") ? "&" : "?") + "token=" + $A.getToken();
                 if (!$A.leftExists(url, "ws://") && !$A.leftExists(url, "wss://")) {
+                    console.log("[WS] Connection nourl ...");
                     return;
                 }
 
                 if ($A.getToken() === false) {
+                    console.log("[WS] Connection noid ...");
                     return;
                 }
 
                 if (this.__instance !== null && force !== true) {
+                    console.log("[WS] Connection already ...");
                     return;
                 }
 
@@ -326,7 +361,7 @@ import '../../sass/main.scss';
 
                 // 连接建立时触发
                 this.__instance.onopen = (event) => {
-                    // console.log("[WS] Connection open ...");
+                    console.log("[WS] Connection open ...");
                 }
 
                 // 接收到服务端推送时执行
@@ -334,6 +369,7 @@ import '../../sass/main.scss';
                     // console.log("[WS] Connection message ...");
                     let msgDetail = $A.jsonParse(event.data);
                     if (msgDetail.messageType === 'open') {
+                        console.log("[WS] Connection connected ...");
                         this.__connected = true;
                     }
                     if (msgDetail.messageType === 'feedback') {
@@ -346,7 +382,7 @@ import '../../sass/main.scss';
 
                 // 连接关闭时触发
                 this.__instance.onclose = (event) => {
-                    // console.log("[WS] Connection closed ...");
+                    console.log("[WS] Connection closed ...");
                     this.__connected = false;
                     this.__instance = null;
                     this.__autoLine();
@@ -354,7 +390,7 @@ import '../../sass/main.scss';
 
                 // 连接出错
                 this.__instance.onerror = (event) => {
-                    // console.log("[WS] Connection error ...");
+                    console.log("[WS] Connection error ...");
                     this.__connected = false;
                     this.__instance = null;
                     this.__autoLine();
@@ -410,16 +446,16 @@ import '../../sass/main.scss';
                 }
                 //
                 if (this.__instance === null) {
-                    console.log("[WS] 服务未连接: " + againNum);
-                    if (againNum >= 12) {
-                        typeof callback === "function" && callback({status: 0, message: '服务未连接'});
-                    } else {
+                    if (againNum < 10 && type != 'team') {
                         setTimeout(() => {
                             this.sendTo(type, target, content, callback, $A.runNum(againNum) + 1)
-                        }, 500);
+                        }, 600);
                         if (againNum === 0) {
                             this.connection();
                         }
+                    } else {
+                        console.log("[WS] 服务未连接");
+                        typeof callback === "function" && callback({status: 0, message: '服务未连接'});
                     }
                     return;
                 }

+ 1 - 0
resources/assets/js/main/mixins/task.js

@@ -23,6 +23,7 @@ export default {
                     if (res.ret === 1) {
                         this.$Message.success(res.msg);
                         $A.triggerTaskInfoListener(complete ? 'complete' : 'unfinished', res.data);
+                        $A.triggerTaskInfoChange(taskDetail.id);
                     } else {
                         this.$set(taskDetail, 'complete', !complete);
                         this.$Modal.error({title: this.$L('温馨提示'), content: res.msg});

+ 26 - 0
resources/assets/js/main/pages/todo.vue

@@ -432,6 +432,32 @@
                         break;
 
                     case "username":        // 负责人
+                        if (detail.username == $A.getUserName()) {
+                            for (let level in this.taskDatas) {
+                                if (level == detail.level) {
+                                    let index = this.taskDatas[level].lists.length;
+                                    this.taskDatas[level].lists.some((task, i) => {
+                                        if (detail.userorder > task.userorder || (detail.userorder == task.userorder && detail.id > task.id)) {
+                                            index = i;
+                                            return true;
+                                        }
+                                    });
+                                    this.taskDatas[level].lists.splice(index, 0, detail);
+                                }
+                            }
+                        } else {
+                            for (let level in this.taskDatas) {
+                                this.taskDatas[level].lists.some((task, i) => {
+                                    if (task.id == detail.id) {
+                                        this.taskDatas[level].lists.splice(i, 1);
+                                        return true;
+                                    }
+                                });
+                            }
+                        }
+                        this.taskSortData = this.getTaskSort();
+                        break;
+
                     case "delete":          // 删除任务
                     case "archived":        // 归档
                         for (let level in this.taskDatas) {