|
|
@@ -41,7 +41,7 @@ $(document).ready(function() {
|
|
|
this.spreadSetting = {
|
|
|
cols: [
|
|
|
{
|
|
|
- title: '分类名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 220, formatter: '@', cellType: 'tree',
|
|
|
+ title: '分类名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 220, formatter: '@', cellType: 'tree', showTips: true,
|
|
|
getValue: function(data) {
|
|
|
return data.name;
|
|
|
},
|
|
|
@@ -53,6 +53,7 @@ $(document).ready(function() {
|
|
|
size: 18,
|
|
|
};
|
|
|
},
|
|
|
+ getTip: function(data) { return _.escape(data.name || ''); },
|
|
|
},
|
|
|
{ title: '文件数', colSpan: '1', rowSpan: '1', field: 'total_file_count', hAlign: 1, width: 70, formatter: '@' },
|
|
|
],
|
|
|
@@ -74,7 +75,9 @@ $(document).ready(function() {
|
|
|
this.curPage = 1;
|
|
|
this.curTotalPage = 1;
|
|
|
this.curFiling = null;
|
|
|
- this.selectRemoveNode = null;
|
|
|
+ this.selectRemoveNodes = [];
|
|
|
+ this._directorySaving = false;
|
|
|
+ this._reloadingFiling = false;
|
|
|
this.fileOrderKey = 'fileOrderSjs';
|
|
|
this.fileOrder = getLocalCache(this.fileOrderKey) || 'create_time|desc';
|
|
|
this.curFilingKey = 'cur-filing-sjs-' + window.location.pathname.split('/')[2];
|
|
|
@@ -229,7 +232,7 @@ $(document).ready(function() {
|
|
|
|
|
|
// 选中行变化事件
|
|
|
this.spread.bind(spreadNS.Events.SelectionChanged, async function(e, info) {
|
|
|
- if (self._isRenaming) return;
|
|
|
+ if (self._isRenaming || self._reloadingFiling) return;
|
|
|
const node = SpreadJsObj.getSelectObject(self.sheet);
|
|
|
if (node && (!self.curFiling || self.curFiling.id !== node.id)) {
|
|
|
await self.setCurFiling(node);
|
|
|
@@ -285,7 +288,7 @@ $(document).ready(function() {
|
|
|
// 双击行内重命名分类
|
|
|
$('#filing-spread').dblclick(function() {
|
|
|
if (!canFiling) return;
|
|
|
- if (self._isRenaming) return;
|
|
|
+ if (self._isRenaming || self._directorySaving) return;
|
|
|
const node = SpreadJsObj.getSelectObject(self.sheet);
|
|
|
if (!node || node.is_fixed) return;
|
|
|
|
|
|
@@ -363,14 +366,14 @@ $(document).ready(function() {
|
|
|
name: '删除',
|
|
|
icon: 'fa-trash-o',
|
|
|
callback: function () {
|
|
|
- const node = SpreadJsObj.getSelectObject(self.sheet);
|
|
|
- if (!node || node.is_fixed) return;
|
|
|
- self.selectRemoveNode = node;
|
|
|
- $('#del-filing').modal('show');
|
|
|
+ self._showDeletePreview();
|
|
|
},
|
|
|
disabled: function () {
|
|
|
- const node = SpreadJsObj.getSelectObject(self.sheet);
|
|
|
- return !canFiling || !node || node.is_fixed;
|
|
|
+ const nodes = self._getSelectedFilings();
|
|
|
+ return self._directorySaving || projectFileLocked || !nodes.length || nodes.some(node => {
|
|
|
+ const permission = self._getFilingPermission(node.id);
|
|
|
+ return Number(node.is_fixed) || !permission.can_view || !permission.can_edit_dir;
|
|
|
+ });
|
|
|
},
|
|
|
},
|
|
|
},
|
|
|
@@ -596,47 +599,79 @@ $(document).ready(function() {
|
|
|
* 添加同级分类
|
|
|
*/
|
|
|
addSiblingFiling(node) {
|
|
|
- const self = this;
|
|
|
const treePid = node.tree_pid === -1 ? '-1' : this._findOriginalId(node.tree_pid);
|
|
|
- postData('filing/add', { tree_pid: treePid, tree_pre_id: node.id }, function(result) {
|
|
|
- filing.push(result);
|
|
|
- self._reloadFilingTree();
|
|
|
- });
|
|
|
+ this._addFiling({ tree_pid: treePid, tree_pre_id: node.id, name: '' });
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 添加子级分类
|
|
|
*/
|
|
|
addChildFiling(node) {
|
|
|
- const self = this;
|
|
|
- postData('filing/add', { tree_pid: node.id }, function(result) {
|
|
|
- filing.push(result);
|
|
|
- self._reloadFilingTree();
|
|
|
- });
|
|
|
+ this._addFiling({ tree_pid: node.id, name: '' });
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 重新加载归档树
|
|
|
*/
|
|
|
- _reloadFilingTree() {
|
|
|
- const convertedData = this._convertData(filing);
|
|
|
- this.filingTree.loadDatas(convertedData);
|
|
|
- SpreadJsObj.loadSheetData(this.sheet, SpreadJsObj.DataType.Tree, this.filingTree);
|
|
|
- this.refreshFileCountHint();
|
|
|
+ _reloadFilingTree(focusId) {
|
|
|
+ const expanded = new Map(this.filingTree.nodes.map(node => [node.id, node.expanded]));
|
|
|
+ const currentId = focusId || (this.curFiling && this.curFiling.id);
|
|
|
+ const topRow = this.sheet.getViewportTopRow(1);
|
|
|
+ const topNode = this.filingTree.nodes[topRow];
|
|
|
+ this._reloadingFiling = true;
|
|
|
+ let currentNode;
|
|
|
+ try {
|
|
|
+ this.filingTree.loadDatas(this._convertData(filing));
|
|
|
+ this.filingTree.nodes.forEach(node => {
|
|
|
+ if (expanded.has(node.id)) node.expanded = expanded.get(node.id);
|
|
|
+ });
|
|
|
+ currentNode = this.filingTree.nodes.find(node => node.id === currentId);
|
|
|
+ if (focusId && currentNode) {
|
|
|
+ let parent = this.filingTree.getParent(currentNode);
|
|
|
+ while (parent) {
|
|
|
+ parent.expanded = true;
|
|
|
+ parent = this.filingTree.getParent(parent);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.filingTree.refreshNodeVisible();
|
|
|
+ SpreadJsObj.loadSheetData(this.sheet, SpreadJsObj.DataType.Tree, this.filingTree);
|
|
|
+ this.resizeSpreadColumns();
|
|
|
+ this.sheet.clearSelection();
|
|
|
+ if (currentNode) this.sheet.setSelection(this.filingTree.nodes.indexOf(currentNode), 0, 1, 1);
|
|
|
+ const targetRow = focusId && currentNode ? this.filingTree.nodes.indexOf(currentNode)
|
|
|
+ : this.filingTree.nodes.findIndex(node => topNode && node.id === topNode.id);
|
|
|
+ if (targetRow >= 0) this.sheet.showRow(targetRow, focusId ? spreadNS.VerticalPosition.center : spreadNS.VerticalPosition.top);
|
|
|
+ this.refreshFileCountHint();
|
|
|
+ } finally {
|
|
|
+ this._reloadingFiling = false;
|
|
|
+ }
|
|
|
+ this.curFiling = null;
|
|
|
+ if (currentNode) {
|
|
|
+ this.setCurFiling(currentNode).catch(() => { $('#file-view').hide(); });
|
|
|
+ } else {
|
|
|
+ canFiling = false;
|
|
|
+ $('.js-can-edit-dir').hide();
|
|
|
+ $('#file-view').hide();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 删除分类
|
|
|
*/
|
|
|
- delFiling(node, callback) {
|
|
|
+ delFiling(nodes, callback) {
|
|
|
+ if (this._directorySaving || !nodes.length) return;
|
|
|
const self = this;
|
|
|
- const parent = this.filingTree.getParent(node);
|
|
|
- postData('filing/del', { id: node.id }, function(result) {
|
|
|
+ const modal = $('#filesjs-del-filing');
|
|
|
+ this._directorySaving = true;
|
|
|
+ $('button', modal).prop('disabled', true);
|
|
|
+ $('#filesjs-del-filing-error').text('');
|
|
|
+ postData('filing/del', { ids: nodes.map(node => node.id) }, function(result) {
|
|
|
// 更新 filing 数组:移除已删除的节点
|
|
|
if (result && result.delete) {
|
|
|
for (const delId of result.delete) {
|
|
|
const idx = filing.findIndex(x => x.id === delId);
|
|
|
if (idx >= 0) filing.splice(idx, 1);
|
|
|
+ delete filingPermissionMap[delId];
|
|
|
}
|
|
|
}
|
|
|
// 更新兄弟节点的 tree_order
|
|
|
@@ -648,9 +683,14 @@ $(document).ready(function() {
|
|
|
}
|
|
|
// 重新加载树
|
|
|
self._reloadFilingTree();
|
|
|
- $('#file-view').hide();
|
|
|
- self.curFiling = null;
|
|
|
+ self._directorySaving = false;
|
|
|
+ $('button', modal).prop('disabled', false);
|
|
|
if (callback) callback();
|
|
|
+ toastr.success(`已删除 ${result.delete.length} 个分类`);
|
|
|
+ }, function(error) {
|
|
|
+ self._directorySaving = false;
|
|
|
+ $('button', modal).prop('disabled', false);
|
|
|
+ $('#filesjs-del-filing-error').text(error || '删除失败,请重试');
|
|
|
});
|
|
|
}
|
|
|
|
|
|
@@ -1192,6 +1232,71 @@ $(document).ready(function() {
|
|
|
$('#filing-name-paste-error').text(error || '保存失败,请重试;若名称已变化,请刷新页面后重新粘贴。');
|
|
|
});
|
|
|
}
|
|
|
+
|
|
|
+ _addFiling(data) {
|
|
|
+ if (this._directorySaving || !canFiling || this._isRenaming) return;
|
|
|
+ this._directorySaving = true;
|
|
|
+ postData('filing/add', data, result => {
|
|
|
+ for (const update of result.update || []) {
|
|
|
+ const source = filing.find(node => node.id === update.id);
|
|
|
+ if (source) Object.assign(source, update);
|
|
|
+ }
|
|
|
+ for (const node of result.create || []) {
|
|
|
+ if (!filing.some(source => source.id === node.id)) filing.push(node);
|
|
|
+ }
|
|
|
+ Object.assign(filingPermissionMap, result.permissionMap || {});
|
|
|
+ this._directorySaving = false;
|
|
|
+ const created = (result.create || [])[0];
|
|
|
+ this._reloadFilingTree(created && created.id);
|
|
|
+ }, () => { this._directorySaving = false; });
|
|
|
+ }
|
|
|
+
|
|
|
+ _getSelectedFilings() {
|
|
|
+ const rows = new Set();
|
|
|
+ for (const selection of this.sheet.getSelections()) {
|
|
|
+ const first = Math.max(0, selection.row);
|
|
|
+ const last = selection.row < 0 ? this.filingTree.nodes.length
|
|
|
+ : Math.min(first + selection.rowCount, this.filingTree.nodes.length);
|
|
|
+ for (let row = first; row < last; row++) {
|
|
|
+ if (this.sheet.getRowVisible(row)) rows.add(row);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return [...rows].sort((a, b) => a - b).map(row => this.filingTree.nodes[row]);
|
|
|
+ }
|
|
|
+
|
|
|
+ _showDeletePreview() {
|
|
|
+ if (this._directorySaving || projectFileLocked) return;
|
|
|
+ const nodes = this._getSelectedFilings();
|
|
|
+ if (!nodes.length) return;
|
|
|
+ const included = new Set(nodes.map(node => node.id));
|
|
|
+ // 树节点按父子顺序排列,检查选中的分类以及折叠的子分类。
|
|
|
+ const scope = this.filingTree.nodes.filter(node => {
|
|
|
+ const parent = this.filingTree.getParent(node);
|
|
|
+ if (parent && included.has(parent.id)) included.add(node.id);
|
|
|
+ return included.has(node.id);
|
|
|
+ });
|
|
|
+ if (scope.some(node => Number(node.file_count || 0) !== 0 || Number(node.total_file_count || 0) !== 0)) {
|
|
|
+ toastr.error('此分类已存在文件,请先删除所有文件。');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (scope.some(node => Number(node.is_fixed))) {
|
|
|
+ toastr.error('固定分类不可删除');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (scope.some(node => {
|
|
|
+ const permission = this._getFilingPermission(node.id);
|
|
|
+ return !permission.can_view || !permission.can_edit_dir;
|
|
|
+ })) {
|
|
|
+ toastr.error('部分分类或子分类没有编辑目录权限,无法删除');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.selectRemoveNodes = nodes;
|
|
|
+ const list = $('#filesjs-del-filing-list').empty();
|
|
|
+ nodes.forEach(node => { $('<li>').text(node.name || '(未命名分类)').appendTo(list); });
|
|
|
+ $('#filesjs-del-filing-summary').text(`已选择 ${nodes.length} 个分类,确认删除?`);
|
|
|
+ $('#filesjs-del-filing-error').text('');
|
|
|
+ $('#filesjs-del-filing').modal('show');
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// 初始化
|
|
|
@@ -2496,13 +2601,19 @@ $(document).ready(function() {
|
|
|
});
|
|
|
|
|
|
// 删除分类确认弹窗
|
|
|
- $('#del-filing-ok').off('click').on('click', function() {
|
|
|
- if (filingSjs.selectRemoveNode) {
|
|
|
- filingSjs.delFiling(filingSjs.selectRemoveNode, function() {
|
|
|
- $('#del-filing').modal('hide');
|
|
|
+ $('#filesjs-del-filing-ok').on('click', function() {
|
|
|
+ if (filingSjs.selectRemoveNodes.length) {
|
|
|
+ filingSjs.delFiling(filingSjs.selectRemoveNodes, function() {
|
|
|
+ $('#filesjs-del-filing').modal('hide');
|
|
|
});
|
|
|
}
|
|
|
});
|
|
|
+ $('#filesjs-del-filing').on('hide.bs.modal', function(e) {
|
|
|
+ if (filingSjs._directorySaving) e.preventDefault();
|
|
|
+ }).on('hidden.bs.modal', function() {
|
|
|
+ filingSjs.selectRemoveNodes = [];
|
|
|
+ filingSjs.spread.focus();
|
|
|
+ });
|
|
|
|
|
|
// 批量删除确认
|
|
|
$('#batch-del-file-ok').off('click').on('click', function() {
|