feat: 新增uni-app移动端工程并集成uView-plus组件库

新增uni-app移动端工程,包含登录、首页、工作台、个人中心等页面,集成uView-plus组件库,优化移动端开发体验。同时更新文档和README,增加移动端相关内容。
This commit is contained in:
zhangtao
2025-04-16 19:51:51 +08:00
parent 3e1576427c
commit a2fa6933e2
54 changed files with 15078 additions and 14 deletions
+51 -2
View File
@@ -3,7 +3,7 @@
<img src="./mkdocs/docs/resources/images/logo.png" height="150" alt="logo"/> <img src="./mkdocs/docs/resources/images/logo.png" height="150" alt="logo"/>
</p> </p>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">Fastapi-Vue3-Admin v1.0.0</h1> <h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">Fastapi-Vue3-Admin v1.0.0</h1>
<h4 align="center">A rapid web application development framework for front-end and back-end separation based on Fastapi-Vue3-Admin</h4> <h4 align="center">A fast development framework for Web + Mini Programs + H5 applications based on the separation of front-end and back-end in Fastapi-Vue-Admin.</h4>
<p align="center"> <p align="center">
<a href="https://gitee.com/tao__tao/fastapi_vue3_admin.git"> <a href="https://gitee.com/tao__tao/fastapi_vue3_admin.git">
<img src="https://gitee.com/tao__tao/fastapi_vue3_admin/badge/star.svg?theme=dark"> <img src="https://gitee.com/tao__tao/fastapi_vue3_admin/badge/star.svg?theme=dark">
@@ -25,7 +25,7 @@ English | [Chinese](./README.md)
## 📚 Project Introduction ## 📚 Project Introduction
**Fastapi-Vue3-Admin** is a fully open-source rapid development platform that provides free usage. It combines modern, high-performance technology stacks to help developers quickly build high-quality backend systems. The project directory structure is as follows: **Fastapi-Vue3-Admin** is a fully open-source modern rapid development platform designed to help developers efficiently build high-quality backend systems. The project integrates the high-performance backend framework FastAPI and the powerful ORM library SQLAlchemy, along with the frontend technology stack Vue3, Vite6, Ant Design Vue, and the mobile development framework UniApp and its component library uView-plus, providing developers with an out-of-the-box solution. The project directory structure is as follows:
```sh ```sh
fastapi_vue_admin fastapi_vue_admin
@@ -33,6 +33,7 @@ fastapi_vue_admin
├─ frontend # Frontend project ├─ frontend # Frontend project
├─ devops # Deployment project ├─ devops # Deployment project
├─ mkdocs # Documentation project ├─ mkdocs # Documentation project
├─ uni-app # Uni-app project
├─ README.en.md # English documentation ├─ README.en.md # English documentation
└─ README.md # Chinese documentation └─ README.md # Chinese documentation
``` ```
@@ -50,6 +51,13 @@ fastapi_vue_admin
- **TypeScript**:Static type checking. - **TypeScript**:Static type checking.
- **Vite**:A fast build tool. - **Vite**:A fast build tool.
- **App**:
- **Vue3**: A progressive JavaScript framework for building user interfaces.
- **Vite**: A fast frontend build tool that supports hot reloading.
- **Pinia**: A state management library for Vue3 that provides a rich set of components.
- **UniApp**: A cross-platform application development framework that supports multi-terminal development.
- **uView-plus**: A Vue3-based UI component library that provides a rich set of components.
- **Authentication**:OAuth2 using hashed passwords and JWT Bearer tokens. - **Authentication**:OAuth2 using hashed passwords and JWT Bearer tokens.
- **Authorization Architecture**:Designed based on RBAC, supporting dynamic permission menus, button-level permission control, and data-level permission control. - **Authorization Architecture**:Designed based on RBAC, supporting dynamic permission menus, button-level permission control, and data-level permission control.
- **Ready-to-use**:Suitable as a starting template for new projects, also useful for learning and reference. - **Ready-to-use**:Suitable as a starting template for new projects, also useful for learning and reference.
@@ -94,6 +102,10 @@ If you find the project helpful, please give it a star!
- **API Management**:Maintains system APIs, such as API addresses and request methods. - **API Management**:Maintains system APIs, such as API addresses and request methods.
- **Documentation Management**:Maintains system API documentation, supports online API calls. - **Documentation Management**:Maintains system API documentation, supports online API calls.
- **App**
- **home**:Application home page.
- **work**:Application work page.
- **me**:Application me page.
## 🍪 Account Information ## 🍪 Account Information
@@ -117,6 +129,8 @@ If you find the project helpful, please give it a star!
| Database | PostgreSQL | 14(Recommended latest version)| | Database | PostgreSQL | 14(Recommended latest version)|
| Database | MongoDB | 8.0(Recommended latest version)| | Database | MongoDB | 8.0(Recommended latest version)|
| Middleware | Redis | 7.0 Recommended latest version| | Middleware | Redis | 7.0 Recommended latest version|
| App | uni-app | 3.0.0 |
| App | uview-plus | ^3.3.74 |
### Get the Code ### Get the Code
@@ -184,6 +198,27 @@ git clone https://gitee.com/tao__tao/fastapi_vue3_admin.git
npm run build npm run build
``` ```
### App
1. Install dependencies
```shell
cd frontend
npm install
```
2. Run the frontend
```shell
npm run dev:h5
```
3. Build the frontend
```shell
npm run build
```
### Access the Project ### Access the Project
- Frontend URL: <http://127.0.0.1:5180> - Frontend URL: <http://127.0.0.1:5180>
@@ -228,6 +263,17 @@ git clone https://gitee.com/tao__tao/fastapi_vue3_admin.git
<td><img src="./mkdocs/docs/resources/images/help.png"/>Help</td> <td><img src="./mkdocs/docs/resources/images/help.png"/>Help</td>
<td><img src="./mkdocs/docs/resources/images/dict.png"/>Dict</td> <td><img src="./mkdocs/docs/resources/images/dict.png"/>Dict</td>
</tr> </tr>
<tr>
<td><img src="./mkdocs/docs/resources/images/app-login.png"/>app-login</td>
<td><img src="./mkdocs/docs/resources/images/app-home.png"/>app-home</td>
</tr>
<tr>
<td><img src="./mkdocs/docs/resources/images/app-work.png"/>app-work</td>
<td><img src="./mkdocs/docs/resources/images/app-me.png"/>app-me</td>
</tr>
<tr>
<td><img src="./mkdocs/docs/resources/images/app-userinfo.png"/>app-userinfo</td>
</tr>
</table> </table>
## ✨ Special Thanks ## ✨ Special Thanks
@@ -241,6 +287,9 @@ Thank you to the following projects for their contributions and support, which h
- [Vue-FastAPI-Admin Project](https://gitee.com/mizhexiaoxiao/vue-fastapi-admin) - [Vue-FastAPI-Admin Project](https://gitee.com/mizhexiaoxiao/vue-fastapi-admin)
- [RuoYi-Vue3-FastAPI Project](https://gitee.com/insistence2022/RuoYi-Vue3-FastAPI) - [RuoYi-Vue3-FastAPI Project](https://gitee.com/insistence2022/RuoYi-Vue3-FastAPI)
- [APScheduler Project](https://github.com/agronholm/apscheduler) - [APScheduler Project](https://github.com/agronholm/apscheduler)
- [Vite Project](https://github.com/vitejs/vite)
- [UniApp Project](https://github.com/dcloudio/uni-app)
- [uView-plus Project](https://uiadmin.net/uview-plus)
## 🎨 WeChat Group ## 🎨 WeChat Group
+52 -2
View File
@@ -3,7 +3,7 @@
<img src="./mkdocs/docs/resources/images/logo.png" height="150" alt="logo"/> <img src="./mkdocs/docs/resources/images/logo.png" height="150" alt="logo"/>
</p> </p>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">Fastapi-Vue3-Admin v1.0.0</h1> <h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">Fastapi-Vue3-Admin v1.0.0</h1>
<h4 align="center">基于Fastapi-Vue-Admin前后端分离的Web应用快速开发框架</h4> <h4 align="center">基于Fastapi-Vue-Admin前后端分离的Web+小程序+H5应用快速开发框架</h4>
<p align="center"> <p align="center">
<a href="https://gitee.com/tao__tao/fastapi_vue3_admin.git"> <a href="https://gitee.com/tao__tao/fastapi_vue3_admin.git">
<img src="https://gitee.com/tao__tao/fastapi_vue3_admin/badge/star.svg?theme=dark"> <img src="https://gitee.com/tao__tao/fastapi_vue3_admin/badge/star.svg?theme=dark">
@@ -25,7 +25,7 @@
## 📚 项目介绍 ## 📚 项目介绍
**Fastapi-Vue3-Admin** 是一套完全开源的快速开发平台,提供免费使用。它结合了现代、高性能的技术栈,旨在帮助开发者快速搭建高质量的中后台系统。项目目录结构如下: **Fastapi-Vue3-Admin** 是一套完全开源的现代化快速开发平台,旨在帮助开发者高效搭建高质量的中后台系统。项目结合了高性能后端框架 FastAPI 和强大的 ORM 库 SQLAlchemy,以及前端技术栈 Vue3、Vite6、Ant Design Vue 和移动端开发框架 UniApp 及其组件库 uView-plus,为开发者提供了开箱即用的解决方案。项目目录结构如下:
```sh ```sh
fastapi_vue_admin fastapi_vue_admin
@@ -33,6 +33,7 @@ fastapi_vue_admin
├─ frontend # 前端工程 ├─ frontend # 前端工程
├─ devops # 部署工程 ├─ devops # 部署工程
├─ mkdocs # 文档工程 ├─ mkdocs # 文档工程
├─ uni-app # 移动端工程
|─ README.en.md # 英文文档 |─ README.en.md # 英文文档
└─ README.md # 中文文档 └─ README.md # 中文文档
``` ```
@@ -50,6 +51,13 @@ fastapi_vue_admin
- **TypeScript**:静态类型检查 - **TypeScript**:静态类型检查
- **Vite**:快速的构建工具 - **Vite**:快速的构建工具
- **app**:
- **Vue3**: 渐进式JavaScript框架,用于构建用户界面。
- **Vite5**: 快速的前端构建工具,支持热重载。
- **Pinia**: 状态管理工具,用于管理前端状态。
- **UniApp**: 跨平台应用开发框架,支持多端开发。
- **uView-plus**: 基于Vue3的UI组件库,提供丰富的组件。
- **权限认证**:使用哈希密码和 JWT Bearer 令牌的 OAuth2 - **权限认证**:使用哈希密码和 JWT Bearer 令牌的 OAuth2
- **权限架构**:基于 RBAC 设计,支持动态权限菜单、按钮级别权限控制、数据级别权限控制 - **权限架构**:基于 RBAC 设计,支持动态权限菜单、按钮级别权限控制、数据级别权限控制
- **开箱即用**:适合新项目启动模板,也可用于学习参考 - **开箱即用**:适合新项目启动模板,也可用于学习参考
@@ -94,6 +102,11 @@ fastapi_vue_admin
- **接口管理**:系统接口维护,如:接口地址、请求方式等。 - **接口管理**:系统接口维护,如:接口地址、请求方式等。
- **文档管理**:系统接口文档维护,支持在线接口调用。 - **文档管理**:系统接口文档维护,支持在线接口调用。
- **App**
- **首页**: 应用首页。
- **工作台**:常用功能入口。
- **个人中心**:系统接口文档维护,支持在线接口调用。
## 🍪 账号信息 ## 🍪 账号信息
| 账户类型 | 账号 | 密码 | | 账户类型 | 账号 | 密码 |
@@ -116,6 +129,8 @@ fastapi_vue_admin
| 数据库 | PostgreSQL | 14(其他版本均未测试)| | 数据库 | PostgreSQL | 14(其他版本均未测试)|
| 数据库 | MongoDB | 8.0(推荐使用最新版)| | 数据库 | MongoDB | 8.0(推荐使用最新版)|
| 中间件 | Redis | 7.0 (推荐使用最新版)| | 中间件 | Redis | 7.0 (推荐使用最新版)|
| 小程序 | uni-app | 3.0.0 |
| 小程序 | uview-plus | ^3.3.74 |
### 获取代码 ### 获取代码
@@ -183,6 +198,27 @@ git clone https://gitee.com/tao__tao/fastapi_vue3_admin.git
npm run build npm run build
``` ```
### 小程序
1. 安装依赖
```shell
cd frontend
npm install
```
2. 运行
```shell
npm run dev:h5
```
3. 打包
```shell
npm run build
```
### 访问项目 ### 访问项目
- 前端地址:<http://127.0.0.1:5180> - 前端地址:<http://127.0.0.1:5180>
@@ -227,6 +263,17 @@ git clone https://gitee.com/tao__tao/fastapi_vue3_admin.git
<td><img src="./mkdocs/docs/resources/images/help.png"/>在线文档</td> <td><img src="./mkdocs/docs/resources/images/help.png"/>在线文档</td>
<td><img src="./mkdocs/docs/resources/images/dict.png"/>字典管理</td> <td><img src="./mkdocs/docs/resources/images/dict.png"/>字典管理</td>
</tr> </tr>
<tr>
<td><img src="./mkdocs/docs/resources/images/app-login.png"/>app登陆</td>
<td><img src="./mkdocs/docs/resources/images/app-home.png"/>app首页</td>
</tr>
<tr>
<td><img src="./mkdocs/docs/resources/images/app-work.png"/>app工作台</td>
<td><img src="./mkdocs/docs/resources/images/app-me.png"/>app个人中心</td>
</tr>
<tr>
<td><img src="./mkdocs/docs/resources/images/app-userinfo.png"/>app个人主页</td>
</tr>
</table> </table>
## ✨ 特别鸣谢 ## ✨ 特别鸣谢
@@ -240,6 +287,9 @@ git clone https://gitee.com/tao__tao/fastapi_vue3_admin.git
- [Vue-FastAPI-Admin 项目](https://gitee.com/mizhexiaoxiao/vue-fastapi-admin) - [Vue-FastAPI-Admin 项目](https://gitee.com/mizhexiaoxiao/vue-fastapi-admin)
- [RuoYi-Vue3-FastAPI 项目](https://gitee.com/insistence2022/RuoYi-Vue3-FastAPI) - [RuoYi-Vue3-FastAPI 项目](https://gitee.com/insistence2022/RuoYi-Vue3-FastAPI)
- [APScheduler 项目](https://github.com/agronholm/apscheduler) - [APScheduler 项目](https://github.com/agronholm/apscheduler)
- [Vite 项目](https://github.com/vitejs/vite)
- [UniApp 项目](https://github.com/dcloudio/uni-app)
- [uView-plus 项目](https://uiadmin.net/uview-plus)
## 🎨 微信群 ## 🎨 微信群
Binary file not shown.
+163 -2
View File
@@ -622,6 +622,51 @@
</span> </span>
</a> </a>
</li>
<li class="md-nav__item">
<a href="#app" class="md-nav__link">
<span class="md-ellipsis">
app登录
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#app_1" class="md-nav__link">
<span class="md-ellipsis">
app首页
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#app_2" class="md-nav__link">
<span class="md-ellipsis">
app工作台
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#app_3" class="md-nav__link">
<span class="md-ellipsis">
app个人中心
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#app_4" class="md-nav__link">
<span class="md-ellipsis">
app个人主页
</span>
</a>
</li> </li>
</ul> </ul>
@@ -636,6 +681,30 @@
</span> </span>
</a> </a>
</li>
<li class="md-nav__item">
<a href="#_31" class="md-nav__link">
<span class="md-ellipsis">
🎨 微信群
</span>
</a>
<nav class="md-nav" aria-label="🎨 微信群">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#_32" class="md-nav__link">
<span class="md-ellipsis">
群二维码
</span>
</a>
</li>
</ul>
</nav>
</li> </li>
</ul> </ul>
@@ -1162,6 +1231,51 @@
</span> </span>
</a> </a>
</li>
<li class="md-nav__item">
<a href="#app" class="md-nav__link">
<span class="md-ellipsis">
app登录
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#app_1" class="md-nav__link">
<span class="md-ellipsis">
app首页
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#app_2" class="md-nav__link">
<span class="md-ellipsis">
app工作台
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#app_3" class="md-nav__link">
<span class="md-ellipsis">
app个人中心
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#app_4" class="md-nav__link">
<span class="md-ellipsis">
app个人主页
</span>
</a>
</li> </li>
</ul> </ul>
@@ -1176,6 +1290,30 @@
</span> </span>
</a> </a>
</li>
<li class="md-nav__item">
<a href="#_31" class="md-nav__link">
<span class="md-ellipsis">
🎨 微信群
</span>
</a>
<nav class="md-nav" aria-label="🎨 微信群">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#_32" class="md-nav__link">
<span class="md-ellipsis">
群二维码
</span>
</a>
</li>
</ul>
</nav>
</li> </li>
</ul> </ul>
@@ -1199,7 +1337,7 @@
<img src="./resources/images/logo.png" height="150" alt="logo"/> <img src="./resources/images/logo.png" height="150" alt="logo"/>
</p> </p>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">Fastapi-Vue3-Admin v1.0.0</h1> <h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">Fastapi-Vue3-Admin v1.0.0</h1>
<h4 align="center">基于Fastapi-Vue-Admi前后端分离的快速开发框架</h4> <h4 align="center">基于Fastapi-Vue-Admin前后端分离的Web+小程序+H5应用快速开发框架</h4>
<p align="center"> <p align="center">
<a href="https://gitee.com/tao__tao/fastapi_vue3_admin.git"> <a href="https://gitee.com/tao__tao/fastapi_vue3_admin.git">
<img src="https://gitee.com/tao__tao/fastapi_vue3_admin/badge/star.svg?theme=dark"> <img src="https://gitee.com/tao__tao/fastapi_vue3_admin/badge/star.svg?theme=dark">
@@ -1218,7 +1356,7 @@
</div> </div>
<h2 id="_1">📚 项目介绍</h2> <h2 id="_1">📚 项目介绍</h2>
<p><strong>Fastapi-Vue3-Admin</strong> 是一套完全开源的快速开发平台,提供免费使用。它结合了现代、高性能的技术栈,旨在帮助开发者快速搭建高质量的中后台系统。项目目录结构如下:</p> <p><strong>Fastapi-Vue3-Admin</strong> 是一套完全开源的现代化快速开发平台,旨在帮助开发者高效搭建高质量的中后台系统。项目结合了高性能后端框架 FastAPI 和强大的 ORM 库 SQLAlchemy,以及前端技术栈 Vue3、Vite6、Ant Design Vue 和移动端开发框架 UniApp 及其组件库 uView-plus,为开发者提供了开箱即用的解决方案。项目目录结构如下:</p>
<pre><code class="language-sh">my_demo_project/fastapi_project <pre><code class="language-sh">my_demo_project/fastapi_project
├─ backend # 后端工程 ├─ backend # 后端工程
├─ frontend # 前端工程 ├─ frontend # 前端工程
@@ -1477,6 +1615,16 @@
<p><img alt="个人信息" src="resources/images/info.png" /></p> <p><img alt="个人信息" src="resources/images/info.png" /></p>
<h3 id="_29">在线文档</h3> <h3 id="_29">在线文档</h3>
<p><img alt="在线文档" src="resources/images/help.png" /></p> <p><img alt="在线文档" src="resources/images/help.png" /></p>
<h3 id="app">app登录</h3>
<p><img alt="app登录" src="resources/images/app-login.png" /></p>
<h3 id="app_1">app首页</h3>
<p><img alt="app首页" src="resources/images/app-home.png" /></p>
<h3 id="app_2">app工作台</h3>
<p><img alt="app工作台" src="resources/images/app-work.png" /></p>
<h3 id="app_3">app个人中心</h3>
<p><img alt="app个人中心" src="resources/images/app-me.png" /></p>
<h3 id="app_4">app个人主页</h3>
<p><img alt="app个人主页" src="resources/images/app-userinfo.png" /></p>
<h2 id="_30">✨ 特别鸣谢</h2> <h2 id="_30">✨ 特别鸣谢</h2>
<p>感谢以下项目的贡献和支持,使本项目得以顺利完成:</p> <p>感谢以下项目的贡献和支持,使本项目得以顺利完成:</p>
<ul> <ul>
@@ -1487,7 +1635,20 @@
<li><a href="https://gitee.com/mizhexiaoxiao/vue-fastapi-admin">Vue-FastAPI-Admin 项目</a></li> <li><a href="https://gitee.com/mizhexiaoxiao/vue-fastapi-admin">Vue-FastAPI-Admin 项目</a></li>
<li><a href="https://gitee.com/insistence2022/RuoYi-Vue3-FastAPI">RuoYi-Vue3-FastAPI 项目</a></li> <li><a href="https://gitee.com/insistence2022/RuoYi-Vue3-FastAPI">RuoYi-Vue3-FastAPI 项目</a></li>
<li><a href="https://github.com/agronholm/apscheduler">APScheduler 项目</a></li> <li><a href="https://github.com/agronholm/apscheduler">APScheduler 项目</a></li>
<li><a href="https://github.com/vitejs/vite">Vite 项目</a></li>
<li><a href="https://github.com/dcloudio/uni-app">UniApp 项目</a></li>
<li><a href="https://uiadmin.net/uview-plus">uView-plus 项目</a></li>
</ul> </ul>
<h2 id="_31">🎨 微信群</h2>
<p>在下方为群二维码,可以用于技术交流,也可以一起讨论在项目使用过程中遇到的各种问题。真心希望大家一起优化该项目,积极讨论,让我们一起抱团取暖!</p>
<h3 id="_32">群二维码</h3>
<table>
<tr>
<td><img src="https://gitee.com/tao__tao/fastapi_vue3_admin/raw/master/mkdocs/docs/resources/images/微信.jpg"/></td>
<td><img src="https://gitee.com/tao__tao/fastapi_vue3_admin/raw/master/mkdocs/docs/resources/images/微信群.jpg"/></td>
<td><img src="https://gitee.com/tao__tao/fastapi_vue3_admin/raw/master/mkdocs/docs/resources/images/wechatPay.jpg"/></td>
</tr>
</table>
Binary file not shown.

After

Width:  |  Height:  |  Size: 707 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 196 KiB

After

Width:  |  Height:  |  Size: 205 KiB

File diff suppressed because one or more lines are too long
+5 -5
View File
@@ -2,22 +2,22 @@
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url> <url>
<loc>http://127.0.0.1:8888/index.html</loc> <loc>http://127.0.0.1:8888/index.html</loc>
<lastmod>2025-04-11</lastmod> <lastmod>2025-04-16</lastmod>
</url> </url>
<url> <url>
<loc>http://127.0.0.1:8888/doc/backend.html</loc> <loc>http://127.0.0.1:8888/doc/backend.html</loc>
<lastmod>2025-04-11</lastmod> <lastmod>2025-04-16</lastmod>
</url> </url>
<url> <url>
<loc>http://127.0.0.1:8888/doc/build.html</loc> <loc>http://127.0.0.1:8888/doc/build.html</loc>
<lastmod>2025-04-11</lastmod> <lastmod>2025-04-16</lastmod>
</url> </url>
<url> <url>
<loc>http://127.0.0.1:8888/doc/frontend.html</loc> <loc>http://127.0.0.1:8888/doc/frontend.html</loc>
<lastmod>2025-04-11</lastmod> <lastmod>2025-04-16</lastmod>
</url> </url>
<url> <url>
<loc>http://127.0.0.1:8888/doc/mkdocs.html</loc> <loc>http://127.0.0.1:8888/doc/mkdocs.html</loc>
<lastmod>2025-04-11</lastmod> <lastmod>2025-04-16</lastmod>
</url> </url>
</urlset> </urlset>
Binary file not shown.
+39 -2
View File
@@ -3,7 +3,7 @@
<img src="./resources/images/logo.png" height="150" alt="logo"/> <img src="./resources/images/logo.png" height="150" alt="logo"/>
</p> </p>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">Fastapi-Vue3-Admin v1.0.0</h1> <h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">Fastapi-Vue3-Admin v1.0.0</h1>
<h4 align="center">基于Fastapi-Vue-Admi前后端分离的快速开发框架</h4> <h4 align="center">基于Fastapi-Vue-Admin前后端分离的Web+小程序+H5应用快速开发框架</h4>
<p align="center"> <p align="center">
<a href="https://gitee.com/tao__tao/fastapi_vue3_admin.git"> <a href="https://gitee.com/tao__tao/fastapi_vue3_admin.git">
<img src="https://gitee.com/tao__tao/fastapi_vue3_admin/badge/star.svg?theme=dark"> <img src="https://gitee.com/tao__tao/fastapi_vue3_admin/badge/star.svg?theme=dark">
@@ -23,7 +23,7 @@
## 📚 项目介绍 ## 📚 项目介绍
**Fastapi-Vue3-Admin** 是一套完全开源的快速开发平台,提供免费使用。它结合了现代、高性能的技术栈,旨在帮助开发者快速搭建高质量的中后台系统。项目目录结构如下: **Fastapi-Vue3-Admin** 是一套完全开源的现代化快速开发平台,旨在帮助开发者高效搭建高质量的中后台系统。项目结合了高性能后端框架 FastAPI 和强大的 ORM 库 SQLAlchemy,以及前端技术栈 Vue3、Vite6、Ant Design Vue 和移动端开发框架 UniApp 及其组件库 uView-plus,为开发者提供了开箱即用的解决方案。项目目录结构如下:
```sh ```sh
my_demo_project/fastapi_project my_demo_project/fastapi_project
@@ -257,6 +257,26 @@ git clone https://gitee.com/tao__tao/fastapi_vue3_admin.git
![在线文档](./resources/images/help.png) ![在线文档](./resources/images/help.png)
### app登录
![app登录](./resources/images/app-login.png)
### app首页
![app首页](./resources/images/app-home.png)
### app工作台
![app工作台](./resources/images/app-work.png)
### app个人中心
![app个人中心](./resources/images/app-me.png)
### app个人主页
![app个人主页](./resources/images/app-userinfo.png)
## ✨ 特别鸣谢 ## ✨ 特别鸣谢
感谢以下项目的贡献和支持,使本项目得以顺利完成: 感谢以下项目的贡献和支持,使本项目得以顺利完成:
@@ -268,3 +288,20 @@ git clone https://gitee.com/tao__tao/fastapi_vue3_admin.git
- [Vue-FastAPI-Admin 项目](https://gitee.com/mizhexiaoxiao/vue-fastapi-admin) - [Vue-FastAPI-Admin 项目](https://gitee.com/mizhexiaoxiao/vue-fastapi-admin)
- [RuoYi-Vue3-FastAPI 项目](https://gitee.com/insistence2022/RuoYi-Vue3-FastAPI) - [RuoYi-Vue3-FastAPI 项目](https://gitee.com/insistence2022/RuoYi-Vue3-FastAPI)
- [APScheduler 项目](https://github.com/agronholm/apscheduler) - [APScheduler 项目](https://github.com/agronholm/apscheduler)
- [Vite 项目](https://github.com/vitejs/vite)
- [UniApp 项目](https://github.com/dcloudio/uni-app)
- [uView-plus 项目](https://uiadmin.net/uview-plus)
## 🎨 微信群
在下方为群二维码,可以用于技术交流,也可以一起讨论在项目使用过程中遇到的各种问题。真心希望大家一起优化该项目,积极讨论,让我们一起抱团取暖!
### 群二维码
<table>
<tr>
<td><img src="https://gitee.com/tao__tao/fastapi_vue3_admin/raw/master/mkdocs/docs/resources/images/微信.jpg"/></td>
<td><img src="https://gitee.com/tao__tao/fastapi_vue3_admin/raw/master/mkdocs/docs/resources/images/微信群.jpg"/></td>
<td><img src="https://gitee.com/tao__tao/fastapi_vue3_admin/raw/master/mkdocs/docs/resources/images/wechatPay.jpg"/></td>
</tr>
</table>
Binary file not shown.

After

Width:  |  Height:  |  Size: 707 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 KiB

+11
View File
@@ -0,0 +1,11 @@
# 环境变量
VITE_ENV = development
# 后端地址
VITE_API_BASE_URL = "http://localhost:8000"
# 后端接口基础路径
VITE_API_BASE_NAME = "/api"
# 请求超时时间
VITE_TIMEOUT = "10000"
+21
View File
@@ -0,0 +1,21 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
*.local
# Editor directories and files
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
+52
View File
@@ -0,0 +1,52 @@
# frontend
```sh
uni-app/
├─ src # 前端源码目录
│ ├─ api # API目录
│ ├─ components # 组件目录
│ ├─ pages # 页面目录
│ ├─ static # 静态资源目录
│ ├─ stores # 状态管理目录
│ ├─ utils # 工具目录
│ ├─ App.vue # 主组件
│ ├─ main.ts # 入口文件
│ ├─ manifest.json # 应用配置文件
│ ├─ pages.json # 页面配置文件
│ ├─ shims-uni.d.ts # 类型声明文件
│ └─ uni.scss # 全局样式文件
├─ .env # 前端目录
├─ .gitignore # git忽略文件
├─ .env # 环境变量
├─ index.html # 首页
├─ package.json # 项目依赖
├─ shims-uni.d.ts # 类型声明文件
├─ vite.config.js # vite配置文件
└─ README.md # 文档说明
```
## 项目初始化
```sh
npm install
```
### 项目启动
```sh
npm run dev:h5
```
### 项目构建
```sh
npm run build
```
### 注意
在sass1.8.0以上版本报错Deprecation Warning: Sass @import rules are deprecated and will be removed in Dart Sass 3.0.0. 因为新版本Sass的@use语法较为激进,如果升级为@use将会是破坏式更新,所以推荐将sass固定在以下版本结局报警。
"uview-plus": "^3.3.74", 版本不要升级
"unocss": "^0.58.9", 版本不要升级
"sass": "1.63.2", //sass版本不要升级
"sass-loader": "10.4.1", //sass-loader版本不要升级
+21
View File
@@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/png" href="/static/favicon.ico" />
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
CSS.supports('top: constant(a)'))
document.write(
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
</script>
<title></title>
<!--preload-links-->
<!--app-context-->
</head>
<body>
<div id="app"><!--app-html--></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
+13235
View File
File diff suppressed because it is too large Load Diff
+70
View File
@@ -0,0 +1,70 @@
{
"name": "uni-preset-vue",
"version": "0.0.0",
"scripts": {
"dev:custom": "uni -p",
"dev:h5": "uni",
"dev:h5:ssr": "uni --ssr",
"dev:mp-alipay": "uni -p mp-alipay",
"dev:mp-baidu": "uni -p mp-baidu",
"dev:mp-jd": "uni -p mp-jd",
"dev:mp-kuaishou": "uni -p mp-kuaishou",
"dev:mp-lark": "uni -p mp-lark",
"dev:mp-qq": "uni -p mp-qq",
"dev:mp-toutiao": "uni -p mp-toutiao",
"dev:mp-weixin": "uni -p mp-weixin",
"dev:mp-xhs": "uni -p mp-xhs",
"dev:quickapp-webview": "uni -p quickapp-webview",
"dev:quickapp-webview-huawei": "uni -p quickapp-webview-huawei",
"dev:quickapp-webview-union": "uni -p quickapp-webview-union",
"build:custom": "uni build -p",
"build:h5": "uni build",
"build:h5:ssr": "uni build --ssr",
"build:mp-alipay": "uni build -p mp-alipay",
"build:mp-baidu": "uni build -p mp-baidu",
"build:mp-jd": "uni build -p mp-jd",
"build:mp-kuaishou": "uni build -p mp-kuaishou",
"build:mp-lark": "uni build -p mp-lark",
"build:mp-qq": "uni build -p mp-qq",
"build:mp-toutiao": "uni build -p mp-toutiao",
"build:mp-weixin": "uni build -p mp-weixin",
"build:mp-xhs": "uni build -p mp-xhs",
"build:quickapp-webview": "uni build -p quickapp-webview",
"build:quickapp-webview-huawei": "uni build -p quickapp-webview-huawei",
"build:quickapp-webview-union": "uni build -p quickapp-webview-union"
},
"dependencies": {
"@dcloudio/uni-app": "3.0.0-4050720250324001",
"@dcloudio/uni-app-harmony": "3.0.0-4050720250324001",
"@dcloudio/uni-app-plus": "3.0.0-4050720250324001",
"@dcloudio/uni-components": "3.0.0-4050720250324001",
"@dcloudio/uni-h5": "3.0.0-4050720250324001",
"@dcloudio/uni-mp-alipay": "3.0.0-4050720250324001",
"@dcloudio/uni-mp-baidu": "3.0.0-4050720250324001",
"@dcloudio/uni-mp-jd": "3.0.0-4050720250324001",
"@dcloudio/uni-mp-kuaishou": "3.0.0-4050720250324001",
"@dcloudio/uni-mp-lark": "3.0.0-4050720250324001",
"@dcloudio/uni-mp-qq": "3.0.0-4050720250324001",
"@dcloudio/uni-mp-toutiao": "3.0.0-4050720250324001",
"@dcloudio/uni-mp-weixin": "3.0.0-4050720250324001",
"@dcloudio/uni-mp-xhs": "3.0.0-4050720250324001",
"@dcloudio/uni-quickapp-webview": "3.0.0-4050720250324001",
"unplugin-auto-import": "^19.1.2",
"uview-plus": "^3.3.74",
"vue": "3.5.13",
"vue-i18n": "9.14.3"
},
"devDependencies": {
"@dcloudio/types": "3.4.14",
"@dcloudio/uni-automator": "3.0.0-4050720250324001",
"@dcloudio/uni-cli-shared": "3.0.0-4050720250324001",
"@dcloudio/uni-stacktracey": "3.0.0-4050720250324001",
"@dcloudio/vite-plugin-uni": "3.0.0-4050720250324001",
"@vue/runtime-core": "3.5.13",
"pinia": "^2.3.0",
"sass": "1.63.2",
"sass-loader": "10.4.1",
"unocss": "^0.58.9",
"vite": "5.2.8"
}
}
+10
View File
@@ -0,0 +1,10 @@
/// <reference types='@dcloudio/types' />
import 'vue'
declare module '@vue/runtime-core' {
type Hooks = App.AppInstance & Page.PageInstance;
interface ComponentCustomOptions extends Hooks {
}
}
+19
View File
@@ -0,0 +1,19 @@
<script setup>
import { onLaunch, onShow, onHide } from "@dcloudio/uni-app";
onLaunch(() => {
});
onShow(() => {
});
onHide(() => {
});
</script>
<style lang="scss">
@import "uview-plus/index.scss";
</style>
+55
View File
@@ -0,0 +1,55 @@
import { request } from "../utils/request";
const contentTypes = {
form: "application/x-www-form-urlencoded",
json: "application/json",
multipart: "multipart/form-data"
};
export function login(data) {
return request({
url: "/api/v1/system/auth/login",
method: "post",
data: data,
header: { "Content-Type": contentTypes.form }
});
}
export function get_captcha() {
return request({
url: "/api/v1/system/auth/captcha/get",
method: "post",
});
}
export function forgot_password(data) {
return request({
url: "/api/v1/system/user/forget/password",
method: "post",
data: data
});
}
export function register(data) {
return request({
url: "/api/v1/system/user/register",
method: "post",
data: data
});
}
export function logout(data) {
return request({
url: "/api/v1/system/auth/logout",
method: "post",
data: data
});
}
export function getCurrentUserInfo() {
return request({
url: "/api/v1/system/user/current/info",
method: "get",
});
}
@@ -0,0 +1,20 @@
<template>
<view class="layout">
<slot name="main"></slot>
</view>
</template>
<script setup>
</script>
<style lang="scss">
.layout {
min-height: (100vh - var(--status-bar-height));
.main {
padding: 20rpx;
}
}
</style>
+15
View File
@@ -0,0 +1,15 @@
import { createSSRApp } from "vue";
import App from "./App.vue";
import uviewPlus, { setConfig } from 'uview-plus';
import * as Pinia from 'pinia';
import 'uno.css';
export function createApp() {
const app = createSSRApp(App);
app.use(uviewPlus)
app.use(Pinia.createPinia());
return {
app,
Pinia
};
}
+72
View File
@@ -0,0 +1,72 @@
{
"name" : "",
"appid" : "",
"description" : "",
"versionName" : "1.0.0",
"versionCode" : "100",
"transformPx" : false,
/* 5+App特有相关 */
"app-plus" : {
"usingComponents" : true,
"nvueStyleCompiler" : "uni-app",
"compilerVersion" : 3,
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : true,
"autoclose" : true,
"delay" : 0
},
/* 模块配置 */
"modules" : {},
/* 应用发布信息 */
"distribute" : {
/* android打包配置 */
"android" : {
"permissions" : [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
]
},
/* ios打包配置 */
"ios" : {},
/* SDK配置 */
"sdkConfigs" : {}
}
},
/* 快应用特有相关 */
"quickapp" : {},
/* 小程序特有相关 */
"mp-weixin" : {
"appid" : "",
"setting" : {
"urlCheck" : false
},
"usingComponents" : true
},
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"uniStatistics": {
"enable": false
},
"vueVersion" : "3"
}
+82
View File
@@ -0,0 +1,82 @@
{
"easycom": {
"autoscan": true,
"custom": {
// uni-ui 规则如下配置
"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue",
// uView-plus 规则如下配置
"^u--(.*)": "uview-plus/components/u-$1/u-$1.vue",
"^up-(.*)": "uview-plus/components/u-$1/u-$1.vue",
"^u-([^-].*)": "uview-plus/components/u-$1/u-$1.vue"
}
},
"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
{
"path": "pages/login/login",
"style": {
"navigationBarTitleText": "登录"
}
},
{
"path": "pages/me/me",
"style": {
"navigationBarTitleText": "个人中心"
}
},
{
"path": "pages/me/profile",
"style": {
"navigationBarTitleText": "个人主页"
}
},
{
"path" : "pages/home/home",
"style" :
{
"navigationBarTitleText" : "首页",
"enablePullDownRefresh": true
}
},
{
"path" : "pages/work/work",
"style" :
{
"navigationBarTitleText" : "工作台",
"enablePullDownRefresh": true
}
}
],
"globalStyle": {
"navigationBarTextStyle": "white",
"navigationBarTitleText": "用户信息管理系统",// 导航蓝字体内容
"navigationBarBackgroundColor": "#3c9cff",//导航蓝背景颜色
"backgroundColor": "#F8F8F8"// 下拉刷新区背景颜色
},
"tabBar": {
"color": "#999",
"selectedColor": "#3c9cff",
"list": [
{
"pagePath": "pages/home/home",
"text": "首页",
"iconPath": "/static/tabbar/home.png",
"selectedIconPath": "/static/tabbar/home_.png"
},
{
"pagePath": "pages/work/work",
"text": "工作台",
"iconPath": "/static/tabbar/work.png",
"selectedIconPath": "/static/tabbar/work_.png"
},
{
"pagePath": "pages/me/me",
"text": "我的",
"iconPath": "/static/tabbar/mine.png",
"selectedIconPath": "/static/tabbar/mine_.png"
}
]
},
"uniIdRouter": {}
}
+226
View File
@@ -0,0 +1,226 @@
<template>
<app-layout>
<template #main>
<view class="home-container">
<up-search :placeholder="'搜索书名/作者/分类'" @search="handleSearch" clear="handleClearSearch" />
<view class="scroll-content">
<!-- 紧凑轮播图 -->
<view class="swiper-section">
<up-swiper :list="swiperList" indicator>
<template v-slot:item="{ item }">
<up-image :src="item.image" width="100%" height="160rpx" mode="aspectFill"
radius="12" />
</template>
</up-swiper>
</view>
<!-- 分类导航 -->
<view class="category-nav">
<scroll-view scroll-x class="nav-scroll">
<view v-for="(item, index) in categories" :key="index" class="nav-item"
:class="{ active: currentCategory === index }" @click="switchCategory(index)">
{{ item }}
</view>
</scroll-view>
</view>
<!-- 热门小说推荐 -->
<view class="novel-section">
<view class="section-header">
<text class="title">热门小说</text>
<text class="more">更多 ></text>
</view>
<scroll-view scroll-x class="novel-scroll">
<view v-for="(item, index) in hotNovels" :key="index" class="novel-card">
<up-image :src="item.cover" width="200rpx" height="280rpx" radius="12" />
<text class="novel-title">{{ item.title }}</text>
<text class="novel-author">{{ item.author }}</text>
</view>
</scroll-view>
</view>
<!-- 排行榜 -->
<view class="ranking-section">
<view class="section-header">
<text class="title">本周热榜</text>
</view>
<view class="ranking-list">
<view v-for="(item, index) in rankingList" :key="index" class="ranking-item">
<text class="rank-num" :class="{ 'top3': index < 3 }">{{ index + 1 }}</text>
<up-image :src="item.cover" width="120rpx" height="160rpx" radius="8" />
<view class="rank-info">
<text class="book-title">{{ item.title }}</text>
<text class="book-author">{{ item.author }}</text>
<text class="book-hot">{{ item.hot }}人在读</text>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
</app-layout>
</template>
<script setup>
import { ref } from 'vue'
const swiperList = ref([
'/static/banner/banner01.jpg',
'/static/banner/banner02.jpg',
'/static/banner/banner03.jpg'
])
const currentCategory = ref(0)
const categories = ref(['推荐', '小说', '文学', '青春', '励志', '生活', '经管', '科技'])
const hotNovels = ref([
{ cover: 'https://bookcover.yuewen.com/qdbimg/349573/1001535109/150.webp', title: '三体', author: '刘慈欣' },
{ cover: 'https://bookcover.yuewen.com/qdbimg/349573/1042581400/150.webp', title: '活着', author: '余华' },
{ cover: 'https://bookcover.yuewen.com/qdbimg/349573/1039864976/150.webp', title: '白夜行', author: '东野圭吾' },
// ...更多小说
])
const rankingList = ref([
{ cover: 'https://bookcover.yuewen.com/qdbimg/349573/1015190643/90.webp', title: '云边有个小卖部', author: '张嘉佳', hot: '12.5万' },
{ cover: 'https://bookcover.yuewen.com/qdbimg/349573/1030657157/90.webp', title: '克拉克公园', author: '史蒂夫', hot: '10.2万' },
{ cover: 'https://bookcover.yuewen.com/qdbimg/349573/1005053098/90.webp', title: '平原上的摩西', author: '双雪涛', hot: '8.9万' },
])
const switchCategory = (index) => {
currentCategory.value = index
}
const handleSearch = (value) => {
console.log('搜索:', value)
}
</script>
<style lang="scss" scoped>
.home-container {
padding: 60rpx 20rpx;
.scroll-content {
padding: 20rpx 24rpx;
}
}
/* 轮播图优化 */
.swiper-section {
margin: 20rpx 0;
:deep(.up-swiper) {
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.04);
}
}
/* 分类导航 */
.category-nav {
margin: 20rpx 0;
.nav-scroll {
white-space: nowrap;
.nav-item {
display: inline-block;
padding: 16rpx 30rpx;
font-size: 28rpx;
color: #666;
&.active {
color: #2979ff;
font-weight: 500;
}
}
}
}
/* 热门小说推荐 */
.novel-section {
margin: 30rpx 0;
.novel-scroll {
white-space: nowrap;
padding: 20rpx 0;
.novel-card {
display: inline-block;
margin-right: 24rpx;
width: 200rpx;
.novel-title {
font-size: 26rpx;
color: #333;
margin-top: 12rpx;
}
.novel-author {
font-size: 22rpx;
color: #999;
}
}
}
}
/* 排行榜 */
.ranking-section {
margin: 30rpx 0;
.ranking-item {
display: flex;
align-items: center;
padding: 20rpx 0;
border-bottom: 1rpx solid #eee;
.rank-num {
width: 40rpx;
font-size: 32rpx;
font-weight: bold;
color: #999;
&.top3 {
color: #ff6b6b;
}
}
.rank-info {
margin-left: 20rpx;
.book-title {
font-size: 28rpx;
color: #333;
}
.book-author {
font-size: 24rpx;
color: #666;
}
.book-hot {
font-size: 22rpx;
color: #ff6b6b;
}
}
}
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20rpx;
.title {
font-size: 32rpx;
font-weight: 500;
color: #333;
}
.more {
font-size: 24rpx;
color: #999;
}
}
</style>
+127
View File
@@ -0,0 +1,127 @@
<template>
<view class="login-container" :style="{ backgroundImage: BACKGROUND_IMAGE }">
<!-- 登录表单 -->
<up-image class="logo" :src="LOGO_PATH" shape="circle" width="100" height="100" mode="aspectFit" />
<up-text class="logo-text" :bold="true" align="center" size="24" lineHeight="40" text="用户管理系统" />
<up-form ref="loginForm" class="auth-form" :model="formData" :rules="rules">
<!-- 用户名 -->
<up-form-item prop="username">
<up-input v-model="formData.username" placeholder="请输入账号" prefix-icon="account" clearable />
</up-form-item>
<!-- 密码 -->
<up-form-item prop="password">
<up-input v-model="formData.password" type="password" placeholder="请输入密码" prefix-icon="lock" clearable />
</up-form-item>
<!-- 验证码 -->
<up-form-item prop="captcha">
<up-input v-model="formData.captcha" placeholder="请输入验证码" prefix-icon="fingerprint" clearable >
<template #suffix>
<up-image :src="captchaState.img_base" @click="requestCaptcha" :preview="false" width="100" height="30" />
</template>
</up-input>
</up-form-item>
<!-- 登录按钮 -->
<up-button class="login-btn" type="primary" text="登录" :loading="loading" @click="handleSubmit" />
</up-form>
<!-- 底部链接 - 左右分开 -->
<view class="footer-links">
<up-text type="primary" @click="navigateTo('register')" text="用户注册" align="left"></up-text>
<up-text type="primary" @click="navigateTo('forget')" text="忘记密码" align="right"></up-text>
</view>
</view>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { onReady, onShow } from '@dcloudio/uni-app'
import { useUserStore } from '../../stores/index'
import { login, get_captcha } from '@/api/apis'
onReady(() => {
requestCaptcha();
})
const LOGO_PATH = '/static/logo.png'
const BACKGROUND_IMAGE = '/static/background.png'
const loading = ref(false)
const loginForm = ref(null)
const formData = ref({
username: '',
password: '',
captcha: '',
captcha_key: ''
})
const captchaState = ref({
key: '',
img_base: ''
})
const rules = {
username: { required: true, message: '请输入账号',trigger: ['change','blur'] },
password: { required: true, message: '请输入密码',trigger: ['change','blur'] },
captcha: { required: true, message: '请输入验证码',trigger: ['change','blur'] },
}
const handleSubmit = async () => {
await loginForm.value.validate()
loading.value = true
formData.value.captcha_key = captchaState.value.key;
login(formData.value).then(response => {
const data = response.data;
useUserStore().setToken(data.access_token, data.refresh_token)
console.log('登录成功', response)
uni.switchTab({ url: '/pages/home/home' })
}).catch(error => {
console.error('登录失败', error)
requestCaptcha();
})
.finally(() => loading.value = false);
}
const requestCaptcha = async () => {
const response = await get_captcha()
console.log('获取验证码', response);
const data = response.data;
captchaState.value = data;
};
const navigateTo = (page) => {
uni.showToast({
title: page+'功能开发中',
icon: "none",
mask: true,
});
}
</script>
<style scoped lang="scss">
.login-container {
padding: 60rpx;
display: flex;
flex-direction: column;
align-items: center;
.auth-form {
margin-top: 40rpx;
width: 100%;
.login-btn {
margin-top: 40rpx;
}
}
.footer-links {
margin-top: 40rpx;
display: flex;
width: 100%;
}
}
</style>
+218
View File
@@ -0,0 +1,218 @@
<template>
<app-layout>
<template #main>
<view class="me-container">
<!-- 个人信息卡片 -->
<up-card padding="40rpx" margin="0 0 30rpx 0" :shadow="3" :borderRadius="20" :show-head="false">
<template #body>
<view class="user-info-container">
<up-avatar :src="formData.avatar || '/static/logo.png'" shape="circle"
size="80" class="user-avatar"></up-avatar>
<view class="user-details">
<up-text :text="formData.name" bold size="20"></up-text>
<up-text :text="formData.username" type="info" margin="10rpx 0 0 0"
prefix-icon="account"></up-text>
<up-text :text="formData.mobile" type="info" margin="10rpx 0 0 0"
prefix-icon="phone"></up-text>
</view>
<up-button type="primary" size="small" text="个人主页" @click="handleToProfile(formData.id)" class="profile-button"></up-button>
</view>
</template>
</up-card>
<!-- 数据统计 -->
<up-grid :border="false" col="4" align="center" class="stats-grid">
<up-grid-item v-for="item in dataItems" :key="item.title" :border="true" class="stats-item">
<view class="stats-content">
<view class="stats-value">
<up-text :text="item.value" size="22" bold></up-text>
</view>
<view class="stats-title">
<up-text :text="item.title" type="info" ></up-text>
</view>
</view>
</up-grid-item>
</up-grid>
<!-- 功能菜单 -->
<view class="menu-section">
<up-cell-group>
<up-cell title="个人资料" icon="account" isLink @click="handleToDetail(formData.id)"></up-cell>
<up-cell title="系统设置" icon="setting" isLink @click="handleToUpdate(formData.id)"></up-cell>
<up-cell title="安全中心" icon="lock" isLink @click="handletoPassword()"></up-cell>
<up-cell title="消息中心" icon="bell" isLink @click="showContact = true"></up-cell>
</up-cell-group>
</view>
<!-- 退出登录按钮 -->
<view class="logout-btn">
<up-button type="error" text="退出登录" :loading="loading" @click="handleLogout"></up-button>
</view>
</view>
</template>
</app-layout>
</template>
<script setup>
import { ref, computed, reactive } from 'vue';
import { onLoad, onReady, onShow } from '@dcloudio/uni-app';
import { logout } from "@/api/apis";
import { useUserStore } from '../../stores/index';
const userStore = useUserStore();
const loading = ref(false);
const formData = ref({
id: null,
name: "",
username: "",
available: null,
is_superuser: null,
avatar: "",
dept_name: "",
email: "",
mobile: "",
gender: null, // 0男 1女 2未知
description: "",
created_at: "",
updated_at: "",
last_login: "",
});
// 数据统计
const dataItems = ref([
{ title: '待办事项', value: '5' },
{ title: '消息通知', value: '3' },
{ title: '收藏项目', value: '8' },
{ title: '已完成', value: '12' }
]);
onReady(async () => {
loading.value = true;
await userStore.getUserInfo();
formData.value = userStore.basic_info;
loading.value = false;
});
// 添加onShow生命周期钩子
onShow(() => {
formData.value = userStore.basic_info;
});
// 弹窗控制
const showContact = ref(false)
// 退出登录
const handleLogout = async () => {
loading.value = true;
logout({ token: userStore.access_token }).then(response => {
if (response.status_code == 200) {
useUserStore().clear();
uni.reLaunch({ url: '/pages/login/login' });
}
}).catch(error => {
console.error('退出登录失败', error)
})
.finally(() => loading.value = false);
};
// 个人主页按钮点击事件
const handleToProfile = () => {
uni.navigateTo({ url: `/pages/me/profile` });
};
</script>
<style lang="scss" scoped>
.me-container {
padding: 40rpx;
}
.user-info-container {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20rpx;
}
.user-avatar {
margin-right: 20rpx;
}
.user-details {
flex: 1;
}
.profile-button {
margin-left: 0;
margin-right: 0;
border-radius: 40rpx 0 0 40rpx;
width: 160rpx;
padding-right: 20rpx;
position: absolute;
right: 0;
}
.stats-item {
position: relative;
padding: 20rpx;
&::after {
content: '';
position: absolute;
right: 0;
top: 20%;
width: 1px;
height: 60%;
background: #ebedf0;
}
}
.stats-content {
display: flex;
flex-direction: column;
align-items: center;
gap: 12rpx;
}
.stats-value {
margin: 8rpx 0;
display: flex;
}
.stats-title {
text-align: center;
}
.menu-section {
margin: 40rpx 0;
background: #ffffff;
border-radius: 20rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
}
.logout-btn {
padding: 20rpx 0;
}
.contact-popup {
width: 600rpx;
padding: 40rpx;
background: #fff;
border-radius: 20rpx;
position: relative;
z-index: 100;
.popup-header {
display: flex;
}
.popup-footer {
text-align: center;
padding: 20rpx 0 0;
border-top: 1px solid #eee;
}
}
</style>
+76
View File
@@ -0,0 +1,76 @@
<template>
<view class="detail-container">
<up-cell-group>
<up-cell title="头像" :border="true">
<template #right-icon>
<up-avatar :src="formData.avatar" shape="circle" size="40" mode="scaleToFill"
bgColor="#c0c4cc" color="#ffffff" fontSize="35px" name="level">
</up-avatar>
</template>
</up-cell>
<up-cell title="编号" :value="formData.id" :border="true"></up-cell>
<up-cell title="用户名" :value="formData.name" :border="true"></up-cell>
<up-cell title="账号" :value="formData.username" :border="true"></up-cell>
<up-cell title="状态">
<template #value>
<up-tag :text="formData.available ? '启用' : '禁用'" :type="formData.available ? 'success' : 'warning'" plain plainFill></up-tag>
</template>
</up-cell>
<up-cell title="类型">
<template #value>
<up-tag :text="formData.is_superuser ? '管理员' : '普通用户'" :type="formData.is_superuser ? 'error' : 'primary'" plain plainFill ></up-tag>
</template>
</up-cell>
<up-cell title="部门" :value="formData.dept_name" :border="true"></up-cell>
<up-cell title="邮箱" :value="formData.email" :border="true"></up-cell>
<up-cell title="手机号" :value="formData.mobile" :border="true"></up-cell>
<up-cell title="性别">
<template #value>
<up-tag :text="formData.gender==0? '男' : formData.gender==1? '女' : '未知'" :type="formData.gender==0? 'success' : formData.gender==1? 'warning' : 'info'" plain plainFill></up-tag>
</template>
</up-cell>
<up-cell title="描述" :value="formData.description || '暂无描述'" :border="true"></up-cell>
<up-cell title="创建时间" :value="formData.created_at" :border="true"></up-cell>
<up-cell title="更新时间" :value="formData.updated_at" :border="true"></up-cell>
</up-cell-group>
</view>
</template>
<script setup>
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { useUserStore } from '../../stores/index';
const userStore = useUserStore();
const loading = ref(false);
const formData = ref({
id: null,
name: "",
username: "",
available: null,
is_superuser: null,
avatar: "",
dept_name: "",
email: "",
mobile: "",
gender: null, // 0男 1女 2未知
description: "",
created_at: "",
updated_at: "",
});
onLoad(async () => {
loading.value = true;
await userStore.getUserInfo();
formData.value = userStore.basic_info;
loading.value = false;
})
</script>
<style lang="scss" scoped>
.detail-container {
padding: 60rpx 60rpx;
}
</style>
+210
View File
@@ -0,0 +1,210 @@
<template>
<app-layout>
<template #main>
<view class="work-container">
<!-- 通知栏 -->
<up-notice-bar :text="noticeText" bg-color="#f0f7ff" color="#2979ff"></up-notice-bar>
<!-- 轮播图 -->
<view class="swiper-box">
<up-swiper :list="swiperList" indicator indicator-pos="bottomCenter" radius="8" />
</view>
<!-- 常用功能 -->
<view class="section-card">
<view class="section-header">
<up-row customStyle="margin-bottom: 10px">
<up-col span="6">
<up-text text="常用功能" bold align="left"></up-text>
</up-col>
<up-col span="6">
<up-text type="primary" text="更多" class="more" @click="navigateToMore" align="right" />
</up-col>
</up-row>
</view>
<up-grid :col="4" :border="false" align="center">
<up-grid-item v-for="(item, index) in commonFunctions" :key="index"
@click="handleFunctionClick(item)">
<view class="function-item">
<up-icon :name="item.icon" :size="22" :color="item.color || '#2979ff'" />
<text class="grid-text" margin-top="8" >{{ item.name }}</text>
</view>
</up-grid-item>
</up-grid>
</view>
<!-- 应用分类 -->
<view class="section-card">
<up-text text="全部功能" bold></up-text>
<view class="section-header">
<up-tabs :list="appTabs" @click="handleTabChange" active-color="#2979ff"></up-tabs>
</view>
<!-- 对应分类内容 -->
<up-grid :col="4" :border="false" align="center">
<up-grid-item v-for="(app, index) in currentApps" :key="index" @click="handleAppClick(app)">
<view class="app-item">
<up-icon :name="app.icon" :size="22" :color="app.color || '#2979ff'"/>
<text class="grid-text" margin-top="8" >{{ app.name }}</text>
</view>
</up-grid-item>
</up-grid>
</view>
</view>
</template>
</app-layout>
</template>
<script setup>
import { ref, computed } from 'vue';
// 常量数据
const noticeText = ref('体验公司全系产品 畅谈你的想法');
const swiperList = ref([
'/static/banner/banner01.jpg',
'/static/banner/banner02.jpg',
'/static/banner/banner03.jpg'
]);
// 常用功能
const commonFunctions = ref([
{ name: '审批', icon: 'file-text', color: '#52c41a' },
{ name: '公告', icon: 'bell', color: '#faad14' },
{ name: '日报', icon: 'edit-pen', color: '#13c2c2' },
{ name: '周报', icon: 'calendar', color: '#2f54eb' },
{ name: '工资单', icon: 'rmb', color: '#f5222d' },
{ name: '待办', icon: 'list-dot', color: '#722ed1' },
{ name: '打卡', icon: 'checkmark-circle', color: '#eb2f96' },
{ name: '添加', icon: 'plus-circle', color: '#1890ff' }
]);
// 应用分类数据
const appTabs = ref([
{ name: '关注' },
{ name: '推荐' },
{ name: '电影' },
{ name: '科技' },
{ name: '音乐' },
{ name: '美食' },
{ name: '文化' },
{ name: '财经' },
{ name: '手工' }
]);
const allApps = ref({
office: [
{ name: '审批', icon: 'checkmark-circle', color: '#52c41a' },
{ name: '日报', icon: 'edit-pen' , color: '#faad14'},
{ name: '周报', icon: 'list-dot' , color: '#13c2c2' },
{ name: '云文档', icon: 'file-text' , color: '#2f54eb'},
{ name: '项目管理', icon: 'grid' , color: '#f5222d'},
{ name: '设计工具', icon: 'photo' , color: '#722ed1'},
{ name: '分贝通', icon: 'coupon' , color: '#eb2f96'},
{ name: '飞书提醒', icon: 'bell', color: '#1890ff' }
],
collab: [
{ name: '项目管理', icon: 'grid', color: '#52c41a' },
{ name: '设计工具', icon: 'photo' , color: '#52c41a'},
{ name: '分贝通', icon: 'coupon' , color: '#52c41a'},
{ name: '飞书提醒', icon: 'bell' , color: '#52c41a'}
],
finance: [
{ name: '工资单', icon: 'rmb' , color: '#2f54eb'},
{ name: '报销', icon: 'wallet' , color: '#2f54eb'},
{ name: '预算', icon: 'pie-chart' , color: '#2f54eb'}
],
other: [
{ name: '通讯录', icon: 'account' , color: '#eb2f96'},
{ name: '设置', icon: 'settings', color: '#eb2f96' }
]
});
// 当前选中标签
const currentTab = ref(0);
const currentApps = computed(() => {
// 假设 appTabs 里有 type 属性对应 allApps 的键
const type = appTabs.value[currentTab.value].type || 'office';
return allApps.value[type] || [];
});
// 事件处理
const handleTabChange = (index) => {
currentTab.value = index;
};
const handleFunctionClick = (item) => {
console.log('点击功能:', item.name);
};
const handleAppClick = (app) => {
console.log('点击应用:', app.name);
};
const navigateToMore = () => {
console.log('跳转到更多页面');
};
</script>
<style lang="scss" scoped>
.work-container {
padding: 20rpx;
}
.search-box {
padding: 20rpx;
background: #fff;
margin: 20rpx;
border-radius: 12rpx;
}
.swiper-box {
margin: 20rpx;
border-radius: 12rpx;
overflow: hidden;
}
.section-card {
background: #fff;
margin: 20rpx;
border-radius: 12rpx;
padding: 24rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
.section-header {
margin-bottom: 24rpx;
}
}
.function-item {
display: flex;
flex-direction: column;
align-items: center;
padding: 20rpx 0;
}
.app-item {
display: flex;
flex-direction: column;
align-items: center;
padding: 16rpx 0;
}
.grid-text {
font-size: 14px;
color: #909399;
padding: 10rpx 0 20rpx 0rpx;
/* #ifndef APP-PLUS */
box-sizing: border-box;
/* #endif */
}
/* 调整tabs样式 */
::v-deep .up-tabs__wrapper {
padding: 0 20rpx;
}
::v-deep .up-tabs__item {
font-size: 28rpx !important;
padding: 20rpx 0 !important;
}
</style>
+6
View File
@@ -0,0 +1,6 @@
export {};
declare module "vue" {
type Hooks = App.AppInstance & Page.PageInstance;
interface ComponentCustomOptions extends Hooks {}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

+55
View File
@@ -0,0 +1,55 @@
import { defineStore } from "pinia";
import { getCurrentUserInfo } from "../api/apis";
export const useUserStore = defineStore('user', {
state: () => ({
basic_info: {},
access_token: uni.getStorageSync('access_token') || '',
refresh_token: uni.getStorageSync('refresh_token') || null
}),
getters: {
baseInfo: (state) => state.basic_info,
accessToken: (state) => state.access_token,
refreshToken: (state) => state.refresh_token
},
actions: {
async getUserInfo() {
try {
const response = await getCurrentUserInfo();
console.log("获取当前用户", response);
const result = response.data;
this.basic_info = { ...this.basic_info, ...result };
} catch (error) {
console.error(error);
}
},
setToken(new_access_token, new_refresh_token) {
if (!new_access_token || !new_refresh_token) return false;
try {
this.access_token = new_access_token;
uni.setStorageSync('access_token', new_access_token);
uni.setStorageSync('refresh_token', new_refresh_token);
return true;
} catch (error) {
console.error('存储token失败:', error);
return false;
}
},
clear() {
this.basicInfo = {};
this.access_token = null;
this.refresh_token = null;
try {
uni.removeStorageSync('access_token');
uni.removeStorageSync('refresh_token');
} catch (error) {
console.error('清除存储信息失败:', error);
}
}
}
});
+78
View File
@@ -0,0 +1,78 @@
/**
* 这里是uni-app内置的常用样式变量
*
* uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
* 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
*
*/
/**
* 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
*
* 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
*/
/* 颜色变量 */
/* 行为相关颜色 */
$uni-color-primary: #007aff;
$uni-color-success: #4cd964;
$uni-color-warning: #f0ad4e;
$uni-color-error: #dd524d;
/* 文字基本颜色 */
$uni-text-color: #333; // 基本色
$uni-text-color-inverse: #fff; // 反色
$uni-text-color-grey: #999; // 辅助灰色,如加载更多的提示信息
$uni-text-color-placeholder: #808080;
$uni-text-color-disable: #c0c0c0;
/* 背景颜色 */
$uni-bg-color: #fff;
$uni-bg-color-grey: #f8f8f8;
$uni-bg-color-hover: #f1f1f1; // 点击状态颜色
$uni-bg-color-mask: rgba(0, 0, 0, 0.4); // 遮罩颜色
/* 边框颜色 */
$uni-border-color: #c8c7cc;
/* 尺寸变量 */
/* 文字尺寸 */
$uni-font-size-sm: 12px;
$uni-font-size-base: 14px;
$uni-font-size-lg: 16;
/* 图片尺寸 */
$uni-img-size-sm: 20px;
$uni-img-size-base: 26px;
$uni-img-size-lg: 40px;
/* Border Radius */
$uni-border-radius-sm: 2px;
$uni-border-radius-base: 3px;
$uni-border-radius-lg: 6px;
$uni-border-radius-circle: 50%;
/* 水平间距 */
$uni-spacing-row-sm: 5px;
$uni-spacing-row-base: 10px;
$uni-spacing-row-lg: 15px;
/* 垂直间距 */
$uni-spacing-col-sm: 4px;
$uni-spacing-col-base: 8px;
$uni-spacing-col-lg: 12px;
/* 透明度 */
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
/* 文章场景相关 */
$uni-color-title: #2c405a; // 文章标题颜色
$uni-font-size-title: 20px;
$uni-color-subtitle: #555; // 二级标题颜色
$uni-font-size-subtitle: 18px;
$uni-color-paragraph: #3f536e; // 文章段落颜色
$uni-font-size-paragraph: 15px;
@import 'uview-plus/theme.scss'; // 引入uview-plus的scss变量
+59
View File
@@ -0,0 +1,59 @@
import { useUserStore } from "../stores/index";
export function request(options) {
const userStore = useUserStore();
uni.showToast({
title: "加载中...",
icon: "loading",
mask: true,
});
return new Promise((resolve, reject) => {
// 普通请求处理
uni.request({
url: import.meta.env.VITE_API_BASE_URL + options.url,
method: options.method || "GET",
data: options.data || "",
header: {
Authorization: userStore.access_token ? `Bearer ${userStore.access_token}` : "",
...(options.header || {}),
},
timeout: import.meta.env.VITE_TIMEOUT,
success: (res) => {
if (res.data.status_code === 200) {
uni.showToast({
title: res.data.msg,
icon: "success",
mask: true,
});
resolve(res.data);
} else if (res.data.status_code === 401) {
uni.showToast({
title: res.data.msg || "未登录",
icon: "none",
mask: true,
});
userStore.clear();
uni.reLaunch({ url: "/pages/login/login" });
reject(res.data);
} else {
uni.showToast({
title: res.data.msg || "请求发生异常",
icon: "none",
mask: true,
});
reject(res.data);
}
},
fail: (error) => {
uni.showToast({
title: "请求异常",
icon: "none",
mask: true,
});
reject(error);
},
});
});
}
+29
View File
@@ -0,0 +1,29 @@
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from "vite";
import uni from "@dcloudio/vite-plugin-uni";
import UnoCSS from 'unocss/vite'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
uni(),
UnoCSS(),
],
server: {
host: "0.0.0.0",
port: 5180,
proxy: {
[process.env.VITE_API_BASE_NAME]: {
target: process.env.VITE_API_BASE_URL,
secure: false, // 请求是否为https
changeOrigin: true, // 是否跨域
rewrite: (path) => path.replace(/^\/api/, ""),
},
},
},
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
});