Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

charlesProject/Account

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

89 Commits

Repository files navigation

最近正在学习Vue2.0相关知识,正好近期饿了么桌面端组件Element-UI发布,便动手做了一款简易个人记账系统,以达到实践及巩固目的。

1.开发环境 Win10 + VS2015 + Sqlserver2008R2 + WebAPI + Dapper + Vue2.0 + Element-UI

2.项目解决方案概览

简单介绍下,Account是WebAPI项目,承载前端请求;Account.BLL、Account.DAL、Account.Entity不废话;Account.Common是对Dapper及Log4net等简单封装;KnockoutFE是较早时候弄的一个基于Bootstrap + Knockout的前端;VueFE是主角,待会儿重点介绍。

Account工程截图:

Account.Common工程截图:

VueFE工程截图:

3.前端实现 初始界面:

1.左边导航部分 使用el-menu + vue-router实现:

复制代码

日消费明细 日消费清单 月消费清单 年消费清单
复制代码

注释掉部分是最开始时候没有采用el-menu组件导航,而是使用了vue-router自己的路由导航。

路由部分对应JS代码:

复制代码 const router = new VueRouter({ routes: [ { name: "manifests", path: "/manifests", component: Manifests }, { name: "daily", path: "/daily", component: Daily }, { name: "monthly", path: "/monthly", component: Monthly }, { name: "yearly", path: "/yearly", component: Yearly } ] }); 复制代码 其中,Manifests、Daily、Monthly、Yearly分别代表日消费明细、日消费清单、月消费清单、年消费清单自定义Vue组件。

2.具体内容页组件实现 这里以日消费明细组件为例来详细介绍,里边囊括了CRUD。

组件完整定义: 复制代码 /// /// /// ///

