feat(custom): i
This commit is contained in:
2
.env
2
.env
@@ -1,3 +1,3 @@
|
||||
VITE_TITLE = 'Vue Naive Admin'
|
||||
VITE_TITLE = '捷兑通 - 商家端'
|
||||
|
||||
VITE_PORT = 3100
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
VITE_PUBLIC_PATH = '/'
|
||||
|
||||
# 是否启用MOCK
|
||||
VITE_USE_MOCK = true
|
||||
VITE_USE_MOCK = false
|
||||
|
||||
# 是否启用MOCK
|
||||
# 是否启用代理
|
||||
VITE_USE_PROXY = true
|
||||
|
||||
# base api
|
||||
VITE_BASE_API = '/api'
|
||||
VITE_BASE_API = '/store'
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# 资源公共路径,需要以 /开头和结尾
|
||||
VITE_PUBLIC_PATH = '/'
|
||||
VITE_PUBLIC_PATH = '/static/mer'
|
||||
|
||||
# 是否启用MOCK
|
||||
VITE_USE_MOCK = true
|
||||
VITE_USE_MOCK = false
|
||||
|
||||
# base api
|
||||
VITE_BASE_API = '/api'
|
||||
VITE_BASE_API = 'https://www.wanzhuanyongcheng.cn/store'
|
||||
|
||||
# 是否启用压缩
|
||||
VITE_USE_COMPRESS = true
|
||||
|
||||
5
.idea/.gitignore
generated
vendored
Normal file
5
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
# 默认忽略的文件
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# 基于编辑器的 HTTP 客户端请求
|
||||
/httpRequests/
|
||||
65
.idea/codeStyles/Project.xml
generated
Normal file
65
.idea/codeStyles/Project.xml
generated
Normal file
@@ -0,0 +1,65 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<option name="LINE_SEPARATOR" value=" " />
|
||||
<HTMLCodeStyleSettings>
|
||||
<option name="HTML_SPACE_INSIDE_EMPTY_TAG" value="true" />
|
||||
<option name="HTML_QUOTE_STYLE" value="Single" />
|
||||
<option name="HTML_ENFORCE_QUOTES" value="true" />
|
||||
</HTMLCodeStyleSettings>
|
||||
<JSCodeStyleSettings version="0">
|
||||
<option name="USE_SEMICOLON_AFTER_STATEMENT" value="false" />
|
||||
<option name="FORCE_SEMICOLON_STYLE" value="true" />
|
||||
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
|
||||
<option name="USE_DOUBLE_QUOTES" value="false" />
|
||||
<option name="FORCE_QUOTE_STYlE" value="true" />
|
||||
<option name="ENFORCE_TRAILING_COMMA" value="Remove" />
|
||||
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
|
||||
<option name="SPACES_WITHIN_IMPORTS" value="true" />
|
||||
</JSCodeStyleSettings>
|
||||
<TypeScriptCodeStyleSettings version="0">
|
||||
<option name="USE_SEMICOLON_AFTER_STATEMENT" value="false" />
|
||||
<option name="FORCE_SEMICOLON_STYLE" value="true" />
|
||||
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
|
||||
<option name="USE_DOUBLE_QUOTES" value="false" />
|
||||
<option name="FORCE_QUOTE_STYlE" value="true" />
|
||||
<option name="ENFORCE_TRAILING_COMMA" value="Remove" />
|
||||
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
|
||||
<option name="SPACES_WITHIN_IMPORTS" value="true" />
|
||||
</TypeScriptCodeStyleSettings>
|
||||
<VueCodeStyleSettings>
|
||||
<option name="INTERPOLATION_NEW_LINE_AFTER_START_DELIMITER" value="false" />
|
||||
<option name="INTERPOLATION_NEW_LINE_BEFORE_END_DELIMITER" value="false" />
|
||||
</VueCodeStyleSettings>
|
||||
<codeStyleSettings language="HTML">
|
||||
<option name="SOFT_MARGINS" value="100" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
<option name="SMART_TABS" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="JavaScript">
|
||||
<option name="SOFT_MARGINS" value="100" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="TypeScript">
|
||||
<option name="SOFT_MARGINS" value="100" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="Vue">
|
||||
<option name="SOFT_MARGINS" value="100" />
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
||||
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
@@ -0,0 +1,5 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</state>
|
||||
</component>
|
||||
12
.idea/mer.iml
generated
Normal file
12
.idea/mer.iml
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/mer.iml" filepath="$PROJECT_DIR$/.idea/mer.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
209
README.EN.md
209
README.EN.md
@@ -1,209 +0,0 @@
|
||||
<p align="center">
|
||||
<a href="https://github.com/zclzone/vue-naive-admin">
|
||||
<img alt="Vue Naive Admin Logo" width="200" src="./src/assets/images/logo.png">
|
||||
</a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://github.com/zclzone/vue-naive-admin"><img alt="stars" src="https://badgen.net/github/stars/zclzone/vue-naive-admin"/></a>
|
||||
<a href="https://github.com/zclzone/vue-naive-admin"><img alt="forks" src="https://badgen.net/github/forks/zclzone/vue-naive-admin"/></a>
|
||||
<a href="./LICENSE"><img allt="MIT License" src="https://badgen.net/github/license/zclzone/vue-naive-admin"/></a>
|
||||
</p>
|
||||
|
||||
<p align='center'>
|
||||
<b>英文</b> |
|
||||
<a href="https://github.com/zclzone/vue-naive-admin/blob/main/README.md">中文</a>
|
||||
</p>
|
||||
|
||||
### Introduction
|
||||
|
||||
[Vue Naive Admin](https://github.com/zclzone/vue-naive-admin) is a **completely open source free and commercially allowed ** admin template,Based on the latest technology stack of front-end such as `Vue3、Vite3、Pinia、Unocss and Naive UI`. Compared with other more popular backend management templates, this project is more concise, lightweight, fresh style, very low learning costs, ideal for small and medium-sized projects or personal projects.
|
||||
|
||||
### Features
|
||||
|
||||
- 🍒 Integrated [Naive UI](https://www.naiveui.com),recommended by Evan You.
|
||||
- 🍑 Integrated login, logout and permission verification.
|
||||
- 🍐 Integrated multi-environment configuration, dev, test, production and github pages environments.
|
||||
- 🍎 Integrated `eslint + prettier`.
|
||||
- 🍌 Integrated `husky + commitlint`.
|
||||
- 🍉 Integrated `Mock`.
|
||||
- 🍍 Integrated `pinia`,lightweight, simple and easy to use alternative to vuex.
|
||||
- 📦 Integrated `unplugin` auto import.
|
||||
- 🤹 Integrated `iconify` icon,support custom svg icons.
|
||||
- 🍇 Integrated `unocss`.
|
||||
|
||||
### Preview
|
||||
|
||||
[https://template.qszone.com](https://template.qszone.com)
|
||||
|
||||
[https://base.isme.top](https://base.isme.top)
|
||||
|
||||
### Docs
|
||||
|
||||
[Vue Naive Admin Docs](https://zclzone.github.io/vue-naive-admin-docs)
|
||||
|
||||
|
||||
### Getting Started
|
||||
|
||||
```shell
|
||||
# Recommended setup git autocrlf 为 false
|
||||
git config --global core.autocrlf false
|
||||
|
||||
# Clone Project
|
||||
git clone https://github.com/zclzone/vue-naive-admin.git
|
||||
|
||||
cd vue-naive-admin
|
||||
|
||||
# Install dependencies(Recommended use pnpm: https://pnpm.io/zh/installation)
|
||||
npm i -g pnpm # Installed and can be ignored
|
||||
pnpm i # or npm i
|
||||
|
||||
# Start
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
### Build and Release
|
||||
|
||||
```shell
|
||||
# Test Environment
|
||||
pnpm build:test
|
||||
|
||||
# Github Environment
|
||||
pnpm build:github
|
||||
|
||||
# Prod Environment
|
||||
pnpm build
|
||||
```
|
||||
|
||||
### Other
|
||||
|
||||
```shell
|
||||
# eslint check
|
||||
pnpm lint
|
||||
|
||||
# eslint check and fix
|
||||
pnpm lint:fix
|
||||
|
||||
# Preview(Need to build first)
|
||||
pnpm preview
|
||||
|
||||
# Commit(husky+commitlint)
|
||||
pnpm cz
|
||||
```
|
||||
|
||||
### Directory description
|
||||
|
||||
```
|
||||
Vue Naive Admin
|
||||
|-- .github // github相关,如推送github仓库后自动部署gh pages
|
||||
|-- .husky // git commit钩子
|
||||
|-- .vscode // vscode编辑器相关
|
||||
| |-- extensions.json // 插件推荐
|
||||
| |-- settings.json // 项目级别的vscode配置,优先级大于全局vscode配置
|
||||
|-- build // 构建相关配置
|
||||
| |-- constant.js // 构建相关的常量
|
||||
| |-- utils.js // 构建相关的工具方法
|
||||
| |-- config
|
||||
| | |-- define.js // 注入全局常量,启动或打包后将添加到window中
|
||||
| | |-- proxy.js // 代理配置
|
||||
| |-- plugin
|
||||
| | |-- html.js // vite-plugin-html插件,用于注入变量或者html标签
|
||||
| | |-- mock.js // vite-plugin-mock插件,处理mock
|
||||
| | |-- unplugin.js // unplugin相关插件,包含DefineOptions和自动导入
|
||||
| |-- script // 打包完成后执行的一些node脚本(不重要)
|
||||
| |-- build-cname.js // 自动生成cname
|
||||
|-- mock // mock
|
||||
| |-- utils.js // mock请求需要用到的工具方法
|
||||
| |-- api // mock接口
|
||||
|-- public // 公共资源,文件夹下的文件会在打包后会直接加到dist根目录下
|
||||
|-- settings // 项目配置
|
||||
| |-- proxy-config.js // 代理配置文件
|
||||
| |-- theme.json // 主题配置项,主题色等
|
||||
|-- src
|
||||
| |-- api // 公共api
|
||||
| |-- assets // 静态资源
|
||||
| | |-- images // 图片
|
||||
| | |-- svg // svg图标
|
||||
| |-- components // 全局组件
|
||||
| | |-- common // 公共组件
|
||||
| | |-- icon // icon相关组件
|
||||
| | |-- page // 页面组件
|
||||
| | |-- query-bar // 查询选项
|
||||
| | |-- table // 封装的表格组件
|
||||
| |-- composables // 封装的组合式函数
|
||||
| |-- layout // 布局相关组件
|
||||
| | |-- components
|
||||
| | |-- AppMain.vue // 主体内容
|
||||
| | |-- header // 头部
|
||||
| | |-- sidebar // 侧边菜单栏
|
||||
| | |-- tags // 多页签栏
|
||||
| |-- router // 路由
|
||||
| | |-- guard // 路由守卫
|
||||
| | |-- routes // 路由列表
|
||||
| |-- store // 状态管理(pinia)
|
||||
| | |-- modules // 模块
|
||||
| | |-- app // 管理页面重新加载、折叠菜单栏和keepAlive等
|
||||
| | |-- permission // 权限相关,管理权限菜单
|
||||
| | |-- tags // 管理多页签
|
||||
| | |-- user // 用户模块,管理用户信息、登录登出
|
||||
| |-- styles // 样式
|
||||
| |-- utils // 封装的工具方法
|
||||
| | |-- auth // 权限相关,如token、跳转登录页等
|
||||
| | |-- common // 通用
|
||||
| | |-- http // 封装axios
|
||||
| | |-- storage // 封装localStorage和sessionStorage
|
||||
| |-- views // 页面
|
||||
| | |-- demo // 示例
|
||||
| | |-- error-page // 错误页
|
||||
| | |-- login // 登录页
|
||||
| | |-- workbench // 首页
|
||||
| |-- App.vue
|
||||
| |-- main.js
|
||||
|-- .cz-config.js // git提交配置
|
||||
|-- .editorconfig // 编辑器配置
|
||||
|-- .env // 环境文件,所有环境都会载入
|
||||
|-- .env.development // 开发环境文件
|
||||
|-- .env.production // 生产环境文件
|
||||
|-- .env.test // 测试环境文件
|
||||
|-- .eslintignore // eslint忽略
|
||||
|-- .eslintrc.js // eslint配置
|
||||
|-- .gitignore // git忽略
|
||||
|-- .prettierignore // prettier格式化忽略
|
||||
|-- commitlint.config.js // commitlint规范配置
|
||||
|-- index.html
|
||||
|-- jsconfig.json // js配置
|
||||
|-- LICENSE // 协议
|
||||
|-- package.json // 依赖描述文件
|
||||
|-- pnpm-lock.yaml // 依赖锁定文件
|
||||
|-- prettier.config.js // prettier格式化配置
|
||||
|-- README.md // 项目描述文档(英文)
|
||||
|-- README.zh-CN.md // 项目描述文档(中文)
|
||||
|-- unocss.config.js // unocss配置
|
||||
|-- vite.config.js // vite配置
|
||||
```
|
||||
|
||||
### TS version: Qs Admin
|
||||
|
||||
#### source code
|
||||
|
||||
- github: [https://github.com/zclzone/qs-admin](https://github.com/zclzone/qs-admin)
|
||||
- gitee: [https://gitee.com/zclzone/qs-admin-ts](https://gitee.com/zclzone/qs-admin-ts)
|
||||
|
||||
#### preview
|
||||
|
||||
- [https://admin.qszone.com](https://admin.qszone.com)
|
||||
- [https://zclzone.github.io/qs-admin](https://zclzone.github.io/qs-admin)
|
||||
|
||||
### Open source projects that use this project:
|
||||
|
||||
- [gin-vue-blog](https://github.com/szluyu99/gin-vue-blog): A full-stack blog project in Golang, the frontend of the blog backend is based on vue-naive-admin and integrates with a real backend service, implementing features such as backend-controlled routing.
|
||||
|
||||
### Communication group & About the author
|
||||
|
||||
<a href="https://blog.qszone.com/about/">
|
||||
<img src="https://assets.qszone.com/images/about.png" style="max-width: 400px" />
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
217
README.md
217
README.md
@@ -1,217 +0,0 @@
|
||||
<p align="center">
|
||||
<a href="https://github.com/zclzone/vue-naive-admin">
|
||||
<img alt="Vue Naive Admin Logo" width="200" src="./src/assets/images/logo.png">
|
||||
</a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://github.com/zclzone/vue-naive-admin"><img alt="stars" src="https://badgen.net/github/stars/zclzone/vue-naive-admin"/></a>
|
||||
<a href="https://github.com/zclzone/vue-naive-admin"><img alt="forks" src="https://badgen.net/github/forks/zclzone/vue-naive-admin"/></a>
|
||||
<a href="./LICENSE"><img alt="MIT License" src="https://badgen.net/github/license/zclzone/vue-naive-admin"/></a>
|
||||
</p>
|
||||
|
||||
<p align='center'>
|
||||
<b>中文</b> |
|
||||
<a href="https://github.com/zclzone/vue-naive-admin/blob/main/README.EN.md">English</a>
|
||||
</p>
|
||||
|
||||
### 简介
|
||||
|
||||
[Vue Naive Admin](https://github.com/zclzone/vue-naive-admin) 是一个 **完全开源免费且允许商用** 的后台管理模板,基于 `Vue3、Vite3、Pinia、Unocss 和 Naive UI` 等前端最新技术栈。相较于其他比较流行的后台管理模板,此项目更加简洁、轻量,风格清新,学习成本非常低,非常适合中小型项目或者个人项目。
|
||||
|
||||
### 功能
|
||||
|
||||
- 🍒 集成 [Naive UI](https://www.naiveui.com)
|
||||
- 🍑 集成登陆、注销及权限验证
|
||||
- 🍐 集成多环境配置,dev、测试、生产和github pages环境
|
||||
- 🍎 集成 `eslint + prettier`,代码约束和格式化统一
|
||||
- 🍌 集成 `husky + commitlint`,代码提交规范化
|
||||
- 🍉 集成 `mock` 接口服务,dev 环境和发布环境都支持,可动态配置是否启用 mock 服务,不启用时不会加载 mock 包,减少打包体积
|
||||
- 🍍 集成 `pinia`,vuex 的替代方案,轻量、简单、易用
|
||||
- 📦 集成 `unplugin` 插件,自动导入,解放双手,开发效率直接起飞
|
||||
- 🤹 集成 `iconify` 图标,支持自定义 svg 图标, 优雅使用icon
|
||||
- 🍇 集成 `unocss`,antfu 开源的原子 css 解决方案,非常轻量
|
||||
|
||||
### 预览
|
||||
|
||||
[https://template.qszone.com](https://template.qszone.com)
|
||||
|
||||
[https://base.isme.top](https://base.isme.top)
|
||||
|
||||
### 文档
|
||||
|
||||
[Vue Naive Admin Docs](https://zclzone.github.io/vue-naive-admin-docs)
|
||||
|
||||
[语雀文档:Vue Naive Admin](https://www.yuque.com/qszone/vue-naive-admin)
|
||||
|
||||
### 快速开始
|
||||
|
||||
```shell
|
||||
# 推荐配置git autocrlf 为 false(本项目规范使用lf换行符,此配置是为防止git自动将源文件转换为crlf)
|
||||
# 不清楚为什么要这样做的请参考这篇文章:https://www.freesion.com/article/4532642129
|
||||
git config --global core.autocrlf false
|
||||
|
||||
# 克隆项目
|
||||
git clone https://github.com/zclzone/vue-naive-admin.git
|
||||
|
||||
# 进入项目目录
|
||||
cd vue-naive-admin
|
||||
|
||||
# 安装依赖(建议使用pnpm: https://pnpm.io/zh/installation)
|
||||
npm i -g pnpm # 装了可忽略
|
||||
pnpm i # 或者 npm i
|
||||
|
||||
# 启动
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
### 构建发布
|
||||
|
||||
```shell
|
||||
# 构建测试环境
|
||||
pnpm build:test
|
||||
|
||||
# 构建github pages环境
|
||||
pnpm build:github
|
||||
|
||||
# 构建生产环境
|
||||
pnpm build
|
||||
```
|
||||
|
||||
### 其他指令
|
||||
|
||||
```shell
|
||||
# eslint代码格式检查
|
||||
pnpm lint
|
||||
|
||||
# 代码检查并修复
|
||||
pnpm lint:fix
|
||||
|
||||
# 预览发布包效果(需先执行构建指令)
|
||||
pnpm preview
|
||||
|
||||
# 提交代码(husky+commitlint)
|
||||
pnpm cz
|
||||
```
|
||||
|
||||
|
||||
### 目录说明
|
||||
|
||||
```
|
||||
Vue Naive Admin
|
||||
|-- .github // github相关,如推送github仓库后自动部署gh pages
|
||||
|-- .husky // git commit钩子
|
||||
|-- .vscode // vscode编辑器相关
|
||||
| |-- extensions.json // 插件推荐
|
||||
| |-- settings.json // 项目级别的vscode配置,优先级大于全局vscode配置
|
||||
|-- build // 构建相关配置
|
||||
| |-- constant.js // 构建相关的常量
|
||||
| |-- utils.js // 构建相关的工具方法
|
||||
| |-- config
|
||||
| | |-- define.js // 注入全局常量,启动或打包后将添加到window中
|
||||
| | |-- proxy.js // 代理配置
|
||||
| |-- plugin
|
||||
| | |-- html.js // vite-plugin-html插件,用于注入变量或者html标签
|
||||
| | |-- mock.js // vite-plugin-mock插件,处理mock
|
||||
| | |-- unplugin.js // unplugin相关插件,包含DefineOptions和自动导入
|
||||
| |-- script // 打包完成后执行的一些node脚本(不重要)
|
||||
| |-- build-cname.js // 自动生成cname
|
||||
|-- mock // mock
|
||||
| |-- utils.js // mock请求需要用到的工具方法
|
||||
| |-- api // mock接口
|
||||
|-- public // 公共资源,文件夹下的文件会在打包后会直接加到dist根目录下
|
||||
|-- settings // 项目配置
|
||||
| |-- proxy-config.js // 代理配置文件
|
||||
| |-- theme.json // 主题配置项,主题色等
|
||||
|-- src
|
||||
| |-- api // 公共api
|
||||
| |-- assets // 静态资源
|
||||
| | |-- images // 图片
|
||||
| | |-- svg // svg图标
|
||||
| |-- components // 全局组件
|
||||
| | |-- common // 公共组件
|
||||
| | |-- icon // icon相关组件
|
||||
| | |-- page // 页面组件
|
||||
| | |-- query-bar // 查询选项
|
||||
| | |-- table // 封装的表格组件
|
||||
| |-- composables // 封装的组合式函数
|
||||
| |-- layout // 布局相关组件
|
||||
| | |-- components
|
||||
| | |-- AppMain.vue // 主体内容
|
||||
| | |-- header // 头部
|
||||
| | |-- sidebar // 侧边菜单栏
|
||||
| | |-- tags // 多页签栏
|
||||
| |-- router // 路由
|
||||
| | |-- guard // 路由守卫
|
||||
| | |-- routes // 路由列表
|
||||
| |-- store // 状态管理(pinia)
|
||||
| | |-- modules // 模块
|
||||
| | |-- app // 管理页面重新加载、折叠菜单栏和keepAlive等
|
||||
| | |-- permission // 权限相关,管理权限菜单
|
||||
| | |-- tags // 管理多页签
|
||||
| | |-- user // 用户模块,管理用户信息、登录登出
|
||||
| |-- styles // 样式
|
||||
| |-- utils // 封装的工具方法
|
||||
| | |-- auth // 权限相关,如token、跳转登录页等
|
||||
| | |-- common // 通用
|
||||
| | |-- http // 封装axios
|
||||
| | |-- storage // 封装localStorage和sessionStorage
|
||||
| |-- views // 页面
|
||||
| | |-- demo // 示例
|
||||
| | |-- error-page // 错误页
|
||||
| | |-- login // 登录页
|
||||
| | |-- workbench // 首页
|
||||
| |-- App.vue
|
||||
| |-- main.js
|
||||
|-- .cz-config.js // git提交配置
|
||||
|-- .editorconfig // 编辑器配置
|
||||
|-- .env // 环境文件,所有环境都会载入
|
||||
|-- .env.development // 开发环境文件
|
||||
|-- .env.production // 生产环境文件
|
||||
|-- .env.test // 测试环境文件
|
||||
|-- .eslintignore // eslint忽略
|
||||
|-- .eslintrc.js // eslint配置
|
||||
|-- .gitignore // git忽略
|
||||
|-- .prettierignore // prettier格式化忽略
|
||||
|-- commitlint.config.js // commitlint规范配置
|
||||
|-- index.html
|
||||
|-- jsconfig.json // js配置
|
||||
|-- LICENSE // 协议
|
||||
|-- package.json // 依赖描述文件
|
||||
|-- pnpm-lock.yaml // 依赖锁定文件
|
||||
|-- prettier.config.js // prettier格式化配置
|
||||
|-- README.md // 项目描述文档(英文)
|
||||
|-- README.zh-CN.md // 项目描述文档(中文)
|
||||
|-- unocss.config.js // unocss配置
|
||||
|-- vite.config.js // vite配置
|
||||
```
|
||||
|
||||
### TS 版本: Qs Admin
|
||||
|
||||
#### 源码
|
||||
|
||||
- github: [https://github.com/zclzone/qs-admin](https://github.com/zclzone/qs-admin)
|
||||
- gitee: [https://gitee.com/zclzone/qs-admin-ts](https://gitee.com/zclzone/qs-admin-ts)
|
||||
|
||||
#### 预览
|
||||
|
||||
- [https://admin.qszone.com](https://admin.qszone.com)
|
||||
- [https://zclzone.github.io/qs-admin](https://zclzone.github.io/qs-admin)
|
||||
|
||||
### 使用该项目的开源项目
|
||||
|
||||
- [gin-vue-blog](https://github.com/szluyu99/gin-vue-blog): Golang 全栈博客项目, 博客后台的前端基于 vue-naive-admin,对接真实后端服务,实现了后端控制路由等特性。
|
||||
|
||||
|
||||
### 入群交流 & 关于作者
|
||||
|
||||
<a href="https://blog.qszone.com/about/">
|
||||
<img src="https://assets.qszone.com/images/about.png" style="max-width: 400px" />
|
||||
</a>
|
||||
|
||||
### ☕ 赞助我
|
||||
|
||||
> 开源不易,请作者喝杯咖啡吧
|
||||
<p>
|
||||
<img src="https://assets.qszone.com/images/zhifu_weixin.jpg" style="width: 220px" />
|
||||
<img src="https://assets.qszone.com/images/zhifu_zhifubao.jpg" style="width: 220px" />
|
||||
</p>
|
||||
@@ -6,28 +6,28 @@ export const PROXY_CONFIG = {
|
||||
* @请求路径 http://localhost:3100/api/user
|
||||
* @转发路径 http://localhost:8080/user
|
||||
*/
|
||||
'/api': {
|
||||
target: 'http://localhost:8080',
|
||||
'/store': {
|
||||
target: 'https://test.wanzhuanyongcheng.cn',
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(new RegExp('^/api'), ''),
|
||||
// rewrite: (path) => path.replace(new RegExp('^/api'), ''),
|
||||
},
|
||||
/**
|
||||
* @desc 不替换匹配值
|
||||
* @请求路径 http://localhost:3100/api/v2/user
|
||||
* @转发路径 http://localhost:8080/api/v2/user
|
||||
*/
|
||||
'/api/v2': {
|
||||
target: 'http://localhost:8080',
|
||||
changeOrigin: true,
|
||||
},
|
||||
// '/api/v2': {
|
||||
// target: 'http://localhost:8080',
|
||||
// changeOrigin: true,
|
||||
// },
|
||||
/**
|
||||
* @desc 替换部分匹配值
|
||||
* @请求路径 http://localhost:3100/api/v3/user
|
||||
* @转发路径 http://localhost:8080/user
|
||||
*/
|
||||
'/api/v3': {
|
||||
target: 'http://localhost:8080',
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(new RegExp('^/api'), ''),
|
||||
},
|
||||
// '/api/v3': {
|
||||
// target: 'http://localhost:8080',
|
||||
// changeOrigin: true,
|
||||
// rewrite: (path) => path.replace(new RegExp('^/api'), ''),
|
||||
// },
|
||||
}
|
||||
|
||||
110
src/components/Editor.vue
Normal file
110
src/components/Editor.vue
Normal file
@@ -0,0 +1,110 @@
|
||||
<template>
|
||||
<div ref="_ref" style="border: 1px solid #ccc">
|
||||
<Toolbar
|
||||
style="border-bottom: 1px solid #ccc"
|
||||
:editor="editorRef"
|
||||
:default-config="toolbarConfig"
|
||||
mode="default"
|
||||
/>
|
||||
<Editor
|
||||
v-model="htmlValue"
|
||||
style="height: 500px; overflow-y: hidden"
|
||||
:default-config="editorConfig"
|
||||
mode="default"
|
||||
@on-created="handleCreated"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import '@wangeditor/editor/dist/css/style.css' // 引入 css
|
||||
|
||||
import { onBeforeUnmount, shallowRef, ref } from 'vue'
|
||||
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
|
||||
import { getToken } from '@/utils'
|
||||
|
||||
const props = defineProps({
|
||||
valueHtml: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:valueHtml'])
|
||||
|
||||
const editorRef = shallowRef()
|
||||
|
||||
const _ref = ref(null)
|
||||
|
||||
const Token = getToken()
|
||||
|
||||
const toolbarConfig = {}
|
||||
|
||||
const editorConfig = { placeholder: '请输入商品详情...', MENU_CONF: {} }
|
||||
|
||||
const htmlValue = computed({
|
||||
get() {
|
||||
console.log('get', props.valueHtml)
|
||||
return props.valueHtml
|
||||
},
|
||||
set(value) {
|
||||
console.log('set', props.valueHtml)
|
||||
emit('update:valueHtml', value)
|
||||
},
|
||||
})
|
||||
|
||||
editorConfig.MENU_CONF['uploadImage'] = {
|
||||
// 其他配置...
|
||||
// 小于该值就插入 base64 格式(而不上传),默认为 0
|
||||
fieldName: 'file',
|
||||
server: '/store/upload',
|
||||
allowedFileTypes: ['image/*'],
|
||||
headers: {
|
||||
Authorization: `Bearer ${Token}`,
|
||||
},
|
||||
base64LimitSize: 5 * 1024, // 5kb
|
||||
// 超时时间,默认为 10 秒
|
||||
timeout: 5 * 1000, // 5 秒
|
||||
// 自定义插入图片
|
||||
customInsert(res, insertFn) {
|
||||
if (res.code === 200) {
|
||||
console.log(res)
|
||||
$message.success('上传成功')
|
||||
insertFn(res.data.data)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
editorConfig.MENU_CONF['uploadVideo'] = {
|
||||
server: '/store/upload',
|
||||
fieldName: 'file',
|
||||
allowedFileTypes: ['video/*'],
|
||||
headers: {
|
||||
Authorization: `Bearer ${Token}`,
|
||||
},
|
||||
// 单个文件上传成功之后
|
||||
customInsert(res, insertFn) {
|
||||
console.log(res)
|
||||
|
||||
// 如果成功了,就把视频的地址,插入到编辑器中
|
||||
insertFn(res.data.data)
|
||||
},
|
||||
}
|
||||
|
||||
// 组件销毁时,也及时销毁编辑器
|
||||
onBeforeUnmount(() => {
|
||||
console.log('销毁')
|
||||
const editor = editorRef.value
|
||||
if (editor == null) return
|
||||
editor.destroy()
|
||||
})
|
||||
|
||||
const handleCreated = (editor) => {
|
||||
editorRef.value = editor // 记录 editor 实例,重要!
|
||||
editor.on('fullScreen', () => {
|
||||
_ref.value.style.zIndex = 10
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
67
src/components/Upload.vue
Normal file
67
src/components/Upload.vue
Normal file
@@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<n-upload
|
||||
v-model:file-list="List"
|
||||
action="/store/upload"
|
||||
:headers="headers"
|
||||
:max="max"
|
||||
list-type="image-card"
|
||||
@before-upload="beforeUpload"
|
||||
@finish="handleFinish"
|
||||
@error="handleError"
|
||||
>
|
||||
点击上传
|
||||
</n-upload>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { getToken } from '@/utils'
|
||||
|
||||
const token = getToken()
|
||||
|
||||
const prop = defineProps({
|
||||
list: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
max: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:list'])
|
||||
|
||||
const headers = ref({
|
||||
Authorization: `Bearer ${token}`,
|
||||
})
|
||||
|
||||
const List = computed({
|
||||
get() {
|
||||
return prop.list
|
||||
},
|
||||
set(val) {
|
||||
emit('update:list', val)
|
||||
},
|
||||
})
|
||||
|
||||
const handleFinish = ({ file, event }) => {
|
||||
const res = JSON.parse(event.target.response)
|
||||
file.url = res.data.data
|
||||
return file
|
||||
}
|
||||
|
||||
const handleError = () => {
|
||||
$message.error('上传失败')
|
||||
}
|
||||
|
||||
// 图片上传限制
|
||||
const beforeUpload = (data) => {
|
||||
if (!(data.file.file?.type === 'image/png' || data.file.file?.type === 'image/jpeg')) {
|
||||
$message.error('只能上传png或jpg格式的图片文件,请重新上传')
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<footer f-c-c flex-col text-14 color="#6a6a6a">
|
||||
<p>
|
||||
<!-- <p>
|
||||
Copyright © 2022-present
|
||||
<a
|
||||
href="https://github.com/zclzone"
|
||||
@@ -18,6 +18,6 @@
|
||||
>
|
||||
赣ICP备2020015008号-1
|
||||
</a>
|
||||
</p>
|
||||
</p> -->
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
<BreadCrumb ml-15 hidden sm:block />
|
||||
</div>
|
||||
<div ml-auto flex items-center>
|
||||
<MessageNotification />
|
||||
<!-- <MessageNotification /> -->
|
||||
<ThemeMode />
|
||||
<GithubSite />
|
||||
<!-- <GithubSite /> -->
|
||||
<FullScreen />
|
||||
<UserAvatar />
|
||||
</div>
|
||||
@@ -17,7 +17,7 @@ import BreadCrumb from './components/BreadCrumb.vue'
|
||||
import MenuCollapse from './components/MenuCollapse.vue'
|
||||
import FullScreen from './components/FullScreen.vue'
|
||||
import UserAvatar from './components/UserAvatar.vue'
|
||||
import GithubSite from './components/GithubSite.vue'
|
||||
// import GithubSite from './components/GithubSite.vue'
|
||||
import ThemeMode from './components/ThemeMode.vue'
|
||||
import MessageNotification from './components/MessageNotification.vue'
|
||||
// import MessageNotification from './components/MessageNotification.vue'
|
||||
</script>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { basicRoutes, EMPTY_ROUTE, NOT_FOUND_ROUTE } from './routes'
|
||||
import { getToken, isNullOrWhitespace } from '@/utils'
|
||||
import { useUserStore, usePermissionStore } from '@/store'
|
||||
|
||||
const isHash = import.meta.env.VITE_USE_HASH === 'true'
|
||||
const isHash = true
|
||||
export const router = createRouter({
|
||||
history: isHash ? createWebHashHistory('/') : createWebHistory('/'),
|
||||
routes: basicRoutes,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const Layout = () => import('@/layout/index.vue')
|
||||
// const Layout = () => import('@/layout/index.vue')
|
||||
|
||||
export const basicRoutes = [
|
||||
{
|
||||
@@ -18,42 +18,42 @@ export const basicRoutes = [
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: 'ExternalLink',
|
||||
path: '/external-link',
|
||||
component: Layout,
|
||||
meta: {
|
||||
title: '外部链接',
|
||||
icon: 'mdi:link-variant',
|
||||
order: 4,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'LinkGithubSrc',
|
||||
path: 'https://github.com/zclzone/vue-naive-admin',
|
||||
meta: {
|
||||
title: '源码 - github',
|
||||
icon: 'mdi:github',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'LinkGiteeSrc',
|
||||
path: 'https://gitee.com/zclzone/vue-naive-admin',
|
||||
meta: {
|
||||
title: '源码 - gitee',
|
||||
icon: 'simple-icons:gitee',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'LinkDocs',
|
||||
path: 'https://zclzone.github.io/vue-naive-admin-docs',
|
||||
meta: {
|
||||
title: '文档 - vuepress',
|
||||
icon: 'mdi:vuejs',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
// {
|
||||
// name: 'ExternalLink',
|
||||
// path: '/external-link',
|
||||
// component: Layout,
|
||||
// meta: {
|
||||
// title: '外部链接',
|
||||
// icon: 'mdi:link-variant',
|
||||
// order: 4,
|
||||
// },
|
||||
// children: [
|
||||
// {
|
||||
// name: 'LinkGithubSrc',
|
||||
// path: 'https://github.com/zclzone/vue-naive-admin',
|
||||
// meta: {
|
||||
// title: '源码 - github',
|
||||
// icon: 'mdi:github',
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// name: 'LinkGiteeSrc',
|
||||
// path: 'https://gitee.com/zclzone/vue-naive-admin',
|
||||
// meta: {
|
||||
// title: '源码 - gitee',
|
||||
// icon: 'simple-icons:gitee',
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// name: 'LinkDocs',
|
||||
// path: 'https://zclzone.github.io/vue-naive-admin-docs',
|
||||
// meta: {
|
||||
// title: '文档 - vuepress',
|
||||
// icon: 'mdi:vuejs',
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
]
|
||||
|
||||
export const NOT_FOUND_ROUTE = {
|
||||
|
||||
19
src/store/modules/goods/index.js
Normal file
19
src/store/modules/goods/index.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
export const useGoodsStore = defineStore('goods', {
|
||||
state() {
|
||||
return {
|
||||
goodType: 'add',
|
||||
row: {},
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
setRow(row) {
|
||||
this.row = row
|
||||
},
|
||||
|
||||
setType(row) {
|
||||
this.goodType = row
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -2,3 +2,4 @@ export * from './app'
|
||||
export * from './permission'
|
||||
export * from './tags'
|
||||
export * from './user'
|
||||
export * from './goods'
|
||||
|
||||
@@ -2,7 +2,7 @@ import { defineStore } from 'pinia'
|
||||
import { resetRouter } from '@/router'
|
||||
import { useTagsStore, usePermissionStore } from '@/store'
|
||||
import { removeToken, toLogin } from '@/utils'
|
||||
import api from '@/api'
|
||||
// import api from '@/api'
|
||||
|
||||
export const useUserStore = defineStore('user', {
|
||||
state() {
|
||||
@@ -26,14 +26,18 @@ export const useUserStore = defineStore('user', {
|
||||
},
|
||||
actions: {
|
||||
async getUserInfo() {
|
||||
try {
|
||||
const res = await api.getUser()
|
||||
const { id, name, avatar, role } = res.data
|
||||
this.userInfo = { id, name, avatar, role }
|
||||
return Promise.resolve(res.data)
|
||||
} catch (error) {
|
||||
return Promise.reject(error)
|
||||
const typeMer = localStorage.getItem('type')
|
||||
this.userInfo = {
|
||||
role: [typeMer],
|
||||
}
|
||||
// try {
|
||||
// const res = await api.getUser()
|
||||
// const { id, name, avatar, role } = res.data
|
||||
// this.userInfo = { id, name, avatar, role }
|
||||
// return Promise.resolve(res.data)
|
||||
// } catch (error) {
|
||||
// return Promise.reject(error)
|
||||
// }
|
||||
},
|
||||
async logout() {
|
||||
const { resetTags } = useTagsStore()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { lStorage } from '@/utils'
|
||||
import api from '@/api'
|
||||
|
||||
const TOKEN_CODE = 'access_token'
|
||||
const TOKEN_CODE = 'mer_token'
|
||||
const DURATION = 6 * 60 * 60
|
||||
|
||||
export function getToken() {
|
||||
|
||||
@@ -28,7 +28,7 @@ export function reqReject(error) {
|
||||
export function resResolve(response) {
|
||||
// TODO: 处理不同的 response.headers
|
||||
const { data, status, config, statusText } = response
|
||||
if (data?.code !== 0) {
|
||||
if (data?.code !== 200) {
|
||||
const code = data?.code ?? status
|
||||
|
||||
/** 根据code处理对应的操作,并返回处理后的message */
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
<template>
|
||||
<CommonPage show-footer>
|
||||
<n-space size="large">
|
||||
<n-card title="按钮 Button">
|
||||
<n-space>
|
||||
<n-button>Default</n-button>
|
||||
<n-button type="tertiary">Tertiary</n-button>
|
||||
<n-button type="primary">Primary</n-button>
|
||||
<n-button type="info">Info</n-button>
|
||||
<n-button type="success">Success</n-button>
|
||||
<n-button type="warning">Warning</n-button>
|
||||
<n-button type="error">Error</n-button>
|
||||
</n-space>
|
||||
</n-card>
|
||||
|
||||
<n-card title="带 Icon 的按钮">
|
||||
<n-space>
|
||||
<n-button type="info">
|
||||
<TheIcon icon="material-symbols:add" :size="18" class="mr-5" />
|
||||
新增
|
||||
</n-button>
|
||||
<n-button type="error">
|
||||
<TheIcon icon="material-symbols:delete-outline" :size="18" class="mr-5" />
|
||||
删除
|
||||
</n-button>
|
||||
<n-button type="warning">
|
||||
<TheIcon icon="material-symbols:edit-outline" :size="18" class="mr-5" />
|
||||
编辑
|
||||
</n-button>
|
||||
<n-button type="primary">
|
||||
<TheIcon icon="majesticons:eye-line" :size="18" class="mr-5" />
|
||||
查看
|
||||
</n-button>
|
||||
</n-space>
|
||||
</n-card>
|
||||
</n-space>
|
||||
|
||||
<n-space size="large" mt-30>
|
||||
<n-card min-w-340 title="通知 Notification">
|
||||
<n-space>
|
||||
<n-button @click="notify('info')">信息</n-button>
|
||||
<n-button @click="notify('success')">成功</n-button>
|
||||
<n-button @click="notify('warning')">警告</n-button>
|
||||
<n-button @click="notify('error')">错误</n-button>
|
||||
</n-space>
|
||||
</n-card>
|
||||
|
||||
<n-card min-w-340 title="确认弹窗 Dialog">
|
||||
<n-button type="error" @click="handleDelete">
|
||||
<icon-mi:delete mr-5 />
|
||||
删除
|
||||
</n-button>
|
||||
</n-card>
|
||||
|
||||
<n-card min-w-340 title="消息提醒 Message">
|
||||
<n-button :loading="loading" type="primary" @click="handleLogin">
|
||||
<icon-mdi:login v-show="!loading" mr-5 />
|
||||
登陆
|
||||
</n-button>
|
||||
</n-card>
|
||||
</n-space>
|
||||
</CommonPage>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const handleDelete = function () {
|
||||
$dialog.confirm({
|
||||
content: '确认删除?',
|
||||
confirm() {
|
||||
$message.success('删除成功')
|
||||
},
|
||||
cancel() {
|
||||
$message.warning('已取消')
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const loading = ref(false)
|
||||
function handleLogin() {
|
||||
loading.value = true
|
||||
$message.loading('登陆中...')
|
||||
setTimeout(() => {
|
||||
$message.error('登陆失败')
|
||||
$message.loading('正在尝试重新登陆...')
|
||||
setTimeout(() => {
|
||||
$message.success('登陆成功')
|
||||
loading.value = false
|
||||
}, 2000)
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
function notify(type) {
|
||||
$notification[type]({
|
||||
content: '说点啥呢',
|
||||
meta: '想不出来',
|
||||
duration: 2500,
|
||||
keepAliveOnHover: true,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -1,31 +0,0 @@
|
||||
<template>
|
||||
<CommonPage show-footer>
|
||||
<div w-350>
|
||||
<n-input v-model:value="inputVal" />
|
||||
<n-input-number v-model:value="number" mt-30 />
|
||||
<p mt-20 text-center text-14 color-gray>注:右击标签重新加载可重置keep-alive</p>
|
||||
</div>
|
||||
</CommonPage>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
defineOptions({ name: 'KeepAlive' })
|
||||
|
||||
const inputVal = ref('')
|
||||
const number = ref(0)
|
||||
|
||||
onMounted(() => {
|
||||
$message.success('onMounted')
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
$message.error('onUnmounted')
|
||||
})
|
||||
|
||||
onActivated(() => {
|
||||
$message.info('onActivated')
|
||||
})
|
||||
onDeactivated(() => {
|
||||
$message.warning('onDeactivated')
|
||||
})
|
||||
</script>
|
||||
@@ -1,43 +0,0 @@
|
||||
const Layout = () => import('@/layout/index.vue')
|
||||
|
||||
export default {
|
||||
name: 'Test',
|
||||
path: '/base',
|
||||
component: Layout,
|
||||
redirect: '/base/index',
|
||||
meta: {
|
||||
title: '基础功能',
|
||||
icon: 'majesticons:compass-line',
|
||||
order: 1,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'BaseComponents',
|
||||
path: 'index',
|
||||
component: () => import('./index.vue'),
|
||||
meta: {
|
||||
title: '基础组件',
|
||||
icon: 'material-symbols:auto-awesome-outline-rounded',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Unocss',
|
||||
path: 'unocss',
|
||||
component: () => import('./unocss/index.vue'),
|
||||
meta: {
|
||||
title: 'Unocss',
|
||||
icon: 'material-symbols:auto-awesome-outline-rounded',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'KeepAlive',
|
||||
path: 'keep-alive',
|
||||
component: () => import('./keep-alive/index.vue'),
|
||||
meta: {
|
||||
title: 'KeepAlive',
|
||||
icon: 'material-symbols:auto-awesome-outline-rounded',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
<template>
|
||||
<CommonPage show-footer>
|
||||
<p>
|
||||
文档:
|
||||
<a c-blue hover-decoration-underline href="https://uno.antfu.me/" target="_blank">
|
||||
https://uno.antfu.me/
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
playground:
|
||||
<a c-blue hover-decoration-underline href="https://unocss.antfu.me/play/" target="_blank">
|
||||
https://unocss.antfu.me/play/
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<div mt-20 w-350 f-c-c flex-col>
|
||||
<div flex flex-wrap justify-around rounded-10 p-10 border="1 solid #ccc">
|
||||
<div m-20 h-50 w-50 f-c-c rounded-5 p-10 border="1 solid">
|
||||
<span h-6 w-6 rounded-3 bg-black dark:bg-white />
|
||||
</div>
|
||||
<div m-20 h-50 w-50 flex justify-between rounded-5 p-10 border="1 solid">
|
||||
<span h-6 w-6 rounded-3 bg-black dark:bg-white />
|
||||
<span h-6 w-6 self-end rounded-3 bg-black dark:bg-white />
|
||||
</div>
|
||||
<div m-20 h-50 w-50 flex justify-between rounded-5 p-10 border="1 solid">
|
||||
<span h-6 w-6 rounded-3 bg-black dark:bg-white />
|
||||
<span h-6 w-6 self-center rounded-3 bg-black dark:bg-white />
|
||||
<span h-6 w-6 self-end rounded-3 bg-black dark:bg-white />
|
||||
</div>
|
||||
<div m-20 h-50 w-50 flex justify-between rounded-5 p-10 border="1 solid">
|
||||
<div flex-col justify-between>
|
||||
<span h-6 w-6 rounded-3 bg-black dark:bg-white />
|
||||
<span h-6 w-6 rounded-3 bg-black dark:bg-white />
|
||||
</div>
|
||||
<div flex-col justify-between>
|
||||
<span h-6 w-6 rounded-3 bg-black dark:bg-white />
|
||||
<span h-6 w-6 rounded-3 bg-black dark:bg-white />
|
||||
</div>
|
||||
</div>
|
||||
<div m-20 h-50 w-50 flex-col items-center justify-between rounded-5 p-10 border="1 solid">
|
||||
<div w-full flex justify-between>
|
||||
<span h-6 w-6 rounded-3 bg-black dark:bg-white />
|
||||
<span h-6 w-6 rounded-3 bg-black dark:bg-white />
|
||||
</div>
|
||||
<div h-6 w-6 rounded-3 bg-black dark:bg-white />
|
||||
<div w-full flex justify-between>
|
||||
<span h-6 w-6 rounded-3 bg-black dark:bg-white />
|
||||
<span h-6 w-6 rounded-3 bg-black dark:bg-white />
|
||||
</div>
|
||||
</div>
|
||||
<div m-20 h-50 w-50 flex-col justify-between rounded-5 p-10 border="1 solid">
|
||||
<div w-full flex justify-between>
|
||||
<span h-6 w-6 rounded-3 bg-black dark:bg-white />
|
||||
<span h-6 w-6 rounded-3 bg-black dark:bg-white />
|
||||
</div>
|
||||
<div w-full flex justify-between>
|
||||
<span h-6 w-6 rounded-3 bg-black dark:bg-white />
|
||||
<span h-6 w-6 rounded-3 bg-black dark:bg-white />
|
||||
</div>
|
||||
<div w-full flex justify-between>
|
||||
<span h-6 w-6 rounded-3 bg-black dark:bg-white />
|
||||
<span h-6 w-6 rounded-3 bg-black dark:bg-white />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h2 mt-10 text-14 font-normal color-gray>Flex 骰子</h2>
|
||||
</div>
|
||||
</CommonPage>
|
||||
</template>
|
||||
@@ -1,47 +0,0 @@
|
||||
<template>
|
||||
<CommonPage>
|
||||
<div h-60 flex items-center bg-white pl-20 pr-20 dark:bg-dark>
|
||||
<input
|
||||
v-model="post.title"
|
||||
class="mr-20 flex-1 pb-15 pt-15 text-20 font-bold color-primary"
|
||||
dark:bg-dark
|
||||
type="text"
|
||||
placeholder="输入文章标题..."
|
||||
/>
|
||||
<n-button type="primary" style="width: 80px" :loading="btnLoading" @click="handleSavePost">
|
||||
<TheIcon v-if="!btnLoading" icon="line-md:confirm-circle" class="mr-5" :size="18" />
|
||||
保存
|
||||
</n-button>
|
||||
</div>
|
||||
<MdEditor v-model="post.content" style="height: calc(100vh - 305px)" dark:bg-dark />
|
||||
</CommonPage>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { MdEditor } from 'md-editor-v3'
|
||||
import 'md-editor-v3/lib/style.css'
|
||||
|
||||
defineOptions({ name: 'MDEditor' })
|
||||
|
||||
// refs
|
||||
let post = ref({})
|
||||
let btnLoading = ref(false)
|
||||
|
||||
function handleSavePost() {
|
||||
btnLoading.value = true
|
||||
$message.loading('正在保存...')
|
||||
setTimeout(() => {
|
||||
$message.success('保存成功')
|
||||
btnLoading.value = false
|
||||
}, 2000)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.md-preview {
|
||||
ul,
|
||||
ol {
|
||||
list-style: revert;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,46 +0,0 @@
|
||||
<template>
|
||||
<AppPage>
|
||||
<div class="h-full flex-col" border="1 solid #ccc" dark:bg-dark>
|
||||
<WangToolbar
|
||||
border-b="1px solid #ccc"
|
||||
:editor="editorRef"
|
||||
:default-config="toolbarConfig"
|
||||
mode="default"
|
||||
/>
|
||||
<WangEditor
|
||||
v-model="valueHtml"
|
||||
style="flex: 1; overflow-y: hidden"
|
||||
:default-config="editorConfig"
|
||||
mode="default"
|
||||
@on-created="handleCreated"
|
||||
/>
|
||||
</div>
|
||||
</AppPage>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import '@wangeditor/editor/dist/css/style.css'
|
||||
import { Editor as WangEditor, Toolbar as WangToolbar } from '@wangeditor/editor-for-vue'
|
||||
|
||||
defineOptions({ name: 'RichTextEditor' })
|
||||
const editorRef = shallowRef()
|
||||
const toolbarConfig = { excludeKeys: 'fullScreen' }
|
||||
const editorConfig = { placeholder: '请输入内容...', MENU_CONF: {} }
|
||||
const valueHtml = ref('')
|
||||
|
||||
const handleCreated = (editor) => {
|
||||
editorRef.value = editor
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
html.dark {
|
||||
--w-e-textarea-bg-color: #333;
|
||||
--w-e-textarea-color: #fff;
|
||||
--w-e-toolbar-bg-color: #333;
|
||||
--w-e-toolbar-color: #fff;
|
||||
--w-e-toolbar-active-bg-color: #666;
|
||||
--w-e-toolbar-active-color: #fff;
|
||||
/* ...其他... */
|
||||
}
|
||||
</style>
|
||||
@@ -1,65 +0,0 @@
|
||||
const Layout = () => import('@/layout/index.vue')
|
||||
|
||||
export default {
|
||||
name: 'Demo',
|
||||
path: '/demo',
|
||||
component: Layout,
|
||||
redirect: '/demo/crud',
|
||||
meta: {
|
||||
title: '示例页面',
|
||||
customIcon: 'logo',
|
||||
role: ['admin'],
|
||||
requireAuth: true,
|
||||
order: 3,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'Crud',
|
||||
path: 'crud',
|
||||
component: () => import('./table/index.vue'),
|
||||
meta: {
|
||||
title: 'CRUD表格',
|
||||
icon: 'ic:baseline-table-view',
|
||||
role: ['admin'],
|
||||
requireAuth: true,
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'MDEditor',
|
||||
path: 'md-editor',
|
||||
component: () => import('./editor/md-editor.vue'),
|
||||
meta: {
|
||||
title: 'MD编辑器',
|
||||
icon: 'ri:markdown-line',
|
||||
role: ['admin'],
|
||||
requireAuth: true,
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'RichTextEditor',
|
||||
path: 'rich-text',
|
||||
component: () => import('./editor/rich-text.vue'),
|
||||
meta: {
|
||||
title: '富文本编辑器',
|
||||
icon: 'ic:sharp-text-rotation-none',
|
||||
role: ['admin'],
|
||||
requireAuth: true,
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Upload',
|
||||
path: 'upload',
|
||||
component: () => import('./upload/index.vue'),
|
||||
meta: {
|
||||
title: '图片上传',
|
||||
icon: 'mdi:upload',
|
||||
role: ['admin'],
|
||||
requireAuth: true,
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import { request } from '@/utils'
|
||||
|
||||
export default {
|
||||
getPosts: (params = {}) => request.get('posts', { params }),
|
||||
getPostById: (id) => request.get(`/post/${id}`),
|
||||
addPost: (data) => request.post('/post', data),
|
||||
updatePost: (data) => request.put(`/post/${data.id}`, data),
|
||||
deletePost: (id) => request.delete(`/post/${id}`),
|
||||
}
|
||||
@@ -1,233 +0,0 @@
|
||||
<template>
|
||||
<CommonPage show-footer title="文章">
|
||||
<template #action>
|
||||
<div>
|
||||
<n-button type="primary" secondary @click="$table?.handleExport()">
|
||||
<TheIcon icon="mdi:download" :size="18" class="mr-5" />
|
||||
导出
|
||||
</n-button>
|
||||
<n-button type="primary" class="ml-16" @click="handleAdd">
|
||||
<TheIcon icon="material-symbols:add" :size="18" class="mr-5" />
|
||||
新建文章
|
||||
</n-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<CrudTable
|
||||
ref="$table"
|
||||
v-model:query-items="queryItems"
|
||||
:extra-params="extraParams"
|
||||
:scroll-x="1200"
|
||||
:columns="columns"
|
||||
:get-data="api.getPosts"
|
||||
@on-checked="onChecked"
|
||||
@on-data-change="(data) => (tableData = data)"
|
||||
>
|
||||
<template #queryBar>
|
||||
<QueryBarItem label="标题" :label-width="50">
|
||||
<n-input
|
||||
v-model:value="queryItems.title"
|
||||
type="text"
|
||||
placeholder="请输入标题"
|
||||
@keypress.enter="$table?.handleSearch"
|
||||
/>
|
||||
</QueryBarItem>
|
||||
</template>
|
||||
</CrudTable>
|
||||
<!-- 新增/编辑/查看 -->
|
||||
<CrudModal
|
||||
v-model:visible="modalVisible"
|
||||
:title="modalTitle"
|
||||
:loading="modalLoading"
|
||||
:show-footer="modalAction !== 'view'"
|
||||
@on-save="handleSave"
|
||||
>
|
||||
<n-form
|
||||
ref="modalFormRef"
|
||||
label-placement="left"
|
||||
label-align="left"
|
||||
:label-width="80"
|
||||
:model="modalForm"
|
||||
:disabled="modalAction === 'view'"
|
||||
>
|
||||
<n-form-item label="作者" path="author">
|
||||
<n-input v-model:value="modalForm.author" disabled />
|
||||
</n-form-item>
|
||||
<n-form-item
|
||||
label="文章标题"
|
||||
path="title"
|
||||
:rule="{
|
||||
required: true,
|
||||
message: '请输入文章标题',
|
||||
trigger: ['input', 'blur'],
|
||||
}"
|
||||
>
|
||||
<n-input v-model:value="modalForm.title" placeholder="请输入文章标题" />
|
||||
</n-form-item>
|
||||
<n-form-item
|
||||
label="文章内容"
|
||||
path="content"
|
||||
:rule="{
|
||||
required: true,
|
||||
message: '请输入文章内容',
|
||||
trigger: ['input', 'blur'],
|
||||
}"
|
||||
>
|
||||
<n-input
|
||||
v-model:value="modalForm.content"
|
||||
placeholder="请输入文章内容"
|
||||
type="textarea"
|
||||
:autosize="{
|
||||
minRows: 3,
|
||||
maxRows: 5,
|
||||
}"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</CrudModal>
|
||||
</CommonPage>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { NButton, NSwitch } from 'naive-ui'
|
||||
import { formatDateTime, renderIcon, isNullOrUndef } from '@/utils'
|
||||
import { useCRUD } from '@/composables'
|
||||
import api from './api'
|
||||
|
||||
defineOptions({ name: 'Crud' })
|
||||
|
||||
const $table = ref(null)
|
||||
/** 表格数据,触发搜索的时候会更新这个值 */
|
||||
const tableData = ref([])
|
||||
/** QueryBar筛选参数(可选) */
|
||||
const queryItems = ref({})
|
||||
/** 补充参数(可选) */
|
||||
const extraParams = ref({})
|
||||
|
||||
onActivated(() => {
|
||||
$table.value?.handleSearch()
|
||||
})
|
||||
|
||||
const columns = [
|
||||
{ type: 'selection', fixed: 'left' },
|
||||
{
|
||||
title: '发布',
|
||||
key: 'isPublish',
|
||||
width: 60,
|
||||
align: 'center',
|
||||
fixed: 'left',
|
||||
render(row) {
|
||||
return h(NSwitch, {
|
||||
size: 'small',
|
||||
rubberBand: false,
|
||||
value: row['isPublish'],
|
||||
loading: !!row.publishing,
|
||||
onUpdateValue: () => handlePublish(row),
|
||||
})
|
||||
},
|
||||
},
|
||||
{ title: '标题', key: 'title', width: 150, ellipsis: { tooltip: true } },
|
||||
{ title: '分类', key: 'category', width: 80, ellipsis: { tooltip: true } },
|
||||
{ title: '创建人', key: 'author', width: 80 },
|
||||
{
|
||||
title: '创建时间',
|
||||
key: 'createDate',
|
||||
width: 150,
|
||||
render(row) {
|
||||
return h('span', formatDateTime(row['createDate']))
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '最后更新时间',
|
||||
key: 'updateDate',
|
||||
width: 150,
|
||||
render(row) {
|
||||
return h('span', formatDateTime(row['updateDate']))
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'actions',
|
||||
width: 240,
|
||||
align: 'center',
|
||||
fixed: 'right',
|
||||
hideInExcel: true,
|
||||
render(row) {
|
||||
return [
|
||||
h(
|
||||
NButton,
|
||||
{
|
||||
size: 'small',
|
||||
type: 'primary',
|
||||
secondary: true,
|
||||
onClick: () => handleView(row),
|
||||
},
|
||||
{ default: () => '查看', icon: renderIcon('majesticons:eye-line', { size: 14 }) }
|
||||
),
|
||||
h(
|
||||
NButton,
|
||||
{
|
||||
size: 'small',
|
||||
type: 'primary',
|
||||
style: 'margin-left: 15px;',
|
||||
onClick: () => handleEdit(row),
|
||||
},
|
||||
{ default: () => '编辑', icon: renderIcon('material-symbols:edit-outline', { size: 14 }) }
|
||||
),
|
||||
|
||||
h(
|
||||
NButton,
|
||||
{
|
||||
size: 'small',
|
||||
type: 'error',
|
||||
style: 'margin-left: 15px;',
|
||||
onClick: () => handleDelete(row.id),
|
||||
},
|
||||
{
|
||||
default: () => '删除',
|
||||
icon: renderIcon('material-symbols:delete-outline', { size: 14 }),
|
||||
}
|
||||
),
|
||||
]
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
// 选中事件
|
||||
function onChecked(rowKeys) {
|
||||
if (rowKeys.length) $message.info(`选中${rowKeys.join(' ')}`)
|
||||
}
|
||||
|
||||
// 发布
|
||||
function handlePublish(row) {
|
||||
if (isNullOrUndef(row.id)) return
|
||||
|
||||
row.publishing = true
|
||||
setTimeout(() => {
|
||||
row.isPublish = !row.isPublish
|
||||
row.publishing = false
|
||||
$message?.success(row.isPublish ? '已发布' : '已取消发布')
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
const {
|
||||
modalVisible,
|
||||
modalAction,
|
||||
modalTitle,
|
||||
modalLoading,
|
||||
handleAdd,
|
||||
handleDelete,
|
||||
handleEdit,
|
||||
handleView,
|
||||
handleSave,
|
||||
modalForm,
|
||||
modalFormRef,
|
||||
} = useCRUD({
|
||||
name: '文章',
|
||||
initForm: { author: '大脸怪' },
|
||||
doCreate: api.addPost,
|
||||
doDelete: api.deletePost,
|
||||
doUpdate: api.updatePost,
|
||||
refresh: () => $table.value?.handleSearch(),
|
||||
})
|
||||
</script>
|
||||
@@ -1,84 +0,0 @@
|
||||
<template>
|
||||
<CommonPage>
|
||||
<n-upload
|
||||
class="mx-auto w-[75%] p-20 text-center"
|
||||
:custom-request="handleUpload"
|
||||
:show-file-list="false"
|
||||
accept=".png,.jpg,.jpeg"
|
||||
@before-upload="onBeforeUpload"
|
||||
>
|
||||
<n-upload-dragger>
|
||||
<div class="h-150 f-c-c flex-col">
|
||||
<TheIcon icon="mdi:upload" :size="68" class="mb-12 c-primary" />
|
||||
<n-text class="text-14 c-gray">点击或者拖动文件到该区域来上传</n-text>
|
||||
</div>
|
||||
</n-upload-dragger>
|
||||
</n-upload>
|
||||
|
||||
<n-card v-if="imgList && imgList.length" class="mt-16 items-center">
|
||||
<n-image-group>
|
||||
<n-space justify="space-between" align="center">
|
||||
<n-card v-for="(item, index) in imgList" :key="index" class="w-280 hover:card-shadow">
|
||||
<div class="h-160 f-c-c">
|
||||
<n-image width="200" :src="item.url" />
|
||||
</div>
|
||||
<n-space class="mt-16" justify="space-evenly">
|
||||
<n-button dashed type="primary" @click="copy(item.url)">url</n-button>
|
||||
<n-button dashed type="primary" @click="copy(``)">
|
||||
MD
|
||||
</n-button>
|
||||
<n-button
|
||||
dashed
|
||||
type="primary"
|
||||
@click="copy(`<img src="${item.url}" />`)"
|
||||
>
|
||||
img
|
||||
</n-button>
|
||||
</n-space>
|
||||
</n-card>
|
||||
<div v-for="i in 4" :key="i" class="w-280" />
|
||||
</n-space>
|
||||
</n-image-group>
|
||||
</n-card>
|
||||
</CommonPage>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useClipboard } from '@vueuse/core'
|
||||
defineOptions({ name: 'Upload' })
|
||||
|
||||
const { copy, copied } = useClipboard()
|
||||
|
||||
const imgList = reactive([
|
||||
{ url: 'https://cdn.qszone.com/images/5c23d52f880511ebb6edd017c2d2eca2.jpg' },
|
||||
{ url: 'https://cdn.qszone.com/images/5c23d52f880511ebb6edd017c2d2eca2.jpg' },
|
||||
{ url: 'https://cdn.qszone.com/images/5c23d52f880511ebb6edd017c2d2eca2.jpg' },
|
||||
{ url: 'https://cdn.qszone.com/images/5c23d52f880511ebb6edd017c2d2eca2.jpg' },
|
||||
])
|
||||
|
||||
watch(copied, (val) => {
|
||||
val && $message.success('已复制到剪切板')
|
||||
})
|
||||
|
||||
function onBeforeUpload({ file }) {
|
||||
if (!file.file?.type.startsWith('image/')) {
|
||||
$message.error('只能上传图片')
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
async function handleUpload({ file, onFinish }) {
|
||||
if (!file || !file.type) {
|
||||
$message.error('请选择文件')
|
||||
}
|
||||
|
||||
// 模拟上传
|
||||
$message.loading('上传中...')
|
||||
setTimeout(() => {
|
||||
$message.success('上传成功')
|
||||
imgList.push({ fileName: file.name, url: URL.createObjectURL(file.file) })
|
||||
onFinish()
|
||||
}, 1500)
|
||||
}
|
||||
</script>
|
||||
@@ -5,6 +5,7 @@ export default {
|
||||
path: '/error-page',
|
||||
component: Layout,
|
||||
redirect: '/error-page/404',
|
||||
isHidden: true,
|
||||
meta: {
|
||||
title: '错误页',
|
||||
icon: 'mdi:alert-circle-outline',
|
||||
|
||||
6
src/views/goods/add/api.js
Normal file
6
src/views/goods/add/api.js
Normal file
@@ -0,0 +1,6 @@
|
||||
import { request } from '@/utils'
|
||||
|
||||
export default {
|
||||
getGoodClass: (data) => request.post('/goods/class', data),
|
||||
addGoods: (data) => request.post('/goods/edit', data),
|
||||
}
|
||||
173
src/views/goods/add/index.vue
Normal file
173
src/views/goods/add/index.vue
Normal file
@@ -0,0 +1,173 @@
|
||||
<template>
|
||||
<CommonPage show-footer :title="$route.title">
|
||||
<!-- {{ model }} -->
|
||||
<n-spin size="large" :show="isShowSpin">
|
||||
<n-form ref="formRef" label-width="100" :model="model" :rules="rules" label-placement="left">
|
||||
<n-grid :cols="2" :x-gap="24">
|
||||
<n-form-item-gi :span="12" label="商品分类:" path="class_id">
|
||||
<n-select
|
||||
v-model:value="model.class_id"
|
||||
label-field="name"
|
||||
value-field="ID"
|
||||
:options="classList"
|
||||
placeholder="选择商品分类"
|
||||
/>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="12" label="商品名称:" path="name">
|
||||
<n-input v-model:value="model.name" placeholder="输入商品名称" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="12" label="商品封面:" path="cover">
|
||||
<Upload v-model:list="model.cover" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="12" label="商品轮播图:" path="rotation">
|
||||
<Upload v-model:list="model.rotation" :max="5" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="12" label="商品价格:" path="number">
|
||||
<n-input-number v-model:value="model.number" placeholder="输入商品价格" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="12" label="市场价格:" path="market_num">
|
||||
<n-input-number v-model:value="model.market_num" placeholder="输入市场价格" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="12" label="商品库存:" path="stock">
|
||||
<n-input-number v-model:value="model.stock" placeholder="输入商品库存" />
|
||||
</n-form-item-gi>
|
||||
|
||||
<n-form-item-gi :span="12" label="商品简介:" path="profile">
|
||||
<n-input v-model:value="model.profile" type="textarea" placeholder="输入商品简介" />
|
||||
</n-form-item-gi>
|
||||
|
||||
<n-form-item-gi :span="12" label="商品详情:" path="details">
|
||||
<Editor v-model:valueHtml="model.details" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="12">
|
||||
<n-button class="m-auto" type="primary" @click="submit">提交</n-button>
|
||||
</n-form-item-gi>
|
||||
</n-grid>
|
||||
</n-form>
|
||||
</n-spin>
|
||||
</CommonPage>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Upload from '@/components/Upload.vue'
|
||||
import Editor from '@/components/Editor.vue'
|
||||
import api from './api'
|
||||
import { useGoodsStore } from '@/store/modules/goods'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const formRef = ref(null)
|
||||
|
||||
const model = ref({
|
||||
name: '',
|
||||
class_id: null,
|
||||
cover: [],
|
||||
rotation: [],
|
||||
profile: '',
|
||||
details: '',
|
||||
stock: null,
|
||||
number: null,
|
||||
market_num: null,
|
||||
})
|
||||
|
||||
const rules = {
|
||||
name: {
|
||||
required: true,
|
||||
message: '请输入商品名称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
class_id: {
|
||||
required: true,
|
||||
type: 'number',
|
||||
message: '请选择商品分类',
|
||||
trigger: 'change',
|
||||
},
|
||||
cover: {
|
||||
required: true,
|
||||
type: 'array',
|
||||
message: '请上传商品封面',
|
||||
trigger: 'change',
|
||||
},
|
||||
rotation: {
|
||||
required: true,
|
||||
type: 'array',
|
||||
message: '请上传商品轮播图',
|
||||
trigger: 'change',
|
||||
},
|
||||
number: {
|
||||
required: true,
|
||||
type: 'number',
|
||||
message: '请输入商品价格',
|
||||
trigger: 'blur',
|
||||
},
|
||||
market_num: {
|
||||
required: true,
|
||||
type: 'number',
|
||||
message: '请输入市场价格',
|
||||
trigger: 'blur',
|
||||
},
|
||||
stock: {
|
||||
required: true,
|
||||
type: 'number',
|
||||
message: '请输入商品库存',
|
||||
trigger: 'blur',
|
||||
},
|
||||
}
|
||||
const { row, setRow, goodType } = useGoodsStore()
|
||||
|
||||
const type = ref('')
|
||||
|
||||
const isShowSpin = ref(false)
|
||||
|
||||
onMounted(() => {
|
||||
type.value = goodType
|
||||
getClassList()
|
||||
})
|
||||
|
||||
const classList = ref([])
|
||||
|
||||
const getClassList = async () => {
|
||||
isShowSpin.value = true
|
||||
const res = await api.getGoodClass()
|
||||
classList.value = res.data.data
|
||||
|
||||
if (row && type.value === 'edit') {
|
||||
console.log(row)
|
||||
type.value = 'edit'
|
||||
model.value = {
|
||||
...row,
|
||||
cover: [{ url: row.cover, status: 'finished', id: 1 }],
|
||||
rotation: row.rotation?.split(',').map((item, index) => ({
|
||||
url: item,
|
||||
status: 'finished',
|
||||
id: index + 1,
|
||||
})),
|
||||
}
|
||||
}
|
||||
isShowSpin.value = false
|
||||
}
|
||||
|
||||
const route = useRouter()
|
||||
|
||||
const submit = () => {
|
||||
formRef.value.validate(async (errors) => {
|
||||
if (errors) return
|
||||
try {
|
||||
const data = {
|
||||
...model.value,
|
||||
cover: model.value.cover.map((item) => item.url)[0],
|
||||
rotation: model.value.rotation.map((item) => item.url).join(','),
|
||||
status: 3,
|
||||
}
|
||||
const res = await api.addGoods(data)
|
||||
console.log(res)
|
||||
// $message.success(res.data.msg)
|
||||
route.back()
|
||||
setRow({})
|
||||
} catch (error) {
|
||||
$message.error(error.msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
6
src/views/goods/index/api.js
Normal file
6
src/views/goods/index/api.js
Normal file
@@ -0,0 +1,6 @@
|
||||
import { request } from '@/utils'
|
||||
|
||||
export default {
|
||||
getGoods: (data) => request.post('/goods', data),
|
||||
getGoodClass: (data) => request.post('/goods/class', data),
|
||||
}
|
||||
170
src/views/goods/index/index.vue
Normal file
170
src/views/goods/index/index.vue
Normal file
@@ -0,0 +1,170 @@
|
||||
<template>
|
||||
<CommonPage show-footer :title="$route.title">
|
||||
<n-button type="primary" @click="addGood(1)">添加商品</n-button>
|
||||
<n-data-table
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
remote
|
||||
/>
|
||||
</CommonPage>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useRouter } from 'vue-router'
|
||||
import { NButton, NEllipsis } from 'naive-ui'
|
||||
import api from './api'
|
||||
import { useGoodsStore } from '@/store/modules/goods'
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
const columns = ref([
|
||||
{
|
||||
title: 'ID',
|
||||
align: 'center',
|
||||
key: 'ID',
|
||||
},
|
||||
{
|
||||
title: '封面',
|
||||
align: 'center',
|
||||
slot: 'cover',
|
||||
render(row) {
|
||||
return h('img', {
|
||||
src: row.cover,
|
||||
style: {
|
||||
width: '30px',
|
||||
height: '30px',
|
||||
},
|
||||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '商品分类',
|
||||
align: 'center',
|
||||
slot: 'class_id',
|
||||
render(row) {
|
||||
const data = optList.value.filter((item) => item.ID === row.class_id)
|
||||
return h('span', data[0]?.name)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '商品名称',
|
||||
align: 'center',
|
||||
slot: 'name',
|
||||
render(row) {
|
||||
return h(
|
||||
NEllipsis,
|
||||
{
|
||||
class: 'w-300',
|
||||
},
|
||||
{ default: () => row.name }
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '商品价格',
|
||||
align: 'center',
|
||||
key: 'number',
|
||||
},
|
||||
{
|
||||
title: '商品库存',
|
||||
align: 'center',
|
||||
key: 'stock',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
align: 'center',
|
||||
slot: 'status',
|
||||
render(row) {
|
||||
return h('span', row.status === 1 ? '已审核' : row.status === 2 ? '已拒绝' : '待审核')
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
key: 'notes',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
align: 'center',
|
||||
slot: 'action',
|
||||
render(row) {
|
||||
if (row.status === 1 || row.status === 2) {
|
||||
return [
|
||||
h(
|
||||
NButton,
|
||||
{
|
||||
type: 'primary',
|
||||
size: 'small',
|
||||
onClick: () => toEdit(row),
|
||||
},
|
||||
() => '编辑'
|
||||
),
|
||||
]
|
||||
}
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
const data = ref([])
|
||||
|
||||
const pagination = ref({
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
itemCount: 0,
|
||||
onChange: (page) => {
|
||||
pagination.value.page = page
|
||||
getList()
|
||||
},
|
||||
onUpdatePageSize: (pageSize) => {
|
||||
pagination.value.pageSize = pageSize
|
||||
pagination.value.page = 1
|
||||
getList()
|
||||
},
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
getclasslist()
|
||||
})
|
||||
|
||||
const optList = ref([])
|
||||
|
||||
const getclasslist = async () => {
|
||||
const res = await api.getGoodClass()
|
||||
optList.value = res.data.data
|
||||
}
|
||||
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await api.getGoods({
|
||||
pageNum: pagination.value.page,
|
||||
pageSize: pagination.value.pageSize,
|
||||
})
|
||||
data.value = res.data.data || []
|
||||
pagination.value.itemCount = res.data.total
|
||||
} catch (error) {
|
||||
$message.error(error.msg)
|
||||
}
|
||||
loading.value = false
|
||||
}
|
||||
const route = useRouter()
|
||||
const { setRow, setType } = useGoodsStore()
|
||||
|
||||
const addGood = (type) => {
|
||||
setType(type === 1 ? 'add' : 'edit')
|
||||
route.push({
|
||||
path: '/goods/goods_add',
|
||||
})
|
||||
}
|
||||
|
||||
const toEdit = (item) => {
|
||||
setRow(item)
|
||||
addGood()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
31
src/views/goods/route.js
Normal file
31
src/views/goods/route.js
Normal file
@@ -0,0 +1,31 @@
|
||||
const Layout = () => import('@/layout/index.vue')
|
||||
|
||||
export default {
|
||||
name: '商品管理',
|
||||
path: '/goods',
|
||||
component: Layout,
|
||||
redirect: '/goods_list',
|
||||
children: [
|
||||
{
|
||||
name: 'Goodslist',
|
||||
path: 'goods_list',
|
||||
component: () => import('./index/index.vue'),
|
||||
meta: {
|
||||
title: '商品列表',
|
||||
icon: 'mdi:account-multiple',
|
||||
order: 10,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Goodsadd',
|
||||
path: 'goods_add',
|
||||
isHidden: true,
|
||||
component: () => import('./add/index.vue'),
|
||||
meta: {
|
||||
title: '添加/编辑商品',
|
||||
icon: 'mdi:account-multiple',
|
||||
order: 10,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { request } from '@/utils'
|
||||
|
||||
export default {
|
||||
login: (data) => request.post('/auth/login', data, { noNeedToken: true }),
|
||||
login: (data) => request.post('/login', data, { noNeedToken: true }),
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
v-model:value="loginInfo.name"
|
||||
autofocus
|
||||
class="h-50 items-center pl-10 text-16"
|
||||
placeholder="admin"
|
||||
placeholder="请输入账号"
|
||||
:maxlength="20"
|
||||
/>
|
||||
</div>
|
||||
@@ -29,7 +29,7 @@
|
||||
class="h-50 items-center pl-10 text-16"
|
||||
type="password"
|
||||
show-password-on="mousedown"
|
||||
placeholder="123456"
|
||||
placeholder="请输入密码"
|
||||
:maxlength="20"
|
||||
@keypress.enter="handleLogin"
|
||||
/>
|
||||
@@ -99,9 +99,10 @@ async function handleLogin() {
|
||||
try {
|
||||
loading.value = true
|
||||
$message.loading('正在验证...')
|
||||
const res = await api.login({ name, password: password.toString() })
|
||||
const res = await api.login({ phone: name, password: password.toString() })
|
||||
$message.success('登录成功')
|
||||
setToken(res.data.token)
|
||||
window.localStorage.setItem('type', res.data.type)
|
||||
if (isRemember.value) {
|
||||
lStorage.set('loginInfo', { name, password })
|
||||
} else {
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<template>
|
||||
<div>a-1-1</div>
|
||||
</template>
|
||||
@@ -1,3 +0,0 @@
|
||||
<template>
|
||||
<div>a-1-2</div>
|
||||
</template>
|
||||
@@ -1,8 +0,0 @@
|
||||
<template>
|
||||
<CommonPage>
|
||||
<div>a-1</div>
|
||||
<div pl-20>
|
||||
<RouterView />
|
||||
</div>
|
||||
</CommonPage>
|
||||
</template>
|
||||
@@ -1,3 +0,0 @@
|
||||
<template>
|
||||
<div>a-2-1</div>
|
||||
</template>
|
||||
@@ -1,8 +0,0 @@
|
||||
<template>
|
||||
<CommonPage>
|
||||
<div>a-2</div>
|
||||
<div pl-20>
|
||||
<RouterView />
|
||||
</div>
|
||||
</CommonPage>
|
||||
</template>
|
||||
@@ -1,8 +0,0 @@
|
||||
<template>
|
||||
<CommonPage>
|
||||
<div>a</div>
|
||||
<div pl-20>
|
||||
<RouterView />
|
||||
</div>
|
||||
</CommonPage>
|
||||
</template>
|
||||
@@ -1,75 +0,0 @@
|
||||
const Layout = () => import('@/layout/index.vue')
|
||||
|
||||
export default {
|
||||
name: 'MultipleMenu',
|
||||
path: '/multi-menu',
|
||||
component: Layout,
|
||||
meta: {
|
||||
title: '多级菜单',
|
||||
icon: 'ic:baseline-menu',
|
||||
role: ['admin'],
|
||||
requireAuth: true,
|
||||
order: 4,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'a-1',
|
||||
path: 'multiple-menu',
|
||||
component: () => import('./a-1/index.vue'),
|
||||
meta: {
|
||||
title: 'a-1',
|
||||
icon: 'ic:baseline-menu',
|
||||
role: ['admin'],
|
||||
requireAuth: true,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'a-1-1',
|
||||
path: 'a-1-1',
|
||||
component: () => import('./a-1/a-1-1/index.vue'),
|
||||
meta: {
|
||||
title: 'a-1-1',
|
||||
icon: 'ic:baseline-menu',
|
||||
role: ['admin'],
|
||||
requireAuth: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'a-1-2',
|
||||
path: 'a-1-2',
|
||||
component: () => import('./a-1/a-1-2/index.vue'),
|
||||
meta: {
|
||||
title: 'a-1-2',
|
||||
icon: 'ic:baseline-menu',
|
||||
role: ['admin'],
|
||||
requireAuth: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'a-2',
|
||||
path: 'a-2',
|
||||
component: () => import('./a-2/index.vue'),
|
||||
meta: {
|
||||
title: 'a-2',
|
||||
icon: 'ic:baseline-menu',
|
||||
role: ['admin'],
|
||||
requireAuth: true,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'a-2-1',
|
||||
path: 'a-2-1',
|
||||
component: () => import('./a-2/a-2-1/index.vue'),
|
||||
meta: {
|
||||
title: 'a-2-1(单个子菜单)',
|
||||
icon: 'ic:baseline-menu',
|
||||
role: ['admin'],
|
||||
requireAuth: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
5
src/views/order/index/api.js
Normal file
5
src/views/order/index/api.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import { request } from '@/utils'
|
||||
|
||||
export default {
|
||||
getOrder: (data) => request.post('/order', data),
|
||||
}
|
||||
105
src/views/order/index/index.vue
Normal file
105
src/views/order/index/index.vue
Normal file
@@ -0,0 +1,105 @@
|
||||
<template>
|
||||
<CommonPage show-footer :title="$route.title">
|
||||
<n-data-table
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
remote
|
||||
/>
|
||||
</CommonPage>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import api from './api'
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
const columns = ref([
|
||||
{
|
||||
title: '订单号',
|
||||
align: 'center',
|
||||
key: 'oid',
|
||||
},
|
||||
{
|
||||
title: '用户',
|
||||
align: 'center',
|
||||
key: 'user_name',
|
||||
},
|
||||
{
|
||||
title: '商品名称',
|
||||
align: 'center',
|
||||
key: 'goods_name',
|
||||
},
|
||||
{
|
||||
title: '商品价格',
|
||||
align: 'center',
|
||||
key: 'number',
|
||||
},
|
||||
{
|
||||
title: '订单状态',
|
||||
align: 'center',
|
||||
slot: 'status',
|
||||
render(row) {
|
||||
switch (row.status) {
|
||||
case 0:
|
||||
return h('span', '待付款')
|
||||
case 1:
|
||||
return h('span', '待使用')
|
||||
case 2:
|
||||
return h('span', '已完成')
|
||||
case 3:
|
||||
return h('span', '已过期')
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
align: 'center',
|
||||
slot: 'action',
|
||||
render(row) {
|
||||
console.log(row)
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
const data = ref([])
|
||||
|
||||
const pagination = ref({
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
itemCount: 0,
|
||||
onChange: (page) => {
|
||||
pagination.value.page = page
|
||||
getList()
|
||||
},
|
||||
onUpdatePageSize: (pageSize) => {
|
||||
pagination.value.pageSize = pageSize
|
||||
pagination.value.page = 1
|
||||
getList()
|
||||
},
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await api.getOrder({
|
||||
pageNum: pagination.value.page,
|
||||
pageSize: pagination.value.pageSize,
|
||||
})
|
||||
console.log(res)
|
||||
data.value = res.data.data || []
|
||||
pagination.value.itemCount = res.data.total
|
||||
} catch (error) {
|
||||
$message.error(error.msg)
|
||||
}
|
||||
loading.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
26
src/views/order/route.js
Normal file
26
src/views/order/route.js
Normal file
@@ -0,0 +1,26 @@
|
||||
const Layout = () => import('@/layout/index.vue')
|
||||
|
||||
export default {
|
||||
name: 'Order',
|
||||
path: '/order',
|
||||
component: Layout,
|
||||
redirect: '/order_list',
|
||||
meta: {
|
||||
title: '订单管理',
|
||||
icon: 'majesticons:compass-line',
|
||||
order: 1,
|
||||
// requireAuth: true,
|
||||
// role: ['1'],
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'OrderList',
|
||||
path: 'order_list',
|
||||
component: () => import('./index/index.vue'),
|
||||
meta: {
|
||||
title: '订单列表',
|
||||
icon: 'material-symbols:auto-awesome-outline-rounded',
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
5
src/views/settlement/index/api.js
Normal file
5
src/views/settlement/index/api.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import { request } from '@/utils'
|
||||
|
||||
export default {
|
||||
getJF: (data) => request.post('/record', data),
|
||||
}
|
||||
75
src/views/settlement/index/index.vue
Normal file
75
src/views/settlement/index/index.vue
Normal file
@@ -0,0 +1,75 @@
|
||||
<template>
|
||||
<!-- <div> -->
|
||||
<CommonPage show-footer :title="$route.title">
|
||||
<n-data-table
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
remote
|
||||
/>
|
||||
</CommonPage>
|
||||
<!-- </div> -->
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import api from './api'
|
||||
|
||||
const loading = ref(false)
|
||||
const columns = ref([
|
||||
{
|
||||
title: 'ID',
|
||||
key: 'ID',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '订单号',
|
||||
key: 'oid',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '获取积分',
|
||||
key: 'number',
|
||||
align: 'center',
|
||||
},
|
||||
])
|
||||
const data = ref([])
|
||||
|
||||
const pagination = ref({
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
itemCount: 0,
|
||||
onChange: (page) => {
|
||||
pagination.value.page = page
|
||||
getList()
|
||||
},
|
||||
onUpdatePageSize: (pageSize) => {
|
||||
pagination.value.pageSize = pageSize
|
||||
pagination.value.page = 1
|
||||
getList()
|
||||
},
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await api.getJF({
|
||||
pageNum: pagination.value.page,
|
||||
pageSize: pagination.value.pageSize,
|
||||
})
|
||||
console.log(res)
|
||||
data.value = res.data.data || []
|
||||
pagination.value.itemCount = res.data.total
|
||||
} catch (error) {
|
||||
$message.error(error.msg)
|
||||
}
|
||||
loading.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
5
src/views/settlement/jf_list/api.js
Normal file
5
src/views/settlement/jf_list/api.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import { request } from '@/utils'
|
||||
|
||||
export default {
|
||||
getList: (data) => request.post('/order', data),
|
||||
}
|
||||
80
src/views/settlement/jf_list/index.vue
Normal file
80
src/views/settlement/jf_list/index.vue
Normal file
@@ -0,0 +1,80 @@
|
||||
<template>
|
||||
<!-- <div> -->
|
||||
<CommonPage show-footer :title="$route.title">
|
||||
<n-data-table
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
remote
|
||||
/>
|
||||
</CommonPage>
|
||||
<!-- </div> -->
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import api from './api'
|
||||
|
||||
const loading = ref(false)
|
||||
const columns = ref([
|
||||
{
|
||||
title: 'ID',
|
||||
key: 'ID',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '商品名称',
|
||||
key: 'goods_name',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '用户名称',
|
||||
key: 'user_name',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '获取积分',
|
||||
key: 'number',
|
||||
align: 'center',
|
||||
},
|
||||
])
|
||||
const data = ref([])
|
||||
|
||||
const pagination = ref({
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
itemCount: 0,
|
||||
onChange: (page) => {
|
||||
pagination.value.page = page
|
||||
getList()
|
||||
},
|
||||
onUpdatePageSize: (pageSize) => {
|
||||
pagination.value.pageSize = pageSize
|
||||
pagination.value.page = 1
|
||||
getList()
|
||||
},
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await api.getList({
|
||||
pageNum: pagination.value.page,
|
||||
pageSize: pagination.value.pageSize,
|
||||
})
|
||||
console.log(res)
|
||||
data.value = res.data.data || []
|
||||
pagination.value.itemCount = res.data.total
|
||||
} catch (error) {
|
||||
$message.error(error.msg)
|
||||
}
|
||||
loading.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
35
src/views/settlement/route.js
Normal file
35
src/views/settlement/route.js
Normal file
@@ -0,0 +1,35 @@
|
||||
const Layout = () => import('@/layout/index.vue')
|
||||
|
||||
export default {
|
||||
name: '积分管理',
|
||||
path: '/settlement',
|
||||
component: Layout,
|
||||
redirect: '/settlement_list',
|
||||
meta: {
|
||||
requireAuth: true,
|
||||
order: 1,
|
||||
role: ['2'],
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'Settlementlist',
|
||||
path: 'settlement_list',
|
||||
component: () => import('./index/index.vue'),
|
||||
meta: {
|
||||
title: '积分明细',
|
||||
icon: 'mdi:account-multiple',
|
||||
order: 10,
|
||||
},
|
||||
},
|
||||
// {
|
||||
// name: 'Jflist',
|
||||
// path: 'jf_list',
|
||||
// component: () => import('./jf_list/index.vue'),
|
||||
// meta: {
|
||||
// title: '积分列表',
|
||||
// icon: 'mdi:account-multiple',
|
||||
// order: 10,
|
||||
// },
|
||||
// },
|
||||
],
|
||||
}
|
||||
5
src/views/user/index/api.js
Normal file
5
src/views/user/index/api.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import { request } from '@/utils'
|
||||
|
||||
export default {
|
||||
getUser: (data) => request.post('/user', data),
|
||||
}
|
||||
102
src/views/user/index/index.vue
Normal file
102
src/views/user/index/index.vue
Normal file
@@ -0,0 +1,102 @@
|
||||
<template>
|
||||
<CommonPage show-footer :title="$route.title">
|
||||
<n-data-table
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
remote
|
||||
/>
|
||||
</CommonPage>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import api from './api'
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
const columns = ref([
|
||||
{
|
||||
title: 'ID',
|
||||
align: 'center',
|
||||
key: 'ID',
|
||||
},
|
||||
{
|
||||
title: '头像',
|
||||
align: 'center',
|
||||
slot: 'avatar',
|
||||
render(row) {
|
||||
return h('img', {
|
||||
src: row.avatar,
|
||||
style: {
|
||||
width: '30px',
|
||||
height: '30px',
|
||||
borderRadius: '50%',
|
||||
},
|
||||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '电话',
|
||||
align: 'center',
|
||||
key: 'phone',
|
||||
},
|
||||
{
|
||||
title: '用户积分',
|
||||
align: 'center',
|
||||
key: 'integral',
|
||||
},
|
||||
{
|
||||
title: '用户豆子',
|
||||
align: 'center',
|
||||
key: 'pulse',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
align: 'center',
|
||||
slot: 'action',
|
||||
render(row) {
|
||||
console.log(row)
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
const data = ref([])
|
||||
|
||||
const pagination = ref({
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
itemCount: 0,
|
||||
onChange: (page) => {
|
||||
pagination.value.page = page
|
||||
getList()
|
||||
},
|
||||
onUpdatePageSize: (pageSize) => {
|
||||
pagination.value.pageSize = pageSize
|
||||
pagination.value.page = 1
|
||||
getList()
|
||||
},
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await api.getUser({
|
||||
pageNum: pagination.value.page,
|
||||
pageSize: pagination.value.pageSize,
|
||||
})
|
||||
data.value = res.data.data
|
||||
pagination.value.itemCount = res.data.total
|
||||
} catch (error) {
|
||||
$message.error(error.msg)
|
||||
}
|
||||
loading.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
20
src/views/user/route.js
Normal file
20
src/views/user/route.js
Normal file
@@ -0,0 +1,20 @@
|
||||
const Layout = () => import('@/layout/index.vue')
|
||||
|
||||
export default {
|
||||
name: '用户管理',
|
||||
path: '/user',
|
||||
component: Layout,
|
||||
redirect: '/user_list',
|
||||
children: [
|
||||
{
|
||||
name: 'Userlist',
|
||||
path: 'user_list',
|
||||
component: () => import('./index/index.vue'),
|
||||
meta: {
|
||||
title: '用户列表',
|
||||
icon: 'mdi:account-multiple',
|
||||
order: 10,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
<p text-16>Hello, {{ userStore.name }}</p>
|
||||
<p mt-5 text-12 op-60>今天又是元气满满的一天</p>
|
||||
</div>
|
||||
<div ml-auto flex items-center>
|
||||
<!-- <div ml-auto flex items-center>
|
||||
<n-statistic label="待办" :value="4">
|
||||
<template #suffix>/ 10</template>
|
||||
</n-statistic>
|
||||
@@ -22,11 +22,11 @@
|
||||
<img alt="forks" src="https://badgen.net/github/forks/zclzone/vue-naive-admin" />
|
||||
</a>
|
||||
</n-statistic>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
</n-card>
|
||||
|
||||
<n-card title="项目" size="small" :segmented="true" mt-15 rounded-10>
|
||||
<!-- <n-card title="项目" size="small" :segmented="true" mt-15 rounded-10>
|
||||
<template #header-extra>
|
||||
<n-button text type="primary">更多</n-button>
|
||||
</template>
|
||||
@@ -46,7 +46,7 @@
|
||||
<div h-0 w-300></div>
|
||||
<div h-0 w-300></div>
|
||||
</div>
|
||||
</n-card>
|
||||
</n-card> -->
|
||||
</div>
|
||||
</AppPage>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user