mirror of
				https://github.com/soybeanjs/soybean-admin.git
				synced 2025-10-31 05:43:42 +08:00 
			
		
		
		
	Compare commits
	
		
			17 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 8b27fc8bb8 | ||
|  | 738964a769 | ||
|  | c429cd0293 | ||
|  | 20aa39f14e | ||
|  | 93f9aa9584 | ||
|  | 8ce627a397 | ||
|  | 1ffb75afce | ||
|  | 32aa5ee75a | ||
|  | 98a7d25cf8 | ||
|  | 1b3463d2e7 | ||
|  | cff11d9175 | ||
|  | 54577f10fc | ||
|  | 6261156c5a | ||
|  | f5a5f44a2b | ||
|  | 3fb7a5f709 | ||
|  | e6c9b35ab4 | ||
|  | 0569666a8f | 
							
								
								
									
										5
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							| @@ -62,7 +62,10 @@ | ||||
| 	"material-icon-theme.folders.associations": { | ||||
| 		"enum": "typescript", | ||||
| 		"store": "context", | ||||
| 		"composable": "hook", | ||||
| 		"composables": "hook", | ||||
| 		"business": "core", | ||||
| 		"directive": "tools", | ||||
| 		"directives": "tools", | ||||
| 		"business": "core" | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										18
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -2,6 +2,24 @@ | ||||
|  | ||||
| All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. | ||||
|  | ||||
| ### [0.0.4](https://github.com/honghuangdc/soybean-admin/compare/v0.0.3...v0.0.4) (2021-11-25) | ||||
|  | ||||
|  | ||||
| ### Features | ||||
|  | ||||
| * **components:** 添加多页签Tab点击后自动往中间滚动 ([8ce627a](https://github.com/honghuangdc/soybean-admin/commit/8ce627a397ee2605d967e7f9c8aa558b99fca22d)) | ||||
| * **projects:** 新增网址导航页面 ([32aa5ee](https://github.com/honghuangdc/soybean-admin/commit/32aa5ee75af80c2f959b74573d5c44c452d2715c)) | ||||
| * **storage:** local存储增加有效期 ([e6c9b35](https://github.com/honghuangdc/soybean-admin/commit/e6c9b35ab402df7d9ebb82306131fc30d0a8b893)) | ||||
|  | ||||
|  | ||||
| ### Bug Fixes | ||||
|  | ||||
| * **components:** 修复多页签按钮风格的tab滚动问题 ([c429cd0](https://github.com/honghuangdc/soybean-admin/commit/c429cd0293dbfbf6b6df539857c276d3218de754)) | ||||
| * **components:** 修复多页签Tab自动滚动问题 ([20aa39f](https://github.com/honghuangdc/soybean-admin/commit/20aa39f14ed0239f02118b62a6aa4706b1f9dd21)) | ||||
| * **projects:** 添加西瓜视频实例在onUnMounted的销毁,多页签居中距离精确 ([738964a](https://github.com/honghuangdc/soybean-admin/commit/738964a76975dc3cb1f3206eb13a7612b92f1aed)) | ||||
| * **projects:** 修复打包构建时图标错误 ([93f9aa9](https://github.com/honghuangdc/soybean-admin/commit/93f9aa9584be803704cf0ff54c8da0f84b71c408)) | ||||
| * **types:** 添加dotEnv类型的非空判断 ([cff11d9](https://github.com/honghuangdc/soybean-admin/commit/cff11d91758a470ad6ff33888ed24747b2cc0c03)) | ||||
|  | ||||
| ### [0.0.3](https://github.com/honghuangdc/soybean-admin/compare/v0.0.2...v0.0.3) (2021-11-23) | ||||
|  | ||||
| ### 0.0.2 (2021-11-21) | ||||
|   | ||||
							
								
								
									
										53
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										53
									
								
								README.md
									
									
									
									
									
								
							| @@ -1,14 +1,9 @@ | ||||
| <div align="center"> | ||||
|   <a href="https://github.com/honghuangdc/soybean-admin"> | ||||
|     <img alt="SoybeanAdmin Logo" width="200" height="200" src="https://s3.bmp.ovh/imgs/2021/09/088571214c76b1e5.png"> | ||||
|   </a><br /><br /> | ||||
| <div style="text-align:center"> | ||||
| 	<img src="https://i.loli.net/2021/11/24/x5lLfuSnEawBAgi.png"/> | ||||
| 	<h1>Soybean Admin</h1> | ||||
|   <br /> | ||||
| </div> | ||||
|  | ||||
| [](LICENSE) | ||||
|  | ||||
|  | ||||
| [](./LICENSE) | ||||
|  | ||||
| ## 简介 | ||||
|  | ||||
| @@ -26,25 +21,26 @@ Soybean Admin 是一个基于 Vue3、Vite、Naive UI、TypeScript 的免费中 | ||||
|  | ||||
| - [soybean-admin](https://soybean.pro/) | ||||
|  | ||||
| <p align="center"> | ||||
| ## 文档 | ||||
|  | ||||
|     <img alt="SoybeanAdmin" width="100%" src="https://raw.githubusercontent.com/honghuangdc/project-assets/main/img/02.png"> | ||||
|  | ||||
|     <img alt="SoybeanAdmin" width="100%" src="https://raw.githubusercontent.com/honghuangdc/project-assets/main/img/03.png"> | ||||
|  | ||||
|     <img alt="SoybeanAdmin" width="100%" src="https://raw.githubusercontent.com/honghuangdc/project-assets/main/img/01.png"> | ||||
|  | ||||
| <img alt="SoybeanAdmin" width="100%" src="https://raw.githubusercontent.com/honghuangdc/project-assets/main/img/04.png"> | ||||
|  | ||||
| <img alt="SoybeanAdmin" width="100%" src="https://raw.githubusercontent.com/honghuangdc/project-assets/main/img/05.png"> | ||||
|  | ||||
| </p> | ||||
| - [项目文档](https://docs.soybean.pro) | ||||
|  | ||||
| ### 代码仓库 | ||||
|  | ||||
| **github**:https://github.com/honghuangdc/soybean-admin | ||||
| - [github](https://github.com/honghuangdc/soybean-admin) | ||||
|  | ||||
| **gitee**:https://gitee.com/honghuangdc/soybean-admin | ||||
| - [gitee](https://gitee.com/honghuangdc/soybean-admin) | ||||
|  | ||||
| ## 项目示例图 | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| ### 使用 Gitpod | ||||
|  | ||||
| @@ -52,10 +48,6 @@ Soybean Admin 是一个基于 Vue3、Vite、Naive UI、TypeScript 的免费中 | ||||
|  | ||||
| [](https://gitpod.io/#https://github.com/honghuangdc/soybean-admin) | ||||
|  | ||||
| ## 文档 | ||||
|  | ||||
| [项目相关文档](./doc) | ||||
|  | ||||
| ## 安装使用 | ||||
|  | ||||
| - 克隆代码 | ||||
| @@ -102,9 +94,10 @@ pnpm i -g commitizen | ||||
|  | ||||
| 支持现代浏览器, 不支持 IE | ||||
|  | ||||
| | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | | ||||
| | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/archive/internet-explorer_9-11/internet-explorer_9-11_48x48.png" alt="IE" width="24px" height="24px"  />](http://godban.github.io/browsers-support-badges/)IE | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)Safari | | ||||
| | :-: | :-: | :-: | :-: | :-: | | ||||
| | not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions | | ||||
|  | ||||
| ## 开源作者 | ||||
|  | ||||
| [@Soybean](https://github.com/honghuangdc) | ||||
| @@ -115,11 +108,11 @@ pnpm i -g commitizen | ||||
|  | ||||
| - QQ 群 `711301266` | ||||
|  | ||||
|   <div style="text-align:left;"> | ||||
|     <img src="https://raw.githubusercontent.com/honghuangdc/project-assets/main/img/qq_qrcode.JPG" style="width:200px" /> | ||||
|   <div style="text-align:left"> | ||||
|     <img src="https://i.loli.net/2021/11/24/1J6REWXiHomU2kM.jpg" style="width:200px" /> | ||||
|   </div> | ||||
|  | ||||
|    | ||||
|  | ||||
|  | ||||
| - 本人微信号:honghuangdc,欢迎来技术交流。 | ||||
|  | ||||
|   | ||||
							
								
								
									
										2
									
								
								build/env/index.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								build/env/index.ts
									
									
									
									
										vendored
									
									
								
							| @@ -2,4 +2,4 @@ import dotenv from 'dotenv'; | ||||
|  | ||||
| const { parsed: viteEnv } = dotenv.config(); // 加载环境 | ||||
|  | ||||
| export default viteEnv; | ||||
| export default viteEnv!; | ||||
|   | ||||
| @@ -1,47 +0,0 @@ | ||||
| ### 1.interface和type | ||||
|  | ||||
| ##### interface和type使用优先级:能用interface表示的类型就用interface。 | ||||
|  | ||||
| ### 2.请求函数 | ||||
|  | ||||
| #### api接口: | ||||
|  | ||||
| 统一以 **fetch** 开头,例如: | ||||
|  | ||||
| ```typescript | ||||
| /** | ||||
|  * 获取用户信息 | ||||
|  * @param id - 用户唯一标识id | ||||
|  */ | ||||
| function fetchUserInfo(id:string) { | ||||
| 	// *** | ||||
| } | ||||
| /** | ||||
|  * 删除列表项 | ||||
|  * @param id - 列表id | ||||
|  */ | ||||
| function fetchDeleteListItem(id:string) { | ||||
| 	// *** | ||||
| } | ||||
| ``` | ||||
|  | ||||
| #### middleware中间件: | ||||
|  | ||||
| 统一以 **handle** 开头,例如 | ||||
|  | ||||
| ```typescript | ||||
| /**接口返回的用户信息 */ | ||||
| interface ResponseUserInfo { | ||||
|   userId: string; | ||||
|   userName: string; | ||||
|   userAge: number; | ||||
| } | ||||
| /** | ||||
|  * 获取用户信息 中间件 | ||||
|  @param data - 返回的用户信息 | ||||
|  */ | ||||
| function handleUserInfo(data: ResponseUserInfo): UserInfo { | ||||
|   // *** | ||||
| } | ||||
| ``` | ||||
|  | ||||
| @@ -1,35 +0,0 @@ | ||||
| ### css书写顺序 | ||||
|  | ||||
| 1. 定位属性: | ||||
|  | ||||
|    `position display float left top right bottom overflow clear z-index` | ||||
|  | ||||
| 2. 自身属性: | ||||
|  | ||||
|    `width height padding border margin background` | ||||
|  | ||||
| 3. 文字样式: | ||||
|  | ||||
|    `font-family font-size font-style font-weight font-varient color` | ||||
|  | ||||
| 4. 文本属性: | ||||
|  | ||||
|    `text-align vertical-align text-wrap text-transform text-indent text-decoration letter-spacing word-spacing white-space text-overflow` | ||||
|  | ||||
| 5. css3中新增属性: | ||||
|  | ||||
|    `content box-shadow border-radius transform` | ||||
|  | ||||
| #### class类名的顺序: | ||||
|  | ||||
| 1. 自定义的class类名(遵循BEM命名法) | ||||
| 2. css插件提供的类名按照以上的css属性对应的顺序 | ||||
|  | ||||
| 例如:自定义类名结合tailwind css | ||||
|  | ||||
| <div class="demo-container absolute flex justify-center items-center left-10px top-12px overflow-hidden wh-full p-10px border-1px border-[#f00] m-24px bg-[#fff] text-32px text-[#0f0]"></div> | ||||
| <style> | ||||
| 	.demo-container { | ||||
| 		box-shadow: 2px 0 8px 0 rgb(29 35 41 / 5%); | ||||
| 	} | ||||
| </style> | ||||
| @@ -1,41 +0,0 @@ | ||||
| ### iconify用法 | ||||
|  | ||||
| #### 一、静态用法:直接用图标的组件名称 | ||||
|  | ||||
| 1. 安装vscode智能提示的插件: Iconify IntelliSense | ||||
| 2. 找图标:网址 https://icones.js.org/ 或者 vscode安装 icones插件 | ||||
| 3. 确定图标名字:找到图标后复制名字 如:**'mdi:emoticon'** 组件为: `<icon-mdi:emoticon />`, icon-为设置的前缀 | ||||
| 4. 设置样式:同html标签一样直接应用style属性或者class属性; 通过设置color和font-size属性设置对应的颜色和大小 | ||||
|  | ||||
| #### 二、多个图标动态渲染 | ||||
|  | ||||
| 1. 确定图标名字,如:'mdi:emoticon' | ||||
|  | ||||
| 2. 引入Icon组件: | ||||
|  | ||||
|    `import { Icon } from '@iconify/vue';` | ||||
|  | ||||
| 3. 动态渲染 | ||||
|  | ||||
|     `<Icon icon="mdi:emoticon" />` | ||||
|  | ||||
| *ps:Icon组件属性 https://docs.iconify.design/icon-components/vue/* | ||||
|  | ||||
| #### 三、结合naiveUI组件动态渲染 | ||||
|  | ||||
| 1. 确定图标名字,如:**'mdi:emoticon'** | ||||
|  | ||||
| 2. 引入vue的h函数: | ||||
|  | ||||
|    `import { h } from 'vue';` | ||||
|  | ||||
| 3. 引入Icon组件 | ||||
|  | ||||
|    `import { Icon } from '@iconify/vue';` | ||||
|  | ||||
| 4. 动态渲染 | ||||
|  | ||||
|    `() => h(Icon, { icon: 'mdi:emoticon', style: { color: '#f00', fontSize: '16px' } })` | ||||
|  | ||||
| *ps:@/uitls已封装好了函数:iconifyRender* | ||||
|  | ||||
							
								
								
									
										209
									
								
								doc/vue书写规范.md
									
									
									
									
									
								
							
							
						
						
									
										209
									
								
								doc/vue书写规范.md
									
									
									
									
									
								
							| @@ -1,209 +0,0 @@ | ||||
| ### script-setup写法 | ||||
|  | ||||
| #### 第一部分 | ||||
|  | ||||
| ##### template | ||||
|  | ||||
| #### 第二部分 | ||||
|  | ||||
| ##### script | ||||
|  | ||||
| ##### 一、import的顺序, 依次按照下面的顺序。 | ||||
|  | ||||
| 1. vue模块 | ||||
|  | ||||
|    ```typescript | ||||
|    import {  } from 'vue'; | ||||
|    ``` | ||||
|  | ||||
| 2. vue相关类型 | ||||
|  | ||||
|    ```typescript | ||||
|    import type {  } from 'vue'; | ||||
|    ``` | ||||
|  | ||||
| 3. vue-router模块 | ||||
|  | ||||
|    ```typescript | ||||
|    import {  } from 'vue-router'; | ||||
|    ``` | ||||
|  | ||||
| 4. vue-router相关类型 | ||||
|  | ||||
|    ```typescript | ||||
|    import type {  } from 'vue-router'; | ||||
|    ``` | ||||
|  | ||||
| 5. UI框架模块 | ||||
|  | ||||
|    ```typescript | ||||
|    import {  } from 'naive-ui'; | ||||
|    ``` | ||||
|  | ||||
| 6. UI框架相关类型 | ||||
|  | ||||
|    ```typescript | ||||
|    import type {  } from 'naive-ui'; | ||||
|    ``` | ||||
|  | ||||
| 7. 第三方依赖 | ||||
|  | ||||
|    ```typescript | ||||
|    import BScroll from 'bscroll'; | ||||
|    ``` | ||||
|  | ||||
| 8. 第三方依赖相关类型 | ||||
|  | ||||
|    ```typescript | ||||
|    import type {  } from 'bscroll'; | ||||
|    ``` | ||||
|  | ||||
| 9. @/enum | ||||
|  | ||||
|    ```typescript | ||||
|    import {  } from '@/enum'; | ||||
|    ``` | ||||
|  | ||||
| 10. @/setting | ||||
|  | ||||
|     ```typescript | ||||
|     import {  } from '@/setting'; | ||||
|     ``` | ||||
|  | ||||
| 11. @/plugins | ||||
|  | ||||
|     ```typescript | ||||
|     import {  } from '@/plugins'; | ||||
|     ``` | ||||
|  | ||||
| 12. @/layouts | ||||
|  | ||||
|     ```typescript | ||||
|     import {  } from '@/layouts'; | ||||
|     ``` | ||||
|  | ||||
| 13. @/views | ||||
|  | ||||
|     ```typescript | ||||
|     import {  } from '@/views'; | ||||
|     ``` | ||||
|  | ||||
| 14. @/components | ||||
|  | ||||
|     ```typescript | ||||
|     import {  } from '@/components'; | ||||
|     ``` | ||||
|  | ||||
| 15. @/hooks | ||||
|  | ||||
|     ```typescript | ||||
|     import {  } from '@/hooks'; | ||||
|     ``` | ||||
|  | ||||
| 16. @/store | ||||
|  | ||||
|     ```typescript | ||||
|     import {  } from '@/store'; | ||||
|     ``` | ||||
|  | ||||
| 17. @/context | ||||
|  | ||||
|     ```typescript | ||||
|     import {  } from '@/context'; | ||||
|     ``` | ||||
|  | ||||
| 18. @/router | ||||
|  | ||||
|     ```typescript | ||||
|     import {  } from '@/router'; | ||||
|     ``` | ||||
|  | ||||
| 19. @/service | ||||
|  | ||||
|     ```typescript | ||||
|     import {  } from '@/service'; | ||||
|     ``` | ||||
|  | ||||
| 20. @/utils | ||||
|  | ||||
|     ```typescript | ||||
|     import {  } from '@/utils'; | ||||
|     ``` | ||||
|  | ||||
| 21. @/interface | ||||
|  | ||||
|     ```typescript | ||||
|     import {  } from '@/interface'; | ||||
|     ``` | ||||
|  | ||||
| 22. @/assets | ||||
|  | ||||
|     ```typescript | ||||
|     import {  } from '@/assets'; | ||||
|     ``` | ||||
|  | ||||
| 23. 相对路径依赖 | ||||
|  | ||||
|     ```typescript | ||||
|     import {  } from './components'; | ||||
|     ``` | ||||
|  | ||||
| ##### 二、TS类型声明 | ||||
|  | ||||
| ```typescript | ||||
| interface Props { | ||||
| 	/**姓名 */ | ||||
|   name: string; | ||||
| 	/**年龄 */ | ||||
|   age?: number; | ||||
| } | ||||
| interface Emits { | ||||
|   /** | ||||
|    * 删除事件 | ||||
|    * @param id - 删除项的id | ||||
|    */ | ||||
| 	(e: 'delete', id: number): void; | ||||
| } | ||||
| ``` | ||||
|   | ||||
|  | ||||
| ##### 三、defineProps、defineEmits、withDefaults | ||||
|  | ||||
| 1. 定义属性,如: | ||||
|  | ||||
| ```typescript | ||||
| const props = withDefaults(defineProps<Props>(), { | ||||
|   age: 24 | ||||
| }); | ||||
| ``` | ||||
|  | ||||
| 其中name是必须的属性,age是可选属性,通过withDefaults添加默认值 | ||||
|  | ||||
| 2. 定义emit事件 | ||||
|  | ||||
| ```typescript | ||||
| const emit = defineEmits<Emits>(); | ||||
| ``` | ||||
|  | ||||
| ##### 四、响应式use函数 | ||||
|  | ||||
| 有些use函数需要传入响应式的变量参数时,则书写在声明的变量下面。 | ||||
|  | ||||
| ```typescript | ||||
| const router = useRouter(); | ||||
| const route = useRoute(); | ||||
| ``` | ||||
|  | ||||
| ```typescript | ||||
| /**dom引用 */ | ||||
| const domRef = ref<HTMLElement | null>(null); | ||||
| const { height: domRefHeight } = useElementSize(domRef); //获取domRef的响应式高度 | ||||
| ``` | ||||
|  | ||||
|  | ||||
|  | ||||
| ##### 五、变量、函数声明 | ||||
|  | ||||
| ##### 六、vue生命周期函数、nextTick执行 | ||||
|  | ||||
| ##### 七、defineExpose | ||||
							
								
								
									
										72
									
								
								doc/命名规范.md
									
									
									
									
									
								
							
							
						
						
									
										72
									
								
								doc/命名规范.md
									
									
									
									
									
								
							| @@ -1,72 +0,0 @@ | ||||
| ### 命名法: | ||||
|  | ||||
| #### 1.驼峰命名法(小驼峰) | ||||
|  | ||||
| **getUser** | ||||
|  | ||||
| #### 2.帕斯卡命名法(大驼峰) | ||||
|  | ||||
|  **GlobalHeader** | ||||
|  | ||||
| #### 3.短横线命名法 | ||||
|  | ||||
| **user-center** | ||||
|  | ||||
| #### 4.下划线命名法 | ||||
|  | ||||
|  **MAX_LENGTH** | ||||
|  | ||||
| ### 文件、文件夹命名: | ||||
|  | ||||
| 1. 文件夹作为**路由页面**时用小写字母,包含多个单词时,单词之间建议使用半角的连词线 ( - ) 分隔, 即**短横线命名法**,此时vue文件为**index.vue**。 | ||||
| 2. 文件夹作为**vue组件**时用**大写驼峰命名法**。 | ||||
| 3. 文件作为**vue组件**时用**大写驼峰命名法**。 | ||||
| 4. 文件作为**use函数**时用**小驼峰命名法**。 | ||||
| 5. 其余文件用**短横线命名法**。 | ||||
|  | ||||
| ### 变量命名: | ||||
| #### 命名方式 : 小驼峰式命名方法 | ||||
| **命名规范 : 类型+对象描述的方式,如果没有明确的类型,就可以使前缀为名词** | ||||
|  | ||||
| 动词 | 含义 | 返回值 | ||||
| ---|---|--- | ||||
| can | 判断是否可执行某个动作 | 函数返回一个布尔值。true:可执行;false:不可执行。 | ||||
| has | 判断是否含有某个值 | 函数返回一个布尔值。true:含有此值;false:不含有此值。 | ||||
| is | 判断是否为某个值 | 函数返回一个布尔值。true:为某个值;false:不为某个值。 | ||||
| get | 获取某个值 | 函数返回一个非布尔值。 | ||||
| set | 设置某个值 | 无返回值、返回是否设置成功或者返回链式对象。 | ||||
|  | ||||
| ```javascript | ||||
| /** 是否可读 */ | ||||
| function canRead(){ | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| /** 获取姓名 */ | ||||
| function getName(){ | ||||
|   return this.name; | ||||
| } | ||||
| ``` | ||||
|  | ||||
|  | ||||
| ### 常量 | ||||
| #### 命名方法 : 使用大写字母和下划线来组合命名,下划线用以分割单词。 | ||||
| ```javascript | ||||
| const MAX_COUNT = 10; | ||||
| const URL = 'http://www.baidu.com'; | ||||
| ``` | ||||
|  | ||||
| ### TS类型接口interface和type | ||||
|  | ||||
| ##### 命名方法:大写驼峰 | ||||
|  | ||||
| ```typescript | ||||
| interface PersonInfo { | ||||
|   /**姓名 */ | ||||
|   name: string; | ||||
|   /**性别 '0':男; '1': 女; '2': 未知 */ | ||||
|   gender: '0' | '1' | '2'; | ||||
|   /**年龄 */ | ||||
|   age: 25; | ||||
| } | ||||
| ``` | ||||
							
								
								
									
										101
									
								
								doc/目录.md
									
									
									
									
									
								
							
							
						
						
									
										101
									
								
								doc/目录.md
									
									
									
									
									
								
							| @@ -1,101 +0,0 @@ | ||||
|  | ||||
| ## 目录规范 | ||||
|  | ||||
| ```javascript | ||||
| qitan-pc | ||||
| ├── build                      //vite构建相关配置和插件 | ||||
| │   ├── define                 //定义的全局常量,通过vite构建时注入 | ||||
| │   ├── env                    //.env环境文件内容加载插件 | ||||
| │   └── plugins                //构建插件 | ||||
| │       ├── html.ts            //html插件(注入变量,压缩代码等) | ||||
| │       ├── iconify.ts         //iconify图标插件 | ||||
| │       ├── visualizer.ts      //构建的依赖大小占比分析插件 | ||||
| │       ├── vue.ts             //vue相关vite插件 | ||||
| │       └── windicss.ts        //css框架插件 | ||||
| ├── doc                        //项目相关说明文档 | ||||
| ├── public                     //公共目录 | ||||
| │   ├── resource               //资源文件夹(不会被打包) | ||||
| │   └── favicon.ico            //网站标签图标 | ||||
| ├── src | ||||
| │   ├── assets                 //静态资源 | ||||
| │   ├── components             //全局组件 | ||||
| │   │   ├── business           //业务相关组件 | ||||
| │   │   ├── common             //公共组件 | ||||
| │   │   └── custom             //自定义组件 | ||||
| │   ├── context                //全局上下文(通过provide和inject实现) | ||||
| │   │   ├── app                //从app.vue注入的上下文 | ||||
| │   │   └── part               //局部组件注入的上下文 | ||||
| │   ├── enum                   //TS枚举 | ||||
| │   │   ├── animate.ts         //动画枚举 | ||||
| │   │   ├── business.ts        //业务相关枚举 | ||||
| │   │   ├── common.ts          //通用枚举 | ||||
| │   │   ├── route.ts           //路由相关枚举 | ||||
| │   │   ├── storage.ts         //存储相关枚举 | ||||
| │   │   └── theme.ts           //系统主题配置相关枚举 | ||||
| │   ├── hooks                  //组合式的钩子函数hooks | ||||
| │   │   ├── business           //业务相关hooks | ||||
| │   │   └── common             //通用hooks | ||||
| │   ├── interface              //TS类型接口 | ||||
| │   │   ├── business.ts        //业务相关类型接口 | ||||
| │   │   ├── common.ts          //通用类型接口 | ||||
| │   │   └── theme.ts           //系统主题配置相关类型接口 | ||||
| │   ├── layouts                //布局组件 | ||||
| │   │   ├── BasicLayout        //基本布局(包含全局头部、侧边栏、底部等公共部分) | ||||
| │   │   ├── BlankLayout        //空白布局组件(单个页面) | ||||
| │   │   └── RouterViewLayout   //路由组件(用于多级路由之间的桥接) | ||||
| │   ├── plugins                //插件 | ||||
| │   │   └── dark-mode.ts       //windicss暗黑模式插件 | ||||
| │   ├── router                 //vue路由 | ||||
| │   │   ├── modules            //路由页面(按模块划分) | ||||
| │   │   ├── permission         //路由权限(路由守卫) | ||||
| │   │   ├── routes         		 //声明的路由 | ||||
| │   │   └── setup              //路由挂载函数 | ||||
| │   ├── service                //网络请求 | ||||
| │   │   ├── api                //接口api | ||||
| │   │   ├── middleware         //请求结果的处理中间件 | ||||
| │   │   └── request            //封装的请求函数 | ||||
| │   ├── settings               //项目初始配置 | ||||
| │   │   └── theme.ts           //项目主题初始配置 | ||||
| │   ├── store                  //状态管理 | ||||
| │   │   └── modules            //状态管理划分的模块 | ||||
| │   ├── styles                 //样式 | ||||
| │   │   ├── css                //css | ||||
| │   │   └── scss               //scss | ||||
| │   ├── typings                //TS类型声明文件(*.d.ts) | ||||
| │   ├── utils                  //全局工具函数 | ||||
| │   │   ├── auth               //用户鉴权 | ||||
| │   │   ├── common             //通用工具函数 | ||||
| │   │   ├── package            //npm依赖 | ||||
| │   │   ├── router             //路由 | ||||
| │   │   ├── request            //请求工具函数 | ||||
| │   │   └── storage            //存储 | ||||
| │   ├── views                  //页面 | ||||
| │   │   ├── about | ||||
| │   │   ├── component | ||||
| │   │   ├── dashboard | ||||
| │   │   ├── document | ||||
| │   │   ├── multi-menu | ||||
| │   │   └── system             //系统内置页面:登录、异常页等 | ||||
| │   ├── App.vue                //vue文件入口 | ||||
| │   ├── AppProvider.vue        //配置naive UI的vue文件(国际化,loadingBar、message等组件) | ||||
| │   └── main.ts                //项目入口ts文件 | ||||
| ├── .cz-config.js              //git cz提交配置 | ||||
| ├── .editorconfig              //统一编辑器配置 | ||||
| ├── .env                       //环境文件 | ||||
| ├── .env.development           //环境文件(开发模式) | ||||
| ├── .env.production            //环境文件(生产模式) | ||||
| ├── .env.staging               //环境文件(自定义staging模式) | ||||
| ├── .eslintignore              //忽略eslint检查的配置文件 | ||||
| ├── .eslintrc.js               //eslint配置文件 | ||||
| ├── .gitignore                 //忽略git提交的配置文件 | ||||
| ├── .husky                     //git commit提交钩子,提交前检查代码格式和提交commit内容的格式 | ||||
| ├── .prettierrc.js             //prettier代码格式插件配置 | ||||
| ├── commitlint.config.js       //commitlint提交规范插件配置 | ||||
| ├── index.html | ||||
| ├── package.json               //npm依赖描述文件 | ||||
| ├── pnpm-lock.yaml             //npm包管理器pnpm依赖锁定文件 | ||||
| ├── README.md                  //项目介绍文档 | ||||
| ├── tsconfig.json              //TS配置 | ||||
| ├── vite.config.ts             //vite配置 | ||||
| └── windi.config.ts            //windicss框架配置 | ||||
| ``` | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|   "name": "soybean-admin", | ||||
|   "version": "0.0.3", | ||||
|   "version": "0.0.4", | ||||
|   "author": { | ||||
|     "name": "Soybean", | ||||
|     "email": "honghuangdc@gmail.com", | ||||
|   | ||||
							
								
								
									
										26
									
								
								src/assets/svg/common/logo.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/assets/svg/common/logo.svg
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 25.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 158.9 158.9" style="enable-background:new 0 0 158.9 158.9;" xml:space="preserve"> | ||||
| <style type="text/css"> | ||||
| 	.st0{fill:none;} | ||||
| 	.st1{fill:#409EFF;} | ||||
| </style> | ||||
| <path class="st0" d="M0,158.9C0,106.3,0,53.7,0,1.1C0,0.2,0.2,0,1.1,0c52.2,0,104.5,0,156.7,0c0.9,0,1.1,0.2,1.1,1.1 | ||||
| 	c0,52.2,0,104.5,0,156.7c0,0.9-0.2,1.1-1.1,1.1C105.2,158.8,52.6,158.8,0,158.9z"/> | ||||
| <path class="st1" d="M81.3,55.9c-0.1-11.7-2.9-22.5-9.4-32.4c-1-1.5-2.1-2.9-2.5-4.7c-0.7-3.4,0.9-6.9,4-8.6c3-1.7,6.8-1.2,9.3,1.2 | ||||
| 	c2.4,2.6,4.4,5.6,5.9,8.8c4.7,8.9,7.6,18.6,8.4,28.6c1,12.5-0.7,25-5.2,36.7c-0.9,2.5-1.9,4.9-3,7.3c-0.3,0.4-0.3,1,0,1.4 | ||||
| 	c9.6,13.3,21.8,23,37.8,27.2c6.4,1.7,13.1,2.3,19.7,1.6c4.2-0.4,7.9,2.7,8.4,6.9c0.7,4.3-2.3,8.3-6.6,9c0,0,0,0-0.1,0 | ||||
| 	c-7.7,0.9-15.5,0.5-23-1.3c-13.9-3.1-26.7-10-36.9-19.9c-4.4-4.2-8.4-8.8-11.9-13.7c-0.5-0.8-1.4-1.2-2.3-1.1 | ||||
| 	c-9.5,0.7-18.8,3.3-27.4,7.6c-11.6,6-20.7,14.6-26.4,26.4c-0.7,1.9-2,3.5-3.7,4.7c-2.9,1.7-6.6,1.5-9.2-0.7c-2.8-2.2-3.8-6-2.4-9.3 | ||||
| 	c2.2-5.2,5.1-10.1,8.7-14.5c12.2-15.4,28.2-24.6,47.3-28.6c4-0.8,8.1-1.4,12.2-1.6c0.5,0,1-0.3,1.2-0.8c3.3-7.1,5.5-14.6,6.5-22.3 | ||||
| 	C81.1,61.2,81.3,58.6,81.3,55.9z"/> | ||||
| <path class="st1" d="M136.3,108.3c-3.8-0.5-7.6-1.4-11.1-2.9c-7.7-2.8-14.4-7.5-19.7-13.8c-2.9-3.3-2.5-8.4,0.8-11.3 | ||||
| 	c1.4-1.2,3.1-1.9,4.9-1.9c2.5-0.1,5,1,6.5,2.9c4.9,5.6,11.6,9.4,18.9,10.8c1.5,0.2,3.1,0.6,4.5,1.2c3.2,1.8,4.8,5.6,3.8,9.2 | ||||
| 	C144,106.1,140.8,108.4,136.3,108.3z"/> | ||||
| <path class="st1" d="M55.7,33.3c3,0.2,5.6,2.2,6.6,5c2.2,5.4,3.4,11.2,3.6,17c0.3,5.9-0.6,11.7-2.5,17.3c-2,5.8-8.2,7.8-12.9,4.2 | ||||
| 	c-2.6-2.2-3.6-5.8-2.4-9c1.4-4,1.9-8.2,1.7-12.4c-0.2-3.8-1-7.5-2.4-11C45.3,38.9,49.2,33.3,55.7,33.3z"/> | ||||
| <path class="st1" d="M77.9,126.6c0,3.9-2.8,7.2-6.7,7.9c-7.8,1.5-14.8,5.9-19.7,12.2c-2.7,3.5-7.6,4.2-11.2,1.6 | ||||
| 	c-3.6-2.6-4.3-7.6-1.7-11.2c0.1-0.1,0.2-0.3,0.3-0.4c4.1-5.2,9.3-9.6,15.1-12.8c4.4-2.5,9.1-4.2,14-5.1 | ||||
| 	C73.3,117.7,77.9,121.3,77.9,126.6z"/> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 2.1 KiB | 
| @@ -24,6 +24,8 @@ const props = withDefaults(defineProps<Props>(), { | ||||
| }); | ||||
|  | ||||
| const COLOR_WHITE = '#ffffff'; | ||||
| const stopColor = computed(() => mixColor(COLOR_WHITE, props.themeColor, 0.7)); | ||||
| const stopColor = computed(() => { | ||||
|   return mixColor(COLOR_WHITE, props.themeColor, 0.7); | ||||
| }); | ||||
| </script> | ||||
| <style scoped></style> | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| <template> | ||||
|   <div ref="scrollbar" class="wh-full text-left"> | ||||
|   <div ref="scrollbar" class="h-full text-left"> | ||||
|     <div ref="scrollbarContent" class="inline-block" :class="{ 'h-full': !isScrollY }"> | ||||
|       <slot></slot> | ||||
|     </div> | ||||
| @@ -14,17 +14,15 @@ import { useElementSize } from '@vueuse/core'; | ||||
|  | ||||
| interface Props { | ||||
|   /** better-scroll的配置: https://better-scroll.github.io/docs/zh-CN/guide/base-scroll-options.html */ | ||||
|   options?: Options; | ||||
|   options: Options; | ||||
| } | ||||
|  | ||||
| const props = withDefaults(defineProps<Props>(), { | ||||
|   options: undefined | ||||
| }); | ||||
| const props = defineProps<Props>(); | ||||
|  | ||||
| const scrollbar = ref<HTMLElement | null>(null); | ||||
| const bsInstance = ref<BScroll | null>(null); | ||||
| const scrollbarContent = ref<HTMLElement | null>(null); | ||||
| const isScrollY = computed(() => Boolean(props.options?.scrollY)); | ||||
| const isScrollY = computed(() => Boolean(props.options.scrollY)); | ||||
|  | ||||
| function initBetterScroll() { | ||||
|   bsInstance.value = new BScroll(scrollbar.value!, props.options); | ||||
| @@ -41,5 +39,7 @@ watch([() => width.value, () => height.value], () => { | ||||
| onMounted(() => { | ||||
|   initBetterScroll(); | ||||
| }); | ||||
|  | ||||
| defineExpose({ bsInstance }); | ||||
| </script> | ||||
| <style scoped></style> | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| <template> | ||||
|   <div | ||||
|     class="relative flex-y-center h-34px px-24px cursor-pointer -mr-18px" | ||||
|     :class="{ 'z-10': isActive, 'z-9': isHover }" | ||||
|     class="relative flex-y-center h-34px px-24px cursor-pointer" | ||||
|     :class="{ '-mr-18px': !isLast, 'z-10': isActive, 'z-9': isHover }" | ||||
|     @mouseenter="setTrue" | ||||
|     @mouseleave="setFalse" | ||||
|   > | ||||
| @@ -39,14 +39,18 @@ interface Props { | ||||
|   closable?: boolean; | ||||
|   /** 暗黑模式 */ | ||||
|   darkMode?: boolean; | ||||
|   /** 是否是最后一个 */ | ||||
|   isLast: boolean; | ||||
| } | ||||
|  | ||||
| withDefaults(defineProps<Props>(), { | ||||
|   isActive: false, | ||||
|   primaryColor: '#409EFF', | ||||
|   closable: true, | ||||
|   darkMode: false | ||||
|   darkMode: false, | ||||
|   isLast: false | ||||
| }); | ||||
|  | ||||
| const emit = defineEmits<{ | ||||
|   /** 点击关闭图标 */ | ||||
|   (e: 'close'): void; | ||||
|   | ||||
| @@ -6,8 +6,8 @@ | ||||
|     @mouseleave="setFalse" | ||||
|   > | ||||
|     <transition name="transition-opacity"> | ||||
|       <icon-carbon-close-filled v-if="isHover" key="hover" class="absolute" /> | ||||
|       <icon-carbon-close v-else key="unhover" class="absolute" /> | ||||
|       <icon-mdi:close-circle v-if="isHover" key="hover" class="absolute" /> | ||||
|       <icon-mdi:close v-else key="unhover" class="absolute" /> | ||||
|     </transition> | ||||
|   </div> | ||||
| </template> | ||||
|   | ||||
							
								
								
									
										40
									
								
								src/components/custom/ThemeSwitch/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/components/custom/ThemeSwitch/index.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| <template> | ||||
|   <hover-container class="w-40px h-full text-14px text-[#999] hover:text-primary" @click="toggleDarkMode"> | ||||
|     <icon-mdi-moon-waning-crescent v-if="dark" /> | ||||
|     <icon-mdi-white-balance-sunny v-else /> | ||||
|   </hover-container> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| import { watch } from 'vue'; | ||||
| import { HoverContainer } from '../../common'; | ||||
| import { useBoolean } from '@/hooks'; | ||||
|  | ||||
| interface Props { | ||||
|   /** 暗黑模式 */ | ||||
|   dark?: boolean; | ||||
| } | ||||
|  | ||||
| interface Emits { | ||||
|   (e: 'update', darkMode: boolean): void; | ||||
| } | ||||
|  | ||||
| const props = withDefaults(defineProps<Props>(), { | ||||
|   dark: false | ||||
| }); | ||||
|  | ||||
| const emit = defineEmits<Emits>(); | ||||
|  | ||||
| const { bool: darkMode, setBool: setDarkMode, toggle: toggleDarkMode } = useBoolean(props.dark); | ||||
|  | ||||
| watch( | ||||
|   () => props.dark, | ||||
|   newValue => { | ||||
|     setDarkMode(newValue); | ||||
|   } | ||||
| ); | ||||
| watch(darkMode, newValue => { | ||||
|   emit('update', newValue); | ||||
| }); | ||||
| </script> | ||||
| <style scoped></style> | ||||
| @@ -5,5 +5,6 @@ import ChromeTab from './ChromeTab/index.vue'; | ||||
| import BetterScroll from './BetterScroll/index.vue'; | ||||
| import WebSiteLink from './WebSiteLink/index.vue'; | ||||
| import GithubLink from './GithubLink/index.vue'; | ||||
| import ThemeSwitch from './ThemeSwitch/index.vue'; | ||||
|  | ||||
| export { CountTo, IconClose, ButtonTab, ChromeTab, BetterScroll, WebSiteLink, GithubLink }; | ||||
| export { CountTo, IconClose, ButtonTab, ChromeTab, BetterScroll, WebSiteLink, GithubLink, ThemeSwitch }; | ||||
|   | ||||
| @@ -12,6 +12,24 @@ export function useDarkMode() { | ||||
|   /** naive-ui暗黑主题 */ | ||||
|   const naiveTheme = computed(() => (theme.darkMode ? darkTheme : undefined)); | ||||
|  | ||||
|   // windicss 暗黑模式 | ||||
|   const DARK_CLASS = 'dark'; | ||||
|   function getHtmlElement() { | ||||
|     return document.querySelector('html'); | ||||
|   } | ||||
|   function addDarkClass() { | ||||
|     const html = getHtmlElement(); | ||||
|     if (html) { | ||||
|       html.classList.add(DARK_CLASS); | ||||
|     } | ||||
|   } | ||||
|   function removeDarkClass() { | ||||
|     const html = getHtmlElement(); | ||||
|     if (html) { | ||||
|       html.classList.remove(DARK_CLASS); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // 监听操作系统主题模式 | ||||
|   watch( | ||||
|     osDark, | ||||
| @@ -22,6 +40,18 @@ export function useDarkMode() { | ||||
|       immediate: true | ||||
|     } | ||||
|   ); | ||||
|   // 监听主题的暗黑模式 | ||||
|   watch( | ||||
|     () => theme.darkMode, | ||||
|     newValue => { | ||||
|       if (newValue) { | ||||
|         addDarkClass(); | ||||
|       } else { | ||||
|         removeDarkClass(); | ||||
|       } | ||||
|     }, | ||||
|     { immediate: true } | ||||
|   ); | ||||
|  | ||||
|   return { | ||||
|     naiveTheme | ||||
|   | ||||
							
								
								
									
										0
									
								
								src/config/business/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								src/config/business/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										2
									
								
								src/config/common/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								src/config/common/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| export * from './service'; | ||||
| export * from './map-sdk'; | ||||
| @@ -1,6 +1,7 @@ | ||||
| /** 百度地图sdk地址 */ | ||||
| export const BAIDU_MAP_SDK_URL = | ||||
|   'https://api.map.baidu.com/getscript?v=3.0&ak=KSezYymXPth1DIGILRX3oYN9PxbOQQmU&services=&t=20210201100830&s=1'; | ||||
| 
 | ||||
| /** 高德地图sdk地址 */ | ||||
| export const GAODE_MAP_SDK_URL = 'https://webapi.amap.com/maps?v=2.0&key=e7bd02bd504062087e6563daf4d6721d'; | ||||
| 
 | ||||
							
								
								
									
										1
									
								
								src/config/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/config/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| export * from './common'; | ||||
							
								
								
									
										0
									
								
								src/directives/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								src/directives/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -1,2 +1,3 @@ | ||||
| export * from './auth'; | ||||
| export * from './demo'; | ||||
| export * from './website'; | ||||
|   | ||||
							
								
								
									
										18
									
								
								src/interface/business/website.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/interface/business/website.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| /** 网址导航 */ | ||||
| export interface Website { | ||||
|   /** 网址名称 */ | ||||
|   title: string; | ||||
|   /** 网址简称 */ | ||||
|   abbr: string; | ||||
|   /** 网址图标(网络地址,形状为正方形) */ | ||||
|   logo: string; | ||||
|   /** 描述 */ | ||||
|   desc: string; | ||||
| } | ||||
|  | ||||
| /** 网址导航 分类 */ | ||||
| export interface WebsiteCategory { | ||||
|   /** 分类名称 */ | ||||
|   title: string; | ||||
|   children: WebsiteCategory[] | Website[]; | ||||
| } | ||||
							
								
								
									
										7
									
								
								src/interface/common/expose.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/interface/common/expose.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| import type { Ref } from 'vue'; | ||||
| import BScroll from '@better-scroll/core'; | ||||
|  | ||||
| /** BetterScroll暴露出的数据的类型 */ | ||||
| export interface ExposeBetterScroll { | ||||
|   bsInstance: Ref<BScroll>; | ||||
| } | ||||
| @@ -1,4 +1,6 @@ | ||||
| export * from './theme'; | ||||
| export * from './system'; | ||||
| export * from './route'; | ||||
| export * from './expose'; | ||||
| export * from './service'; | ||||
| export * from './api'; | ||||
|   | ||||
| @@ -55,4 +55,5 @@ export type RouteKey = | ||||
|   | 'exception_403' | ||||
|   | 'exception_404' | ||||
|   | 'exception_500' | ||||
|   | 'about'; | ||||
|   | 'about' | ||||
|   | 'website'; | ||||
|   | ||||
| @@ -32,8 +32,6 @@ export interface CustomSuccessRequestResult<ResponseData> { | ||||
|   error: null; | ||||
|   /** 请求数据 */ | ||||
|   data: ResponseData; | ||||
|   /** 网络状态 */ | ||||
|   networkStatus: boolean; | ||||
| } | ||||
|  | ||||
| /** 自定义的请求失败结果 */ | ||||
| @@ -42,8 +40,6 @@ export interface CustomFailRequestResult { | ||||
|   error: RequestServiceError; | ||||
|   /** 请求数据 */ | ||||
|   data: null; | ||||
|   /** 网络状态 */ | ||||
|   networkStatus: boolean; | ||||
| } | ||||
|  | ||||
| /** 自定义的请求结果 */ | ||||
|   | ||||
| @@ -1,3 +1,2 @@ | ||||
| export * from './common'; | ||||
| export * from './business'; | ||||
| export * from './theme'; | ||||
|   | ||||
| @@ -16,7 +16,7 @@ | ||||
| import { NLayout, NLayoutContent, NLayoutHeader } from 'naive-ui'; | ||||
| import { useThemeStore } from '@/store'; | ||||
| import { useLayoutConfig } from '@/composables'; | ||||
| import { GlobalHeader, GlobalContent, GlobalFooter, GlobalTab, SpacePlaceholder } from '../common'; | ||||
| import { GlobalHeader, GlobalContent, GlobalFooter, GlobalTab, SpacePlaceholder } from '@/layouts/common'; | ||||
|  | ||||
| const theme = useThemeStore(); | ||||
| const { headerInverted, headerPosition, scrollbarContentStyle, scrollbar } = useLayoutConfig(); | ||||
|   | ||||
| @@ -39,7 +39,7 @@ | ||||
| import { NLayout, NLayoutContent, NLayoutSider, NLayoutHeader, NScrollbar } from 'naive-ui'; | ||||
| import { useThemeStore, useAppStore } from '@/store'; | ||||
| import { useLayoutConfig } from '@/composables'; | ||||
| import { GlobalHeader, GlobalContent, GlobalFooter, GlobalTab, GlobalMenu, SpacePlaceholder } from '../common'; | ||||
| import { GlobalHeader, GlobalContent, GlobalFooter, GlobalTab, GlobalMenu, SpacePlaceholder } from '@/layouts/common'; | ||||
|  | ||||
| const theme = useThemeStore(); | ||||
| const app = useAppStore(); | ||||
|   | ||||
| @@ -45,7 +45,7 @@ import { | ||||
|   SpacePlaceholder, | ||||
|   GlobalLogo, | ||||
|   GlobalMenu | ||||
| } from '../common'; | ||||
| } from '@/layouts/common'; | ||||
|  | ||||
| const theme = useThemeStore(); | ||||
| const app = useAppStore(); | ||||
|   | ||||
| @@ -21,7 +21,7 @@ | ||||
| import { NLayout, NLayoutContent, NLayoutHeader } from 'naive-ui'; | ||||
| import { useThemeStore } from '@/store'; | ||||
| import { useLayoutConfig } from '@/composables'; | ||||
| import { MixSider, GlobalHeader, GlobalContent, GlobalFooter, GlobalTab, SpacePlaceholder } from '../common'; | ||||
| import { MixSider, GlobalHeader, GlobalContent, GlobalFooter, GlobalTab, SpacePlaceholder } from '@/layouts/common'; | ||||
|  | ||||
| const theme = useThemeStore(); | ||||
| const { headerInverted, headerPosition, globalSiderClassAndStyle, scrollbarContentStyle, scrollbar } = | ||||
|   | ||||
| @@ -1,40 +0,0 @@ | ||||
| <template> | ||||
|   <div class="multi-tab flex-center w-full pl-16px" :style="{ height: multiTabHeight }"> | ||||
|     <div class="flex-1-hidden h-full"> | ||||
|       <better-scroll :options="{ scrollX: true, scrollY: false, click: isMobile }"> | ||||
|         <multi-tab /> | ||||
|       </better-scroll> | ||||
|     </div> | ||||
|     <reload-button /> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| import { useRoute } from 'vue-router'; | ||||
| import { useAppStore } from '@/store'; | ||||
| import { useLayoutConfig, routeFullPathWatcher, useIsMobile } from '@/composables'; | ||||
| import { BetterScroll } from '@/components'; | ||||
| import { MultiTab, ReloadButton } from './components'; | ||||
|  | ||||
| const route = useRoute(); | ||||
| const { initMultiTab, addMultiTab, setActiveMultiTab } = useAppStore(); | ||||
| const { multiTabHeight } = useLayoutConfig(); | ||||
| const isMobile = useIsMobile(); | ||||
|  | ||||
| function init() { | ||||
|   initMultiTab(); | ||||
| } | ||||
|  | ||||
| routeFullPathWatcher(fullPath => { | ||||
|   addMultiTab(route); | ||||
|   setActiveMultiTab(fullPath); | ||||
| }); | ||||
|  | ||||
| // 初始化 | ||||
| init(); | ||||
| </script> | ||||
| <style scoped> | ||||
| .multi-tab { | ||||
|   box-shadow: 0 1px 4px rgb(0 21 41 / 8%); | ||||
| } | ||||
| </style> | ||||
| @@ -4,4 +4,3 @@ import HorizontalLayout from './HorizontalLayout/index.vue'; | ||||
| import HorizontalMixLayout from './HorizontalMixLayout/index.vue'; | ||||
|  | ||||
| export { VerticalLayout, VerticalMixLayout, HorizontalLayout, HorizontalMixLayout }; | ||||
| export * from './common'; | ||||
|   | ||||
| @@ -7,7 +7,8 @@ | ||||
| import type { Component } from 'vue'; | ||||
| import { useThemeStore } from '@/store'; | ||||
| import type { NavMode } from '@/interface'; | ||||
| import { VerticalLayout, VerticalMixLayout, HorizontalLayout, HorizontalMixLayout, SettingDrawer } from './components'; | ||||
| import { VerticalLayout, VerticalMixLayout, HorizontalLayout, HorizontalMixLayout } from './components'; | ||||
| import { SettingDrawer } from '../common'; | ||||
|  | ||||
| type LayoutComponent = { | ||||
|   [key in NavMode]: Component; | ||||
|   | ||||
| @@ -1,31 +1,14 @@ | ||||
| <template> | ||||
|   <n-scrollbar ref="scrollbar" class="h-full" :content-class="routeProps.fullPage ? 'h-full' : ''"> | ||||
|     <div class="inline-block wh-full bg-[#f6f9f8]"> | ||||
|       <router-view v-slot="{ Component, route: itemRoute }"> | ||||
|         <transition :name="theme.pageAnimateType" mode="out-in" appear> | ||||
|           <keep-alive :include="cacheRoutes"> | ||||
|             <component | ||||
|               :is="Component" | ||||
|               v-if="app.reloadFlag" | ||||
|               :key="itemRoute.fullPath" | ||||
|               :class="{ 'min-h-100vh': !routeProps.fullPage }" | ||||
|             /> | ||||
|           </keep-alive> | ||||
|         </transition> | ||||
|       </router-view> | ||||
|     </div> | ||||
|   <n-scrollbar ref="scrollbar" class="h-full" :content-style="scrollbarContentStyle"> | ||||
|     <global-content :show-padding="false" /> | ||||
|   </n-scrollbar> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| import { NScrollbar } from 'naive-ui'; | ||||
| import { useThemeStore, useAppStore } from '@/store'; | ||||
| import { cacheRoutes } from '@/router'; | ||||
| import { useRouteProps } from '@/composables'; | ||||
| import { useLayoutConfig } from '@/composables'; | ||||
| import { GlobalContent } from '../common'; | ||||
|  | ||||
| const theme = useThemeStore(); | ||||
| const app = useAppStore(); | ||||
|  | ||||
| const routeProps = useRouteProps(); | ||||
| const { scrollbarContentStyle } = useLayoutConfig(); | ||||
| </script> | ||||
| <style scoped></style> | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| <template> | ||||
|   <div | ||||
|     class="flex-1 flex-col-stretch bg-[#f6f9f8] dark:bg-deep-dark p-16px transition-all duration-300 ease-in-out" | ||||
|     :class="{ 'overflow-hidden': routeProps.fullPage }" | ||||
|     class="flex-1 flex-col-stretch bg-[#f6f9f8] dark:bg-deep-dark transition-all duration-300 ease-in-out" | ||||
|     :class="{ 'overflow-hidden': routeProps.fullPage, 'p-16px': showPadding }" | ||||
|   > | ||||
|     <router-view v-slot="{ Component, route }"> | ||||
|       <transition :name="theme.pageAnimateType" mode="out-in" appear> | ||||
| @@ -18,6 +18,15 @@ import { cacheRoutes } from '@/router'; | ||||
| import { useAppStore, useThemeStore } from '@/store'; | ||||
| import { useRouteProps } from '@/composables'; | ||||
| 
 | ||||
| interface Props { | ||||
|   /** 显示padding */ | ||||
|   showPadding?: boolean; | ||||
| } | ||||
| 
 | ||||
| withDefaults(defineProps<Props>(), { | ||||
|   showPadding: true | ||||
| }); | ||||
| 
 | ||||
| const theme = useThemeStore(); | ||||
| const app = useAppStore(); | ||||
| const routeProps = useRouteProps(); | ||||
| @@ -1,12 +1,13 @@ | ||||
| <template> | ||||
|   <div v-if="theme.multiTabStyle.mode === 'chrome'" class="flex items-end h-full"> | ||||
|   <div v-if="theme.multiTabStyle.mode === 'chrome'" ref="tabRef" class="flex items-end h-full"> | ||||
|     <chrome-tab | ||||
|       v-for="item in app.multiTab.routes" | ||||
|       v-for="(item, index) in app.multiTab.routes" | ||||
|       :key="item.path" | ||||
|       :is-active="app.multiTab.activeRoute === item.fullPath" | ||||
|       :primary-color="theme.themeColor" | ||||
|       :closable="item.name !== ROUTE_HOME.name" | ||||
|       :dark-mode="theme.darkMode" | ||||
|       :is-last="index === app.multiTab.routes.length - 1" | ||||
|       @click="handleClickTab(item.fullPath)" | ||||
|       @close="removeMultiTab(item.fullPath)" | ||||
|       @contextmenu="handleContextMenu($event, item.fullPath)" | ||||
| @@ -14,7 +15,7 @@ | ||||
|       {{ item.meta?.title }} | ||||
|     </chrome-tab> | ||||
|   </div> | ||||
|   <div v-if="theme.multiTabStyle.mode === 'button'" class="flex-y-center h-full"> | ||||
|   <div v-if="theme.multiTabStyle.mode === 'button'" ref="tabRef" class="flex-y-center h-full"> | ||||
|     <button-tab | ||||
|       v-for="item in app.multiTab.routes" | ||||
|       :key="item.path" | ||||
| @@ -39,7 +40,7 @@ | ||||
| </template> | ||||
| 
 | ||||
| <script setup lang="ts"> | ||||
| import { reactive, nextTick } from 'vue'; | ||||
| import { ref, reactive, nextTick, watch } from 'vue'; | ||||
| import { useEventListener } from '@vueuse/core'; | ||||
| import { useThemeStore, useAppStore } from '@/store'; | ||||
| import { ROUTE_HOME } from '@/router'; | ||||
| @@ -48,6 +49,12 @@ import { useBoolean } from '@/hooks'; | ||||
| import { setTabRouteStorage } from '@/utils'; | ||||
| import { ContextMenu } from './components'; | ||||
| 
 | ||||
| interface Emits { | ||||
|   (e: 'scroll', clientX: number): void; | ||||
| } | ||||
| 
 | ||||
| const emit = defineEmits<Emits>(); | ||||
| 
 | ||||
| const theme = useThemeStore(); | ||||
| const app = useAppStore(); | ||||
| const { removeMultiTab, handleClickTab } = useAppStore(); | ||||
| @@ -62,6 +69,22 @@ function setDropdownConfig(x: number, y: number, currentPath: string) { | ||||
|   Object.assign(dropdownConfig, { x, y, currentPath }); | ||||
| } | ||||
| 
 | ||||
| // 获取当前激活的tab的clientX | ||||
| const tabRef = ref<HTMLElement | null>(null); | ||||
| async function getActiveTabClientX() { | ||||
|   await nextTick(); | ||||
|   const index = app.activeMultiTabIndex; | ||||
|   if (tabRef.value) { | ||||
|     const activeTabElement = tabRef.value.children[index]; | ||||
|     const { x, width } = activeTabElement.getBoundingClientRect(); | ||||
|     const clientX = x + width / 2; | ||||
|     setTimeout(() => { | ||||
|       emit('scroll', clientX); | ||||
|     }, 50); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // 右键菜单 | ||||
| function handleContextMenu(e: MouseEvent, fullPath: string) { | ||||
|   e.preventDefault(); | ||||
|   const { clientX, clientY } = e; | ||||
| @@ -76,5 +99,15 @@ function handleContextMenu(e: MouseEvent, fullPath: string) { | ||||
| useEventListener(window, 'beforeunload', () => { | ||||
|   setTabRouteStorage(app.multiTab.routes); | ||||
| }); | ||||
| 
 | ||||
| watch( | ||||
|   () => app.activeMultiTabIndex, | ||||
|   () => { | ||||
|     getActiveTabClientX(); | ||||
|   }, | ||||
|   { | ||||
|     immediate: true | ||||
|   } | ||||
| ); | ||||
| </script> | ||||
| <style scoped></style> | ||||
							
								
								
									
										59
									
								
								src/layouts/common/GlobalTab/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								src/layouts/common/GlobalTab/index.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | ||||
| <template> | ||||
|   <div class="multi-tab flex-center w-full pl-16px" :style="{ height: multiTabHeight }"> | ||||
|     <div ref="bsWrapperRef" class="flex-1-hidden h-full"> | ||||
|       <better-scroll ref="bsScroll" :options="{ scrollX: true, scrollY: false, click: isMobile }"> | ||||
|         <multi-tab @scroll="handleScroll" /> | ||||
|       </better-scroll> | ||||
|     </div> | ||||
|     <reload-button /> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| import { ref } from 'vue'; | ||||
| import { useRoute } from 'vue-router'; | ||||
| import { useElementBounding } from '@vueuse/core'; | ||||
| import { useAppStore } from '@/store'; | ||||
| import { useLayoutConfig, routeFullPathWatcher, useIsMobile } from '@/composables'; | ||||
| import { BetterScroll } from '@/components'; | ||||
| import type { ExposeBetterScroll } from '@/interface'; | ||||
| import { MultiTab, ReloadButton } from './components'; | ||||
|  | ||||
| const route = useRoute(); | ||||
| const { initMultiTab, addMultiTab, setActiveMultiTab } = useAppStore(); | ||||
| const { multiTabHeight } = useLayoutConfig(); | ||||
| const isMobile = useIsMobile(); | ||||
|  | ||||
| const bsWrapperRef = ref<HTMLElement | null>(null); | ||||
| const { width: bsWrapperWidth, left: bsWrapperLeft } = useElementBounding(bsWrapperRef); | ||||
|  | ||||
| const bsScroll = ref<ExposeBetterScroll | null>(null); | ||||
|  | ||||
| function handleScroll(clientX: number) { | ||||
|   const currentX = clientX - bsWrapperLeft.value; | ||||
|   const deltaX = currentX - bsWrapperWidth.value / 2; | ||||
|   if (bsScroll.value) { | ||||
|     const { maxScrollX, x: leftX } = bsScroll.value.bsInstance; | ||||
|     const rightX = maxScrollX - leftX; | ||||
|     const update = deltaX > 0 ? Math.max(-deltaX, rightX) : Math.min(-deltaX, -leftX); | ||||
|     bsScroll.value?.bsInstance.scrollBy(update, 0, 300); | ||||
|   } | ||||
| } | ||||
|  | ||||
| function init() { | ||||
|   initMultiTab(); | ||||
| } | ||||
|  | ||||
| routeFullPathWatcher(fullPath => { | ||||
|   addMultiTab(route); | ||||
|   setActiveMultiTab(fullPath); | ||||
| }); | ||||
|  | ||||
| // 初始化 | ||||
| init(); | ||||
| </script> | ||||
| <style scoped> | ||||
| .multi-tab { | ||||
|   box-shadow: 0 1px 4px rgb(0 21 41 / 8%); | ||||
| } | ||||
| </style> | ||||
| @@ -3,13 +3,11 @@ import App from './App.vue'; | ||||
| import AppProvider from './AppProvider.vue'; | ||||
| import { setupStore } from './store'; | ||||
| import { setupRouter } from './router'; | ||||
| import { setupAssets, setupWindicssDarkMode } from './plugins'; | ||||
| import { setupAssets } from './plugins'; | ||||
|  | ||||
| function setupPlugins() { | ||||
|   /** 引入静态资源 */ | ||||
|   setupAssets(); | ||||
|   // 配置windicss暗黑主题 | ||||
|   setupWindicssDarkMode(); | ||||
| } | ||||
|  | ||||
| async function setupApp() { | ||||
|   | ||||
| @@ -1,36 +0,0 @@ | ||||
| import { watch } from 'vue'; | ||||
| import { useThemeStore } from '@/store'; | ||||
|  | ||||
| export default function setupWindicssDarkMode() { | ||||
|   const theme = useThemeStore(); | ||||
|  | ||||
|   const DARK_CLASS = 'dark'; | ||||
|  | ||||
|   function getHtmlElement() { | ||||
|     return document.querySelector('html'); | ||||
|   } | ||||
|   function addDarkClass() { | ||||
|     const html = getHtmlElement(); | ||||
|     if (html) { | ||||
|       html.classList.add(DARK_CLASS); | ||||
|     } | ||||
|   } | ||||
|   function removeDarkClass() { | ||||
|     const html = getHtmlElement(); | ||||
|     if (html) { | ||||
|       html.classList.remove(DARK_CLASS); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   watch( | ||||
|     () => theme.darkMode, | ||||
|     newValue => { | ||||
|       if (newValue) { | ||||
|         addDarkClass(); | ||||
|       } else { | ||||
|         removeDarkClass(); | ||||
|       } | ||||
|     }, | ||||
|     { immediate: true } | ||||
|   ); | ||||
| } | ||||
| @@ -1,4 +1,3 @@ | ||||
| import setupAssets from './assets'; | ||||
| import setupWindicssDarkMode from './dark-mode'; | ||||
|  | ||||
| export { setupAssets, setupWindicssDarkMode }; | ||||
| export { setupAssets }; | ||||
|   | ||||
| @@ -258,6 +258,14 @@ const routeConstMap = new Map<RouteKey, RouteConst>([ | ||||
|       path: '/about', | ||||
|       title: '关于' | ||||
|     } | ||||
|   ], | ||||
|   [ | ||||
|     'website', | ||||
|     { | ||||
|       name: 'website', | ||||
|       path: '/website', | ||||
|       title: '网址导航' | ||||
|     } | ||||
|   ] | ||||
| ]); | ||||
|  | ||||
|   | ||||
							
								
								
									
										27
									
								
								src/router/modules/website.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/router/modules/website.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| import type { CustomRoute } from '@/interface'; | ||||
| import { setSingleRoute } from '@/utils'; | ||||
| import { BlankLayout } from '@/layouts'; | ||||
| import Website from '@/views/website/index.vue'; | ||||
| import { getRouteConst, routeName } from '../constant'; | ||||
|  | ||||
| const { name, path, title } = getRouteConst('website'); | ||||
|  | ||||
| const WEBSITE: CustomRoute = setSingleRoute({ | ||||
|   route: { | ||||
|     name, | ||||
|     path, | ||||
|     component: Website, | ||||
|     meta: { | ||||
|       title, | ||||
|       icon: 'codicon:remote-explorer', | ||||
|       isNotMenu: true | ||||
|     } | ||||
|   }, | ||||
|   container: BlankLayout, | ||||
|   meta: { | ||||
|     order: 8 | ||||
|   }, | ||||
|   notFoundName: routeName('not-found') | ||||
| }); | ||||
|  | ||||
| export default WEBSITE; | ||||
| @@ -1,5 +1,6 @@ | ||||
| import { requestMiddleware } from '@/utils'; | ||||
| import type { ResponseDictionary, Dictionary } from '@/interface'; | ||||
| import { request, resultMiddleware } from '../request'; | ||||
| import { request } from '../request'; | ||||
| import { fecthDictionaryMiddleware } from '../middleware'; | ||||
|  | ||||
| // 接口示例 | ||||
| @@ -23,5 +24,5 @@ export async function fetchDictionaryWithMiddleware(keyword: string) { | ||||
|     indiCatorName: keyword | ||||
|   }); | ||||
|  | ||||
|   return resultMiddleware<Dictionary[]>(fecthDictionaryMiddleware, [res]); | ||||
|   return requestMiddleware<Dictionary[]>(fecthDictionaryMiddleware, [res]); | ||||
| } | ||||
|   | ||||
| @@ -1,8 +0,0 @@ | ||||
| import type { AxiosRequestConfig } from 'axios'; | ||||
| import CustomAxiosInstance from './instance'; | ||||
| import Request from './request'; | ||||
|  | ||||
| export function createRequest(axiosConfig: AxiosRequestConfig) { | ||||
|   const customInstance = new CustomAxiosInstance(axiosConfig); | ||||
|   return new Request(customInstance.instance); | ||||
| } | ||||
| @@ -1,3 +0,0 @@ | ||||
| export * from './transform'; | ||||
| export * from './error'; | ||||
| export * from './handler'; | ||||
| @@ -1,9 +1,7 @@ | ||||
| import { createRequest } from './axios'; | ||||
| import { REQUEST_TIMEOUT } from './config'; | ||||
| import { REQUEST_TIMEOUT } from '@/config'; | ||||
| import { createRequest } from './request'; | ||||
|  | ||||
| export const request = createRequest({ | ||||
|   baseURL: import.meta.env.VITE_HTTP_URL, | ||||
|   timeout: REQUEST_TIMEOUT | ||||
| }); | ||||
|  | ||||
| export { resultMiddleware } from './helpers'; | ||||
|   | ||||
| @@ -1,8 +1,7 @@ | ||||
| import axios from 'axios'; | ||||
| import type { AxiosRequestConfig, AxiosInstance, AxiosError, CancelTokenStatic } from 'axios'; | ||||
| import { getToken } from '@/utils'; | ||||
| import { getToken, transformRequestData, handleAxiosError, handleResponseError, handleBackendError } from '@/utils'; | ||||
| import type { BackendServiceResult } from '@/interface'; | ||||
| import { transformRequestData, handleAxiosError, handleResponseError, handleBackendError } from '../helpers'; | ||||
| 
 | ||||
| /** | ||||
|  * 封装axios请求类 | ||||
| @@ -1,11 +1,12 @@ | ||||
| import type { AxiosRequestConfig, AxiosInstance, AxiosResponse } from 'axios'; | ||||
| import type { RequestServiceError, CustomSuccessRequestResult, CustomFailRequestResult } from '@/interface'; | ||||
| import CustomAxiosInstance from './instance'; | ||||
| 
 | ||||
| /** | ||||
|  * 封装各个请求方法及结果处理的类 | ||||
|  * @author Soybean<honghuangdc@gmail.com> | ||||
|  */ | ||||
| export default class Request { | ||||
| export class Request { | ||||
|   instance: AxiosInstance; | ||||
| 
 | ||||
|   constructor(instance: AxiosInstance) { | ||||
| @@ -15,8 +16,7 @@ export default class Request { | ||||
|   static successHandler<ResponseData>(response: AxiosResponse) { | ||||
|     const successResult: CustomSuccessRequestResult<ResponseData> = { | ||||
|       data: response as unknown as ResponseData, | ||||
|       error: null, | ||||
|       networkStatus: window.navigator.onLine | ||||
|       error: null | ||||
|     }; | ||||
| 
 | ||||
|     return successResult; | ||||
| @@ -25,8 +25,7 @@ export default class Request { | ||||
|   static failHandler(error: RequestServiceError) { | ||||
|     const failResult: CustomFailRequestResult = { | ||||
|       data: null, | ||||
|       error, | ||||
|       networkStatus: window.navigator.onLine | ||||
|       error | ||||
|     }; | ||||
| 
 | ||||
|     return failResult; | ||||
| @@ -60,3 +59,8 @@ export default class Request { | ||||
|       .catch(Request.failHandler); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export function createRequest(axiosConfig: AxiosRequestConfig) { | ||||
|   const customInstance = new CustomAxiosInstance(axiosConfig); | ||||
|   return new Request(customInstance.instance); | ||||
| } | ||||
| @@ -1,2 +1,2 @@ | ||||
| export * from './theme'; | ||||
| export * from './sdk'; | ||||
| export * from './website'; | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user