const Manifests = { template: "#manifests", created: function () { this.fetchData(); }, data: function () { let currentDate = new Date(); let costValidator = (rule, value, callback) => { if (!/^[0-9]+(.[0-9]{2})?$/.test(value)) { callback(new Error("请输入合法金额")); } else { callback(); } }; return { start: new Date(currentDate.getFullYear(), currentDate.getMonth() - 3, 1), end: new Date(), manifests: [], title: "", manifest: {}, showOperateManifest: false, isAdd: false, rules: { Date: [ { type: "date", required: true, message: "请选择消费日期", trigger: "change" } ], Cost: [ { required: true, message: "请填写消费金额", trigger: "blur" }, { validator: costValidator, trigger: "change" } ], Remark: [ { required: true, message: "请填写消费明细", trigger: "blur" } ] }, pageIndex: 0, pageSize: 10, total: 0, pageSizes: [10, 20, 50, 100] } }, methods: { fetchData: function () { this.manifests = []; this.$http.get("http://localhost:1500/api/Manifests/paged", { params: { start: this.start.format("yyyy-MM-dd"), end: this.end.format("yyyy-MM-dd"), pageIndex: this.pageIndex, pageSize: this.pageSize } }) .then(response => { this.total = response.body.count; this.manifests = response.body.data; }) .catch(response => this.$alert(response.body.Message, "日消费明细", { type: "error" })); }, add: function () { this.title = "添加消费明细"; this.manifest = { ID: Guid.NewGuid().ToString("D"), Date: new Date(), Cost: "", Remark: "" }; this.isAdd = true; this.showOperateManifest = true; }, save: function () { this.$refs.formManifest.validate(valid => { if (valid) { let operateManifest = JSON.parse(JSON.stringify(this.manifest)); operateManifest.Date = this.manifest.Date.format("yyyy-MM-dd"); if (this.isAdd) { this.$http.post("http://localhost:1500/api/Manifests", operateManifest) .then(() => { this.manifests.push(operateManifest); this.showOperateManifest = false; bus.$emit("manifestChanged"); this.$message({ message: "添加成功", type: "success" }); }) .catch(err => { //console.log(err); this.$alert(err.body.Message, "添加日消费明细", { type: "error" }); }); } else { this.$http.put("http://localhost:1500/api/Manifests", operateManifest) .then(response => { let updatedManifest = this.manifests.find(x => x.ID == this.manifest.ID); updatedManifest.Date = operateManifest.Date; updatedManifest.Cost = operateManifest.Cost; updatedManifest.Remark = operateManifest.Remark; this.showOperateManifest = false; bus.$emit("manifestChanged"); this.$message({ message: "修改成功", type: "success" }); }) .catch(err => { //console.log(err); this.$alert(err.body.Message, "修改消费明细", { type: "error" }); }); } } else { return false; } }); }, cancel: function () { this.manifest = {}; this.showOperateManifest = false; }, edit: function (ID) { let currentManifest = this.manifests.find(x => x.ID == ID); this.manifest = JSON.parse(JSON.stringify(currentManifest)); this.manifest.Date = new Date(this.manifest.Date); this.title = "编辑消费明细"; this.isAdd = false; this.showOperateManifest = true; }, del: function (ID) { this.$confirm("是否删除?", "警告", { type: "warning" }) .then(() => { this.$http.delete("http://localhost:1500/api/Manifests/" + ID) .then(response => { let index = this.manifests.findIndex(x => x.ID == ID); this.manifests.splice(index, 1); bus.$emit("manifestChanged"); this.$message({ message: "删除成功", type: "success" }); }) .catch(err => { this.$alert(err.body.Message, "删除消费明细", { type: "error" }); //console.log(err); }); }); }, dialogClosed: function () { this.$refs.formManifest.resetFields(); }, sizeChange: function (pageSize) { this.pageSize = pageSize; this.fetchData(); }, pageIndexChange: function (pageIndex) { this.pageIndex = pageIndex; this.fetchData(); } } } 复制代码 组件对应的模板定义: 复制代码

<script type="text/x-template" id="manifests">
开始日期: 结束日期: 查 询 添 加
编 辑 删 除
确 定 取 消
</script>

复制代码

查询部分 :

复制代码

开始日期: 结束日期: 查 询 添 加
复制代码

这里关于事件处理绑定,官网推荐简写的@click,但这里没有采用,而是使用了完整绑定V-on:click,因为考虑到以后可能会和Razor整合,@符可能会冲突

查询JS:

复制代码 fetchData: function () { this.manifests = []; this.$http.get("http://localhost:1500/api/Manifests/paged", { params: { start: this.start.format("yyyy-MM-dd"), end: this.end.format("yyyy-MM-dd"), pageIndex: this.pageIndex, pageSize: this.pageSize } }) .then(response => { this.total = response.body.count; this.manifests = response.body.data; }) .catch(response => this.$alert(response.body.Message, "日消费明细", { type: "error" })); } 复制代码

API请求采用了Vue开源社区的vue-resource,简单轻便,再搭配ES6 Promise,写起来很顺手。

添加/编辑的实现:

这里使用了el-dialog嵌套el-form

复制代码 确 定 取 消 复制代码 复制代码 save: function () { this.$refs.formManifest.validate(valid => { if (valid) { let operateManifest = JSON.parse(JSON.stringify(this.manifest)); operateManifest.Date = this.manifest.Date.format("yyyy-MM-dd"); if (this.isAdd) { this.$http.post("http://localhost:1500/api/Manifests", operateManifest) .then(() => { this.manifests.push(operateManifest); this.showOperateManifest = false; bus.$emit("manifestChanged"); this.$message({ message: "添加成功", type: "success" }); }) .catch(err => { //console.log(err); this.$alert(err.body.Message, "添加日消费明细", { type: "error" }); }); } else { this.$http.put("http://localhost:1500/api/Manifests", operateManifest) .then(response => { let updatedManifest = this.manifests.find(x => x.ID == this.manifest.ID); updatedManifest.Date = operateManifest.Date; updatedManifest.Cost = operateManifest.Cost; updatedManifest.Remark = operateManifest.Remark; this.showOperateManifest = false; bus.$emit("manifestChanged"); this.$message({ message: "修改成功", type: "success" }); }) .catch(err => { //console.log(err); this.$alert(err.body.Message, "修改消费明细", { type: "error" }); }); } } else { return false; } }); } 复制代码

其中包括了表单验证部分,也是采用Element-UI文档中介绍的验证方式,目前有些验证支持不是很好,比如number,可能是哪里用的不对吧,所以上边对金额部分采取了正则自定义验证。

底部分页部分:

 </el-pagination>

如上所示,直接使用了饿了么分页组件,设置几个属性, 再绑定几个JS属性、分页事件处理程序即可,十分方便

Vue Date对象中分页相关的属性:

页索引及分页大小变动事件处理:

复制代码 sizeChange: function (pageSize) { this.pageSize = pageSize; this.fetchData(); }, pageIndexChange: function (pageIndex) { this.pageIndex = pageIndex; this.fetchData(); } 复制代码 没什么特别, 根据最新页索引或页尺寸大小从新拉取一遍数据就行了。

About

个人账务管理添加

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • JavaScript 61.9%
  • C# 28.6%
  • CSS 5.6%
  • HTML 3.9%

AltStyle によって変換されたページ (->オリジナル) /