Commit 617b8af4 authored by 周远喜's avatar 周远喜

vuex更新

parent 75dd27ad
......@@ -23,17 +23,31 @@
>
GitHub222
</a>
<h1>总数:{{counter}}</h1>
<h2>admin,user{{this.$store.state.admin.user.counter}}</h2>
<Button @click="increment">+</Button>
</div>
</div>
</div>
</template>
<script>
import { mapState } from 'vuex'
import Logo from '~/components/Logo.vue'
export default {
fetch ({ store }) {
store.commit('increment')
},
computed: mapState([
'counter'
]),
components: {
Logo
},methods: {
increment () {
this.$store.commit('increment')
}
}
}
</script>
\ No newline at end of file
/**
* 注册、登录、注销
* */
import util from '@/libs/util';
import router from '@/router';
import { AccountLogin, AccountRegister } from '@/api/account';
import { Modal } from 'view-design';
export const actions={
/**
* @description 登录
* @param {Object} param context
* @param {Object} param username {String} 用户账号
* @param {Object} param password {String} 密码
* @param {Object} param route {Object} 登录成功后定向的路由对象 任何 vue-router 支持的格式
*/
login ({ dispatch }, {
username = '',
password = ''
} = {}) {
return new Promise((resolve, reject) => {
// 开始请求登录接口
AccountLogin({
username,
password
})
.then(async res => {
// 设置 cookie 一定要存 uuid 和 token 两个 cookie
// 整个系统依赖这两个数据进行校验和存储
// uuid 是用户身份唯一标识 用户注册的时候确定 并且不可改变 不可重复
// token 代表用户当前登录状态 建议在网络请求中携带 token
// 如有必要 token 需要定时更新,默认保存一天,可在 setting.js 中修改
// 如果你的 token 不是通过 cookie 携带,而是普通字段,也可视情况存储在 localStorage
util.cookies.set('uuid', res.uuid);
util.cookies.set('token', res.token);
// 设置 vuex 用户信息
await dispatch('admin/user/set', res.info, { root: true });
// 用户登录后从持久化数据加载一系列的设置
await dispatch('load');
// 结束
resolve();
})
.catch(err => {
// console.log('err: ', err);
reject(err);
})
})
},
/**
* @description 退出登录
* */
logout ({ commit, dispatch }, { confirm = false, vm } = {}) {
async function logout () {
// 删除cookie
util.cookies.remove('token');
util.cookies.remove('uuid');
// 清空 vuex 用户信息
await dispatch('admin/user/set', {}, { root: true });
// 跳转路由
router.push({
name: 'login'
});
}
if (confirm) {
Modal.confirm({
title: vm.$t('basicLayout.logout.confirmTitle'),
content: vm.$t('basicLayout.logout.confirmContent'),
onOk () {
logout();
}
});
} else {
logout();
}
},
/**
* @description 注册
* @param {Object} param context
* @param {Object} param mail {String} 邮箱
* @param {Object} param password {String} 密码
* @param {Object} param mobile {String} 手机号码
* @param {Object} param captcha {String} 验证码
*/
register ({ dispatch }, {
mail = '',
password = '',
mobile = '',
captcha = ''
} = {}) {
return new Promise((resolve, reject) => {
// 开始请求登录接口
AccountRegister({
mail,
password,
mobile,
captcha
})
.then(async res => {
// 注册成功后,完成与登录一致的操作
// 注册也可视情况不返还 uuid、token 等数据,在注册完成后,由前端自动执行一次登录逻辑
util.cookies.set('uuid', res.uuid);
util.cookies.set('token', res.token);
// 设置 vuex 用户信息
await dispatch('admin/user/set', res.info, { root: true });
// 用户登录后从持久化数据加载一系列的设置
await dispatch('load');
// 结束
resolve();
})
.catch(err => {
// console.log('err: ', err);
reject(err);
})
})
},
/**
* @description 用户登录后从持久化数据加载一系列的设置
* @param {Object} state vuex state
* @param {Object} dispatch vuex dispatch
*/
load ({ state, dispatch }) {
return new Promise(async resolve => {
// 加载用户登录信息
await dispatch('admin/user/load', null, { root: true });
// 持久化数据加载上次退出时的多页列表
await dispatch('admin/page/openedLoad', null, { root: true });
// end
resolve();
})
}
}
\ No newline at end of file
/**
* 持久化存储
* 一般情况下,您无需修改此文件
* */
import util from '@/libs/util';
import router from '@/router';
import { cloneDeep } from 'lodash';
/**
* @description 检查路径是否存在 不存在的话初始化
* @param {Object} dbName {String} 数据库名称
* @param {Object} path {String} 路径
* @param {Object} user {Boolean} 区分用户
* @param {Object} validator {Function} 数据校验钩子 返回 true 表示验证通过
* @param {Object} defaultValue {*} 初始化默认值
* @returns {String} 可以直接使用的路径
*/
function pathInit ({
dbName = 'database',
path = '',
user = true,
validator = () => true,
defaultValue = ''
}) {
const uuid = util.cookies.get('uuid') || 'ghost-uuid';
const currentPath = `${dbName}.${user ? `user.${uuid}` : 'public'}${path ? `.${path}` : ''}`;
const value = util.db.get(currentPath).value();
if (!(value !== undefined && validator(value))) {
util.db.set(currentPath, defaultValue).write();
}
return currentPath;
}
export { pathInit };
export const actions={
/**
* @description 将数据存储到指定位置 | 路径不存在会自动初始化
* @description 效果类似于取值 dbName.path = value
* @param context context
* @param {Object} dbName {String} 数据库名称
* @param {Object} path {String} 存储路径
* @param {Object} value {*} 需要存储的值
* @param {Object} user {Boolean} 是否区分用户
*/
set (context, {
dbName = 'database',
path = '',
value = '',
user = false
}) {
util.db.set(pathInit({
dbName,
path,
user
}), value).write()
},
/**
* @description 获取数据
* @description 效果类似于取值 dbName.path || defaultValue
* @param context context
* @param {Object} dbName {String} 数据库名称
* @param {Object} path {String} 存储路径
* @param {Object} defaultValue {*} 取值失败的默认值
* @param {Object} user {Boolean} 是否区分用户
*/
get (context, {
dbName = 'database',
path = '',
defaultValue = '',
user = false
}) {
return new Promise(resolve => {
resolve(cloneDeep(util.db.get(pathInit({
dbName,
path,
user,
defaultValue
})).value()))
})
},
/**
* @description 获取存储数据库对象
* @param {Object} context context
* @param {Object} user {Boolean} 是否区分用户
*/
database (context, {
user = false
} = {}) {
return new Promise(resolve => {
resolve(util.db.get(pathInit({
dbName: 'database',
path: '',
user,
defaultValue: {}
})))
})
},
/**
* @description 清空存储数据库对象
* @param {Object} context context
* @param {Object} user {Boolean} 是否区分用户
*/
databaseClear (context, {
user = false
} = {}) {
return new Promise(resolve => {
resolve(util.db.get(pathInit({
dbName: 'database',
path: '',
user,
validator: () => false,
defaultValue: {}
})))
})
},
/**
* @description 获取存储数据库对象 [ 区分页面 ]
* @param {Object} context context
* @param {Object} basis {String} 页面区分依据 [ name | path | fullPath ]
* @param {Object} user {Boolean} 是否区分用户
*/
databasePage (context, {
basis = 'fullPath',
user = false
} = {}) {
return new Promise(resolve => {
resolve(util.db.get(pathInit({
dbName: 'database',
path: `$page.${router.app.$route[basis]}`,
user,
defaultValue: {}
})))
})
},
/**
* @description 清空存储数据库对象 [ 区分页面 ]
* @param {Object} context context
* @param {Object} basis {String} 页面区分依据 [ name | path | fullPath ]
* @param {Object} user {Boolean} 是否区分用户
*/
databasePageClear (context, {
basis = 'fullPath',
user = false
} = {}) {
return new Promise(resolve => {
resolve(util.db.get(pathInit({
dbName: 'database',
path: `$page.${router.app.$route[basis]}`,
user,
validator: () => false,
defaultValue: {}
})))
})
},
/**
* @description 快速将页面当前的数据 ( $data ) 持久化
* @param {Object} context context
* @param {Object} instance {Object} vue 实例
* @param {Object} basis {String} 页面区分依据 [ name | path | fullPath ]
* @param {Object} user {Boolean} 是否区分用户
*/
pageSet (context, {
instance,
basis = 'fullPath',
user = false
}) {
return new Promise(resolve => {
resolve(util.db.get(pathInit({
dbName: 'database',
path: `$page.${router.app.$route[basis]}.$data`,
user,
validator: () => false,
defaultValue: cloneDeep(instance.$data)
})))
})
},
/**
* @description 快速获取页面快速持久化的数据
* @param {Object} context context
* @param {Object} instance {Object} vue 实例
* @param {Object} basis {String} 页面区分依据 [ name | path | fullPath ]
* @param {Object} user {Boolean} 是否区分用户
*/
pageGet (context, {
instance,
basis = 'fullPath',
user = false
}) {
return new Promise(resolve => {
resolve(cloneDeep(util.db.get(pathInit({
dbName: 'database',
path: `$page.${router.app.$route[basis]}.$data`,
user,
defaultValue: cloneDeep(instance.$data)
})).value()))
})
},
/**
* @description 清空页面快照
* @param {Object} context context
* @param {Object} basis {String} 页面区分依据 [ name | path | fullPath ]
* @param {Object} user {Boolean} 是否区分用户
*/
pageClear (context, {
basis = 'fullPath',
user = false
}) {
return new Promise(resolve => {
resolve(util.db.get(pathInit({
dbName: 'database',
path: `$page.${router.app.$route[basis]}.$data`,
user,
validator: () => false,
defaultValue: {}
})))
})
}
}
\ No newline at end of file
/**
* 多语言
* */
import Languages from '@/i18n/locale';
import Setting from '@/setting';
import util from '@/libs/util';
import { pathInit } from '@/store/modules/admin/modules/db';
const savedLocaleKey = 'i18n-locale';
export const state=()=>({
locale: ''
})
export const actions={
/**
* @description 获取当前语言
* */
getLocale ({ state }) {
let locale;
const db = util.db.get(pathInit({
dbName: 'database',
path: '',
user: true,
defaultValue: {}
}));
const savedLocale = db.get(savedLocaleKey).value();
// 先判断本地存储是否已有语言选择
if (savedLocale) {
locale = savedLocale;
} else {
// 判断是否开启自动识别语言
if (Setting.i18n.auto) {
// 如果自动识别的语言,本地没有该语言包,则设置为默认语言
const navLang = navigator.language;
if (Languages[navLang]) {
locale = navLang;
} else {
locale = Setting.i18n.default;
}
} else {
locale = Setting.i18n.default;
}
// 将初次的语言保存在本地
db.set(savedLocaleKey, locale).write();
}
state.locale = locale;
},
/**
* @description 设置当前语言
* */
setLocale ({ state }, { locale = Setting.i18n.default, vm }) {
const db = util.db.get(pathInit({
dbName: 'database',
path: '',
user: true,
defaultValue: {}
}));
// 将语言保存在本地
db.set(savedLocaleKey, locale).write();
// 设置当前语言
state.locale = locale;
// 设置 vue-i18n 的语言
vm.$i18n.locale = locale;
// 更新网页标题
util.title({
title: vm.$route.meta.title
});
}
}
\ No newline at end of file
/**
* 布局配置
* */
import screenfull from 'screenfull';
import Setting from '@/setting';
export const state=()=>({
...Setting.layout,
isMobile: false, // 是否为手机
isTablet: false, // 是否为平板
isDesktop: true, // 是否为桌面
isFullscreen: false // 是否切换到了全屏
})
export const mutations={
/**
* @description 设置设备类型
* @param {Object} state vuex state
* @param {String} type 设备类型,可选值为 Mobile、Tablet、Desktop
*/
setDevice (state, type) {
state.isMobile = false;
state.isTablet = false;
state.isDesktop = false;
state[`is${type}`] = true;
},
/**
* @description 修改 menuCollapse
* @param {Object} state vuex state
* @param {Boolean} collapse 折叠状态
* */
updateMenuCollapse (state, collapse) {
state.menuCollapse = collapse;
},
/**
* @description 设置全屏状态
* @param {Object} state vuex state
* @param {Boolean} isFullscreen vuex
* */
setFullscreen (state, isFullscreen) {
state.isFullscreen = isFullscreen;
},
/**
* @description 更改指定布局配置
* @param {Object} state vuex state
* @param {Object} key layout 名称,对应 Setting.layout
* @param {Object} value layout 值
* */
updateLayoutSetting (state, { key, value }) {
state[key] = value;
}
}
export const actions={
/**
* @description 初始化监听全屏状态
*/
listenFullscreen ({ commit }) {
return new Promise(resolve => {
if (screenfull.enabled) {
screenfull.on('change', () => {
if (!screenfull.isFullscreen) {
commit('setFullscreen', false)
}
})
}
// end
resolve();
});
},
/**
* @description 切换全屏
*/
toggleFullscreen ({ commit }) {
return new Promise(resolve => {
if (screenfull.isFullscreen) {
screenfull.exit();
commit('setFullscreen', false);
} else {
screenfull.request();
commit('setFullscreen', true);
}
// end
resolve();
});
}
}
\ No newline at end of file
import dayjs from 'dayjs';
import { get } from 'lodash';
import util from '@/libs/util.js';
export const state=()=>({
/**
* @description 错误日志,单条属性:
* message: 必填,日志信息
* type: 非必填,类型,可选值为 info(默认值)| success | warning | error,其中 error 会以具体数目强调显示,其它以点轻量显示
* time: 必填,日志记录时间
* meta: 非必填,其它携带信息
* */
log: []
})
export const getters={
/**
* @description 返回现存 log (all) 的条数
* @param {*} state vuex state
*/
length (state) {
return state.log.length;
},
/**
* @description 返回现存 log (error) 的条数
* @param {*} state vuex state
*/
lengthError (state) {
return state.log.filter(log => log.type === 'error').length;
}
}
export const actions={
/**
* @description 添加一个日志
* @param {String} param message {String} 信息
* @param {String} param type {String} 类型
* @param {Object} param meta {Object} 附带的信息
*/
push ({ rootState, commit }, { message, type = 'info', meta }) {
commit('push', {
message,
type,
time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
meta: {
// 当前用户信息
user: rootState.admin.user.info,
// 当前用户的 uuid
uuid: util.cookies.get('uuid'),
// 当前的 token
token: util.cookies.get('token'),
// 当前地址
url: get(window, 'location.href', ''),
// 用户设置
...meta
}
});
}
}
export const mutations={
/**
* @description 添加日志
* @param {Object} state vuex state
* @param {Object} log data
*/
push (state, log) {
state.log.push(log);
},
/**
* @description 清空日志
* @param {Object} state vuex state
*/
clean (state) {
state.log = [];
}
}
\ No newline at end of file
/**
* 菜单
* */
import { cloneDeep } from 'lodash';
import { includeArray } from '@/libs/system';
// 根据 menu 配置的权限,过滤菜单
function filterMenu (menuList, access, lastList) {
menuList.forEach(menu => {
let menuAccess = menu.auth;
if (!menuAccess || includeArray(menuAccess, access)) {
let newMenu = {};
for (let i in menu) {
if (i !== 'children') newMenu[i] = cloneDeep(menu[i]);
}
if (menu.children && menu.children.length) newMenu.children = [];
lastList.push(newMenu);
menu.children && filterMenu(menu.children, access, newMenu.children);
}
});
return lastList;
}
export const state=()=>({
// 顶部菜单
header: [],
// 侧栏菜单
sider: [],
// 当前顶栏菜单的 name
headerName: '',
// 当前所在菜单的 path
activePath: '',
// 展开的子菜单 name 集合
openNames: []
})
export const getters={
/**
* @description 根据 user 里登录用户权限,对侧边菜单进行鉴权过滤
* */
filterSider (state, getters, rootState) {
const userInfo = rootState.admin.user.info;
// @权限
const access = userInfo.access;
if (access && access.length) {
return filterMenu(state.sider, access, []);
} else {
return filterMenu(state.sider, [], []);
}
},
/**
* @description 根据 user 里登录用户权限,对顶栏菜单进行鉴权过滤
* */
filterHeader (state, getters, rootState) {
const userInfo = rootState.admin.user.info;
// @权限
const access = userInfo.access;
if (access && access.length) {
return state.header.filter(item => {
let state = true;
if (item.auth && !includeArray(item.auth, access)) state = false;
return state;
});
} else {
return state.header.filter(item => {
let state = true;
if (item.auth && item.auth.length) state = false;
return state;
});
}
},
/**
* @description 当前 header 的全部信息
* */
currentHeader (state) {
return state.header.find(item => item.name === state.headerName);
},
/**
* @description 在当前 header 下,是否隐藏 sider(及折叠按钮)
* */
hideSider (state, getters) {
let visible = false;
if (getters.currentHeader && 'hideSider' in getters.currentHeader) visible = getters.currentHeader.hideSider;
return visible;
}
}
export const mutations={
/**
* @description 设置侧边栏菜单
* @param {Object} state vuex state
* @param {Array} menu menu
*/
setSider (state, menu) {
state.sider = menu;
},
/**
* @description 设置顶栏菜单
* @param {Object} state vuex state
* @param {Array} menu menu
*/
setHeader (state, menu) {
state.header = menu;
},
/**
* @description 设置当前顶栏菜单 name
* @param {Object} state vuex state
* @param {Array} name headerName
*/
setHeaderName (state, name) {
state.headerName = name;
},
/**
* @description 设置当前所在菜单的 path,用于侧栏菜单高亮当前项
* @param {Object} state vuex state
* @param {Array} path fullPath
*/
setActivePath (state, path) {
state.activePath = path;
},
/**
* @description 设置当前所在菜单的全部展开父菜单的 names 集合
* @param {Object} state vuex state
* @param {Array} names openNames
*/
setOpenNames (state, names) {
state.openNames = names;
}
}
\ No newline at end of file
This diff is collapsed.
export const state=()=>({
info:{}
})
export const mutations={
increment(state){
state.counter++
}
}
export const actions={
/**
* @description 设置用户数据
* @param {Object} state vuex state
* @param {Object} dispatch vuex dispatch
* @param {*} info info
*/
set ({ state, dispatch }, info) {
return new Promise(async resolve => {
// store 赋值
state.info = info;
// 持久化
await dispatch('admin/db/set', {
dbName: 'sys',
path: 'user.info',
value: info,
user: true
}, { root: true });
// end
resolve();
})
},
/**
* @description 从数据库取用户数据
* @param {Object} state vuex state
* @param {Object} dispatch vuex dispatch
*/
load ({ state, dispatch }) {
return new Promise(async resolve => {
// store 赋值
state.info = await dispatch('admin/db/get', {
dbName: 'sys',
path: 'user.info',
defaultValue: {},
user: true
}, { root: true });
// end
resolve();
})
}
}
\ No newline at end of file
import Vue from 'vue';
import Vuex from 'vuex';
import admin from './modules/admin'
Vue.use(Vuex);
export default new Vuex.Store({
modules: {
admin
}
export const state=()=>({
counter:0
})
export const mutations={
increment(state){
state.counter++
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment