本帖最后由 Winny 于 2025-3-28 13:46 编辑
需求背景:在填报项目中,经常会遇到不同客户需要编辑同一个表的不同区域,在SpreadJS V18以前,通过表单保护结合单元格tag就可以实现,具体可以参考示例贴:
SpreadJS特定区域数据保护。这个方案的优势在于功能设置上与Excel中的能力完全相同,可以兼容导入导出。但缺点在于设计过于复杂,需要两步执行。
SpreadJS V18中,推出了allowEditInCell API,通过一行代码即可实现控制哪些区域单元格可以编辑。本文将该功能和用户结合,实现一个简单的编辑权限控制。
实现方案:
1. 自定义右键菜单,在右键菜单中弹出用户组织
- function customeMenu(designer) {
- // 自定义右键菜单
- let config = JSON.parse(JSON.stringify(GC.Spread.Sheets.Designer.DefaultConfig))
- let selectEditUser = {
- "text": "选择编辑人",
- commandName: "selectEditUser",
- execute: (context) => {
- // context代表的是designer对象
- let modal = document.getElementById("modal")
- modal.style.display = "flex"
- }
- }
- // 追加自定义命令
- config.contextMenu.unshift("selectEditUser")
- config.commandMap = {
- selectEditUser
- }
- return config
- }
复制代码
2. 选中目标区域,设计填写范围
在这里,我们对不同角色的用户,将其能编辑的范围写入了名称管理器中。
- document.getElementById("confirmEditUser").onclick = () => {
- let modal = document.getElementById("modal")
- // 获取当前选中的radio
- let selected = document.querySelector('input[name="user"]:checked')
- if (!selected) {
- alert("尚未分配用户")
- } else {
- let user = selected.value
- //获取当前激活的sheet中选中的区域,这里为方便,只拿第一个选中区域
- let spread = designer.getWorkbook()
- let sheet = spread.getActiveSheet()
- let selection = sheet.getSelections()[0]
- let rangeString = GC.Spread.Sheets.rangeToFormula(selection, 0, 0, GC.Spread.Sheets.CalcEngine.RangeReferenceRelative.allRelative)
- // 名称管理不允许重名,如果已经添加过提示需要更新,而不是添加
- if (sheet.getCustomName(user)) {
- let isUpdate = confirm("该用户已经设置过编辑区域,是否需要更新?")
- if (isUpdate) {
- sheet.removeCustomName(user)
- sheet.addCustomName(user, rangeString, 0, 0, `${user}编辑区域`);
- alert("更新成功")
- modal.style.display = "none"
- } else {
- alert("取消更新")
- }
- } else {
- sheet.addCustomName(user, rangeString, 0, 0, `${selected.name}编辑区域`);
- alert("添加成功")
- modal.style.display = "none"
- }
- }
- }
复制代码 3. 切换用户,根据名称管理器区域信息,设置编辑条件。
- select.addEventListener('change', function () {
- const selectedOption = this.options[this.selectedIndex];
- /***
- 切换用前,先保存上个用户编辑记录,对于管理员多有单元格可以编辑,
- 其它权限用户根据配置的区域走
- **/
- let spread = designer.getWorkbook()
- let sheet = spread.getActiveSheet() // demo只处理了一个sheet,实际业务根据sheet数量循环去处理即可
- sheet.suspendPaint()
- if (selectedOption.dataset.editRange === 'all') {
- designer.setConfig(customeConfig)
- sheet.getRange(0,0,sheet.getRowCount(),sheet.getColumnCount()).allowEditInCell(true)
- } else {
- designer.setConfig(JSON.parse(JSON.stringify(GC.Spread.Sheets.Designer.DefaultConfig)))
- let editRange = selectedOption.dataset.editRange
- let customeName = sheet.getCustomName(editRange)
- if (customeName) {
- let customeRef = customeName.getExpression()
- let { row, column, endRow, endColumn } = customeRef
- sheet.getRange(0,0,sheet.getRowCount(),sheet.getColumnCount()).allowEditInCell(false)
- sheet.getRange(row, column, endRow - row+1, endColumn - column+1).allowEditInCell(true)
- } else {
- sheet.getRange(0,0,sheet.getRowCount(),sheet.getColumnCount()).allowEditInCell(false)
- }
- }
- sheet.resumePaint()
- });
复制代码
详细的示例工程和操作教程,参考附件文件。
|
|