|
@@ -1,3 +1,4 @@
|
|
|
+
|
|
|
function setAlign(sheet, headers) {
|
|
|
const fuc = () => {
|
|
|
headers.forEach(({ hAlign, vAlign }, index) => {
|
|
@@ -32,6 +33,15 @@ function showData(sheet, data, headers, emptyRows) {
|
|
|
const TIME_OUT = 10000;
|
|
|
const libID = window.location.search.match(/libID=([^&]+)/)[1];
|
|
|
|
|
|
+const UpdateType = {
|
|
|
+ UPDATE: 'update',
|
|
|
+ DELETE: 'delete',
|
|
|
+ CREATE: 'create',
|
|
|
+};
|
|
|
+
|
|
|
+const DEBOUNCE_TIME = 200;
|
|
|
+
|
|
|
+const locked = lockUtil.getLocked();
|
|
|
|
|
|
// 地区表
|
|
|
const AREA_BOOK = (() => {
|
|
@@ -41,6 +51,8 @@ const AREA_BOOK = (() => {
|
|
|
};
|
|
|
// 初始化表格
|
|
|
const workBook = initSheet($('#area-spread')[0], setting);
|
|
|
+ lockUtil.lockSpreads([workBook], locked);
|
|
|
+ workBook.options.allowExtendPasteRange = false;
|
|
|
const sheet = workBook.getSheet(0);
|
|
|
|
|
|
// 显示数据
|
|
@@ -78,15 +90,16 @@ const AREA_BOOK = (() => {
|
|
|
|
|
|
const curArea = { ID: null };
|
|
|
// 焦点变更处理
|
|
|
+ const debounceSelectionChanged = _.debounce(function (e, info) {
|
|
|
+ const row = info.newSelections && info.newSelections[0] ? info.newSelections[0].row : 0;
|
|
|
+ handleSelectionChanged(row);
|
|
|
+ }, DEBOUNCE_TIME, { leading: true }); // leading = true : 先触发再延迟
|
|
|
function handleSelectionChanged(row) {
|
|
|
const areaItem = cache[row];
|
|
|
curArea.ID = areaItem && areaItem.ID || null;
|
|
|
CLASS_BOOK.initData(libID, curArea.ID);
|
|
|
}
|
|
|
- sheet.bind(GC.Spread.Sheets.Events.SelectionChanged, function (e, info) {
|
|
|
- const row = info.newSelections && info.newSelections[0] ? info.newSelections[0].row : 0;
|
|
|
- handleSelectionChanged(row);
|
|
|
- });
|
|
|
+ sheet.bind(GC.Spread.Sheets.Events.SelectionChanged, debounceSelectionChanged);
|
|
|
|
|
|
// 新增
|
|
|
async function insert() {
|
|
@@ -111,7 +124,7 @@ const AREA_BOOK = (() => {
|
|
|
$.bootstrapLoading.end();
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// 删除
|
|
|
async function del() {
|
|
|
try {
|
|
@@ -153,6 +166,9 @@ const AREA_BOOK = (() => {
|
|
|
insert: {
|
|
|
name: '新增',
|
|
|
icon: "fa-arrow-left",
|
|
|
+ disabled: function () {
|
|
|
+ return locked;
|
|
|
+ },
|
|
|
callback: function (key, opt) {
|
|
|
insert();
|
|
|
}
|
|
@@ -161,7 +177,7 @@ const AREA_BOOK = (() => {
|
|
|
name: '删除',
|
|
|
icon: "fa-arrow-left",
|
|
|
disabled: function () {
|
|
|
- return !cache[target.row];
|
|
|
+ return locked || !cache[target.row];
|
|
|
},
|
|
|
callback: function (key, opt) {
|
|
|
del();
|
|
@@ -214,6 +230,7 @@ const CLASS_BOOK = (() => {
|
|
|
};
|
|
|
// 初始化表格
|
|
|
const workBook = initSheet($('#class-spread')[0], setting);
|
|
|
+ workBook.options.allowExtendPasteRange = false;
|
|
|
const sheet = workBook.getSheet(0);
|
|
|
|
|
|
let tree;
|
|
@@ -236,6 +253,8 @@ const CLASS_BOOK = (() => {
|
|
|
controller = TREE_SHEET_CONTROLLER.createNew(tree, sheet, setting.controller, false);
|
|
|
controller.showTreeData();
|
|
|
handleSelectionChanged(0);
|
|
|
+ sheet.setSelection(0, 0, 1, 1);
|
|
|
+ lockUtil.lockSpreads([workBook], locked);
|
|
|
} catch (err) {
|
|
|
tree = null;
|
|
|
controller = null;
|
|
@@ -252,13 +271,14 @@ const CLASS_BOOK = (() => {
|
|
|
changedCells.forEach(({ row, col }) => {
|
|
|
updateData.push({
|
|
|
row,
|
|
|
- ID: tree.items[row].data.ID,
|
|
|
- name: sheet.getValue(row, col)
|
|
|
+ type: UpdateType.UPDATE,
|
|
|
+ filter: { ID: tree.items[row].data.ID },
|
|
|
+ update: { name: sheet.getValue(row, col) }
|
|
|
});
|
|
|
});
|
|
|
try {
|
|
|
await ajaxPost('/priceInfo/editClassData', { updateData }, TIME_OUT);
|
|
|
- updateData.forEach(({ row, name }) => tree.items[row].data.name = name);
|
|
|
+ updateData.forEach(({ row, update: { name } }) => tree.items[row].data.name = name);
|
|
|
} catch (err) {
|
|
|
// 恢复各单元格数据
|
|
|
sheetCommonObj.renderSheetFunc(sheet, () => {
|
|
@@ -276,17 +296,330 @@ const CLASS_BOOK = (() => {
|
|
|
handleEdit(info.changedCells);
|
|
|
});
|
|
|
|
|
|
+ // 树操作相关
|
|
|
+ const $insert = $('#tree-insert');
|
|
|
+ const $remove = $('#tree-remove');
|
|
|
+ const $upLevel = $('#tree-up-level');
|
|
|
+ const $downLevel = $('#tree-down-level');
|
|
|
+ const $downMove = $('#tree-down-move');
|
|
|
+ const $upMove = $('#tree-up-move');
|
|
|
+
|
|
|
+ // 插入
|
|
|
+ let canInsert = true;
|
|
|
+ async function insert() {
|
|
|
+ try {
|
|
|
+ if (!canInsert) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ canInsert = false;
|
|
|
+ $.bootstrapLoading.start();
|
|
|
+ const updateData = [];
|
|
|
+ const selected = tree.selected;
|
|
|
+ const newItem = {
|
|
|
+ libID,
|
|
|
+ areaID: AREA_BOOK.curArea.ID,
|
|
|
+ ID: uuid.v1(),
|
|
|
+ name: '',
|
|
|
+ ParentID: '-1',
|
|
|
+ NextSiblingID: '-1'
|
|
|
+ };
|
|
|
+ if (selected) {
|
|
|
+ newItem.ParentID = selected.data.ParentID;
|
|
|
+ updateData.push({
|
|
|
+ type: UpdateType.UPDATE,
|
|
|
+ filter: { ID: selected.data.ID },
|
|
|
+ update: { NextSiblingID: newItem.ID }
|
|
|
+ });
|
|
|
+ if (selected.nextSibling) {
|
|
|
+ newItem.NextSiblingID = selected.nextSibling.data.ID;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ updateData.push({
|
|
|
+ type: UpdateType.CREATE,
|
|
|
+ document: newItem
|
|
|
+ });
|
|
|
+ await ajaxPost('/priceInfo/editClassData', { updateData });
|
|
|
+ controller.insertByID(newItem.ID);
|
|
|
+ handleSelectionChanged(sheet.getActiveRowIndex());
|
|
|
+ } catch (err) {
|
|
|
+ alert(err);
|
|
|
+ } finally {
|
|
|
+ canInsert = true;
|
|
|
+ $.bootstrapLoading.end();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ $insert.click(_.debounce(insert, DEBOUNCE_TIME, { leading: true }));
|
|
|
+
|
|
|
+ // 删除
|
|
|
+ let canRemove = true;
|
|
|
+ async function remove() {
|
|
|
+ try {
|
|
|
+ if (!canRemove) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ canRemove = false;
|
|
|
+ $.bootstrapLoading.start();
|
|
|
+ const updateData = [];
|
|
|
+ const selected = tree.selected;
|
|
|
+ const children = selected.getPosterity();
|
|
|
+ [selected, ...children].forEach(node => updateData.push({
|
|
|
+ type: UpdateType.DELETE,
|
|
|
+ filter: { ID: node.data.ID }
|
|
|
+ }));
|
|
|
+ if (selected.preSibling) {
|
|
|
+ updateData.push({
|
|
|
+ type: UpdateType.UPDATE,
|
|
|
+ filter: { ID: selected.preSibling.data.ID },
|
|
|
+ update: { NextSiblingID: selected.data.NextSiblingID }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ await ajaxPost('/priceInfo/editClassData', { updateData });
|
|
|
+ controller.delete();
|
|
|
+ handleSelectionChanged(sheet.getActiveRowIndex());
|
|
|
+ } catch (err) {
|
|
|
+ alert(err);
|
|
|
+ } finally {
|
|
|
+ canRemove = true;
|
|
|
+ $.bootstrapLoading.end();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ $remove.click(_.debounce(remove, DEBOUNCE_TIME, { leading: true }));
|
|
|
+
|
|
|
+ // 升级
|
|
|
+ let canUpLevel = true;
|
|
|
+ async function upLevel() {
|
|
|
+ try {
|
|
|
+ if (!canUpLevel) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ canUpLevel = false;
|
|
|
+ $.bootstrapLoading.start();
|
|
|
+ const updateData = [];
|
|
|
+ const selected = tree.selected;
|
|
|
+ if (selected.preSibling) {
|
|
|
+ updateData.push({
|
|
|
+ type: UpdateType.UPDATE,
|
|
|
+ filter: { ID: selected.preSibling.data.ID },
|
|
|
+ update: { NextSiblingID: -1 }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ if (selected.parent) {
|
|
|
+ updateData.push({
|
|
|
+ type: UpdateType.UPDATE,
|
|
|
+ filter: { ID: selected.parent.data.ID },
|
|
|
+ update: { NextSiblingID: selected.data.ID }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ updateData.push({
|
|
|
+ type: UpdateType.UPDATE,
|
|
|
+ filter: { ID: selected.data.ID },
|
|
|
+ update: { ParentID: selected.parent.data.ParentID, NextSiblingID: selected.parent.data.NextSiblingID }
|
|
|
+ });
|
|
|
+ let curNode = selected.nextSibling;
|
|
|
+ while (curNode) {
|
|
|
+ updateData.push({
|
|
|
+ type: UpdateType.UPDATE,
|
|
|
+ filter: { ID: curNode.data.ID },
|
|
|
+ update: { ParentID: selected.data.ID }
|
|
|
+ });
|
|
|
+ curNode = curNode.nextSibling;
|
|
|
+ }
|
|
|
+ await ajaxPost('/priceInfo/editClassData', { updateData });
|
|
|
+ controller.upLevel();
|
|
|
+ refreshTreeButton(tree.selected);
|
|
|
+ } catch (err) {
|
|
|
+ alert(err);
|
|
|
+ } finally {
|
|
|
+ canUpLevel = true;
|
|
|
+ $.bootstrapLoading.end();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ $upLevel.click(_.debounce(upLevel, DEBOUNCE_TIME, { leading: true }));
|
|
|
+
|
|
|
+ // 降级
|
|
|
+ let canDownLevel = true;
|
|
|
+ async function downLevel() {
|
|
|
+ try {
|
|
|
+ if (!canDownLevel) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ canDownLevel = false;
|
|
|
+ $.bootstrapLoading.start();
|
|
|
+ const updateData = [];
|
|
|
+ const selected = tree.selected;
|
|
|
+ if (selected.preSibling) {
|
|
|
+ updateData.push({
|
|
|
+ type: UpdateType.UPDATE,
|
|
|
+ filter: { ID: selected.preSibling.data.ID },
|
|
|
+ update: { NextSiblingID: selected.data.NextSiblingID }
|
|
|
+ });
|
|
|
+ const preSiblingLastChild = selected.preSibling.children[selected.preSibling.children.length - 1];
|
|
|
+ if (preSiblingLastChild) {
|
|
|
+ updateData.push({
|
|
|
+ type: UpdateType.UPDATE,
|
|
|
+ filter: { ID: preSiblingLastChild.data.ID },
|
|
|
+ update: { NextSiblingID: selected.data.ID }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ updateData.push({
|
|
|
+ type: UpdateType.UPDATE,
|
|
|
+ filter: { ID: selected.data.ID },
|
|
|
+ update: { ParentID: selected.preSibling.data.ID, NextSiblingID: -1 }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ await ajaxPost('/priceInfo/editClassData', { updateData });
|
|
|
+ controller.downLevel();
|
|
|
+ refreshTreeButton(tree.selected);
|
|
|
+ } catch (err) {
|
|
|
+ alert(err);
|
|
|
+ } finally {
|
|
|
+ canDownLevel = true;
|
|
|
+ $.bootstrapLoading.end();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ $downLevel.click(_.debounce(downLevel, DEBOUNCE_TIME, { leading: true }));
|
|
|
+
|
|
|
+ // 下移
|
|
|
+ let canDownMove = true;
|
|
|
+ async function downMove() {
|
|
|
+ try {
|
|
|
+ if (!canDownMove) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ canDownMove = false;
|
|
|
+ $.bootstrapLoading.start();
|
|
|
+ const updateData = [];
|
|
|
+ const selected = tree.selected;
|
|
|
+ if (selected.preSibling) {
|
|
|
+ updateData.push({
|
|
|
+ type: UpdateType.UPDATE,
|
|
|
+ filter: { ID: selected.preSibling.data.ID },
|
|
|
+ update: { NextSiblingID: selected.data.NextSiblingID }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ updateData.push({
|
|
|
+ type: UpdateType.UPDATE,
|
|
|
+ filter: { ID: selected.data.ID },
|
|
|
+ update: { NextSiblingID: selected.nextSibling.data.NextSiblingID }
|
|
|
+ });
|
|
|
+ updateData.push({
|
|
|
+ type: UpdateType.UPDATE,
|
|
|
+ filter: { ID: selected.nextSibling.data.ID },
|
|
|
+ update: { NextSiblingID: selected.data.ID }
|
|
|
+ });
|
|
|
+ await ajaxPost('/priceInfo/editClassData', { updateData });
|
|
|
+ controller.downMove();
|
|
|
+ refreshTreeButton(tree.selected);
|
|
|
+ } catch (err) {
|
|
|
+ alert(err);
|
|
|
+ } finally {
|
|
|
+ canDownMove = true;
|
|
|
+ $.bootstrapLoading.end();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ $downMove.click(_.debounce(downMove, DEBOUNCE_TIME, { leading: true }));
|
|
|
+
|
|
|
+ // 上移
|
|
|
+ let canUpMove = true;
|
|
|
+ async function upMove() {
|
|
|
+ try {
|
|
|
+ if (!canUpMove) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ canUpMove = false;
|
|
|
+ $.bootstrapLoading.start();
|
|
|
+ const updateData = [];
|
|
|
+ const selected = tree.selected;
|
|
|
+ if (selected.preSibling) {
|
|
|
+ updateData.push({
|
|
|
+ type: UpdateType.UPDATE,
|
|
|
+ filter: { ID: selected.preSibling.data.ID },
|
|
|
+ update: { NextSiblingID: selected.data.NextSiblingID }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ const prePreSibling = selected.preSibling.preSibling;
|
|
|
+ if (prePreSibling) {
|
|
|
+ updateData.push({
|
|
|
+ type: UpdateType.UPDATE,
|
|
|
+ filter: { ID: prePreSibling.data.ID },
|
|
|
+ update: { NextSiblingID: selected.data.ID }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ updateData.push({
|
|
|
+ type: UpdateType.UPDATE,
|
|
|
+ filter: { ID: selected.data.ID },
|
|
|
+ update: { NextSiblingID: selected.preSibling.data.ID }
|
|
|
+ });
|
|
|
+ await ajaxPost('/priceInfo/editClassData', { updateData });
|
|
|
+ controller.upMove();
|
|
|
+ refreshTreeButton(tree.selected);
|
|
|
+ } catch (err) {
|
|
|
+ alert(err);
|
|
|
+ } finally {
|
|
|
+ canUpMove = true;
|
|
|
+ $.bootstrapLoading.end();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ $upMove.click(_.debounce(upMove, DEBOUNCE_TIME, { leading: true }));
|
|
|
+
|
|
|
+
|
|
|
+ // 刷新树操作按钮有效性
|
|
|
+ function refreshTreeButton(selected) {
|
|
|
+ if (locked) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ $insert.removeClass('disabled');
|
|
|
+ $remove.removeClass('disabled');
|
|
|
+ $upLevel.removeClass('disabled');
|
|
|
+ $downLevel.removeClass('disabled');
|
|
|
+ $downMove.removeClass('disabled');
|
|
|
+ $upMove.removeClass('disabled');
|
|
|
+ if (!selected) {
|
|
|
+ $remove.addClass('disabled');
|
|
|
+ $upLevel.addClass('disabled');
|
|
|
+ $downLevel.addClass('disabled');
|
|
|
+ $downMove.addClass('disabled');
|
|
|
+ $upMove.addClass('disabled');
|
|
|
+ } else {
|
|
|
+ if (!selected.preSibling) {
|
|
|
+ $downLevel.addClass('disabled');
|
|
|
+ $upMove.addClass('disabled');
|
|
|
+ }
|
|
|
+ if (!selected.nextSibling) {
|
|
|
+ $downMove.addClass('disabled');
|
|
|
+ }
|
|
|
+ if (!selected.parent) {
|
|
|
+ $upLevel.addClass('disabled');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// 焦点变更处理
|
|
|
const curClass = { ID: null };
|
|
|
function handleSelectionChanged(row) {
|
|
|
- const classNode = tree.items[row];
|
|
|
+ const classNode = tree.items[row] || null;
|
|
|
+ tree.selected = classNode;
|
|
|
+ refreshTreeButton(classNode);
|
|
|
curClass.ID = classNode && classNode.data && classNode.data.ID || null;
|
|
|
- PRICE_BOOK.initData(curClass.ID);
|
|
|
+ const classIDList = []
|
|
|
+ if (classNode) {
|
|
|
+ classIDList.push(classNode.data.ID);
|
|
|
+ const children = classNode.getPosterity();
|
|
|
+ children.forEach(child => classIDList.push(child.data.ID));
|
|
|
+ }
|
|
|
+ PRICE_BOOK.initData(classIDList);
|
|
|
}
|
|
|
- sheet.bind(GC.Spread.Sheets.Events.SelectionChanged, function (e, info) {
|
|
|
+ const debounceSelectionChanged = _.debounce(function (e, info) {
|
|
|
const row = info.newSelections && info.newSelections[0] ? info.newSelections[0].row : 0;
|
|
|
handleSelectionChanged(row);
|
|
|
- });
|
|
|
+ }, DEBOUNCE_TIME, { leading: true });
|
|
|
+ sheet.bind(GC.Spread.Sheets.Events.SelectionChanged, debounceSelectionChanged);
|
|
|
|
|
|
return {
|
|
|
initData,
|
|
@@ -310,6 +643,7 @@ const PRICE_BOOK = (() => {
|
|
|
};
|
|
|
// 初始化表格
|
|
|
const workBook = initSheet($('#price-spread')[0], setting);
|
|
|
+ lockUtil.lockSpreads([workBook], locked);
|
|
|
const sheet = workBook.getSheet(0);
|
|
|
|
|
|
let cache = [];
|
|
@@ -319,13 +653,13 @@ const PRICE_BOOK = (() => {
|
|
|
sheet.setRowCount(0);
|
|
|
}
|
|
|
// 初始化数据
|
|
|
- async function initData(classID) {
|
|
|
- if (!classID) {
|
|
|
+ async function initData(classIDList) {
|
|
|
+ if (!classIDList || !classIDList.length) {
|
|
|
return clear();
|
|
|
}
|
|
|
$.bootstrapLoading.start();
|
|
|
try {
|
|
|
- cache = await ajaxPost('/priceInfo/getPriceData', { classID }, TIME_OUT);
|
|
|
+ cache = await ajaxPost('/priceInfo/getPriceData', { classIDList }, TIME_OUT);
|
|
|
showData(sheet, cache, setting.header, 5);
|
|
|
} catch (err) {
|
|
|
cache = [];
|
|
@@ -381,11 +715,11 @@ const PRICE_BOOK = (() => {
|
|
|
if (Object.keys(rowData).length) { // 还有数据,更新
|
|
|
const diffData = getRowDiffData(rowData, cache[row], setting.header);
|
|
|
if (diffData) {
|
|
|
- postData.push({ type: 'update', ID: cache[row].ID, data: diffData });
|
|
|
+ postData.push({ type: UpdateType.UPDATE, ID: cache[row].ID, data: diffData });
|
|
|
updateData.push({ row, data: diffData });
|
|
|
}
|
|
|
} else { // 该行无数据了,删除
|
|
|
- postData.push({ type: 'delete', ID: cache[row].ID });
|
|
|
+ postData.push({ type: UpdateType.DELETE, ID: cache[row].ID });
|
|
|
deleteData.push(cache[row]);
|
|
|
}
|
|
|
} else { // 新增
|
|
@@ -395,7 +729,7 @@ const PRICE_BOOK = (() => {
|
|
|
rowData.libID = libID;
|
|
|
rowData.areaID = AREA_BOOK.curArea.ID;
|
|
|
rowData.classID = CLASS_BOOK.curClass.ID;
|
|
|
- postData.push({ type: 'create', data: rowData });
|
|
|
+ postData.push({ type: UpdateType.CREATE, data: rowData });
|
|
|
insertData.push(rowData);
|
|
|
}
|
|
|
}
|
|
@@ -445,5 +779,8 @@ const PRICE_BOOK = (() => {
|
|
|
})();
|
|
|
|
|
|
$(document).ready(() => {
|
|
|
+ $('[data-toggle="tooltip"]').tooltip();
|
|
|
AREA_BOOK.handleSelectionChanged(0);
|
|
|
+ const $range = $(document.body);
|
|
|
+ lockUtil.lockTools($range, locked);
|
|
|
});
|