基于前端技术实现的全面预算编制系统

葡萄城技术团队
葡萄城官方账号
博客专家认证
2024-03-25 09:52:38

前言

在现代商业环境中,预测销售数据和实际成本是每个公司CEO和领导都极为重视的关键指标。然而,由于市场的不断变化,准确地预测和管理这些数据变得愈发具有挑战性。为了应对这一挑战,建立一个高效的系统来管理和审查销售数据的重要性不言而喻。今天小编就将为大家介绍一下如何使用葡萄城公司的纯前端表格控件SpreadJS实现一个预算编制系统。

环境准备

Node.js

VSCode代码编辑器

完整代码Github地址(可在阅读本文时配合参考使用)

使用代码实现的在线Demo地址(可在阅读本文时配合参考使用)

实现步骤

1)自定义菜单栏

上图中红色方框划出来的菜单栏叫做在线表格编辑器(Designer),Designer的菜单提供了各种定制化的能力,如新增菜单,修改菜单执行的逻辑,修改图标,修改文字以及删除菜单等功能。

观察上图中,首先新建了一个“预算操作(定制按钮)”tab ,此tab内容包括了三部分,分别是“预算类型”、“预算编制”、“数据”。对应的代码如下:

let config = JSON.parse(JSON.stringify(GC.Spread.Sheets.Designer.DefaultConfig));
config.ribbon.push(
    {
    id: "fill-custom",
    text: "预算操作(定制按钮)",
    buttonGroups: [
    {
        label:"预算类型",commandGroup:{}  
    },    
    {
        label: "预算编制", commandGroup:{}
       
    },
    {
        label: "数据", commandGroup:{}
      
    }]
})
designer.setConfig(config)

通过上述代码,我们来看看实现结果:

Ok ,发现添加了一个“预算操作(定制按钮)”tab,点击此tab,已经有了基础框架

接下来,继续,我们设置当前tab为激活状态,加上active属性,这样子页面初始化后看到的当前tab就是“预算操作(定制按钮)”

{
    id: "fill-custom",
    text: "预算操作(定制按钮)",
    active: true,
    buttonGroups: []
}

接下来,我们设置预算模型command, 我们再次看上面的第一张图,发现预算类型只有一个节点,且该节点是一个下拉框。对应的代码实现方式如下:

{
    label:"预算类型",
    commandGroup: {
        children: ["selectBudgetType"]
    }
}, 

接下来定义“selectBudgetType”,代码如下所示:( 关于定义下拉框子菜单的实现方法详细解释,可以参考此篇文章

const budgetType = {
    cost: 'cost' ,   //成本预算
    sales: 'sales'   //销售预算
}
let selectBudgetType = {
    text: "选择预算类型",
    comboWidth: 120,
    type:"comboBox",
    commandName: "selectBudgetType",
    dropdownList:[
        {
            text:"成本预算",
            value: budgetType.cost
        },{
            text:"销售预算",
            value:budgetType.sales
        },
    ],
    execute:(context,propertyName) => {
        console.log('选择',propertyName)
    },
}
config.commandMap = {selectBudgetType}
designer.setConfig(config)

上述代码为子菜单“selectBudgetType”定义了text,type ,以及dropdownList以及点击事件。exexute方法中propertyName对应的是dropdownList中的value值。

结果如下:

上述代码已经熟悉了如何定义菜单以及子菜单,接下来的两个子菜单(预算编制和数据)就不重复详细介绍,直接上代码:

config.ribbon.push(
    {
    id: "fill-custom",
    text: "预算操作(定制按钮)",
    active: true,
    buttonGroups: [
    {
        label:"预算类型",
        commandGroup: {
            children: ["selectBudgetType"]
        }
    },    
    {
        label: "预算编制",
        thumbnailClass: "ribbon-thumbnail-editing",
        commandGroup: {
            children: [ "distributeTask"]
        }
    },
    {
        label: "数据",
        commandGroup: {
            children: ["clearLocalData"]
        }
    }]
})
config.commandMap = {
    selectBudgetType:{
        text: "选择预算类型",
        comboWidth: 120,
        type:"comboBox",
        commandName: "selectBudgetType",
        dropdownList:[
            {
                text:"成本预算",
                value: budgetType.cost
            },{
                text:"销售预算",
                value:budgetType.sales
            },
        ],
        execute:(context,propertyName) => {
              console.log('选择',propertyName)
        }
    },
    distributeTask: {
        title: "下发预算任务",
        text: "预算编制",
        iconClass: "distribute-icon",
        bigButton: true,
        commandName: "distributeTask",
        execute: function (context) {
           
        }
    },
    clearLocalData: {
        title: "清除本地缓存",
        text: "清除本地缓存",
        iconClass: "clear-local-icon",
        bigButton: true,
        commandName: "clearLocalData",
        execute: function () {
            localStorage.clear()
        }
    },
}
designer.setConfig(config)

icon相关代码,注意iconClass要添加相应的背景图片。

.clear-local-icon {
  background: url("../assets/clear.png");
  background-size: 35px 35px;
}
.distribute-icon {
  background: url("../assets/distribute.png");
  background-size: 35px 35px;
}

上述三个子菜单中的execute方法需要自定义,如选择选择预算类型后,模板需要进行切换。

2)设置模板

