This commit is contained in:
XiaoDaiGua-Ray 2023-08-11 21:50:58 +08:00
parent 3b0dcfc8e2
commit 018f4a9aca
53 changed files with 489 additions and 295 deletions

View File

@ -1,5 +1,16 @@
# CHANGE LOG
## 4.1.7
### Feats
- 新增 mock 支持
- 重新梳理 demo views 包
### Fixes
- 修复 RayCollapseGrid 组件显示问题,现在如果未存在溢出情况,不会显示 展开/收起 按钮
## 4.1.6
### Feats

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020-present, Ray
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

171
MANUAL.md
View File

@ -1,171 +0,0 @@
## Ray Template 使用手册
## 前言
> `Ray Template` 默认使用 `pnpm` 作为包管理器,并且默认启用严格模式的 `eslint`。在导入模块的时候除 `.ts` `.tsx` `.d.ts` 文件等不需要手动补全后缀名,其余的模块导入应该手动补全所有后缀名。
### 使用
#### 项目安装
```sh
# github
git clone https://github.com/XiaoDaiGua-Ray/ray-template.git
# 如果你的下载速度很慢,可以切换到下面的代理地址
git clone https://gh.yka.moe/https://github.com/XiaoDaiGua-Ray/ray-template.git
```
#### 依赖安装
```sh
# yarn
yarn
# npm
npm i
```
#### 启动项目
```sh
# yarn
yarn dev
# npm
npm run dev
```
#### 构建项目
```sh
# yarn
yarn build
# npm
npm run build
```
### 国际化
#### Tip
- 每个新的语言包文件的文件名视为 path 开头menu.json => menu.xxx
#### 新增语言包、新增语言模块
> 项目国际化管理模块,统一放置于 `src/locales` 下。
##### 文件包
- lang
- helper.ts
- index.ts
- useI18n.ts
> 项目中使用 t locale 方法时使用模板提供方法useI18n.ts
```tsx
// 引入包
import { useI18n } from '@/locales/useI18n'
const { t, locale } = useI18n()
/**
*
* t: 用于绑定国际化 path
* locale: 用于切换系统语言。参数 key 必须与 lang 包中的语言包一致
*/
const demo = () => <span>{t('demo.demo')}</span>
locale('zh-CN')
locale('en-US')
```
##### 新增语言包
> 我们举例新增台湾地区语言包。
- `src/locales/lang` 文件下创建对应新语言包文件夹与语言文件
- zh-TW 文件夹
- zh-TW.ts 文件
- 创建与原有语言格式一样的文件夹(可以直接 cv 过去)
- 配置语言下拉项LOCAL_OPTIONS
- 配置 dayjs 国际化映射DAYJS_LOCAL_MAP
> 具体注意事项看注释。
##### 最后
> 按照上述步骤操作后,就已经给模板添加了一个新的语言包了。可以在页面的右上角国际化下拉框中看到新增的下拉选项,点击切换后,即可切换到对应的语言了。
### 路由
#### Tip
- 在该模板中,路由 path 属性视 `/` 开头的路由为根路由
- 路由会在初始化的时候将所有路由进行提升(全部提升为顶级路由),所以注意第一条 Tip
- 路由模块会影响菜单的输出显示(菜单模块与路由模块进行拆分开来的)
- 具体路由支持配置属性看 router/README.md 文件
#### 文件包
- constant 文件放置一些公共东西
- helper 文件放置 router 的一些 hook 方法
- modules 页面路由入口modules 文件中每一个 xxx.ts 文件都会被视为是一个路由模块)
- utils router 拓展方法
- ...
##### 新增路由页面
- modules 中添加一个新的模块log.ts
- 配置路由的相关信息
- views 中创建 log 相关的页面信息
```ts
// 辅助函数,配合 i18n-ally 插件使用
import { t } from '@/locales/useI18n'
// 路由配置类型提示
import type { AppRouteRecordRaw } from '@/router/type'
const log: AppRouteRecordRaw = {
path: '/log',
name: 'Log',
component: () => import('@/views/log/index.vue'),
meta: {
i18nKey: t('menu.Log'),
icon: 'log',
order: 3,
},
children: [
{
path: 'my-log',
name: 'MyLog',
component: () => import('@/views/my-log/index.vue'),
meta: {
i18nKey: t('menu.MyLog'),
order: 0,
},
},
{
path: 'group-log',
name: 'MyLog',
component: () => import('@/views/group-log/index.vue'),
meta: {
i18nKey: t('menu.GroupLog'),
order: 0,
},
},
],
}
export default log
```
##### 最后
> 打开浏览器可以看到页面菜单上已经有一个日志菜单。
#### 未完待续。。。后续慢慢更新该手册

