update 调整代码格式
This commit is contained in:
		| @ -3,71 +3,71 @@ import zhCn from 'element-plus/es/locale/lang/zh-cn'; | ||||
| import en from 'element-plus/es/locale/lang/en'; | ||||
|  | ||||
| export const useAppStore = defineStore('app', () => { | ||||
| 	const sidebarStatus = Cookies.get('sidebarStatus'); | ||||
| 	const sidebar = reactive({ | ||||
| 		opened: sidebarStatus ? !!+sidebarStatus : true, | ||||
| 		withoutAnimation: false, | ||||
| 		hide: false | ||||
| 	}); | ||||
| 	const device = ref<string>('desktop'); | ||||
| 	const size = ref(Cookies.get('size') || 'default'); | ||||
| 	// 语言 | ||||
| 	const language = ref(Cookies.get('language')); | ||||
| 	const locale = computed(() => { | ||||
| 		if (language?.value == 'en') { | ||||
| 			return en; | ||||
| 		} else { | ||||
| 			return zhCn; | ||||
| 		} | ||||
| 	}); | ||||
|   const sidebarStatus = Cookies.get('sidebarStatus'); | ||||
|   const sidebar = reactive({ | ||||
|     opened: sidebarStatus ? !!+sidebarStatus : true, | ||||
|     withoutAnimation: false, | ||||
|     hide: false | ||||
|   }); | ||||
|   const device = ref<string>('desktop'); | ||||
|   const size = ref(Cookies.get('size') || 'default'); | ||||
|   // 语言 | ||||
|   const language = ref(Cookies.get('language')); | ||||
|   const locale = computed(() => { | ||||
|     if (language?.value == 'en') { | ||||
|       return en; | ||||
|     } else { | ||||
|       return zhCn; | ||||
|     } | ||||
|   }); | ||||
|  | ||||
| 	const toggleSideBar = (withoutAnimation?: boolean) => { | ||||
| 		if (sidebar.hide) { | ||||
| 			return false; | ||||
| 		} | ||||
|   const toggleSideBar = (withoutAnimation?: boolean) => { | ||||
|     if (sidebar.hide) { | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
| 		sidebar.opened = !sidebar.opened; | ||||
| 		sidebar.withoutAnimation = withoutAnimation as boolean; | ||||
| 		if (sidebar.opened) { | ||||
| 			Cookies.set('sidebarStatus', '1'); | ||||
| 		} else { | ||||
| 			Cookies.set('sidebarStatus', '0'); | ||||
| 		} | ||||
| 	}; | ||||
|     sidebar.opened = !sidebar.opened; | ||||
|     sidebar.withoutAnimation = withoutAnimation as boolean; | ||||
|     if (sidebar.opened) { | ||||
|       Cookies.set('sidebarStatus', '1'); | ||||
|     } else { | ||||
|       Cookies.set('sidebarStatus', '0'); | ||||
|     } | ||||
|   }; | ||||
|  | ||||
| 	const closeSideBar = ({ withoutAnimation }: any): void => { | ||||
| 		Cookies.set('sidebarStatus', '0'); | ||||
| 		sidebar.opened = false; | ||||
| 		sidebar.withoutAnimation = withoutAnimation; | ||||
| 	}; | ||||
| 	const toggleDevice = (d: string): void => { | ||||
| 		device.value = d; | ||||
| 	}; | ||||
| 	const setSize = (s: string): void => { | ||||
| 		size.value = s; | ||||
| 		Cookies.set('size', s); | ||||
| 	}; | ||||
| 	const toggleSideBarHide = (status: boolean): void => { | ||||
| 		sidebar.hide = status; | ||||
| 	}; | ||||
|   const closeSideBar = ({ withoutAnimation }: any): void => { | ||||
|     Cookies.set('sidebarStatus', '0'); | ||||
|     sidebar.opened = false; | ||||
|     sidebar.withoutAnimation = withoutAnimation; | ||||
|   }; | ||||
|   const toggleDevice = (d: string): void => { | ||||
|     device.value = d; | ||||
|   }; | ||||
|   const setSize = (s: string): void => { | ||||
|     size.value = s; | ||||
|     Cookies.set('size', s); | ||||
|   }; | ||||
|   const toggleSideBarHide = (status: boolean): void => { | ||||
|     sidebar.hide = status; | ||||
|   }; | ||||
|  | ||||
| 	const changeLanguage = (val: string): void => { | ||||
| 		language.value = val; | ||||
| 	}; | ||||
|   const changeLanguage = (val: string): void => { | ||||
|     language.value = val; | ||||
|   }; | ||||
|  | ||||
| 	return { | ||||
| 		device, | ||||
| 		sidebar, | ||||
| 		language, | ||||
| 		locale, | ||||
| 		size, | ||||
| 		changeLanguage, | ||||
| 		toggleSideBar, | ||||
| 		closeSideBar, | ||||
| 		toggleDevice, | ||||
| 		setSize, | ||||
| 		toggleSideBarHide | ||||
| 	}; | ||||
|   return { | ||||
|     device, | ||||
|     sidebar, | ||||
|     language, | ||||
|     locale, | ||||
|     size, | ||||
|     changeLanguage, | ||||
|     toggleSideBar, | ||||
|     closeSideBar, | ||||
|     toggleDevice, | ||||
|     setSize, | ||||
|     toggleSideBarHide | ||||
|   }; | ||||
| }); | ||||
|  | ||||
| export default useAppStore; | ||||
|  | ||||
| @ -1,78 +1,78 @@ | ||||
| export const useDictStore = defineStore('dict', () => { | ||||
| 	const dict = ref< | ||||
| 		Array<{ | ||||
| 			key: string; | ||||
| 			value: DictDataOption[]; | ||||
| 		}> | ||||
| 	>([]); | ||||
|   const dict = ref< | ||||
|     Array<{ | ||||
|       key: string; | ||||
|       value: DictDataOption[]; | ||||
|     }> | ||||
|   >([]); | ||||
|  | ||||
| 	/** | ||||
| 	 * 获取字典 | ||||
| 	 * @param _key 字典key | ||||
| 	 */ | ||||
| 	const getDict = (_key: string): DictDataOption[] | null => { | ||||
| 		if (_key == null && _key == '') { | ||||
| 			return null; | ||||
| 		} | ||||
| 		try { | ||||
| 			for (let i = 0; i < dict.value.length; i++) { | ||||
| 				if (dict.value[i].key == _key) { | ||||
| 					return dict.value[i].value; | ||||
| 				} | ||||
| 			} | ||||
| 		} catch (e) { | ||||
| 			return null; | ||||
| 		} | ||||
| 		return null; | ||||
| 	}; | ||||
|   /** | ||||
|    * 获取字典 | ||||
|    * @param _key 字典key | ||||
|    */ | ||||
|   const getDict = (_key: string): DictDataOption[] | null => { | ||||
|     if (_key == null && _key == '') { | ||||
|       return null; | ||||
|     } | ||||
|     try { | ||||
|       for (let i = 0; i < dict.value.length; i++) { | ||||
|         if (dict.value[i].key == _key) { | ||||
|           return dict.value[i].value; | ||||
|         } | ||||
|       } | ||||
|     } catch (e) { | ||||
|       return null; | ||||
|     } | ||||
|     return null; | ||||
|   }; | ||||
|  | ||||
| 	/** | ||||
| 	 * 设置字典 | ||||
| 	 * @param _key 字典key | ||||
| 	 * @param _value 字典value | ||||
| 	 */ | ||||
| 	const setDict = (_key: string, _value: DictDataOption[]) => { | ||||
| 		if (_key !== null && _key !== '') { | ||||
| 			dict.value.push({ | ||||
| 				key: _key, | ||||
| 				value: _value | ||||
| 			}); | ||||
| 		} | ||||
| 	}; | ||||
|   /** | ||||
|    * 设置字典 | ||||
|    * @param _key 字典key | ||||
|    * @param _value 字典value | ||||
|    */ | ||||
|   const setDict = (_key: string, _value: DictDataOption[]) => { | ||||
|     if (_key !== null && _key !== '') { | ||||
|       dict.value.push({ | ||||
|         key: _key, | ||||
|         value: _value | ||||
|       }); | ||||
|     } | ||||
|   }; | ||||
|  | ||||
| 	/** | ||||
| 	 * 删除字典 | ||||
| 	 * @param _key | ||||
| 	 */ | ||||
| 	const removeDict = (_key: string): boolean => { | ||||
| 		let bln = false; | ||||
| 		try { | ||||
| 			for (let i = 0; i < dict.value.length; i++) { | ||||
| 				if (dict.value[i].key == _key) { | ||||
| 					dict.value.splice(i, 1); | ||||
| 					return true; | ||||
| 				} | ||||
| 			} | ||||
| 		} catch (e) { | ||||
| 			bln = false; | ||||
| 		} | ||||
| 		return bln; | ||||
| 	}; | ||||
|   /** | ||||
|    * 删除字典 | ||||
|    * @param _key | ||||
|    */ | ||||
|   const removeDict = (_key: string): boolean => { | ||||
|     let bln = false; | ||||
|     try { | ||||
|       for (let i = 0; i < dict.value.length; i++) { | ||||
|         if (dict.value[i].key == _key) { | ||||
|           dict.value.splice(i, 1); | ||||
|           return true; | ||||
|         } | ||||
|       } | ||||
|     } catch (e) { | ||||
|       bln = false; | ||||
|     } | ||||
|     return bln; | ||||
|   }; | ||||
|  | ||||
| 	/** | ||||
| 	 * 清空字典 | ||||
| 	 */ | ||||
| 	const cleanDict = (): void => { | ||||
| 		dict.value = []; | ||||
| 	}; | ||||
|   /** | ||||
|    * 清空字典 | ||||
|    */ | ||||
|   const cleanDict = (): void => { | ||||
|     dict.value = []; | ||||
|   }; | ||||
|  | ||||
| 	return { | ||||
| 		dict, | ||||
| 		getDict, | ||||
| 		setDict, | ||||
| 		removeDict, | ||||
| 		cleanDict | ||||
| 	}; | ||||
|   return { | ||||
|     dict, | ||||
|     getDict, | ||||
|     setDict, | ||||
|     removeDict, | ||||
|     cleanDict | ||||
|   }; | ||||
| }); | ||||
|  | ||||
| export default useDictStore; | ||||
|  | ||||
| @ -11,134 +11,134 @@ import { RouteOption } from 'vue-router'; | ||||
| const modules = import.meta.glob('./../../views/**/*.vue'); | ||||
|  | ||||
| export const usePermissionStore = defineStore('permission', () => { | ||||
| 	const routes = ref<RouteOption[]>([]); | ||||
| 	const addRoutes = ref<RouteOption[]>([]); | ||||
| 	const defaultRoutes = ref<RouteOption[]>([]); | ||||
| 	const topbarRouters = ref<RouteOption[]>([]); | ||||
| 	const sidebarRouters = ref<RouteOption[]>([]); | ||||
|   const routes = ref<RouteOption[]>([]); | ||||
|   const addRoutes = ref<RouteOption[]>([]); | ||||
|   const defaultRoutes = ref<RouteOption[]>([]); | ||||
|   const topbarRouters = ref<RouteOption[]>([]); | ||||
|   const sidebarRouters = ref<RouteOption[]>([]); | ||||
|  | ||||
| 	const setRoutes = (newRoutes: RouteOption[]): void => { | ||||
| 		addRoutes.value = newRoutes; | ||||
| 		routes.value = constantRoutes.concat(newRoutes); | ||||
| 	}; | ||||
| 	const setDefaultRoutes = (routes: RouteOption[]): void => { | ||||
| 		defaultRoutes.value = constantRoutes.concat(routes); | ||||
| 	}; | ||||
| 	const setTopbarRoutes = (routes: RouteOption[]): void => { | ||||
| 		topbarRouters.value = routes; | ||||
| 	}; | ||||
| 	const setSidebarRouters = (routes: RouteOption[]): void => { | ||||
| 		sidebarRouters.value = routes; | ||||
| 	}; | ||||
| 	const generateRoutes = async (): Promise<RouteOption[]> => { | ||||
| 		const res = await getRouters(); | ||||
| 		const { data } = res; | ||||
| 		const sdata = JSON.parse(JSON.stringify(data)); | ||||
| 		const rdata = JSON.parse(JSON.stringify(data)); | ||||
| 		const defaultData = JSON.parse(JSON.stringify(data)); | ||||
| 		const sidebarRoutes = filterAsyncRouter(sdata); | ||||
| 		const rewriteRoutes = filterAsyncRouter(rdata, undefined, true); | ||||
| 		const defaultRoutes = filterAsyncRouter(defaultData); | ||||
| 		const asyncRoutes = filterDynamicRoutes(dynamicRoutes); | ||||
| 		asyncRoutes.forEach((route) => { | ||||
| 			router.addRoute(route); | ||||
| 		}); | ||||
| 		setRoutes(rewriteRoutes); | ||||
| 		setSidebarRouters(constantRoutes.concat(sidebarRoutes)); | ||||
| 		setDefaultRoutes(sidebarRoutes); | ||||
| 		setTopbarRoutes(defaultRoutes); | ||||
| 		return new Promise<RouteOption[]>((resolve) => resolve(rewriteRoutes)); | ||||
| 	}; | ||||
|   const setRoutes = (newRoutes: RouteOption[]): void => { | ||||
|     addRoutes.value = newRoutes; | ||||
|     routes.value = constantRoutes.concat(newRoutes); | ||||
|   }; | ||||
|   const setDefaultRoutes = (routes: RouteOption[]): void => { | ||||
|     defaultRoutes.value = constantRoutes.concat(routes); | ||||
|   }; | ||||
|   const setTopbarRoutes = (routes: RouteOption[]): void => { | ||||
|     topbarRouters.value = routes; | ||||
|   }; | ||||
|   const setSidebarRouters = (routes: RouteOption[]): void => { | ||||
|     sidebarRouters.value = routes; | ||||
|   }; | ||||
|   const generateRoutes = async (): Promise<RouteOption[]> => { | ||||
|     const res = await getRouters(); | ||||
|     const { data } = res; | ||||
|     const sdata = JSON.parse(JSON.stringify(data)); | ||||
|     const rdata = JSON.parse(JSON.stringify(data)); | ||||
|     const defaultData = JSON.parse(JSON.stringify(data)); | ||||
|     const sidebarRoutes = filterAsyncRouter(sdata); | ||||
|     const rewriteRoutes = filterAsyncRouter(rdata, undefined, true); | ||||
|     const defaultRoutes = filterAsyncRouter(defaultData); | ||||
|     const asyncRoutes = filterDynamicRoutes(dynamicRoutes); | ||||
|     asyncRoutes.forEach((route) => { | ||||
|       router.addRoute(route); | ||||
|     }); | ||||
|     setRoutes(rewriteRoutes); | ||||
|     setSidebarRouters(constantRoutes.concat(sidebarRoutes)); | ||||
|     setDefaultRoutes(sidebarRoutes); | ||||
|     setTopbarRoutes(defaultRoutes); | ||||
|     return new Promise<RouteOption[]>((resolve) => resolve(rewriteRoutes)); | ||||
|   }; | ||||
|  | ||||
| 	/** | ||||
| 	 * 遍历后台传来的路由字符串,转换为组件对象 | ||||
| 	 * @param asyncRouterMap 后台传来的路由字符串 | ||||
| 	 * @param lastRouter 上一级路由 | ||||
| 	 * @param type 是否是重写路由 | ||||
| 	 */ | ||||
| 	const filterAsyncRouter = (asyncRouterMap: RouteOption[], lastRouter?: RouteOption, type = false): RouteOption[] => { | ||||
| 		return asyncRouterMap.filter((route) => { | ||||
| 			if (type && route.children) { | ||||
| 				route.children = filterChildren(route.children, undefined); | ||||
| 			} | ||||
| 			if (route.component) { | ||||
| 				// Layout ParentView 组件特殊处理 | ||||
| 				if (route.component === 'Layout') { | ||||
| 					route.component = Layout; | ||||
| 				} else if (route.component === 'ParentView') { | ||||
| 					route.component = ParentView; | ||||
| 				} else if (route.component === 'InnerLink') { | ||||
| 					route.component = InnerLink; | ||||
| 				} else { | ||||
| 					route.component = loadView(route.component); | ||||
| 				} | ||||
| 			} | ||||
| 			if (route.children != null && route.children && route.children.length) { | ||||
| 				route.children = filterAsyncRouter(route.children, route, type); | ||||
| 			} else { | ||||
| 				delete route.children; | ||||
| 				delete route.redirect; | ||||
| 			} | ||||
| 			return true; | ||||
| 		}); | ||||
| 	}; | ||||
| 	const filterChildren = (childrenMap: RouteOption[], lastRouter?: RouteOption): RouteOption[] => { | ||||
| 		let children: RouteOption[] = []; | ||||
| 		childrenMap.forEach((el) => { | ||||
| 			if (el.children && el.children.length) { | ||||
| 				if (el.component === 'ParentView' && !lastRouter) { | ||||
| 					el.children.forEach((c) => { | ||||
| 						c.path = el.path + '/' + c.path; | ||||
| 						if (c.children && c.children.length) { | ||||
| 							children = children.concat(filterChildren(c.children, c)); | ||||
| 							return; | ||||
| 						} | ||||
| 						children.push(c); | ||||
| 					}); | ||||
| 					return; | ||||
| 				} | ||||
| 			} | ||||
| 			if (lastRouter) { | ||||
| 				el.path = lastRouter.path + '/' + el.path; | ||||
| 			} | ||||
| 			children = children.concat(el); | ||||
| 		}); | ||||
| 		return children; | ||||
| 	}; | ||||
| 	return { routes, setRoutes, generateRoutes, setSidebarRouters, topbarRouters, sidebarRouters, defaultRoutes }; | ||||
|   /** | ||||
|    * 遍历后台传来的路由字符串,转换为组件对象 | ||||
|    * @param asyncRouterMap 后台传来的路由字符串 | ||||
|    * @param lastRouter 上一级路由 | ||||
|    * @param type 是否是重写路由 | ||||
|    */ | ||||
|   const filterAsyncRouter = (asyncRouterMap: RouteOption[], lastRouter?: RouteOption, type = false): RouteOption[] => { | ||||
|     return asyncRouterMap.filter((route) => { | ||||
|       if (type && route.children) { | ||||
|         route.children = filterChildren(route.children, undefined); | ||||
|       } | ||||
|       if (route.component) { | ||||
|         // Layout ParentView 组件特殊处理 | ||||
|         if (route.component === 'Layout') { | ||||
|           route.component = Layout; | ||||
|         } else if (route.component === 'ParentView') { | ||||
|           route.component = ParentView; | ||||
|         } else if (route.component === 'InnerLink') { | ||||
|           route.component = InnerLink; | ||||
|         } else { | ||||
|           route.component = loadView(route.component); | ||||
|         } | ||||
|       } | ||||
|       if (route.children != null && route.children && route.children.length) { | ||||
|         route.children = filterAsyncRouter(route.children, route, type); | ||||
|       } else { | ||||
|         delete route.children; | ||||
|         delete route.redirect; | ||||
|       } | ||||
|       return true; | ||||
|     }); | ||||
|   }; | ||||
|   const filterChildren = (childrenMap: RouteOption[], lastRouter?: RouteOption): RouteOption[] => { | ||||
|     let children: RouteOption[] = []; | ||||
|     childrenMap.forEach((el) => { | ||||
|       if (el.children && el.children.length) { | ||||
|         if (el.component === 'ParentView' && !lastRouter) { | ||||
|           el.children.forEach((c) => { | ||||
|             c.path = el.path + '/' + c.path; | ||||
|             if (c.children && c.children.length) { | ||||
|               children = children.concat(filterChildren(c.children, c)); | ||||
|               return; | ||||
|             } | ||||
|             children.push(c); | ||||
|           }); | ||||
|           return; | ||||
|         } | ||||
|       } | ||||
|       if (lastRouter) { | ||||
|         el.path = lastRouter.path + '/' + el.path; | ||||
|       } | ||||
|       children = children.concat(el); | ||||
|     }); | ||||
|     return children; | ||||
|   }; | ||||
|   return { routes, setRoutes, generateRoutes, setSidebarRouters, topbarRouters, sidebarRouters, defaultRoutes }; | ||||
| }); | ||||
|  | ||||
| // 动态路由遍历,验证是否具备权限 | ||||
| export const filterDynamicRoutes = (routes: RouteOption[]) => { | ||||
| 	const res: RouteOption[] = []; | ||||
| 	routes.forEach((route) => { | ||||
| 		if (route.permissions) { | ||||
| 			if (auth.hasPermiOr(route.permissions)) { | ||||
| 				res.push(route); | ||||
| 			} | ||||
| 		} else if (route.roles) { | ||||
| 			if (auth.hasRoleOr(route.roles)) { | ||||
| 				res.push(route); | ||||
| 			} | ||||
| 		} | ||||
| 	}); | ||||
| 	return res; | ||||
|   const res: RouteOption[] = []; | ||||
|   routes.forEach((route) => { | ||||
|     if (route.permissions) { | ||||
|       if (auth.hasPermiOr(route.permissions)) { | ||||
|         res.push(route); | ||||
|       } | ||||
|     } else if (route.roles) { | ||||
|       if (auth.hasRoleOr(route.roles)) { | ||||
|         res.push(route); | ||||
|       } | ||||
|     } | ||||
|   }); | ||||
|   return res; | ||||
| }; | ||||
|  | ||||
| export const loadView = (view: any) => { | ||||
| 	let res; | ||||
| 	for (const path in modules) { | ||||
| 		const dir = path.split('views/')[1].split('.vue')[0]; | ||||
| 		if (dir === view) { | ||||
| 			res = () => modules[path](); | ||||
| 		} | ||||
| 	} | ||||
| 	return res; | ||||
|   let res; | ||||
|   for (const path in modules) { | ||||
|     const dir = path.split('views/')[1].split('.vue')[0]; | ||||
|     if (dir === view) { | ||||
|       res = () => modules[path](); | ||||
|     } | ||||
|   } | ||||
|   return res; | ||||
| }; | ||||
|  | ||||
| // 非setup | ||||
| export const usePermissionStoreHook = () => { | ||||
| 	return usePermissionStore(store); | ||||
|   return usePermissionStore(store); | ||||
| }; | ||||
|  | ||||
| export default usePermissionStore; | ||||
|  | ||||
| @ -5,50 +5,50 @@ import { useDynamicTitle } from '@/utils/dynamicTitle'; | ||||
| import { Ref } from 'vue'; | ||||
|  | ||||
| export const useSettingsStore = defineStore('setting', () => { | ||||
| 	const storageSetting = JSON.parse(localStorage.getItem('layout-setting') || '{}'); | ||||
|   const storageSetting = JSON.parse(localStorage.getItem('layout-setting') || '{}'); | ||||
|  | ||||
| 	const prop: { [key: string]: Ref<any> } = { | ||||
| 		title: ref<string>(''), | ||||
| 		theme: ref<string>(storageSetting.theme || defaultSettings.theme), | ||||
| 		sideTheme: ref<string>(storageSetting.sideTheme || defaultSettings.sideTheme), | ||||
| 		showSettings: ref<boolean>(storageSetting.showSettings), | ||||
| 		topNav: ref<boolean>(storageSetting.topNav || defaultSettings.topNav), | ||||
| 		tagsView: ref<boolean>(storageSetting.tagsView || defaultSettings.tagsView), | ||||
| 		fixedHeader: ref<boolean>(storageSetting.fixedHeader || defaultSettings.fixedHeader), | ||||
| 		sidebarLogo: ref<boolean>(storageSetting.sidebarLogo || defaultSettings.sidebarLogo), | ||||
| 		dynamicTitle: ref<boolean>(storageSetting.dynamicTitle || defaultSettings.dynamicTitle), | ||||
| 		animationEnable: ref<boolean>(storageSetting.animationEnable || defaultSettings.animationEnable), | ||||
| 		dark: ref<boolean>(storageSetting.dark || defaultSettings.dark) | ||||
| 	}; | ||||
|   const prop: { [key: string]: Ref<any> } = { | ||||
|     title: ref<string>(''), | ||||
|     theme: ref<string>(storageSetting.theme || defaultSettings.theme), | ||||
|     sideTheme: ref<string>(storageSetting.sideTheme || defaultSettings.sideTheme), | ||||
|     showSettings: ref<boolean>(storageSetting.showSettings), | ||||
|     topNav: ref<boolean>(storageSetting.topNav || defaultSettings.topNav), | ||||
|     tagsView: ref<boolean>(storageSetting.tagsView || defaultSettings.tagsView), | ||||
|     fixedHeader: ref<boolean>(storageSetting.fixedHeader || defaultSettings.fixedHeader), | ||||
|     sidebarLogo: ref<boolean>(storageSetting.sidebarLogo || defaultSettings.sidebarLogo), | ||||
|     dynamicTitle: ref<boolean>(storageSetting.dynamicTitle || defaultSettings.dynamicTitle), | ||||
|     animationEnable: ref<boolean>(storageSetting.animationEnable || defaultSettings.animationEnable), | ||||
|     dark: ref<boolean>(storageSetting.dark || defaultSettings.dark) | ||||
|   }; | ||||
|  | ||||
| 	const { title, theme, sideTheme, showSettings, topNav, tagsView, fixedHeader, sidebarLogo, dynamicTitle, animationEnable, dark } = prop; | ||||
|   const { title, theme, sideTheme, showSettings, topNav, tagsView, fixedHeader, sidebarLogo, dynamicTitle, animationEnable, dark } = prop; | ||||
|  | ||||
| 	// actions | ||||
| 	const changeSetting = (param: { key: SettingTypeEnum; value: any }) => { | ||||
| 		const { key, value } = param; | ||||
| 		if (key in prop) { | ||||
| 			prop[key].value = value; | ||||
| 		} | ||||
| 	}; | ||||
| 	const setTitle = (value: string) => { | ||||
| 		title.value = value; | ||||
| 		useDynamicTitle(); | ||||
| 	}; | ||||
| 	return { | ||||
| 		title, | ||||
| 		theme, | ||||
| 		sideTheme, | ||||
| 		showSettings, | ||||
| 		topNav, | ||||
| 		tagsView, | ||||
| 		fixedHeader, | ||||
| 		sidebarLogo, | ||||
| 		dynamicTitle, | ||||
| 		animationEnable, | ||||
| 		dark, | ||||
| 		changeSetting, | ||||
| 		setTitle | ||||
| 	}; | ||||
|   // actions | ||||
|   const changeSetting = (param: { key: SettingTypeEnum; value: any }) => { | ||||
|     const { key, value } = param; | ||||
|     if (key in prop) { | ||||
|       prop[key].value = value; | ||||
|     } | ||||
|   }; | ||||
|   const setTitle = (value: string) => { | ||||
|     title.value = value; | ||||
|     useDynamicTitle(); | ||||
|   }; | ||||
|   return { | ||||
|     title, | ||||
|     theme, | ||||
|     sideTheme, | ||||
|     showSettings, | ||||
|     topNav, | ||||
|     tagsView, | ||||
|     fixedHeader, | ||||
|     sidebarLogo, | ||||
|     dynamicTitle, | ||||
|     animationEnable, | ||||
|     dark, | ||||
|     changeSetting, | ||||
|     setTitle | ||||
|   }; | ||||
| }); | ||||
|  | ||||
| export default useSettingsStore; | ||||
|  | ||||
| @ -1,198 +1,198 @@ | ||||
| import { TagView } from 'vue-router'; | ||||
|  | ||||
| export const useTagsViewStore = defineStore('tagsView', () => { | ||||
| 	const visitedViews = ref<TagView[]>([]); | ||||
| 	const cachedViews = ref<string[]>([]); | ||||
| 	const iframeViews = ref<TagView[]>([]); | ||||
|   const visitedViews = ref<TagView[]>([]); | ||||
|   const cachedViews = ref<string[]>([]); | ||||
|   const iframeViews = ref<TagView[]>([]); | ||||
|  | ||||
| 	const addView = (view: TagView) => { | ||||
| 		addVisitedView(view); | ||||
| 		addCachedView(view); | ||||
| 	}; | ||||
|   const addView = (view: TagView) => { | ||||
|     addVisitedView(view); | ||||
|     addCachedView(view); | ||||
|   }; | ||||
|  | ||||
| 	const addIframeView = (view: TagView): void => { | ||||
| 		if (iframeViews.value.some((v) => v.path === view.path)) return; | ||||
| 		iframeViews.value.push( | ||||
| 			Object.assign({}, view, { | ||||
| 				title: view.meta?.title || 'no-name' | ||||
| 			}) | ||||
| 		); | ||||
| 	}; | ||||
| 	const delIframeView = (view: TagView): Promise<TagView[]> => { | ||||
| 		return new Promise((resolve) => { | ||||
| 			iframeViews.value = iframeViews.value.filter((item) => item.path !== view.path); | ||||
| 			resolve([...iframeViews.value]); | ||||
| 		}); | ||||
| 	}; | ||||
| 	const addVisitedView = (view: TagView): void => { | ||||
| 		if (visitedViews.value.some((v) => v.path === view.path)) return; | ||||
| 		visitedViews.value.push( | ||||
| 			Object.assign({}, view, { | ||||
| 				title: view.meta?.title || 'no-name' | ||||
| 			}) | ||||
| 		); | ||||
| 	}; | ||||
| 	const delView = (view: TagView): Promise<{ visitedViews: TagView[]; cachedViews: string[] }> => { | ||||
| 		return new Promise((resolve) => { | ||||
| 			delVisitedView(view); | ||||
| 			delCachedView(view); | ||||
| 			resolve({ | ||||
| 				visitedViews: [...visitedViews.value], | ||||
| 				cachedViews: [...cachedViews.value] | ||||
| 			}); | ||||
| 		}); | ||||
| 	}; | ||||
|   const addIframeView = (view: TagView): void => { | ||||
|     if (iframeViews.value.some((v) => v.path === view.path)) return; | ||||
|     iframeViews.value.push( | ||||
|       Object.assign({}, view, { | ||||
|         title: view.meta?.title || 'no-name' | ||||
|       }) | ||||
|     ); | ||||
|   }; | ||||
|   const delIframeView = (view: TagView): Promise<TagView[]> => { | ||||
|     return new Promise((resolve) => { | ||||
|       iframeViews.value = iframeViews.value.filter((item) => item.path !== view.path); | ||||
|       resolve([...iframeViews.value]); | ||||
|     }); | ||||
|   }; | ||||
|   const addVisitedView = (view: TagView): void => { | ||||
|     if (visitedViews.value.some((v) => v.path === view.path)) return; | ||||
|     visitedViews.value.push( | ||||
|       Object.assign({}, view, { | ||||
|         title: view.meta?.title || 'no-name' | ||||
|       }) | ||||
|     ); | ||||
|   }; | ||||
|   const delView = (view: TagView): Promise<{ visitedViews: TagView[]; cachedViews: string[] }> => { | ||||
|     return new Promise((resolve) => { | ||||
|       delVisitedView(view); | ||||
|       delCachedView(view); | ||||
|       resolve({ | ||||
|         visitedViews: [...visitedViews.value], | ||||
|         cachedViews: [...cachedViews.value] | ||||
|       }); | ||||
|     }); | ||||
|   }; | ||||
|  | ||||
| 	const delVisitedView = (view: TagView): Promise<TagView[]> => { | ||||
| 		return new Promise((resolve) => { | ||||
| 			for (const [i, v] of visitedViews.value.entries()) { | ||||
| 				if (v.path === view.path) { | ||||
| 					visitedViews.value.splice(i, 1); | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
| 			resolve([...visitedViews.value]); | ||||
| 		}); | ||||
| 	}; | ||||
| 	const delCachedView = (view: TagView): Promise<string[]> => { | ||||
| 		const viewName = view.name as string; | ||||
| 		return new Promise((resolve) => { | ||||
| 			const index = cachedViews.value.indexOf(viewName); | ||||
| 			index > -1 && cachedViews.value.splice(index, 1); | ||||
| 			resolve([...cachedViews.value]); | ||||
| 		}); | ||||
| 	}; | ||||
| 	const delOthersViews = (view: TagView): Promise<{ visitedViews: TagView[]; cachedViews: string[] }> => { | ||||
| 		return new Promise((resolve) => { | ||||
| 			delOthersVisitedViews(view); | ||||
| 			delOthersCachedViews(view); | ||||
| 			resolve({ | ||||
| 				visitedViews: [...visitedViews.value], | ||||
| 				cachedViews: [...cachedViews.value] | ||||
| 			}); | ||||
| 		}); | ||||
| 	}; | ||||
|   const delVisitedView = (view: TagView): Promise<TagView[]> => { | ||||
|     return new Promise((resolve) => { | ||||
|       for (const [i, v] of visitedViews.value.entries()) { | ||||
|         if (v.path === view.path) { | ||||
|           visitedViews.value.splice(i, 1); | ||||
|           break; | ||||
|         } | ||||
|       } | ||||
|       resolve([...visitedViews.value]); | ||||
|     }); | ||||
|   }; | ||||
|   const delCachedView = (view: TagView): Promise<string[]> => { | ||||
|     const viewName = view.name as string; | ||||
|     return new Promise((resolve) => { | ||||
|       const index = cachedViews.value.indexOf(viewName); | ||||
|       index > -1 && cachedViews.value.splice(index, 1); | ||||
|       resolve([...cachedViews.value]); | ||||
|     }); | ||||
|   }; | ||||
|   const delOthersViews = (view: TagView): Promise<{ visitedViews: TagView[]; cachedViews: string[] }> => { | ||||
|     return new Promise((resolve) => { | ||||
|       delOthersVisitedViews(view); | ||||
|       delOthersCachedViews(view); | ||||
|       resolve({ | ||||
|         visitedViews: [...visitedViews.value], | ||||
|         cachedViews: [...cachedViews.value] | ||||
|       }); | ||||
|     }); | ||||
|   }; | ||||
|  | ||||
| 	const delOthersVisitedViews = (view: TagView): Promise<TagView[]> => { | ||||
| 		return new Promise((resolve) => { | ||||
| 			visitedViews.value = visitedViews.value.filter((v) => { | ||||
| 				return v.meta?.affix || v.path === view.path; | ||||
| 			}); | ||||
| 			resolve([...visitedViews.value]); | ||||
| 		}); | ||||
| 	}; | ||||
| 	const delOthersCachedViews = (view: TagView): Promise<string[]> => { | ||||
| 		const viewName = view.name as string; | ||||
| 		return new Promise((resolve) => { | ||||
| 			const index = cachedViews.value.indexOf(viewName); | ||||
| 			if (index > -1) { | ||||
| 				cachedViews.value = cachedViews.value.slice(index, index + 1); | ||||
| 			} else { | ||||
| 				cachedViews.value = []; | ||||
| 			} | ||||
| 			resolve([...cachedViews.value]); | ||||
| 		}); | ||||
| 	}; | ||||
|   const delOthersVisitedViews = (view: TagView): Promise<TagView[]> => { | ||||
|     return new Promise((resolve) => { | ||||
|       visitedViews.value = visitedViews.value.filter((v) => { | ||||
|         return v.meta?.affix || v.path === view.path; | ||||
|       }); | ||||
|       resolve([...visitedViews.value]); | ||||
|     }); | ||||
|   }; | ||||
|   const delOthersCachedViews = (view: TagView): Promise<string[]> => { | ||||
|     const viewName = view.name as string; | ||||
|     return new Promise((resolve) => { | ||||
|       const index = cachedViews.value.indexOf(viewName); | ||||
|       if (index > -1) { | ||||
|         cachedViews.value = cachedViews.value.slice(index, index + 1); | ||||
|       } else { | ||||
|         cachedViews.value = []; | ||||
|       } | ||||
|       resolve([...cachedViews.value]); | ||||
|     }); | ||||
|   }; | ||||
|  | ||||
| 	const delAllViews = (): Promise<{ visitedViews: TagView[]; cachedViews: string[] }> => { | ||||
| 		return new Promise((resolve) => { | ||||
| 			delAllVisitedViews(); | ||||
| 			delAllCachedViews(); | ||||
| 			resolve({ | ||||
| 				visitedViews: [...visitedViews.value], | ||||
| 				cachedViews: [...cachedViews.value] | ||||
| 			}); | ||||
| 		}); | ||||
| 	}; | ||||
| 	const delAllVisitedViews = (): Promise<TagView[]> => { | ||||
| 		return new Promise((resolve) => { | ||||
| 			visitedViews.value = visitedViews.value.filter((tag) => tag.meta?.affix); | ||||
| 			resolve([...visitedViews.value]); | ||||
| 		}); | ||||
| 	}; | ||||
|   const delAllViews = (): Promise<{ visitedViews: TagView[]; cachedViews: string[] }> => { | ||||
|     return new Promise((resolve) => { | ||||
|       delAllVisitedViews(); | ||||
|       delAllCachedViews(); | ||||
|       resolve({ | ||||
|         visitedViews: [...visitedViews.value], | ||||
|         cachedViews: [...cachedViews.value] | ||||
|       }); | ||||
|     }); | ||||
|   }; | ||||
|   const delAllVisitedViews = (): Promise<TagView[]> => { | ||||
|     return new Promise((resolve) => { | ||||
|       visitedViews.value = visitedViews.value.filter((tag) => tag.meta?.affix); | ||||
|       resolve([...visitedViews.value]); | ||||
|     }); | ||||
|   }; | ||||
|  | ||||
| 	const delAllCachedViews = (): Promise<string[]> => { | ||||
| 		return new Promise((resolve) => { | ||||
| 			cachedViews.value = []; | ||||
| 			resolve([...cachedViews.value]); | ||||
| 		}); | ||||
| 	}; | ||||
|   const delAllCachedViews = (): Promise<string[]> => { | ||||
|     return new Promise((resolve) => { | ||||
|       cachedViews.value = []; | ||||
|       resolve([...cachedViews.value]); | ||||
|     }); | ||||
|   }; | ||||
|  | ||||
| 	const updateVisitedView = (view: TagView): void => { | ||||
| 		for (let v of visitedViews.value) { | ||||
| 			if (v.path === view.path) { | ||||
| 				v = Object.assign(v, view); | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 	}; | ||||
| 	const delRightTags = (view: TagView): Promise<TagView[]> => { | ||||
| 		return new Promise((resolve) => { | ||||
| 			const index = visitedViews.value.findIndex((v) => v.path === view.path); | ||||
| 			if (index === -1) { | ||||
| 				return; | ||||
| 			} | ||||
| 			visitedViews.value = visitedViews.value.filter((item, idx) => { | ||||
| 				if (idx <= index || (item.meta && item.meta.affix)) { | ||||
| 					return true; | ||||
| 				} | ||||
| 				const i = cachedViews.value.indexOf(item.name as string); | ||||
| 				if (i > -1) { | ||||
| 					cachedViews.value.splice(i, 1); | ||||
| 				} | ||||
| 				return false; | ||||
| 			}); | ||||
| 			resolve([...visitedViews.value]); | ||||
| 		}); | ||||
| 	}; | ||||
| 	const delLeftTags = (view: TagView): Promise<TagView[]> => { | ||||
| 		return new Promise((resolve) => { | ||||
| 			const index = visitedViews.value.findIndex((v) => v.path === view.path); | ||||
| 			if (index === -1) { | ||||
| 				return; | ||||
| 			} | ||||
| 			visitedViews.value = visitedViews.value.filter((item, idx) => { | ||||
| 				if (idx >= index || (item.meta && item.meta.affix)) { | ||||
| 					return true; | ||||
| 				} | ||||
| 				const i = cachedViews.value.indexOf(item.name as string); | ||||
| 				if (i > -1) { | ||||
| 					cachedViews.value.splice(i, 1); | ||||
| 				} | ||||
| 				return false; | ||||
| 			}); | ||||
| 			resolve([...visitedViews.value]); | ||||
| 		}); | ||||
| 	}; | ||||
|   const updateVisitedView = (view: TagView): void => { | ||||
|     for (let v of visitedViews.value) { | ||||
|       if (v.path === view.path) { | ||||
|         v = Object.assign(v, view); | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|   }; | ||||
|   const delRightTags = (view: TagView): Promise<TagView[]> => { | ||||
|     return new Promise((resolve) => { | ||||
|       const index = visitedViews.value.findIndex((v) => v.path === view.path); | ||||
|       if (index === -1) { | ||||
|         return; | ||||
|       } | ||||
|       visitedViews.value = visitedViews.value.filter((item, idx) => { | ||||
|         if (idx <= index || (item.meta && item.meta.affix)) { | ||||
|           return true; | ||||
|         } | ||||
|         const i = cachedViews.value.indexOf(item.name as string); | ||||
|         if (i > -1) { | ||||
|           cachedViews.value.splice(i, 1); | ||||
|         } | ||||
|         return false; | ||||
|       }); | ||||
|       resolve([...visitedViews.value]); | ||||
|     }); | ||||
|   }; | ||||
|   const delLeftTags = (view: TagView): Promise<TagView[]> => { | ||||
|     return new Promise((resolve) => { | ||||
|       const index = visitedViews.value.findIndex((v) => v.path === view.path); | ||||
|       if (index === -1) { | ||||
|         return; | ||||
|       } | ||||
|       visitedViews.value = visitedViews.value.filter((item, idx) => { | ||||
|         if (idx >= index || (item.meta && item.meta.affix)) { | ||||
|           return true; | ||||
|         } | ||||
|         const i = cachedViews.value.indexOf(item.name as string); | ||||
|         if (i > -1) { | ||||
|           cachedViews.value.splice(i, 1); | ||||
|         } | ||||
|         return false; | ||||
|       }); | ||||
|       resolve([...visitedViews.value]); | ||||
|     }); | ||||
|   }; | ||||
|  | ||||
| 	const addCachedView = (view: TagView): void => { | ||||
| 		const viewName = view.name as string; | ||||
| 		if (cachedViews.value.includes(viewName)) return; | ||||
| 		if (!view.meta?.noCache) { | ||||
| 			cachedViews.value.push(viewName); | ||||
| 		} | ||||
| 	}; | ||||
|   const addCachedView = (view: TagView): void => { | ||||
|     const viewName = view.name as string; | ||||
|     if (cachedViews.value.includes(viewName)) return; | ||||
|     if (!view.meta?.noCache) { | ||||
|       cachedViews.value.push(viewName); | ||||
|     } | ||||
|   }; | ||||
|  | ||||
| 	return { | ||||
| 		visitedViews, | ||||
| 		cachedViews, | ||||
| 		iframeViews, | ||||
| 		addVisitedView, | ||||
| 		addCachedView, | ||||
| 		delVisitedView, | ||||
| 		delCachedView, | ||||
| 		updateVisitedView, | ||||
| 		addView, | ||||
| 		delView, | ||||
| 		delAllViews, | ||||
| 		delAllVisitedViews, | ||||
| 		delAllCachedViews, | ||||
| 		delOthersViews, | ||||
| 		delRightTags, | ||||
| 		delLeftTags, | ||||
| 		addIframeView, | ||||
| 		delIframeView | ||||
| 	}; | ||||
|   return { | ||||
|     visitedViews, | ||||
|     cachedViews, | ||||
|     iframeViews, | ||||
|     addVisitedView, | ||||
|     addCachedView, | ||||
|     delVisitedView, | ||||
|     delCachedView, | ||||
|     updateVisitedView, | ||||
|     addView, | ||||
|     delView, | ||||
|     delAllViews, | ||||
|     delAllVisitedViews, | ||||
|     delAllCachedViews, | ||||
|     delOthersViews, | ||||
|     delRightTags, | ||||
|     delLeftTags, | ||||
|     addIframeView, | ||||
|     delIframeView | ||||
|   }; | ||||
| }); | ||||
|  | ||||
| export default useTagsViewStore; | ||||
|  | ||||
| @ -6,78 +6,78 @@ import { login as loginApi, logout as logoutApi, getInfo as getUserInfo } from ' | ||||
| import { LoginData } from '@/api/types'; | ||||
|  | ||||
| export const useUserStore = defineStore('user', () => { | ||||
| 	const token = ref(getToken()); | ||||
| 	const name = ref(''); | ||||
| 	const nickname = ref(''); | ||||
| 	const userId = ref<string | number>(''); | ||||
| 	const avatar = ref(''); | ||||
| 	const roles = ref<Array<string>>([]); // 用户角色编码集合 → 判断路由权限 | ||||
| 	const permissions = ref<Array<string>>([]); // 用户权限编码集合 → 判断按钮权限 | ||||
|   const token = ref(getToken()); | ||||
|   const name = ref(''); | ||||
|   const nickname = ref(''); | ||||
|   const userId = ref<string | number>(''); | ||||
|   const avatar = ref(''); | ||||
|   const roles = ref<Array<string>>([]); // 用户角色编码集合 → 判断路由权限 | ||||
|   const permissions = ref<Array<string>>([]); // 用户权限编码集合 → 判断按钮权限 | ||||
|  | ||||
| 	/** | ||||
| 	 * 登录 | ||||
| 	 * @param userInfo | ||||
| 	 * @returns | ||||
| 	 */ | ||||
| 	const login = async (userInfo: LoginData): Promise<void> => { | ||||
| 		const [err, res] = await to(loginApi(userInfo)); | ||||
| 		if (res) { | ||||
| 			const data = res.data; | ||||
| 			setToken(data.token); | ||||
| 			token.value = data.token; | ||||
| 			return Promise.resolve(); | ||||
| 		} | ||||
| 		return Promise.reject(err); | ||||
| 	}; | ||||
|   /** | ||||
|    * 登录 | ||||
|    * @param userInfo | ||||
|    * @returns | ||||
|    */ | ||||
|   const login = async (userInfo: LoginData): Promise<void> => { | ||||
|     const [err, res] = await to(loginApi(userInfo)); | ||||
|     if (res) { | ||||
|       const data = res.data; | ||||
|       setToken(data.token); | ||||
|       token.value = data.token; | ||||
|       return Promise.resolve(); | ||||
|     } | ||||
|     return Promise.reject(err); | ||||
|   }; | ||||
|  | ||||
| 	// 获取用户信息 | ||||
| 	const getInfo = async (): Promise<void> => { | ||||
| 		const [err, res] = await to(getUserInfo()); | ||||
| 		if (res) { | ||||
| 			const data = res.data; | ||||
| 			const user = data.user; | ||||
| 			const profile = user.avatar == '' || user.avatar == null ? defAva : user.avatar; | ||||
|   // 获取用户信息 | ||||
|   const getInfo = async (): Promise<void> => { | ||||
|     const [err, res] = await to(getUserInfo()); | ||||
|     if (res) { | ||||
|       const data = res.data; | ||||
|       const user = data.user; | ||||
|       const profile = user.avatar == '' || user.avatar == null ? defAva : user.avatar; | ||||
|  | ||||
| 			if (data.roles && data.roles.length > 0) { | ||||
| 				// 验证返回的roles是否是一个非空数组 | ||||
| 				roles.value = data.roles; | ||||
| 				permissions.value = data.permissions; | ||||
| 			} else { | ||||
| 				roles.value = ['ROLE_DEFAULT']; | ||||
| 			} | ||||
| 			name.value = user.userName; | ||||
| 			nickname.value = user.nickName; | ||||
| 			avatar.value = profile; | ||||
| 			userId.value = user.userId; | ||||
| 			return Promise.resolve(); | ||||
| 		} | ||||
| 		return Promise.reject(err); | ||||
| 	}; | ||||
|       if (data.roles && data.roles.length > 0) { | ||||
|         // 验证返回的roles是否是一个非空数组 | ||||
|         roles.value = data.roles; | ||||
|         permissions.value = data.permissions; | ||||
|       } else { | ||||
|         roles.value = ['ROLE_DEFAULT']; | ||||
|       } | ||||
|       name.value = user.userName; | ||||
|       nickname.value = user.nickName; | ||||
|       avatar.value = profile; | ||||
|       userId.value = user.userId; | ||||
|       return Promise.resolve(); | ||||
|     } | ||||
|     return Promise.reject(err); | ||||
|   }; | ||||
|  | ||||
| 	// 注销 | ||||
| 	const logout = async (): Promise<void> => { | ||||
| 		await logoutApi(); | ||||
| 		token.value = ''; | ||||
| 		roles.value = []; | ||||
| 		permissions.value = []; | ||||
| 		removeToken(); | ||||
| 	}; | ||||
|   // 注销 | ||||
|   const logout = async (): Promise<void> => { | ||||
|     await logoutApi(); | ||||
|     token.value = ''; | ||||
|     roles.value = []; | ||||
|     permissions.value = []; | ||||
|     removeToken(); | ||||
|   }; | ||||
|  | ||||
| 	return { | ||||
| 		userId, | ||||
| 		token, | ||||
| 		nickname, | ||||
| 		avatar, | ||||
| 		roles, | ||||
| 		permissions, | ||||
| 		login, | ||||
| 		getInfo, | ||||
| 		logout | ||||
| 	}; | ||||
|   return { | ||||
|     userId, | ||||
|     token, | ||||
|     nickname, | ||||
|     avatar, | ||||
|     roles, | ||||
|     permissions, | ||||
|     login, | ||||
|     getInfo, | ||||
|     logout | ||||
|   }; | ||||
| }); | ||||
|  | ||||
| export default useUserStore; | ||||
| // 非setup | ||||
| export function useUserStoreHook() { | ||||
| 	return useUserStore(store); | ||||
|   return useUserStore(store); | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 疯狂的狮子Li
					疯狂的狮子Li