项目演示地址:https://hujiyi.github.io/acme-world-web/
LeanCloud 数据存储
LeanCloud 数据存储 的两种 Class
LeanCloud 数据存储的 Class 有两种,一种是创建应用时就自带的,这一种Class的名字以 下划线开头,可以在这些 Class 中添加字段, 但一般不要删除;
另一种是用户自己创建的 Class,可以由用户自定义需要的字段, 同时,自定义的每个 Class 还会有四个系统自带的字段:objectId
, ACL
, createdAt
, updatedAt
, 说明如下:
objectId
: 主键字段,实际使用时,可以通过 类名.id
获取值;
ACL
: 访问控制列表, 用于权限管理开发,免费用户不可用;
createdAt
: 记录创建时间,添加记录时自动产生,不能更改;
updatedAt
: 记录更新时间,记录有更新时自动修改,不能由用户进行修改;
在数据存储中创建 Class
在数据存储中创建 Class 有两个方法:
方法一:在 LeanCloud
数据存储 的管理界面 手工
添加 Class
, 然后再逐个添加字段(也可以从一个 数据存储 中导出 Class
, 然后到另一个应用中导入);
方法二:直接在程序中创建一个 JSON 格式的数据,通过 LeanStorage 数据存储
SDK 保存, LeanCloud
服务器端即可根据JSON
数据格式自动添加 Class
, 以及添加 Class
中没有的字段。 总的来说,我现在比较喜欢用这一种方法。
通用的数据存储服务类
除了创建 LeanCloud
应用时系统自动的 Class 以外,其他用户自行添加的 Class 进行查、改、增、删 时执行的操作都是类似的,所以可以定义一个通用的数据存储服务基类,然后每个 Class 再继承这个基类,就可以实现大部分代码共用了。
在 src/api/service/
文件夹下添加文件:base_service.js
。
打开文件 src/api/service/base_service.js
, 编辑其代码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
| import LC from 'leancloud-storage';
class BaseService {
constructor(table_name) { this.TABLE_NAME = table_name; }
async fetchAll(limit = 10, skip = 0, include = [], sort_fields = []) { try { let query = new LC.Query(this.TABLE_NAME); if (include[0]) { query.include(include); }
if (sort_fields.length > 0) { for (let i = 0; i < sort_fields.length; i++) { if (i === 0) { if (this.isMinus(sort_fields[0])) { query.descending(sort_fields[0].substr(1)); } else { query.ascending(sort_fields[0]); } } else { if (this.isMinus(sort_fields[i])) { query.addDescending(sort_fields[i].substr(1)); } else { query.addAscending(sort_fields[i]); } } } } let total = await query.count(); let response = await query.limit(limit).skip(skip).find(); return { "status_code": "ok", "totalCount": total, "reslut": response, }; } catch (e) { console.log('查询数据错误:', e.code, e); return { "status_code": e.code, "totalCount": 0, "reslut": e, }; }
}
async create(data) { try { let Collection = LC.Object.extend(this.TABLE_NAME); let query = new Collection(data); let response = await query.save(); return response; } catch (e) { console.log('添加数据错误:', e.code, e); } return null; }
async update(id, data) { try { let query = LC.Object.createWithoutData(this.TABLE_NAME, id); query.set(data); let response = await query.save(); return response; } catch (e) { console.log('修改数据错误:', e.code, e); } return null; }
async updateBatch(items) { console.log('items:', items); try { let id_list = items.map(item => { return item.id }); let query = new LC.Query(this.TABLE_NAME); let response = await query .containedIn('objectId', id_list) .find(); let result = response.map(item => { let data = items.find(it => { console.log('update batch:', it); return it.id === item.id }); item.set(data); return item; }); return await LC.Object.saveAll(result); } catch (e) { console.log('批量修改数据错误:', e.code, e); } return null; }
async delete(id) { try { let query = LC.Object.createWithoutData(this.TABLE_NAME, id); let response = await query.destroy(); return response; } catch (e) { console.log('删除数据错误:', e.code, e); } return null; }
async deleteBatch(items) { try { let id_list = items.map(item => { return item.id }); let query = new LC.Query(this.TABLE_NAME); let response = await query .containedIn('objectId', id_list) .destroyAll(); console.log('deleteBatch:', response) return true; } catch (e) { console.log('批量删除数据错误:', e.code, e); } return null; }
async existsFieldValue(field = 'title', val) { try { let query = new LC.Query(this.TABLE_NAME); let count = await query.equalTo(field, val).count(); console.log(count); return count > 0; } catch (e) { console.log('查询错误:', e.code, e); } return false; }
async currentUser() { return LC.User.current(); }
isMinus(val) { if (val[0] === '-') { return true; } return false; } }
export default BaseService;
|
LeanCloud 数据存储的基类创建完毕等待应用。
路由守卫的使用
后台管理(仪表盘)一般来说,都要求用户成功登录后才能访问,但在之前的代码中,并没有做这样的限制, 所以任何人都可以直接进入后台管理。
这里使用 vue router
的路由守卫
来实现进入后台管理的权限验证
打开文件 src/router/index.js
, 给后台管理的的父路由项
添加路由元信息 meta: { requiresAuth: true },
, 同时添加相应的路由守卫。修改其如以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
| import Vue from 'vue'; import VueRouter from 'vue-router';
Vue.use(VueRouter);
const routes = [ { path: '/', name: 'Home', component: () => import('../views/home/Index.vue'), }, { path: '/account', redirect: '/login', component: () => import('../views/account/Index.vue'), children: [ { path: '/login', name: 'Login', component: () => import('../views/account/pages/Login.vue'), }, { path: '/signup', name: 'SignUp', component: () => import('../views/account/pages/SignUp.vue'), }, { path: '/password_reset', name: 'PasswordReset', component: () => import('../views/account/pages/PasswordReset.vue'), }, ] }, { path: '/dashboard', component: () => import('../views/dashboard/Index.vue'), meta: { requiresAuth: true }, children: [ { path: '', alias: 'index', name: 'Dashboard', component: () => import('@/views/dashboard/pages/MainIndex.vue'), }, { path: 'topic_manager', name: 'TopicManager', component: () => import('@/views/dashboard/forum/TopicManager.vue'), }, { path: 'comment_manager', name: 'CommentManager', component: () => import('@/views/dashboard/forum/CommentManager.vue'), },
], } ];
const router = new VueRouter({ routes });
router.beforeEach((to, from, next) => { let login_router = ['/account', '/login']; if (to.path in login_router) { localStorage.setItem("preRoute", router.currentRoute.fullPath); }
if (to.matched.some(record => record.meta.requiresAuth)) { if (!localStorage.getItem('token')) { next({ path: '/login', query: { redirect: to.fullPath } }) } else { next(); } } else { next(); } });
export default router;
|
路由守卫
通过 路由元信息
判断该路由项是否需要登录后才能访问,如果需要,但当前没有已登录用户,则自动跳转到 登录界面,登录成功后,返回之前的页面(返回前一页在登录页实现,之前完成的登录页已经包含相应代码)
后继内容:
使用 Element UI 和 Leancloud 的 Vue.js 项目开发 VIII
===END===