128
README.md
View File

@ -1,4 +1,7 @@
# `Ray Template`
<div align="center"> <a href="https://github.com/XiaoDaiGua-Ray/ray-template"> <img alt="Ray Template" width="200" height="200" src="https://usc1.contabostorage.com/c2e495d7890844d392e8ec0c6e5d77eb:alist/ray/ray.svg?sign=ZklU9Bh5b6oKp1X0LOhGwkx4g5mW4wk_w9Jt5zlZ5EQ=:0"> </a> <br> <br>
<h1>Ray Template</h1>
</div>
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
@ -6,9 +9,16 @@
<!-- ALL-CONTRIBUTORS-BADGE:END -->
## 前言
> 该项目模板采用 `vue3.x` `vite4.x` `pinia` `tsx` 进行开发。
> 使用 `naive ui` 作为组件库。
> 预设了最佳构建体验的配置与常用搬砖工具。意在提供一个简洁、快速上手的模板。
> 该模板不支持移动端设备。
## 感谢
> 感谢 <https://me.yka.moe/> 对于本人的支持。
> 感谢 [`yun`](https://me.yka.moe/) 对于本人的支持。
## 预览地址
@ -28,48 +38,39 @@
- [常见问题](https://github.com/XiaoDaiGua-Ray/ray-template/blob/main/COMMONPROBLEM.md)
## 功能
## 特性
- 主题切换
- 任意深度页面缓存
- 系统配置化
- 锁屏
- 自动化路由
- 带有拓展功能的表格
- 封装 `axios` 自动取消重复请求,暴露拦截器注册器
- 全局菜单搜索
- 动态菜单(多级菜单)
- 主题色切换
- 错误页
- 面包屑
- 标签页
- 国际化(允许按模块管理语言包)
- 权限路由
- 动态切换主题、贴花的 `EChart`
- 最佳构建体验
- 体积分析
- 还有一些不值一提的小东西...
- **最新技术栈**:使用 Vue3.x/vite4.x 等前端前沿技术开发
- **TypeScript**:应用程序级 JavaScript 的语言
- **主题**:可配置的主题
- **国际化**:内置完善的国际化方案
- **Mock 数据**:内置 Mock 数据方案
- **权限**:内置完善的动态路由权限生成方案
- **组件**:二次封装了多个常用的组件
- **Axios 请求**:二次封装 axios 库
## 准备
- [node](http://nodejs.org/) 和 [git](https://git-scm.com/) -项目开发环境
- [Vite](https://vitejs.dev/) - 熟悉 vite 特性
- [Vue3](https://v3.vuejs.org/) - 熟悉 Vue 基础语法
- [TypeScript](https://www.typescriptlang.org/) - 熟悉 TypeScript 基本语法
- [Es6+](http://es6.ruanyifeng.com/) - 熟悉 es6 基本语法
- [Vue-Router-Next](https://next.router.vuejs.org/) - 熟悉 vue-router4.x 基本使用
- [Naive-UI](https://www.naiveui.com) - ui 基本使用
- [Mock.js](https://github.com/nuysoft/Mock) - mockjs 基本语法
- [Pinia](https://pinia.vuejs.org/zh/introduction.html) - 状态管理器 pinia 使用
- [TSX](https://github.com/vuejs/babel-plugin-jsx/blob/main/packages/babel-plugin-jsx/README-zh_CN.md) - tsx 基本语法
## 未来
> 根据个人时间空余情况,会不定时对该模板进行更新和迭代。希望将该工具的功能不断补全(虽然现在已经是足够日常开发和使用),将该模板打造为一个更加健全的中后台模板。如果你有好的想法和建议,可以直接联系我或者直接提 `issues` 即可。
## 前言
> 该项目模板采用 `vue3.x` `vite4.x` `pinia` `tsx` 进行开发。
> 使用 `naive ui` 作为组件库。
> 预设了最佳构建体验的配置与常用搬砖工具。意在提供一个简洁、快速上手的模板。
> 该模板不支持移动端设备。
## 提示
> 项目默认启用严格模式 `eslint`,但是由于 `vite-plugin-eslint` 插件优先级最高,所以如果出现自动导入类型错误提示,请优先解决其他问题。
> 建议开启 `vscode` 保存自动修复功能。
## 版本说明
> 做了一些大的改动升级,让模板更加好用了一点,默认主题色也做了变更更好看了一点。啰嗦两句,好像也没啥其他的了...
## 项目安装
```sh
@ -150,63 +151,14 @@ yarn report
npm run report
```
## 项目依赖
- [pinia](https://pinia.vuejs.org/) `全局状态管理器`
- [@vueuse](https://vueuse.org/) `vue3 hooks`
- [vue-router](https://router.vuejs.org/zh/) `router`
- [axios](http://axios-js.com/zh-cn/docs/index.html) `ajax request`
- [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html) `国际化`
- [scrollreveal.js](https://scrollrevealjs.org/) `滚动加载动画`(暂时移除)
- [crypto-js](https://github.com/brix/crypto-js) `加密`
- [vite-svg-loader](https://github.com/jpkleemans/vite-svg-loader) `svg组件化`
- [vite-plugin-svg-icons](https://github.com/vbenjs/vite-plugin-svg-icons/blob/main/README.zh_CN.md) `svg雪碧图`
- [echarts5](https://echarts.apache.org/examples/zh/index.html#chart-type-line) `可视化`
- [lodash-es](https://www.lodashjs.com/) `拓展方法`
- 还有一些后续补充的,懒得写了。。。自己看项目依赖页面
## 基础组件
- `RayIcon` `svg icon`
- `RayChart` 基于 `echarts5.x` 封装可视化组件
- `RayTransitionComponent` 带过渡动画路由组件,效果与 `RouterView` 相同
- `RayTable` 基于 `Naive UI DataTable` 组件封装,实现了一些小功能
- `RayCollapseGrid` 基于 `Naive UI NGrid` 组件封装的可折叠操作栏
## 项目结构
```
- locales: 国际化多语言入口(本项目采用 json 格式)
- assets: 项目静态资源入口
- component: 全局共用组件
- icons: 项目svg图标资源需要配合 RayIcon 组件使用
- language: 国际化
- layout: 全局页面结构入口
- router: 路由表
- store: 全局状态管理入口
- styles: 全局公共样式入口
- types: 全局 type
- utils: 工具包
- views: 页面入口
- vite-plugin: 插件注册
```
## 浏览器支持
> 仅支持现代浏览器,不支持 `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 |
| :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
| not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
## 最后,希望大家搬砖愉快
## 贡献者
@ -240,3 +192,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
## License
[MIT © Ray-2020](./LICENSE)

9
cfg.ts
View File

@ -98,16 +98,11 @@ const config: AppConfigExport = {
allow: [],
},
proxy: {
'/api': {
target: 'url',
'^/api': {
target: 'http://localhost',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
'/office': {
target: 'https://office.yka.one/',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/office/, ''),
},
},
},
/**

51
mock/demo/person.mock.ts Normal file
View File

@ -0,0 +1,51 @@
import { defineMock } from 'vite-plugin-mock-dev-server'
import Mock from 'mockjs'
import { pagination, stringify, response } from '../shared/utils'
import { array } from '../shared/database'
export const getPersonList = defineMock({
url: '/api/list',
method: 'GET',
delay: 500,
response: (req, res) => {
const person = () => ({
id: Mock.Random.guid(),
address: Mock.Random.county(true),
email: Mock.Random.email(),
name: Mock.Random.cname(),
age: Mock.Random.integer(18, 60),
createDate: Mock.Random.date(),
})
const {
query: { page, pageSize, email },
} = req
let list = array(100).map(() => person())
let length = list.length
if (!page || !pageSize) {
res.end(
stringify(
response(list, 200, '请求成功', {
total: length,
}),
),
)
} else {
list = pagination(page, pageSize, list)
if (email) {
list = list.filter((curr) => curr.email.includes(email))
length = list.length
}
res.end(
stringify(
response(list, 200, '请求成功', {
total: length,
}),
),
)
}
},
})

14
mock/shared/database.ts Normal file
View File

@ -0,0 +1,14 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-Ray>
*
* @date 2023-08-11
*
* @workspace ray-template
*
* @remark
*/
export function array(length: number) {
return new Array(length).fill(0)
}

64
mock/shared/utils.ts Normal file
View File

@ -0,0 +1,64 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-Ray>
*
* @date 2023-08-11
*
* @workspace ray-template
*
* @remark
*/
/* eslint-disable @typescript-eslint/no-explicit-any */
/**
*
* @param pageCurrent
* @param pageSize
* @param array
*
* mock
*/
export function pagination<T = any>(
pageCurrent: number,
pageSize: number,
array: T[],
): T[] {
const offset = (pageCurrent - 1) * Number(pageSize)
return offset + Number(pageSize) >= array.length
? array.slice(offset, array.length)
: array.slice(offset, offset + Number(pageSize))
}
/**
*
* @param value
*
* json
*/
export function stringify<T = unknown>(value: T) {
return JSON.stringify(value)
}
/**
*
* @param res
* @param code
* @param msg
*/
export function response<T = any>(
res: T,
code: number,
msg: string,
params?: object,
) {
const basic = {
code,
msg,
data: res,
...params,
}
return basic
}

View File

@ -32,6 +32,7 @@
"dayjs": "^1.11.7",
"echarts": "^5.4.0",
"lodash-es": "^4.17.21",
"mockjs": "1.1.0",
"naive-ui": "^2.34.4",
"pinia": "^2.1.4",
"pinia-plugin-persistedstate": "^3.1.0",
@ -54,6 +55,7 @@
"@intlify/unplugin-vue-i18n": "^0.12.1",
"@types/crypto-js": "^4.1.1",
"@types/lodash-es": "^4.17.7",
"@types/mockjs": "1.0.7",
"@types/scrollreveal": "^0.0.8",
"@typescript-eslint/eslint-plugin": "^5.61.0",
"@typescript-eslint/parser": "^5.61.0",
@ -89,6 +91,7 @@
"vite-plugin-eslint": "1.8.1",
"vite-plugin-imp": "^2.3.1",
"vite-plugin-inspect": "^0.7.26",
"vite-plugin-mock-dev-server": "1.3.0",
"vite-plugin-svg-icons": "^2.0.1",
"vite-svg-loader": "^4.0.0",
"vue-tsc": "^1.8.4"
@ -108,8 +111,11 @@
"admin template",
"中后台模板"
],
"author": "Ray",
"license": "ISC",
"license": "MIT",
"author": {
"name": "Ray",
"url": "https://github.com/XiaoDaiGua-Ray"
},
"bugs": {
"url": "https://github.com/XiaoDaiGua-Ray/xiaodaigua-ray.github.io/issues"
},

View File

@ -0,0 +1,27 @@
import { request } from '@/axios/index'
import type { BasicResponse, PaginationResponse } from '@/types/modules/axios'
export interface MockListParams {
page: number
pageSize: number
}
export interface Person {
name: string
id: string
age: number
address: string
createDate: string
email: string | null
}
export const getPersonList = (
params: Partial<Pick<MockListParams & Person, 'email' | 'pageSize' | 'page'>>,
) => {
return request<PaginationResponse<Person[]>>({
url: '/api/list',
method: 'get',
params,
})
}

View File

@ -21,7 +21,7 @@
import { request } from '@/axios/index'
import type { AxiosResponseBody } from '@/types/modules/axios'
import type { BasicResponse } from '@/types/modules/axios'
interface AxiosTestResponse extends UnknownObjectKey {
data: UnknownObjectKey[]

View File

@ -76,10 +76,14 @@ const RayCollapseGrid = defineComponent({
>
{this.$slots.default?.()}
<NGridItem suffix class="ray-collapse-grid__suffix--btn">
{{
default: ({ overflow }: { overflow: boolean }) => (
<NSpace justify="end">
{this.$slots.action?.()}
{this.CollapseIcon()}
{overflow ? this.CollapseIcon() : ''}
</NSpace>
),
}}
</NGridItem>
</NGrid>
),

View File

@ -255,6 +255,7 @@ const RayTable = defineComponent({
}
},
render() {
console.log(this.action)
return (
<NCard
class="ray-table"
@ -293,7 +294,7 @@ const RayTable = defineComponent({
)}
</>
),
header: () => this.title,
header: () => this.title || <div style="display: none;"></div>,
'header-extra': () =>
this.action ? (
<div class="ray-table-header-extra__space">

View File

@ -17,5 +17,6 @@
"Office_Spreadsheet": "Spreadsheet",
"CalculatePrecision": "Precision",
"Directive": "Directive",
"RouterDemo": "Same Level Router Demo"
"RouterDemo": "Same Level Router Demo",
"Mock": "Mock"
}

View File

@ -17,5 +17,6 @@
"Office_Spreadsheet": "表格",
"CalculatePrecision": "数字精度",
"Directive": "指令",
"RouterDemo": "页面详情模式"
"RouterDemo": "页面详情模式",
"Mock": "mock 数据"
}

View File

@ -6,7 +6,7 @@ import type { AppRouteRecordRaw } from '@/router/type'
const axios: AppRouteRecordRaw = {
path: '/axios',
name: 'RAxios',
component: () => import('@/views/axios/index'),
component: () => import('@/views/demo/axios/index'),
meta: {
i18nKey: t('menu.Axios'),
icon: 'axios',

View File

@ -6,7 +6,7 @@ import type { AppRouteRecordRaw } from '@/router/type'
const directive: AppRouteRecordRaw = {
path: '/directive',
name: 'RDirective',
component: () => import('@/views/directive/index'),
component: () => import('@/views/demo/directive/index'),
meta: {
i18nKey: t('menu.Directive'),
icon: 'other',

View File

@ -16,7 +16,7 @@ const doc: AppRouteRecordRaw = {
{
path: 'doc-inside',
name: 'RDocInside',
component: () => import('@/views/doc/index'),
component: () => import('@/views/demo/doc/index'),
meta: {
i18nKey: t('menu.DocLocalInside'),
},

View File

@ -6,7 +6,7 @@ import type { AppRouteRecordRaw } from '@/router/type'
const echart: AppRouteRecordRaw = {
path: '/echart',
name: 'REchart',
component: () => import('@/views/echart/index'),
component: () => import('@/views/demo/echart/index'),
meta: {
i18nKey: t('menu.Echart'),
icon: 'echart',

View File

@ -5,7 +5,7 @@ import type { AppRouteRecordRaw } from '@/router/type'
const iframe: AppRouteRecordRaw = {
path: '/iframe',
name: 'IframeDemo',
component: () => import('@/views/iframe/index'),
component: () => import('@/views/demo/iframe/index'),
meta: {
icon: 'other',
order: 2,

View File

@ -0,0 +1,18 @@
import { t } from '@/locales/useI18n'
import { LAYOUT } from '@/router/constant/index'
import type { AppRouteRecordRaw } from '@/router/type'
const mockDemo: AppRouteRecordRaw = {
path: '/mock-demo',
name: 'MockDemo',
component: () => import('@/views/demo/mock-demo/index'),
meta: {
i18nKey: t('menu.Mock'),
icon: 'other',
order: 3,
keepAlive: true,
},
}
export default mockDemo

View File

@ -16,7 +16,7 @@ const multiMenu: AppRouteRecordRaw = {
{
path: 'multi-menu-one',
name: 'MultiMenuOne',
component: () => import('@/views/multi/views/multi-menu-one/index'),
component: () => import('@/views/demo/multi/views/multi-menu-one/index'),
meta: {
noLocalTitle: '多级菜单-1',
keepAlive: true,
@ -35,7 +35,7 @@ const multiMenu: AppRouteRecordRaw = {
name: 'SubMenuOther',
component: () =>
import(
'@/views/multi/views/multi-menu-two/views/sub-menu-other/index'
'@/views/demo/multi/views/multi-menu-two/views/sub-menu-other/index'
),
meta: {
noLocalTitle: '多级菜单-2-1',
@ -56,7 +56,7 @@ const multiMenu: AppRouteRecordRaw = {
name: 'MultiMenuTwoOne',
component: () =>
import(
'@/views/multi/views/multi-menu-two/views/sub-menu/views/multi-menu-two-one/index'
'@/views/demo/multi/views/multi-menu-two/views/sub-menu/views/multi-menu-two-one/index'
),
meta: {
noLocalTitle: '多级菜单-2-2-1',

View File

@ -6,7 +6,7 @@ import type { AppRouteRecordRaw } from '@/router/type'
const office: AppRouteRecordRaw = {
path: '/office',
name: 'ROffice',
component: () => import('@/views/office/index'),
component: () => import('@/views/demo/office/index'),
meta: {
i18nKey: t('menu.Office'),
icon: 'office',
@ -16,7 +16,7 @@ const office: AppRouteRecordRaw = {
{
path: 'document',
name: 'Document',
component: () => import('@/views/office/views/document/index'),
component: () => import('@/views/demo/office/views/document/index'),
meta: {
i18nKey: 'Office_Document',
},
@ -24,7 +24,7 @@ const office: AppRouteRecordRaw = {
{
path: 'presentation',
name: 'Presentation',
component: () => import('@/views/office/views/presentation/index'),
component: () => import('@/views/demo/office/views/presentation/index'),
meta: {
i18nKey: 'Office_Presentation',
},
@ -32,7 +32,7 @@ const office: AppRouteRecordRaw = {
{
path: 'spreadsheet',
name: 'Spreadsheet',
component: () => import('@/views/office/views/spreadsheet/index'),
component: () => import('@/views/demo/office/views/spreadsheet/index'),
meta: {
i18nKey: 'Office_Spreadsheet',
},

View File

@ -6,7 +6,7 @@ import type { AppRouteRecordRaw } from '@/router/type'
const precision: AppRouteRecordRaw = {
path: '/precision',
name: 'CalculatePrecision',
component: () => import('@/views/precision/index'),
component: () => import('@/views/demo/precision/index'),
meta: {
i18nKey: t('menu.CalculatePrecision'),
icon: 'other',

View File

@ -16,7 +16,7 @@ const rely: AppRouteRecordRaw = {
{
path: 'rely-about',
name: 'RelyAbout',
component: () => import('@/views/rely/views/rely-about/index'),
component: () => import('@/views/demo/rely/views/rely-about/index'),
meta: {
i18nKey: 'RelyAbout',
},

View File

@ -16,7 +16,8 @@ const routerDemo: AppRouteRecordRaw = {
{
path: 'router-demo-home',
name: 'RouterDemoHome',
component: () => import('@/views/router-demo/router-demo-home/index'),
component: () =>
import('@/views/demo/router-demo/router-demo-home/index'),
meta: {
noLocalTitle: '人员信息(平级模式)',
},
@ -24,7 +25,8 @@ const routerDemo: AppRouteRecordRaw = {
{
path: 'router-demo-detail',
name: 'RouterDemoDetail',
component: () => import('@/views/router-demo/router-demo-detail/index'),
component: () =>
import('@/views/demo/router-demo/router-demo-detail/index'),
meta: {
noLocalTitle: '信息详情',
hidden: true,

View File

@ -12,7 +12,7 @@ import type { AppRouteRecordRaw } from '@/router/type'
const scrollReveal: AppRouteRecordRaw = {
path: '/scroll-reveal',
name: 'ScrollReveal',
component: () => import('@/views/scroll-reveal/index'),
component: () => import('@/views/demo/scroll-reveal/index'),
meta: {
i18nKey: t('menu.scrollReveal'),
icon: 'scroll_reveal',

View File

@ -6,7 +6,7 @@ import type { AppRouteRecordRaw } from '@/router/type'
const table: AppRouteRecordRaw = {
path: '/table',
name: 'TableView',
component: () => import('@/views/table/index'),
component: () => import('@/views/demo/table/index'),
meta: {
i18nKey: t('menu.Table'),
icon: 'other',

View File

@ -1,5 +1,10 @@
export interface AxiosResponseBody<T = unknown> {
/* eslint-disable @typescript-eslint/no-explicit-any */
export interface BasicResponse<T> {
data: T
message: string
msg: string
code: number
}
export interface PaginationResponse<T> extends BasicResponse<T> {
total: number
}

View File

@ -1,7 +1,7 @@
import './index.scss'
import { NCard, NLayout, NSpace, NInput, NButton } from 'naive-ui'
import { getWeather, getTypicode } from '@use-api/test'
import { getWeather, getTypicode } from '@/axios/api/demo/test'
import { useRequest, useHookPlusRequest } from '@/axios/index'
const Axios = defineComponent({

View File

@ -0,0 +1,173 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-Ray>
*
* @date 2023-08-11
*
* @workspace ray-template
*
* @remark
*/
import { NSpace, NCard, NButton, NFormItemGi, NInput, NForm } from 'naive-ui'
import RayTable from '@/components/RayTable/index'
import RayCollapseGrid from '@/components/RayCollapseGrid/index'
import { useHookPlusRequest } from '@/axios/index'
import { getPersonList } from '@/axios/api/demo/mock/person'
import type { Person } from '@/axios/api/demo/mock/person'
const MockDemo = defineComponent({
name: 'MockDemo',
setup() {
const paginationRef = reactive({
page: 1,
pageSize: 10,
itemCount: 0,
pageSizes: [10, 20, 30, 40, 50],
showSizePicker: true,
onUpdatePage: (page: number) => {
paginationRef.page = page
getPerson()
},
onUpdatePageSize: (pageSize: number) => {
paginationRef.pageSize = pageSize
paginationRef.page = 1
getPerson()
},
})
const {
data: personData,
loading: personLoading,
run: personFetchRun,
} = useHookPlusRequest(getPersonList, {
manual: true,
})
const columns = [
{
title: 'id',
key: 'id',
},
{
title: '邮箱',
key: 'email',
},
{
title: '地址',
key: 'address',
},
{
title: '姓名',
key: 'name',
},
{
title: '年龄',
key: 'age',
},
{
title: '创建时间',
key: 'createDate',
},
{
title: '操作',
key: 'action',
render: (row: Person) => {
return (
<NSpace align="center">
<NButton type="primary" text>
</NButton>
<NButton type="primary" text>
</NButton>
<NButton type="error" text>
</NButton>
</NSpace>
)
},
},
]
const condition = reactive({
email: null,
})
const getPerson = () => {
const { pageSize, page } = paginationRef
const { email } = condition
personFetchRun({
page,
pageSize,
email,
})
}
watchEffect(() => {
if (personData.value) {
paginationRef.itemCount = personData.value.total
}
})
onBeforeMount(() => {
getPerson()
})
return {
personData,
personLoading,
paginationRef,
columns,
...toRefs(condition),
getPerson,
}
},
render() {
return (
<NSpace vertical wrapItem={false}>
<NCard title="Mock 数据">
<h2> mock 使</h2>
</NCard>
<NCard title="提示">
<h2>
RayTable
remote true itemCount pageCount
</h2>
</NCard>
<NForm labelPlacement="left">
<RayCollapseGrid bordered={false} cols={3}>
{{
default: () => (
<>
<NFormItemGi label="邮箱">
<NInput v-model:value={this.email} clearable />
</NFormItemGi>
<NFormItemGi>
<NButton type="primary" onClick={this.getPerson.bind(this)}>
</NButton>
</NFormItemGi>
</>
),
}}
</RayCollapseGrid>
</NForm>
<RayTable
title="分页表格"
data={this.personData?.data}
loading={this.personLoading}
columns={this.columns}
pagination={this.paginationRef}
remote
action
/>
</NSpace>
)
},
})
export default MockDemo

View File

@ -16,6 +16,7 @@ import viteCompression from 'vite-plugin-compression' // 压缩打包
import { ViteEjsPlugin as viteEjsPlugin } from 'vite-plugin-ejs'
import viteAutoImport from 'unplugin-auto-import/vite'
import viteEslint from 'vite-plugin-eslint'
import mockDevServerPlugin from 'vite-plugin-mock-dev-server'
import { NaiveUiResolver } from 'unplugin-vue-components/resolvers' // 模板自动导入组件并且按需打包
import { VueHooksPlusResolver } from '@vue-hooks-plus/resolvers'
@ -156,6 +157,20 @@ export default defineConfig(async ({ mode }) => {
appPrimaryColor,
}),
viteInspect(), // 仅适用于开发模式(检查 `Vite` 插件的中间状态)
mockDevServerPlugin({
include: ['mock/**/*.mock.ts'],
exclude: [
'**/node_modules/**',
'**/test/**',
'**/cypress/**',
'src/**',
'**/.vscode/**',
'**/.git/**',
'**/dist/**',
'mock/shared/**',
],
reload: true,
}),
],
optimizeDeps: {
include: ['vue', 'vue-router', 'pinia', 'vue-i18n', '@vueuse/core'],