当“选择预算类型”选择“成本预算”时,加载cost.json文件

当“选择预算类型”选择“销售预算”时,加载sales.json文件

let selectBudgetType = {
    text: "选择预算类型",
    comboWidth: 120,
    type:"comboBox",
    commandName: "selectBudgetType",
    dropdownList:[
        {
            text:"成本预算",
            value: budgetType.cost
        },{
            text:"销售预算",
            value:budgetType.sales
        },
    ],
    execute:(context,propertyName) => {
        if(propertyName){
            selectedBudget.value = propertyName
            loadTemplate(context,propertyName,taskId)
         }  
    },
    getState:(context)=>{
        return selectedBudget.value
    },
}

const loadTemplate = async (designer,fileName,taskId) => {
    let templateStr = await BusinessType.getTemplate(fileName)
    let template = JSON.parse(templateStr)
    let spread = designer.getWorkbook()
    spread.fromJSON(template)  
}

上述代码介绍了【选择预算类型】下拉框选中的事件,选中后,导入对应的json文件,通过fromJSON进行导入。

对于需要设置的模板,可以通过Designer中菜单快速设计,其菜单基本与Excel一致,对于熟悉Excel的用户来说,真的很友好。

3)设置数据源

下面小编以“销售预算”模板为例,介绍如何设置数据源:

点击“数据”tab,接下来点击“工作表绑定”,此时出现右侧字段列表Panel。发现字段列表中存在“id”和“name ",这是因为在模板(sales.json)中已经设置好字段。

此时进行数据绑定setDataSource():

const bindInitialData = (spread,type,taskId) => {
    // 绑定初始数据
    let data = defaultBudgetData[type]
    let source = new GC.Spread.Sheets.Bindings.CellBindingSource(data)
    spread.suspendPaint()
    let sheetCount = spread.getSheetCount()
    for(let i=0; i<sheetCount;i++){
        let sheet = spread.getSheet(i)
        sheet.setDataSource(source)
    }
    spread.resumePaint()
    taskId.value = data.id
}
const defaultBudgetData = {
  [budgetType.cost]: {
    id:`成本NV-${getNowTime()}`,//项目编号
    name:'',    //项目名称
    city: '',   //项目所在地
    customer: '',    //客户名称
    price: 0        //本次报价
},
  [budgetType.sales]:{
    id: `销售NV-${getNowTime()}`,
    name:''
  }
}

4)任务下发

(1)在任务下发前 ,需要确认预测因子,预测因子基于往年数据,确认接下来的销售计划。

(2)填写预算名称 。

(3)点击“预算编制”菜单。

distributeTask: {
    title: "下发预算任务",
    text: "预算编制",
    iconClass: "distribute-icon",
    bigButton: true,
    commandName: "distributeTask",
    execute: function (context) {
        confirmDistribute(context,selectedBudget,distributeVisible)
    }
},

const confirmDistribute = (context,selectBudgetType,distributeVisible) => {
    /**预算任务下发时必填信息校验 */
    let sheet = context.getWorkbook().getSheet(0)
    let source = sheet.getDataSource().getSource()
    for(let key in source){
        if(!source[key]){
            ElMessage.error("红色区域必填项信息缺失")
            return
        }
    }
    // 确认是否下发编制任务
    ElMessageBox.confirm("确认下发预算编制任务吗?","下发确认",{
        confirmButtonText:'确认',
        cancelButtonText:"取消",
        type:'warning'
    }).then(() => {
        // 确认下发,存储当前预算模板,下发部门信息
        saveBudgetRecord(context, selectBudgetType)
        distributeBudgetTask(context,distributeVisible)
    }).catch(() => {
        ElMessage({
            type:'error',
            message:'取消发布'
        })
    })
}

在上述代码confirmDistribute()中,通过getDataSource()获取数据源,来判断红色区域的必填项是否填写。当确认下发任务后,执行saveBudgetRecord 、distributeBudgetTask方法。

5)填写任务

当确定下发任务后,对不同部门生成不同的编制链接。此弹窗可以参考代码中的OnlineDesigner.vue文件。

部门经理获取链接,打开链接,显示内容是自己部门区域预算明细填写和实际填写,此时,部门经理可以在左侧蓝色区域填写,而其他单元格不能编辑,这个是怎么做到的呢?具体可以参考这篇文章中第二点对少部分单元格可以编辑。

var defaultStyle = new GC.Spread.Sheets.Style();
defaultStyle.locked = false;
sheet.setDefaultStyle(defaultStyle, GC.Spread.Sheets.SheetArea.viewport);
// 设置第1行不可编辑
var style = new GC.Spread.Sheets.Style();
style.locked = true;
style.backColor = "red";
sheet.setStyle(0, -1, style);
// 设置表单保护
sheet.options.isProtected = true;  

介绍完单元格的权限后,我们再来看下上图中还有哪些值得说一说的功能。

(1)添加签名

当经理设置完预算后,可以在区域总监单元格右键,看到多出来两个菜单“添加签名”和“添加手写签名”。

所以接下来介绍如何在右键菜单中新增菜单并定义其事件,代码如下:

let signMenu = {
    text:"添加签名",
    name:"signName",
    command:"signMenuCommand",
    workArea: "viewport"
}
spread.contextMenu.menuData.push(signMenu)

上述代码在spread.contextMenu.menuData中push了一条对象,结果就是可以在右键菜单中看见“添加签名菜单” ,观察到上述对象定义了command属性,接下来定义“signMenuCommand”:

let signMenuCommand = {
    canUndo: true,
    execute: function(context,options,isUndo){
        if(isUndo){
            GC.Spread.Sheets.Commands.undoTransaction(context,options)
            return true
        }else{
            GC.Spread.Sheets.Commands.startTransaction(context,options)
            let {activeRow,activeCol,sheetName} = options
            let sheet = context.getSheetFromName(sheetName)
            sheet.getCell(activeRow,activeCol).value(user).backColor('#F7A711').font('bold normal 15px normal')
            GC.Spread.Sheets.Commands.endTransaction(context,options)
            return true
        }
    }
}
commandManager.register("signMenuCommand",signMenuCommand,null, false, false, false, false)

上述代码是SpreadJS中注册命令的方法,并提供了撤销机制。我们主要看else里面的内容:首先从上下文context中获取sheet对象,接着获取单元格并设置内容、背景色、字体等。上述两段代码就实现了在SpreadJS中在右键菜单中添加菜单,并完整相应的点击逻辑。

