mirror of
https://github.com/zclzone/vue-naive-admin.git
synced 2025-12-29 04:20:22 +08:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9c5f4eaa3d | ||
|
|
361fb52345 | ||
|
|
5993e8d7d0 | ||
|
|
8648f16ed8 | ||
|
|
33aaadba60 | ||
|
|
437d87f19e | ||
|
|
dfcc8c2158 | ||
|
|
51a583fc1e | ||
|
|
396428104a | ||
|
|
ff2c25ff75 | ||
|
|
4f78bcb77c | ||
|
|
f62f59720d | ||
|
|
f296490569 |
2
.env
2
.env
@@ -3,4 +3,4 @@ VITE_APP_TITLE = 'Vue Naive Admin'
|
||||
VITE_PORT = 3100
|
||||
|
||||
# 打包时自动生成CNAME文件,用于配置github pages自定义域名,如不需要可注释或者直接删除
|
||||
VITE_APP_GLOB_CNAME = 'template.qszone.com'
|
||||
# VITE_APP_GLOB_CNAME = 'template.qszone.com'
|
||||
17
README.md
17
README.md
@@ -76,3 +76,20 @@ npm run lint:fix
|
||||
# 预览发布包效果(需先执行构建指令)
|
||||
npm run preview
|
||||
```
|
||||
|
||||
## Git 提交规范
|
||||
|
||||
- `feat` 增加新功能
|
||||
- `fix` 修复问题/BUG
|
||||
- `style` 代码风格相关无影响运行结果的
|
||||
- `perf` 优化/性能提升
|
||||
- `refactor` 重构
|
||||
- `revert` 撤销修改
|
||||
- `test` 测试相关
|
||||
- `docs` 文档/注释
|
||||
- `chore` 依赖更新/脚手架配置修改等
|
||||
- `workflow` 工作流改进
|
||||
- `ci` 持续集成
|
||||
- `types` 类型定义文件更改
|
||||
- `wip` 开发中
|
||||
- `mod` 不确定分类的修改
|
||||
|
||||
@@ -7,7 +7,7 @@ export function configMockPlugin(isBuild) {
|
||||
localEnabled: !isBuild,
|
||||
prodEnabled: isBuild,
|
||||
injectCode: `
|
||||
import { setupProdMockServer } from '../mock/_createProdServer';
|
||||
import { setupProdMockServer } from '../mock/_create-prod-server';
|
||||
setupProdMockServer();
|
||||
`,
|
||||
})
|
||||
|
||||
@@ -4,21 +4,21 @@ const users = {
|
||||
admin: {
|
||||
id: 1,
|
||||
name: '大脸怪(admin)',
|
||||
avatar: 'https://gitee.com/zclzone/res/raw/master/qs-zone/blob/img/lADPDiQ3QDTwsz3NAarNAaw_428_426.jpg',
|
||||
avatar: 'https://assets.qszone.com/images/avatar.jpg',
|
||||
email: 'Ronnie@123.com',
|
||||
role: ['admin'],
|
||||
},
|
||||
editor: {
|
||||
id: 2,
|
||||
name: '大脸怪(editor)',
|
||||
avatar: 'https://gitee.com/zclzone/res/raw/master/qs-zone/blob/img/lADPDiQ3QDTwsz3NAarNAaw_428_426.jpg',
|
||||
avatar: 'https://assets.qszone.com/images/avatar.jpg',
|
||||
email: 'Ronnie@123.com',
|
||||
role: ['editor'],
|
||||
},
|
||||
guest: {
|
||||
id: 3,
|
||||
name: '访客(guest)',
|
||||
avatar: 'https://gitee.com/zclzone/res/raw/master/qs-zone/blob/img/lADPDiQ3QDTwsz3NAarNAaw_428_426.jpg',
|
||||
avatar: 'https://assets.qszone.com/images/avatar.jpg',
|
||||
role: [],
|
||||
},
|
||||
}
|
||||
|
||||
34
package.json
34
package.json
@@ -13,35 +13,35 @@
|
||||
"dependencies": {
|
||||
"@vicons/fa": "^0.11.0",
|
||||
"axios": "^0.21.4",
|
||||
"dayjs": "^1.10.7",
|
||||
"dayjs": "^1.11.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"md-editor-v3": "^1.10.2",
|
||||
"md-editor-v3": "^1.11.4",
|
||||
"mockjs": "^1.1.0",
|
||||
"pinia": "^2.0.11",
|
||||
"vue": "^3.2.30",
|
||||
"vue-router": "^4.0.12"
|
||||
"pinia": "^2.0.13",
|
||||
"vue": "^3.2.31",
|
||||
"vue-router": "^4.0.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@unocss/preset-attributify": "^0.16.4",
|
||||
"@unocss/preset-icons": "^0.16.4",
|
||||
"@unocss/preset-uno": "^0.16.4",
|
||||
"@vitejs/plugin-vue": "^1.10.2",
|
||||
"@vue/compiler-sfc": "^3.2.30",
|
||||
"chalk": "^5.0.0",
|
||||
"@vue/compiler-sfc": "^3.2.31",
|
||||
"chalk": "^5.0.1",
|
||||
"dotenv": "^10.0.0",
|
||||
"eslint": "^8.6.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-vue": "^8.2.0",
|
||||
"eslint-plugin-vue": "^8.5.0",
|
||||
"esno": "^0.13.0",
|
||||
"fs-extra": "^10.0.0",
|
||||
"naive-ui": "^2.25.2",
|
||||
"prettier": "^2.5.1",
|
||||
"sass": "^1.38.1",
|
||||
"fs-extra": "^10.0.1",
|
||||
"naive-ui": "^2.27.0",
|
||||
"prettier": "^2.6.1",
|
||||
"sass": "^1.49.10",
|
||||
"unocss": "^0.16.4",
|
||||
"unplugin-vue-components": "^0.17.18",
|
||||
"vite": "^2.8.0",
|
||||
"vite-plugin-html": "^2.1.1",
|
||||
"unplugin-vue-components": "^0.17.21",
|
||||
"vite": "^2.9.1",
|
||||
"vite-plugin-html": "^2.1.2",
|
||||
"vite-plugin-mock": "^2.9.6",
|
||||
"vite-plugin-vue-setup-extend": "^0.3.0"
|
||||
}
|
||||
|
||||
831
pnpm-lock.yaml
generated
831
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
@@ -40,21 +40,21 @@ function switchRole() {
|
||||
{
|
||||
id: 1,
|
||||
name: '大脸怪(admin)',
|
||||
avatar: 'https://gitee.com/zclzone/res/raw/master/qs-zone/blob/img/lADPDiQ3QDTwsz3NAarNAaw_428_426.jpg',
|
||||
avatar: 'https://assets.qszone.com/images/avatar.jpg',
|
||||
email: 'Ronnie@123.com',
|
||||
role: ['admin'],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '大脸怪(editor)',
|
||||
avatar: 'https://gitee.com/zclzone/res/raw/master/qs-zone/blob/img/lADPDiQ3QDTwsz3NAarNAaw_428_426.jpg',
|
||||
avatar: 'https://assets.qszone.com/images/avatar.jpg',
|
||||
email: 'Ronnie@123.com',
|
||||
role: ['editor'],
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: '访客(guest)',
|
||||
avatar: 'https://gitee.com/zclzone/res/raw/master/qs-zone/blob/img/lADPDiQ3QDTwsz3NAarNAaw_428_426.jpg',
|
||||
avatar: 'https://assets.qszone.com/images/avatar.jpg',
|
||||
role: [],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -12,7 +12,7 @@ import HeaderAction from './HeaderAction.vue'
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.header {
|
||||
padding: 0 35px;
|
||||
padding: 0 24px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
@@ -11,18 +11,22 @@ import AppMain from './components/AppMain.vue'
|
||||
<side-menu />
|
||||
</n-layout-sider>
|
||||
<n-layout>
|
||||
<n-layout-header style="height: 100px; background-color: #f5f6fb">
|
||||
<n-layout-header>
|
||||
<app-header />
|
||||
</n-layout-header>
|
||||
<n-layout
|
||||
position="absolute"
|
||||
content-style="padding: 0 35px 35px;height: 100%;"
|
||||
style="top: 100px; background-color: #f5f6fb"
|
||||
:native-scrollbar="false"
|
||||
>
|
||||
<n-layout position="absolute" style="top: 60px; background-color: #f5f6fb" :native-scrollbar="false">
|
||||
<app-main />
|
||||
</n-layout>
|
||||
</n-layout>
|
||||
</n-layout>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.n-layout-header {
|
||||
height: 60px;
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #eee;
|
||||
border-left: 1px solid #eee;
|
||||
}
|
||||
</style>
|
||||
|
||||
10
src/main.js
10
src/main.js
@@ -2,18 +2,18 @@ import '@/styles/index.scss'
|
||||
import 'uno.css'
|
||||
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
|
||||
import { setupRouter } from '@/router'
|
||||
import { setupStore } from '@/store'
|
||||
import App from './App.vue'
|
||||
|
||||
async function bootstrap() {
|
||||
function setupApp() {
|
||||
const app = createApp(App)
|
||||
|
||||
setupStore(app)
|
||||
|
||||
setupRouter(app)
|
||||
|
||||
app.mount('#app', true)
|
||||
app.mount('#app')
|
||||
}
|
||||
|
||||
bootstrap()
|
||||
setupApp()
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { createPageLoadingGuard } from './pageLoadingGuard'
|
||||
import { createPermissionGuard } from './permissionGuard'
|
||||
import { createPageLoadingGuard } from './page-loading-guard'
|
||||
import { createPageTitleGuard } from './page-title-guard'
|
||||
import { createPermissionGuard } from './permission-guard'
|
||||
|
||||
export function setupRouterGuard(router) {
|
||||
createPageLoadingGuard(router)
|
||||
createPermissionGuard(router)
|
||||
createPageTitleGuard(router)
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
export function createPageLoadingGuard(router) {
|
||||
router.beforeEach(() => {
|
||||
$loadingBar.start()
|
||||
window.$loadingBar?.start()
|
||||
})
|
||||
|
||||
router.afterEach(() => {
|
||||
setTimeout(() => {
|
||||
$loadingBar.finish()
|
||||
window.$loadingBar?.finish()
|
||||
}, 200)
|
||||
})
|
||||
|
||||
router.onError(() => {
|
||||
$loadingBar.error()
|
||||
window.$loadingBar?.error()
|
||||
})
|
||||
}
|
||||
12
src/router/guard/page-title-guard.js
Normal file
12
src/router/guard/page-title-guard.js
Normal file
@@ -0,0 +1,12 @@
|
||||
const baseTitle = import.meta.env.VITE_APP_TITLE
|
||||
|
||||
export function createPageTitleGuard(router) {
|
||||
router.afterEach((to) => {
|
||||
const pageTitle = to.meta?.title
|
||||
if (pageTitle) {
|
||||
document.title = `${pageTitle} | ${baseTitle}`
|
||||
} else {
|
||||
document.title = baseTitle
|
||||
}
|
||||
})
|
||||
}
|
||||
2
src/utils/cache/index.js
vendored
2
src/utils/cache/index.js
vendored
@@ -1,4 +1,4 @@
|
||||
import { createWebStorage } from './webStorage'
|
||||
import { createWebStorage } from './web-storage'
|
||||
|
||||
export const createLocalStorage = function (option = {}) {
|
||||
return createWebStorage({ prefixKey: option.prefixKey || '', storage: localStorage })
|
||||
|
||||
@@ -1,3 +1,68 @@
|
||||
<template>
|
||||
<h1>首页</h1>
|
||||
<div>
|
||||
<n-card>
|
||||
<div flex items-center>
|
||||
<img width="60" style="border-radius: 50%" :src="userStore.avatar" />
|
||||
<div ml20>
|
||||
<p text-16>Hello, {{ userStore.name }}</p>
|
||||
<p op80 text-12 mt5>今天又是元气满满的一天</p>
|
||||
</div>
|
||||
<div flex ml-auto>
|
||||
<n-statistic label="待办" :value="4">
|
||||
<template #suffix> / 10 </template>
|
||||
</n-statistic>
|
||||
<n-statistic ml80 label="Stars">
|
||||
<n-number-animation ref="starsNumberRef" show-separator :from="0" :to="999" />
|
||||
</n-statistic>
|
||||
<n-statistic ml80 label="Forks">
|
||||
<n-number-animation ref="starsNumberRef" show-separator :from="0" :to="299" />
|
||||
</n-statistic>
|
||||
</div>
|
||||
</div>
|
||||
</n-card>
|
||||
|
||||
<div p15 flex>
|
||||
<n-card title="项目" size="small" :segmented="true">
|
||||
<template #header-extra>
|
||||
<n-button text type="primary">更多</n-button>
|
||||
</template>
|
||||
<div class="card-list">
|
||||
<n-card v-for="i in 10" :key="i" title="Vue Naive Admin" size="small">
|
||||
<p op60>一个基于 Vue3.0、Vite、Naive UI 的轻量级后台管理模板</p>
|
||||
</n-card>
|
||||
<div class="blank"></div>
|
||||
<div class="blank"></div>
|
||||
<div class="blank"></div>
|
||||
<div class="blank"></div>
|
||||
</div>
|
||||
</n-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
|
||||
const userStore = useUserStore()
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.card-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
.n-card {
|
||||
width: 300px;
|
||||
flex-shrink: 0;
|
||||
margin: 10px 0;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
box-shadow: 0 1px 2px -2px #00000029, 0 3px 6px #0000001f, 0 5px 12px 4px #00000017;
|
||||
}
|
||||
}
|
||||
.blank {
|
||||
width: 300px;
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -7,10 +7,10 @@ const { replace } = useRouter()
|
||||
<div class="page-404">
|
||||
<n-result status="404" description="抱歉,您访问的页面不存在。">
|
||||
<template #icon>
|
||||
<img src="@/assets/imgs/404/404.png" width="500" />
|
||||
<img src="@/assets/images/404.png" width="500" />
|
||||
</template>
|
||||
<template #footer>
|
||||
<n-button @click="replace('/')">返回首页</n-button>
|
||||
<n-button color="#002d6f" @click="replace('/')">返回首页</n-button>
|
||||
</template>
|
||||
</n-result>
|
||||
</div>
|
||||
@@ -19,6 +19,7 @@ const { replace } = useRouter()
|
||||
<style lang="scss" scoped>
|
||||
.page-404 {
|
||||
height: 100%;
|
||||
min-height: calc(100vh - 60px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div>
|
||||
<div p24>
|
||||
<div class="action-btns">
|
||||
<n-button size="small" type="primary" @click="handleCreate">新建文章</n-button>
|
||||
</div>
|
||||
@@ -11,7 +11,7 @@
|
||||
:columns="columns"
|
||||
:pagination="pagination"
|
||||
:row-key="(row) => row.id"
|
||||
max-height="calc(100vh - 260px)"
|
||||
max-height="calc(100vh - 250px)"
|
||||
@update:checked-row-keys="handleCheck"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<input v-model="post.title" type="text" placeholder="输入文章标题..." class="title" />
|
||||
<n-button type="primary" style="width: 80px" :loading="btnLoading" @click="handleSavePost">保存</n-button>
|
||||
</div>
|
||||
<md-editor v-model="post.content" style="height: calc(100vh - 180px)" />
|
||||
<md-editor v-model="post.content" style="height: calc(100vh - 140px)" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -13,5 +13,7 @@ const handleDelete = function () {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-button @click="handleDelete">删除</n-button>
|
||||
<div p24>
|
||||
<n-button type="error" @click="handleDelete">删除</n-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -16,5 +16,7 @@ onDeactivated(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-gradient-text gradient="linear-gradient(90deg, red 0%, green 50%, blue 100%)"> 注意查看提示语 </n-gradient-text>
|
||||
<div p24>
|
||||
<n-gradient-text gradient="linear-gradient(90deg, red 0%, green 50%, blue 100%)"> 注意查看提示语 </n-gradient-text>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -12,5 +12,7 @@ function handleLogin() {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-button @click="handleLogin">点击登陆</n-button>
|
||||
<div p24>
|
||||
<n-button type="primary" @click="handleLogin">点击登陆</n-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="content-box">
|
||||
<div p24>
|
||||
<div p20 bg="#fff">
|
||||
<p text-12>测试12px</p>
|
||||
<p text-13>测试13px</p>
|
||||
<p text-14>测试14px</p>
|
||||
@@ -13,11 +13,3 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.content-box {
|
||||
background-color: #fff;
|
||||
border-radius: 15px;
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user