Browse Source

台账分解,书签相关

MaiXinRong 4 years ago
parent
commit
58cb94ee42

+ 29 - 12
app/public/css/main.css

@@ -65,7 +65,21 @@ font-size: .875rem;
 }
 }
 .bs-popover-auto[x-placement^="bottom"] .arrow::after, .bs-popover-bottom .arrow::after{
 .bs-popover-auto[x-placement^="bottom"] .arrow::after, .bs-popover-bottom .arrow::after{
   border-bottom-color:#000;
   border-bottom-color:#000;
-}/*
+}
+.custom-control-warning-input:checked ~ .custom-control-warning-label::before{
+  border-color:#da9500 ;
+  background-color:#da9500 
+}
+.custom-control-warning-label{
+  color:#da9500;
+}
+.custom-control-label::before{
+  top:.15rem;
+}
+.custom-control-label::after{
+  top:.15rem;
+}
+/*
 .btn.disabled, .btn:disabled {
 .btn.disabled, .btn:disabled {
   opacity:.4
   opacity:.4
 }*/
 }*/
@@ -144,6 +158,12 @@ font-size: .875rem;
 .border-secondary-50{
 .border-secondary-50{
   border:1px solid #ccc;
   border:1px solid #ccc;
 }
 }
+.input-group-cancel{
+  position: absolute;
+  margin-left: -15px;
+  margin-top: 2px;
+  font-size: 14px
+}
 /*在谷歌下移除input[number]的上下箭头*/
 /*在谷歌下移除input[number]的上下箭头*/
 input.nospin[type='number']::-webkit-outer-spin-button,
 input.nospin[type='number']::-webkit-outer-spin-button,
 input.nospin[type='number']::-webkit-inner-spin-button{
 input.nospin[type='number']::-webkit-inner-spin-button{
@@ -198,7 +218,7 @@ input.nospin[type="number"]{-moz-appearance:textfield;}
 .sjs-height-4,.sjs-height-5,.sjs-height-6,.sjs-option-height{
 .sjs-height-4,.sjs-height-5,.sjs-height-6,.sjs-option-height{
   overflow: auto;
   overflow: auto;
 }
 }
-.sjs-bar-1,.sjs-bar-2,.sjs-bar-3,.sjs-bar-4{
+.sjs-bar-1,.sjs-bar-2,.sjs-bar-3,.sjs-bar-4,.sjs-bar-5{
   height:30px;
   height:30px;
   padding-top:3px;
   padding-top:3px;
 }
 }
@@ -453,6 +473,9 @@ input.nospin[type="number"]{-moz-appearance:textfield;}
 .border-bottom-1 {
 .border-bottom-1 {
   border-bottom:1px solid #dee2e6;
   border-bottom:1px solid #dee2e6;
 }
 }
+.save-confirm {
+  position:absolute;
+}
 /*滚动*/
 /*滚动*/
 .scrollbar-auto {
 .scrollbar-auto {
     overflow-y: auto;
     overflow-y: auto;
@@ -1021,12 +1044,6 @@ legend {
     right:0;
     right:0;
     top:35px;
     top:35px;
   }
   }
-.custom-control-label::before{
-  top:.1rem;
-}
-.custom-control-label::after{
-  top:.1rem;
-}
 .form-control-sm{
 .form-control-sm{
   height:calc(1.4125rem + 2px);
   height:calc(1.4125rem + 2px);
 }
 }
@@ -1218,9 +1235,9 @@ overflow-y: auto;
 .context-menu-icon.context-menu-icon--fa.text-info::before {
 .context-menu-icon.context-menu-icon--fa.text-info::before {
     color: #17a2b8;!important;
     color: #17a2b8;!important;
 }
 }
-.context-menu-icon.context-menu-icon--fa span{
-     color: #fff;!important;
- }
-.context-menu-icon.context-menu-hover.context-menu-icon--fa.text-success span{
+.context-menu-icon.context-menu-icon--fa.fa-tag span{
+    color: #2f2f2f;!important;
+}
+.context-menu-icon.context-menu-hover.context-menu-icon--fa.fa-tag span{
     color: #fff;!important;
     color: #fff;!important;
 }
 }

+ 21 - 1
app/public/css/main_s.css

@@ -65,7 +65,21 @@ font-size: .875rem;
 }
 }
 .bs-popover-auto[x-placement^="bottom"] .arrow::after, .bs-popover-bottom .arrow::after{
 .bs-popover-auto[x-placement^="bottom"] .arrow::after, .bs-popover-bottom .arrow::after{
   border-bottom-color:#000;
   border-bottom-color:#000;
-}/*
+}
+.custom-control-warning-input:checked ~ .custom-control-warning-label::before{
+  border-color:#da9500 ;
+  background-color:#da9500 
+}
+.custom-control-warning-label{
+  color:#da9500;
+}
+.custom-control-label::before{
+  top:.15rem;
+}
+.custom-control-label::after{
+  top:.15rem;
+}
+/*
 .btn.disabled, .btn:disabled {
 .btn.disabled, .btn:disabled {
   opacity:.4
   opacity:.4
 }*/
 }*/
@@ -144,6 +158,12 @@ font-size: .875rem;
 .border-secondary-50{
 .border-secondary-50{
   border:1px solid #ccc;
   border:1px solid #ccc;
 }
 }
+.input-group-cancel{
+  position: absolute;
+  margin-left: -15px;
+  margin-top: 2px;
+  font-size: 14px
+}
 /*在谷歌下移除input[number]的上下箭头*/
 /*在谷歌下移除input[number]的上下箭头*/
 input.nospin[type='number']::-webkit-outer-spin-button,
 input.nospin[type='number']::-webkit-outer-spin-button,
 input.nospin[type='number']::-webkit-inner-spin-button{
 input.nospin[type='number']::-webkit-inner-spin-button{

+ 27 - 7
app/public/js/ledger.js

@@ -70,6 +70,10 @@ $(document).ready(function() {
     const billsTag = $.billsTag({
     const billsTag = $.billsTag({
         selector: '#bills-tag',
         selector: '#bills-tag',
         relaSpread: ledgerSpread,
         relaSpread: ledgerSpread,
+        updateUrl: window.location.pathname + '/tag',
+        afterModify: function (nodes) {
+            SpreadJsObj.repaintNodesRowHeader(ledgerSpread.getActiveSheet(), nodes);
+        },
         afterLocated:  function () {
         afterLocated:  function () {
             posOperationObj.loadCurPosData();
             posOperationObj.loadCurPosData();
         },
         },
@@ -311,6 +315,7 @@ $(document).ready(function() {
                     const rows = [];
                     const rows = [];
                     for (const u of data.update) {
                     for (const u of data.update) {
                         rows.push(tree.nodes.indexOf(u));
                         rows.push(tree.nodes.indexOf(u));
+                        billsTag.refreshBillsTagView(u);
                     }
                     }
                     SpreadJsObj.reLoadRowsData(sheet, rows);
                     SpreadJsObj.reLoadRowsData(sheet, rows);
                 }
                 }
@@ -1000,9 +1005,10 @@ $(document).ready(function() {
                 getTagHtml: function (index, data) {
                 getTagHtml: function (index, data) {
                     if (!data) return;
                     if (!data) return;
                     const getHtml = function (list) {
                     const getHtml = function (list) {
+                        if (!list || list.length === 0) return '';
                         const html = [];
                         const html = [];
                         for (const l of list) {
                         for (const l of list) {
-                            html.push('<div class="row">');
+                            html.push('<div class="row mr-1">');
                             html.push(`<div class="col-auto pr-1 ${l.tagClass}">`, '<i class="fa fa-tag"></i>', '</div>');
                             html.push(`<div class="col-auto pr-1 ${l.tagClass}">`, '<i class="fa fa-tag"></i>', '</div>');
                             html.push('<div class="col p-0">', '<p>', l.comment, '</p>', '</div>');
                             html.push('<div class="col p-0">', '<p>', l.comment, '</p>', '</div>');
                             html.push('</div>');
                             html.push('</div>');
@@ -1189,9 +1195,11 @@ $(document).ready(function() {
     //     const $obj = $('<div>' + item.name +)
     //     const $obj = $('<div>' + item.name +)
     // };
     // };
     // 右键菜单
     // 右键菜单
+    let addTagShare = true;
     const billsContextMenuOptions = {
     const billsContextMenuOptions = {
         selector: '#ledger-spread',
         selector: '#ledger-spread',
         build: function ($trigger, e) {
         build: function ($trigger, e) {
+            addTagShare = true;
             const target = SpreadJsObj.safeRightClickSelection($trigger, e, ledgerSpread);
             const target = SpreadJsObj.safeRightClickSelection($trigger, e, ledgerSpread);
             return target.hitTestType === spreadNS.SheetArea.viewport || target.hitTestType === spreadNS.SheetArea.rowHeader;
             return target.hitTestType === spreadNS.SheetArea.viewport || target.hitTestType === spreadNS.SheetArea.rowHeader;
         },
         },
@@ -1579,13 +1587,25 @@ $(document).ready(function() {
     billsContextMenuOptions.items.tag = {
     billsContextMenuOptions.items.tag = {
         name: '书签',
         name: '书签',
         items: {
         items: {
+            tagShare: {
+                name: '参与人可见',
+                type: 'checkbox',
+                selected: true,
+                events: {
+                    change: function () {
+                        addTagShare = this.checked;
+                    }
+                }
+            },
+            tagSpr: '--------------',
             tagPrimary: {
             tagPrimary: {
                 icon: 'fa-tag text-primary mt-2 mb-2',
                 icon: 'fa-tag text-primary mt-2 mb-2',
                 name: '靛青',
                 name: '靛青',
-                callback: function (key, opt) {
+                callback: function (key, opt, menu, e) {
                     const node = SpreadJsObj.getSelectObject(ledgerSpread.getActiveSheet());
                     const node = SpreadJsObj.getSelectObject(ledgerSpread.getActiveSheet());
-                    postData(window.location.pathname + '/tag', {add: { color: '#007bff', lid: node.id }}, function (data) {
+                    postData(window.location.pathname + '/tag', {add: { color: '#007bff', lid: node.id, share: addTagShare }}, function (data) {
                         if (data.add) data.add.node = node;
                         if (data.add) data.add.node = node;
+                        billsTag.updateDatasAndShow(data);
                         SpreadJsObj.repaintNodesRowHeader(ledgerSpread.getActiveSheet(), node);
                         SpreadJsObj.repaintNodesRowHeader(ledgerSpread.getActiveSheet(), node);
                     });
                     });
                 },
                 },
@@ -1595,7 +1615,7 @@ $(document).ready(function() {
                 name: '果绿',
                 name: '果绿',
                 callback: function (key, opt) {
                 callback: function (key, opt) {
                     const node = SpreadJsObj.getSelectObject(ledgerSpread.getActiveSheet());
                     const node = SpreadJsObj.getSelectObject(ledgerSpread.getActiveSheet());
-                    postData(window.location.pathname + '/tag', {add: { color: '#28a745', lid: node.id }}, function (data) {
+                    postData(window.location.pathname + '/tag', {add: { color: '#28a745', lid: node.id, share: addTagShare }}, function (data) {
                         if (data.add) data.add.node = node;
                         if (data.add) data.add.node = node;
                         billsTag.updateDatasAndShow(data);
                         billsTag.updateDatasAndShow(data);
                         SpreadJsObj.repaintNodesRowHeader(ledgerSpread.getActiveSheet(), node);
                         SpreadJsObj.repaintNodesRowHeader(ledgerSpread.getActiveSheet(), node);
@@ -1607,7 +1627,7 @@ $(document).ready(function() {
                 name: '朱砂',
                 name: '朱砂',
                 callback: function (key, opt) {
                 callback: function (key, opt) {
                     const node = SpreadJsObj.getSelectObject(ledgerSpread.getActiveSheet());
                     const node = SpreadJsObj.getSelectObject(ledgerSpread.getActiveSheet());
-                    postData(window.location.pathname + '/tag', {add: { color: '#dc3545', lid: node.id }}, function (data) {
+                    postData(window.location.pathname + '/tag', {add: { color: '#dc3545', lid: node.id, share: addTagShare }}, function (data) {
                         if (data.add) data.add.node = node;
                         if (data.add) data.add.node = node;
                         billsTag.updateDatasAndShow(data);
                         billsTag.updateDatasAndShow(data);
                         SpreadJsObj.repaintNodesRowHeader(ledgerSpread.getActiveSheet(), node);
                         SpreadJsObj.repaintNodesRowHeader(ledgerSpread.getActiveSheet(), node);
@@ -1619,7 +1639,7 @@ $(document).ready(function() {
                 name: '姜黄',
                 name: '姜黄',
                 callback: function (key, opt) {
                 callback: function (key, opt) {
                     const node = SpreadJsObj.getSelectObject(ledgerSpread.getActiveSheet());
                     const node = SpreadJsObj.getSelectObject(ledgerSpread.getActiveSheet());
-                    postData(window.location.pathname + '/tag', {add: { color: '#da9500', lid: node.id }}, function (data) {
+                    postData(window.location.pathname + '/tag', {add: { color: '#da9500', lid: node.id, share: addTagShare }}, function (data) {
                         if (data.add) data.add.node = node;
                         if (data.add) data.add.node = node;
                         billsTag.updateDatasAndShow(data);
                         billsTag.updateDatasAndShow(data);
                         SpreadJsObj.repaintNodesRowHeader(ledgerSpread.getActiveSheet(), node);
                         SpreadJsObj.repaintNodesRowHeader(ledgerSpread.getActiveSheet(), node);
@@ -1631,7 +1651,7 @@ $(document).ready(function() {
                 name: '天蓝',
                 name: '天蓝',
                 callback: function (key, opt) {
                 callback: function (key, opt) {
                     const node = SpreadJsObj.getSelectObject(ledgerSpread.getActiveSheet());
                     const node = SpreadJsObj.getSelectObject(ledgerSpread.getActiveSheet());
-                    postData(window.location.pathname + '/tag', {add: { color: '#17a2b8', lid: node.id }}, function (data) {
+                    postData(window.location.pathname + '/tag', {add: { color: '#17a2b8', lid: node.id, share: addTagShare }}, function (data) {
                         if (data.add) data.add.node = node;
                         if (data.add) data.add.node = node;
                         billsTag.updateDatasAndShow(data);
                         billsTag.updateDatasAndShow(data);
                         SpreadJsObj.repaintNodesRowHeader(ledgerSpread.getActiveSheet(), node);
                         SpreadJsObj.repaintNodesRowHeader(ledgerSpread.getActiveSheet(), node);

+ 185 - 22
app/public/js/shares/cs_tools.js

@@ -603,7 +603,7 @@ const showSelectTab = function(select, spread, afterShow) {
         ];
         ];
         const obj = $(setting.selector);
         const obj = $(setting.selector);
         const html = [], pageLength = 15;
         const html = [], pageLength = 15;
-        let billsTags = [], classIndexes = [], billsIndexes = {};
+        let billsTags = [], classIndexes = [], billsIndexes = {}, curShow = [];
         html.push('<div class="sjs-bar d-flex justify-content-between">');
         html.push('<div class="sjs-bar d-flex justify-content-between">');
         // 下拉过滤
         // 下拉过滤
         html.push('<div class="dropdown mr-2">');
         html.push('<div class="dropdown mr-2">');
@@ -618,8 +618,10 @@ const showSelectTab = function(select, spread, afterShow) {
         html.push('</div>', '</div>');
         html.push('</div>', '</div>');
         // 搜索框
         // 搜索框
         html.push('<div class="input-group input-group-sm">');
         html.push('<div class="input-group input-group-sm">');
-        html.push('<input type="text" class="form-control" placeholder="可查找 项目节编号 / 清单编号 /名称">');
-        html.push('<div class="input-group-append">', '<button class="btn btn-outline-secondary" type="button" id="bills-tag-search">搜索</button>', '</div>');
+        html.push('<input type="text" class="form-control" placeholder="可查找 项目节编号 / 清单编号 /名称" id="bills-tag-keyword">');
+        html.push('<div class="input-group-append">', '<div class="input-group-cancel">',
+            '<a href="javascript: void(0);" id="bills-tag-clear" class="text-danger"><i class="fa fa-times-circle" title="移除搜索结果"></i></a>', '</div>',
+            '<button class="btn btn-outline-secondary" type="button" id="bills-tag-search">搜索</button>', '</div>');
         html.push('</div>');
         html.push('</div>');
         html.push('</div>');
         html.push('</div>');
         // 书签列表
         // 书签列表
@@ -627,16 +629,55 @@ const showSelectTab = function(select, spread, afterShow) {
         obj.html(html.join(''));
         obj.html(html.join(''));
 
 
         const clearViewTags = function () {
         const clearViewTags = function () {
-            const viewTags = $('[name=billsTag]', obj);
+            const viewTags = $('.tag-item', obj);
             if (viewTags && viewTags.length > 0) viewTags.remove();
             if (viewTags && viewTags.length > 0) viewTags.remove();
             billsTags.forEach(x => {x.display = false});
             billsTags.forEach(x => {x.display = false});
         };
         };
 
 
-        const getTagDisplayHtml = function(tag) {
+        const getTagEditHtml = function(tag) {
             const tagClass = classIndexes.find(x => {return x.color === tag.color});
             const tagClass = classIndexes.find(x => {return x.color === tag.color});
             const tagHtml = [];
             const tagHtml = [];
+            tagHtml.push('<div name="tag-edit">');
             tagHtml.push('<div class="card-header p-2"><div class="dropdown">');
             tagHtml.push('<div class="card-header p-2"><div class="dropdown">');
-            tagHtml.push(`<a class="pull-left mr-2" href="" id="dropdownMenuButton" data-toggle="dropdown" aria-expanded="false"><i class="fa fa-tag ${tagClass.tagClass}" title="修改书签颜色"></i></a>`);
+            tagHtml.push(`<a class="pull-left mr-2" href="javascript: void(0);" id="tag-change-color" tag-color="${tag.color}" data-toggle="dropdown" aria-expanded="false"><i class="fa fa-tag ${tagClass.tagClass}" title="修改书签颜色"></i></a>`);
+            // 下拉选择颜色
+            tagHtml.push('<div class="dropdown-menu" aria-labelledby="tag-change-color" style="min-width:60px">',
+                '<a class="dropdown-item text-primary" href="javascript: void(0);" name="tag-color"><i class="fa fa-tint"></i></a>',
+                '<a class="dropdown-item text-success " href="javascript: void(0);" name="tag-color"><i class="fa fa-tint"></i></a>',
+                '<a class="dropdown-item text-danger " href="javascript: void(0);" name="tag-color"><i class="fa fa-tint"></i></a>',
+                '<a class="dropdown-item text-warning " href="javascript: void(0);" name="tag-color"><i class="fa fa-tint"></i></a>',
+                '<a class="dropdown-item text-info " href="javascript: void(0);" name="tag-color"><i class="fa fa-tint"></i></a>', '</div>');
+            tagHtml.push('</div>');
+            tag.node && tagHtml.push((tag.node.code || '') + (tag.node.b_code || ''), ' / ', tag.node.name || '');
+            tagHtml.push('</div>');
+
+            tagHtml.push('<div class="card-body p-2">');
+            tagHtml.push('<p class="card-text">', '<textarea class="form-control" id="tag-comment">', tag.comment, '</textarea>', '</p>');
+
+            tagHtml.push('<div class="d-flex justify-content-between">');
+            // 参与人可见
+            tagHtml.push('<div class="custom-control custom-switch mr-2">');
+            tagHtml.push('<input type="checkbox" class="custom-control-input custom-control-warning-input" id="tag-share">');
+            tagHtml.push('<label class="custom-control-label custom-control-warning-label" for="tag-share" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="所有参与台帐审批管理的用户都可以看到这条书签"><i class="fa fa-users"></i> 参与者可见</label>');
+            tagHtml.push('</div>');
+            // 编辑按钮
+            tagHtml.push('<div>', '<button type="button" class="btn btn-sm btn-outline-danger mr-3" id="tag-del"><i class="fa fa-close"></i>  删除书签</button>',
+                '<button type="button" class="btn btn-sm btn-outline-success mr-1" id="tag-edit-ok"><i class="fa fa-check"></i> 确定</button>',
+                '<button type="button" class="btn btn-sm btn-outline-secondary" id="tag-edit-cancel">取消</button>', '</div>');
+            tagHtml.push('</div>');
+
+            tagHtml.push('</div>');
+
+            tagHtml.push('</div>');
+            return tagHtml.join('');
+        };
+
+        const getTagDisplayHtml = function (tag) {
+            const tagClass = classIndexes.find(x => {return x.color === tag.color});
+            const tagHtml = [];
+            tagHtml.push('<div name="tag-view">');
+            tagHtml.push('<div class="card-header p-2"><div class="dropdown">');
+            tagHtml.push(`<div class="pull-left mr-2"><i class="fa fa-tag ${tagClass.tagClass}"></i></div>`);
             tagHtml.push('</div>');
             tagHtml.push('</div>');
             tag.node && tagHtml.push((tag.node.code || '') + (tag.node.b_code || ''), ' / ', tag.node.name || '');
             tag.node && tagHtml.push((tag.node.code || '') + (tag.node.b_code || ''), ' / ', tag.node.name || '');
             if (tag.share) {
             if (tag.share) {
@@ -645,19 +686,51 @@ const showSelectTab = function(select, spread, afterShow) {
             tagHtml.push('<div class="pull-right edit-tag-btn">');
             tagHtml.push('<div class="pull-right edit-tag-btn">');
             const lid = tag.node ? tag.node.ledger_id : -1;
             const lid = tag.node ? tag.node.ledger_id : -1;
             tagHtml.push(`<a class="mr-1" name="bills-tag-locate" href="javascript: void(0);" lid="${lid}"><i class="fa fa-crosshairs"></i> 定位</a>`);
             tagHtml.push(`<a class="mr-1" name="bills-tag-locate" href="javascript: void(0);" lid="${lid}"><i class="fa fa-crosshairs"></i> 定位</a>`);
-            if (tag.uid === userID) tagHtml.push('<a href="javascript: void(0);"><i class="fa fa-edit"></i> 编辑</a>');
+            if (tag.uid === userID) tagHtml.push(`<a href="javascript: void(0);" name="bills-tag-edit" tag-id="${tag.id}"><i class="fa fa-edit"></i> 编辑</a>`);
             tagHtml.push('</div>');
             tagHtml.push('</div>');
             tagHtml.push('<div class="card-body p-2">', '<p class="card-text">', tag.comment, '</p>', '</div>');
             tagHtml.push('<div class="card-body p-2">', '<p class="card-text">', tag.comment, '</p>', '</div>');
+            tagHtml.push('</div>');
             return tagHtml.join('');
             return tagHtml.join('');
         };
         };
 
 
+        const searchTagsAndShow = function () {
+            const keyword = $('#bills-tag-keyword').val();
+            const filterClass = $('#bills-tag-filter')[0].classList;
+            const tagClass = filterClass.length > 2 ? filterClass[2] : null;
+            const ci = tagClass ? classIndexes.find(x => {return x.tagClass === tagClass}) : null;
+            curShow = billsTags.filter(x => {
+                if (ci && ci.color !== x.color) return false;
+                if (!keyword) return true;
+                if (x.node.code && x.node.code.indexOf(keyword) >= 0) return true;
+                if (x.node.b_code && x.node.b_code.indexOf(keyword) >= 0) return true;
+                if (x.node.name && x.node.name.indexOf(keyword) >= 0) return true;
+                return false;
+            });
+            reloadViewTags();
+        };
+
+        const refreshTagView = function (tag) {
+            const obj = $('#bills-tag-' + tag.id);
+            if (obj && obj.length > 0) {
+                obj.html(getTagDisplayHtml(tag));
+            }
+        };
+
+        const refreshBillsTagView = function (bills) {
+            const bi = billsIndexes[bills.id] || [];
+
+            for (const tag of bi) {
+                refreshTagView(tag);
+            }
+        };
+
         const reviewTag = function (tag, isTop = false) {
         const reviewTag = function (tag, isTop = false) {
             const obj = $('#bills-tag-' + tag.id);
             const obj = $('#bills-tag-' + tag.id);
             if (obj && obj.length > 0) {
             if (obj && obj.length > 0) {
                 obj.html(getTagDisplayHtml(tag));
                 obj.html(getTagDisplayHtml(tag));
             } else {
             } else {
                 const objHtml = [];
                 const objHtml = [];
-                objHtml.push(`<div class="card border-primary my-2 tag-item" id="bills-tag-${tag.id}">`);
+                objHtml.push(`<div class="card border-primary my-2 tag-item" id="bills-tag-${tag.id}" tag-id="${tag.id}">`);
                 objHtml.push(getTagDisplayHtml(tag));
                 objHtml.push(getTagDisplayHtml(tag));
                 objHtml.push('</div>');
                 objHtml.push('</div>');
                 if (isTop) {
                 if (isTop) {
@@ -669,9 +742,9 @@ const showSelectTab = function(select, spread, afterShow) {
             tag.display = true;
             tag.display = true;
         };
         };
 
 
-        const loadViewTags = function (tags) {
+        const loadViewTags = function () {
             let showCount = 0;
             let showCount = 0;
-            for (const t of tags) {
+            for (const t of curShow) {
                 if (showCount >= pageLength) continue;
                 if (showCount >= pageLength) continue;
                 if (t.display) continue;
                 if (t.display) continue;
                 reviewTag(t);
                 reviewTag(t);
@@ -679,6 +752,12 @@ const showSelectTab = function(select, spread, afterShow) {
             }
             }
         };
         };
 
 
+        const reloadViewTags = function () {
+            clearViewTags();
+            $("#bills-tag-lis").scrollTop(0);
+            loadViewTags();
+        };
+
         const _addToBillsIndex = function(data, isTop = false) {
         const _addToBillsIndex = function(data, isTop = false) {
             let bi = billsIndexes[data.lid];
             let bi = billsIndexes[data.lid];
             if (!bi) {
             if (!bi) {
@@ -695,28 +774,23 @@ const showSelectTab = function(select, spread, afterShow) {
                 billsTags.push(d);
                 billsTags.push(d);
                 _addToBillsIndex(d);
                 _addToBillsIndex(d);
             }
             }
-            for (const ci of classIndexes) {
-                ci.tags = billsTags.filter(x => {return x.color === ci.color});
-            }
-            clearViewTags();
-            loadViewTags(billsTags);
+            curShow = billsTags;
+            reloadViewTags();
         };
         };
 
 
         const updateDatas = function (data) {
         const updateDatas = function (data) {
             const refresh = {};
             const refresh = {};
             if (data.add) {
             if (data.add) {
                 billsTags.push(data.add);
                 billsTags.push(data.add);
-                const tagClass = classIndexes.find(x => {return x.color === data.add.color});
-                if (tagClass) tagClass.tags.push(data.add);
                 _addToBillsIndex(data.add, true);
                 _addToBillsIndex(data.add, true);
                 refresh.add = data.add;
                 refresh.add = data.add;
             }
             }
             if (data.del) {
             if (data.del) {
-                const delTag = billsTags.find(x => {return x.id === data.del.id});
+                const delTag = billsTags.find(x => {return x.id === data.del});
                 billsTags.splice(billsTags.indexOf(delTag), 1);
                 billsTags.splice(billsTags.indexOf(delTag), 1);
-                const tagClass = classIndexes.find(x => {x.color = delTag.color});
-                if (tagClass) tagClass.splice(tagClass.indexOf(delTag), -1);
-                refresh.del = data.del
+                const bi = billsIndexes[delTag.node.id];
+                bi.splice(bi.indexOf(delTag), 1);
+                refresh.del = delTag;
             }
             }
             if (data.update) {
             if (data.update) {
                 const updateTag = billsTags.find(x => {return x.id === data.update.id});
                 const updateTag = billsTags.find(x => {return x.id === data.update.id});
@@ -729,10 +803,21 @@ const showSelectTab = function(select, spread, afterShow) {
         };
         };
 
 
         const updateDatasAndShow = function (data) {
         const updateDatasAndShow = function (data) {
+            const relaBills = [];
             const refresh = updateDatas(data);
             const refresh = updateDatas(data);
             if (refresh.add) {
             if (refresh.add) {
                 reviewTag(refresh.add, true);
                 reviewTag(refresh.add, true);
+                relaBills.push(refresh.add.node);
             }
             }
+            if (refresh.del) {
+                $('#bills-tag-' + refresh.del.id).remove();
+                relaBills.push(refresh.del.node);
+            }
+            if (refresh.update) {
+                refreshTagView(refresh.update);
+                relaBills.push(refresh.update.node);
+            }
+            return relaBills;
         };
         };
 
 
         const show = function () {
         const show = function () {
@@ -757,7 +842,85 @@ const showSelectTab = function(select, spread, afterShow) {
             SpreadJsObj.locateTreeNode(setting.relaSpread.getActiveSheet(), lid);
             SpreadJsObj.locateTreeNode(setting.relaSpread.getActiveSheet(), lid);
             setting.afterLocated && setting.afterLocated();
             setting.afterLocated && setting.afterLocated();
         });
         });
+        $('body').on('click', '[name=bills-tag-edit]', function () {
+            const tagId = this.getAttribute('tag-id');
+            const tag = billsTags.find(x => {return x.id == tagId});
+            if (tag) {
+                const obj = $('#bills-tag-' + tag.id);
+                $('[name=tag-view]', obj).hide();
+                obj.append(getTagEditHtml(tag));
+            }
+        });
+        $('body').on('click', '#tag-edit-cancel', function () {
+            const obj = $('[name=tag-edit]').parent();
+            $('[name=tag-edit]').remove();
+            $('[name=tag-view]', obj).show();
+        });
+        $('body').on('click', '#tag-del', function () {
+            const obj = $('[name=tag-edit]').parent();
+            postData(setting.updateUrl, {del: parseInt(obj.attr('tag-id'))}, function (result) {
+                if (!result.del) return;
+
+                const bills = updateDatasAndShow(result);
+                setting.afterModify && setting.afterModify(bills);
+            });
+        });
+        $('body').on('click', '#tag-edit-ok', function () {
+            const obj = $('[name=tag-edit]').parent();
+            const data = {
+                id: parseInt(obj.attr('tag-id')),
+                share: $('#tag-share')[0].checked,
+                comment: $('#tag-comment').val(),
+                color: $('#tag-change-color').attr('tag-color'),
+            };
+            postData(setting.updateUrl, {update: data}, function (result) {
+                if (!result.update) return;
+
+                const bills = updateDatasAndShow(result);
+                setting.afterModify && setting.afterModify(bills);
+            });
+        });
+        $('body').on('click', '[name=tag-color]', function () {
+            const tagClass = this.classList[1];
+            const ci = classIndexes.find(tc => {return tc.tagClass === tagClass});
+            const tcc = $('#tag-change-color');
+            tcc.attr('tag-color', ci.color);
+            tcc.find('i').attr('class', 'fa fa-tag ' + tagClass);
+        });
+        $('body').on('click', '[tagType]', function () {
+            const tagClass = this.getAttribute('tagType');
+            if (tagClass === 'all') {
+                $('#bills-tag-filter').attr('class', 'fa fa-list-ol');
+            } else {
+                $('#bills-tag-filter').attr('class', 'fa fa-tag ' + tagClass);
+            }
+            searchTagsAndShow();
+        });
+        // 防抖
+        function debounce(fun, delay) {
+            let timer = null;
+            return function () {
+                if (timer) {
+                    clearTimeout(timer);
+                }
+                timer = setTimeout(fun, delay);
+            }
+        }
+        $('#bills-tag-list').bind('scroll', debounce(function (e) {
+            const obj = $('#bills-tag-list');
+            var sum = obj[0].scrollHeight;
+            if (sum <= obj.scrollTop() + obj.height()) {
+                loadViewTags();
+            }
+        }, 300));
+        $('#bills-tag-clear').bind('click', () => {
+            if (!$('#bills-tag-keyword').val()) return;
+            $('#bills-tag-keyword').val('');
+            searchTagsAndShow();
+        });
+        $('#bills-tag-search').bind('click', () => {searchTagsAndShow();});
+        $('#bills-tag-keyword').bind('keydown', e => {if (e.keyCode === 13) searchTagsAndShow();});
 
 
-        return { loadDatas, updateDatasAndShow, show, getBillsTagsColor, getBillsTagsInfo }
+        return { loadDatas, updateDatasAndShow, show, getBillsTagsColor, getBillsTagsInfo, refreshBillsTagView, }
     }
     }
 })(jQuery);
 })(jQuery);

+ 46 - 5
app/public/js/spreadjs_rela/spreadjs_zh.js

@@ -2384,17 +2384,58 @@ const SpreadJsObj = {
                 spreadNS.CellTypes.RowHeader.prototype.paint.apply(this, [canvas, '', x, y, w , h, style, options]);
                 spreadNS.CellTypes.RowHeader.prototype.paint.apply(this, [canvas, '', x, y, w , h, style, options]);
                 spreadNS.CellTypes.Text.prototype.paint.apply(this, [canvas, value, x, y, w - this.indent, h, style, options]);
                 spreadNS.CellTypes.Text.prototype.paint.apply(this, [canvas, value, x, y, w - this.indent, h, style, options]);
                 const node = SpreadJsObj.getRowObject(options.sheet, options.row);
                 const node = SpreadJsObj.getRowObject(options.sheet, options.row);
-                let sel = options.sheet.getSelections();
-                sel = sel ? sel[0] : null;
-                const actualStyle = options.sheet.getActualStyle(options.row, options.col, options.sheetArea, false);
-                if (options.row === 1) console.log(actualStyle);
-                const backColor = style.backColor || (sel && options.row >= sel.row && options.row < sel.row + sel.rowCount ? '#dddfe1' : '#e9ecef');
+                let backColor = style.backColor;
+                if (!backColor) {
+                    const tag = options.sheet.getTag(options.row, options.col, options.sheetArea);
+                    if (tag && tag === 'hover') backColor = '#dddfe1';
+                    if (!backColor) {
+                        let sel = options.sheet.getSelections();
+                        sel = sel ? sel[0] : null;
+                        backColor = (sel && options.row >= sel.row && options.row < sel.row + sel.rowCount ? '#dddfe1' : '#e9ecef');
+                    }
+                }
                 let color = this.getTagColor(options.row, node);
                 let color = this.getTagColor(options.row, node);
                 color = color instanceof Array ? color : [color];
                 color = color instanceof Array ? color : [color];
                 for (let i = color.length - 1; i >= 0; i--) {
                 for (let i = color.length - 1; i >= 0; i--) {
                     drawCircle2(canvas, x + w - this.indent + 5 + i*5 , y + h/2, 6, backColor, color[i]);
                     drawCircle2(canvas, x + w - this.indent + 5 + i*5 , y + h/2, 6, backColor, color[i]);
                 }
                 }
             };
             };
+            /**
+             * 获取点击信息
+             * @param {Number} x
+             * @param {Number} y
+             * @param {Object} cellStyle
+             * @param {Object} cellRect
+             * @param {Object} context
+             * @returns {{x: *, y: *, row: *, col: *|boolean|*[]|number|{}|UE.dom.dtd.col, cellStyle: *, cellRect: *, sheet: *|StyleSheet, sheetArea: *}}
+             */
+            proto.getHitInfo = function (x, y, cellStyle, cellRect, context) {
+                return {
+                    x: x,
+                    y: y,
+                    row: context.row,
+                    col: context.col,
+                    cellStyle: cellStyle,
+                    cellRect: cellRect,
+                    sheet: context.sheet,
+                    sheetArea: context.sheetArea,
+                    ctx: context.sheet.getParent().xs,
+                };
+            };
+            /**
+             * 鼠标进入单元格事件 - 显示悬浮提示
+             * @param {Object} hitinfo - 见getHitInfo返回值
+             */
+            proto.processMouseEnter = function (hitinfo) {
+                hitinfo.sheet.setTag(hitinfo.row, hitinfo.col, 'hover', hitinfo.sheetArea);
+            };
+            /**
+             * 鼠标移出单元格事件 - 隐藏悬浮提示
+             * @param {Object} hitinfo - 见getHitInfo返回值
+             */
+            proto.processMouseLeave = function (hitinfo) {
+                hitinfo.sheet.setTag(hitinfo.row, hitinfo.col, undefined, hitinfo.sheetArea);
+            };
             return new CircleTagCellType();
             return new CircleTagCellType();
         },
         },
     },
     },

+ 12 - 9
app/service/ledger_tag.js

@@ -31,11 +31,14 @@ module.exports = app => {
          * @returns {Promise<void>}
          * @returns {Promise<void>}
          */
          */
         async getDatas(tid, sid = -1) {
         async getDatas(tid, sid = -1) {
-            return await this.db.select(this.tableName, {
-                where: {tid: tid, sid: -1},
-                columns: ['id', 'uid', 'lid', 'share', 'color', 'comment'],
-                orders: [['create_time', 'desc']],
-            });
+            // return await this.db.select(this.tableName, {
+            //     where: {tid: tid, sid: -1},
+            //     columns: ['id', 'uid', 'lid', 'share', 'color', 'comment'],
+            //     orders: [['create_time', 'desc']],
+            // });
+            const sql = 'SELECT id, uid, lid, share, color, comment FROM ' + this.tableName +
+                '  WHERE tid = ? and sid = ? and (uid = ? or share) ORDER BY create_time DESC';
+            return await this.db.query(sql, [tid, sid, this.ctx.session.sessionUser.accountId]);
         }
         }
 
 
         /**
         /**
@@ -68,7 +71,7 @@ module.exports = app => {
         }
         }
 
 
         async _delTag(id) {
         async _delTag(id) {
-            const tag = this.getDataById(id);
+            const tag = await this.getDataById(id);
             if (tag.uid !== this.ctx.session.sessionUser.accountId) throw '您无权删除该数据';
             if (tag.uid !== this.ctx.session.sessionUser.accountId) throw '您无权删除该数据';
 
 
             await this.deleteById(id);
             await this.deleteById(id);
@@ -76,13 +79,13 @@ module.exports = app => {
         }
         }
 
 
         async _updateTag(data) {
         async _updateTag(data) {
-            const tag = this.getDataById(data.id);
-            if (tag.uid !== this.ctx.session.sessionUser.accountId) throw '您无权删除该数据';
+            const tag = await this.getDataById(data.id);
+            if (tag.uid !== this.ctx.session.sessionUser.accountId) throw '您无权修改该数据';
 
 
             this._filterInvalidField(data);
             this._filterInvalidField(data);
             data.modify_time = new Date();
             data.modify_time = new Date();
             data.id = tag.id;
             data.id = tag.id;
-            const result = await this.db.udpate(this.tableName, data);
+            const result = await this.db.update(this.tableName, data);
             if (result.affectedRows === 1) return data;
             if (result.affectedRows === 1) return data;
         }
         }