(2)添加手写签名

接下来,我们看看如何设置“添加手写签名”:

// 注册签名的右键菜单
let commandManager = spread.commandManager()
let signMenu = {
    text:"添加手写签名",
    name:"handWriteName",
    command:"handWriteCommand",
    workArea: "viewport"
}
spread.contextMenu.menuData.push(signMenu)
let handWriteCommand = {
    canUndo: false,
    execute: function(context,options,isUndo){
        showWriteDialog.value = true
    }
}
commandManager.register("handWriteCommand",handWriteCommand,null, false, false, false, false)

添加菜单和菜单命令的方式与前文一致,不同的就是execute的执行逻辑。

最后,签名设置后,就可以点击“提交预算”按钮。

对了,如果数据不符合预期,可能会有红色预警,比如

这个是SpreadJS的数据验证功能,我们可以通过UI方式设置。如下图所示:

6)编制完成

当所有部门经理填写完预算后,就可以点击“编制完成”

此时点击“预算审核”,预算类型设置为“销售预算”,可以看到有一条待审核的标签,点进去看看。

看到了我们熟悉的页面

此时点击“华东”sheet看看

这个时候就看到了华东部门经理填写的销售预测数据,这个时候点击右上角的“导入年度实际销售数据”看看。

嗯,表格内容基本上填写完整了,这时候审核员(副总经理)如果对销售数据表示满意,可以签上自己的大名,就可以点击“审核完毕了”

当四个sheet都“审核完毕”,此时返回首页,发现标签变了。

这时候可以进行打印了。

最后

简单的全面预算编制系统就算介绍完了。大家可以在Demo地址实际体验下。总结下本文介绍的SpreadJS的几个知识点:

1、自定义Designer菜单

2、导入模板

3、设置数据源

4、获取数据源

5、自定义右键菜单

6、单元格权限

如果您想了解更多的信息,欢迎点击这篇参考资料查看。

扩展链接:

【干货放送】财务报表勾稽分析要点,一文读尽!

为什么你的财务报表不出色?推荐你了解这四个设计要点和!

纯前端类 Excel 表格控件在报表勾稽分析领域的应用场景解析

...全文
879 1 打赏 收藏 转发到动态 举报
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复

软著代理申请,包通过 未通过退全款。
【办理时间】
软著受理后60日,审查没问题下证;
如果审查期间出现补正,下证时间会拉长,最终看版权中心发放证书时间为准。
【加急的优势】
下证大概快半个月,1.5个月下证;
出现补正不会延长审查时间;
下证率高,99%!

财会审计 46 2020第4期 【摘 要】  随着大数据时代的到来,会计信息的获取变得 越来越便捷。对于财务会计来说大数据犹如一把双刃剑,在给 会计工作人员带来便捷的同时,也给会计的工作带来了新的挑 战。本文以大数据的概念及特点为基础,分析大数据时代对会 计的管理模式、信息安全等方面带来的影响。 【关键词】  大数据 会计 财务数据 1. 相关概念 1.1 大数据的概念。大数据本身没有什么概念,只是大量 的图片、文字等信息汇集到一起所形成的数据库。是指以多元 形式,许多来源搜集而构成的庞大数据组,往往具有实时性。 本文将大数据引申为需要新处理模式才能具有更强的决策力、 洞察力和流程优化能力的海量、高增长率和多样化的信息资产。 对大数据来说可以不用随机分析法这样的捷径,而是可以对所 有数据进行分析处理。 大数据时代下,大数据主要有数据体量巨大、数据类型繁 多、价值密度低、处理速度快等特点。大数据正在迅速发展, 当下我们的生活被各类数据信息包围着。很多企业高层管理者 并没有认识到大数据时代会对会计工作产生何种影响,对于会 计工作的职能定位只局限于核算功能,并没有向管理功能方向 延伸,也没有针对会计报表中有价值的数据进行挖掘与利用。 1.2 会计的概念。会计是以会计凭证为依据,以货币为主 要计量单位,以提高经济效益为主要目标,运用专门方法对企 业及其他组织的经济活动进行全面、连续、系统地核算和监督, 提供会计信息,并随着社会经济的日益发展,逐步开展预测、 决策、控制和分析的一种经济管理活动,是经济管理活动的重 要组成部分。并向相关会计信息使用者提供符合会计法律法规 和规章制度要求的会计信息的一项管理工作。 2. 大数据时代对会计的影响 2.1 实现财务数据一体化。财务会计具有核算、 监督、 评价、 决策的职能。财务会计人员每天做的最基础的工作就是数据核 算。传统的财务会计流程是财务人员根据业务员提交的业务数 据进行核算和决算,需要会计经常审核业务部门提出的各项申 请。而大数据时代的到来,使得数据来得及时来的准确,财务 人员可以对当下的数据进行实时处理,还可以更便捷的获取历 史数据,给财务人员提供了一个可以和数据面对面交流的机会。 财务人员可以随时接触到业务前端,实时分析,实时挖掘出有 效又实用的信息。 在报表分析过程中,也可以利用大数据的不同处理方式, 提高数据处理效率,对数据进行多维度展开分析,形成多样化 的财务报告。在风险识别、风险分析和风险评价中,还可以利 用大数据查找出企业风险,并分析数据特征,评价各种风险对 企业实现目标的影响程度,排列风险次序等。 2.2 实现财务信息增值,提高财务决策的可靠性。现在大 部分的企业在预算分析过程中很多都是依靠初级的、比较简单 的数据进行分析,距离专业的财务分析还有一定的距离,所以 往往容易导致预算偏离实际。而大数据信息技术可以全面的对 企业的各个流程、各个阶段的数据以及企业内外部数据进行全 面而系统的分析,可以帮助实现大数据下企业全面预算管理的 目标,实现目标分解、预算编制、预算执行与监督,以及预算 与绩效管理的有效集成。 通过优化企业内部资源配置,实现客户需求的精准定位, 在准确预测市场的情况下生产,基于大数据的财务决策,利用 大数据的优势,为企业的决策者提供良好的策略。并且大数据 时代提供的数据种类繁多,很多种数据信息可以同时描述同一 种事物,在这样的情况下,财务工作者在对同一个方面进行判 断的同时,可以收集到更多更有力的数据以支持自己的结论。 更多的数据种类和更大的数据量可以帮助发现更多的事实,提 高财务决策的可信赖程度。 2.3 对会计信息要求更高。大数据时代的到来,其标志是 大量的数据和信息的出现,预示着会计工作者对各种各样的信 息都应该给予全面关注,这样才能牢牢抓住有效信息。但是由 于财务数据来源比较复杂,会计工作者除了需要处理结构化信 息以外还需要特别关注非结构化信息。这样就要求会计信息要 具有相关性,有用性,保证能够收集到决策有用的财务信息, 这样会计工作才能顺利开展。除此之外,会计信息还必须保证 准确性,围绕精确而且相关的会计信息进行工作从而做出有效 的财务决策。随着会计信息数量的增加,会计信息的处理难度 就不断加大,会计工作者加工会计信息的工作量也随之加大, 需要反复检查财务数据,才能保证数据的准确性,这就预示着 会计人员要花费大量的精力在信息选择上。 2.4 财务数据的安全性受到挑战。在大数据时代,人们既 享受着数据共享的便捷性,又不得不面临信息安全的问题。尤 其对于企业的财务信息来说,记载着企业经营发展和管理决策 等诸多重要数据,其安全可靠性、真实完整性对于企业的发展 而言意义重大。但是,从当前的会计信息安全管理成效来看, 除了一些技术上的漏洞以外,还存在着财务软件

87,914

社区成员

发帖
与我相关
我的任务
社区描述
Web 开发 JavaScript
社区管理员
  • JavaScript
  • 无·法
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