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
|
VITE_PORT = 3100
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
VITE_PUBLIC_PATH = '/'
|
VITE_PUBLIC_PATH = '/'
|
||||||
|
|
||||||
# 是否启用MOCK
|
# 是否启用MOCK
|
||||||
VITE_USE_MOCK = true
|
VITE_USE_MOCK = false
|
||||||
|
|
||||||
# 是否启用MOCK
|
# 是否启用代理
|
||||||
VITE_USE_PROXY = true
|
VITE_USE_PROXY = true
|
||||||
|
|
||||||
# base api
|
# base api
|
||||||
VITE_BASE_API = '/api'
|
VITE_BASE_API = '/store'
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
# 资源公共路径,需要以 /开头和结尾
|
# 资源公共路径,需要以 /开头和结尾
|
||||||
VITE_PUBLIC_PATH = '/'
|
VITE_PUBLIC_PATH = '/static/mer'
|
||||||
|
|
||||||
# 是否启用MOCK
|
# 是否启用MOCK
|
||||||
VITE_USE_MOCK = true
|
VITE_USE_MOCK = false
|
||||||
|
|
||||||
# base api
|
# base api
|
||||||
VITE_BASE_API = '/api'
|
VITE_BASE_API = 'https://www.wanzhuanyongcheng.cn/store'
|
||||||
|
|
||||||
# 是否启用压缩
|
# 是否启用压缩
|
||||||
VITE_USE_COMPRESS = true
|
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:3100/api/user
|
||||||
* @转发路径 http://localhost:8080/user
|
* @转发路径 http://localhost:8080/user
|
||||||
*/
|
*/
|
||||||
'/api': {
|
'/store': {
|
||||||
target: 'http://localhost:8080',
|
target: 'https://test.wanzhuanyongcheng.cn',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
rewrite: (path) => path.replace(new RegExp('^/api'), ''),
|
// rewrite: (path) => path.replace(new RegExp('^/api'), ''),
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @desc 不替换匹配值
|
* @desc 不替换匹配值
|
||||||
* @请求路径 http://localhost:3100/api/v2/user
|
* @请求路径 http://localhost:3100/api/v2/user
|
||||||
* @转发路径 http://localhost:8080/api/v2/user
|
* @转发路径 http://localhost:8080/api/v2/user
|
||||||
*/
|
*/
|
||||||
'/api/v2': {
|
// '/api/v2': {
|
||||||
target: 'http://localhost:8080',
|
// target: 'http://localhost:8080',
|
||||||
changeOrigin: true,
|
// changeOrigin: true,
|
||||||
},
|
// },
|
||||||
/**
|
/**
|
||||||
* @desc 替换部分匹配值
|
* @desc 替换部分匹配值
|
||||||
* @请求路径 http://localhost:3100/api/v3/user
|
* @请求路径 http://localhost:3100/api/v3/user
|
||||||
* @转发路径 http://localhost:8080/user
|
* @转发路径 http://localhost:8080/user
|
||||||
*/
|
*/
|
||||||
'/api/v3': {
|
// '/api/v3': {
|
||||||
target: 'http://localhost:8080',
|
// target: 'http://localhost:8080',
|
||||||
changeOrigin: true,
|
// changeOrigin: true,
|
||||||
rewrite: (path) => path.replace(new RegExp('^/api'), ''),
|
// 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>
|
<template>
|
||||||
<footer f-c-c flex-col text-14 color="#6a6a6a">
|
<footer f-c-c flex-col text-14 color="#6a6a6a">
|
||||||
<p>
|
<!-- <p>
|
||||||
Copyright © 2022-present
|
Copyright © 2022-present
|
||||||
<a
|
<a
|
||||||
href="https://github.com/zclzone"
|
href="https://github.com/zclzone"
|
||||||
@@ -18,6 +18,6 @@
|
|||||||
>
|
>
|
||||||
赣ICP备2020015008号-1
|
赣ICP备2020015008号-1
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p> -->
|
||||||
</footer>
|
</footer>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
<BreadCrumb ml-15 hidden sm:block />
|
<BreadCrumb ml-15 hidden sm:block />
|
||||||
</div>
|
</div>
|
||||||
<div ml-auto flex items-center>
|
<div ml-auto flex items-center>
|
||||||
<MessageNotification />
|
<!-- <MessageNotification /> -->
|
||||||
<ThemeMode />
|
<ThemeMode />
|
||||||
<GithubSite />
|
<!-- <GithubSite /> -->
|
||||||
<FullScreen />
|
<FullScreen />
|
||||||
<UserAvatar />
|
<UserAvatar />
|
||||||
</div>
|
</div>
|
||||||
@@ -17,7 +17,7 @@ import BreadCrumb from './components/BreadCrumb.vue'
|
|||||||
import MenuCollapse from './components/MenuCollapse.vue'
|
import MenuCollapse from './components/MenuCollapse.vue'
|
||||||
import FullScreen from './components/FullScreen.vue'
|
import FullScreen from './components/FullScreen.vue'
|
||||||
import UserAvatar from './components/UserAvatar.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 ThemeMode from './components/ThemeMode.vue'
|
||||||
import MessageNotification from './components/MessageNotification.vue'
|
// import MessageNotification from './components/MessageNotification.vue'
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { basicRoutes, EMPTY_ROUTE, NOT_FOUND_ROUTE } from './routes'
|
|||||||
import { getToken, isNullOrWhitespace } from '@/utils'
|
import { getToken, isNullOrWhitespace } from '@/utils'
|
||||||
import { useUserStore, usePermissionStore } from '@/store'
|
import { useUserStore, usePermissionStore } from '@/store'
|
||||||
|
|
||||||
const isHash = import.meta.env.VITE_USE_HASH === 'true'
|
const isHash = true
|
||||||
export const router = createRouter({
|
export const router = createRouter({
|
||||||
history: isHash ? createWebHashHistory('/') : createWebHistory('/'),
|
history: isHash ? createWebHashHistory('/') : createWebHistory('/'),
|
||||||
routes: basicRoutes,
|
routes: basicRoutes,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const Layout = () => import('@/layout/index.vue')
|
// const Layout = () => import('@/layout/index.vue')
|
||||||
|
|
||||||
export const basicRoutes = [
|
export const basicRoutes = [
|
||||||
{
|
{
|
||||||
@@ -18,42 +18,42 @@ export const basicRoutes = [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
// {
|
||||||
name: 'ExternalLink',
|
// name: 'ExternalLink',
|
||||||
path: '/external-link',
|
// path: '/external-link',
|
||||||
component: Layout,
|
// component: Layout,
|
||||||
meta: {
|
// meta: {
|
||||||
title: '外部链接',
|
// title: '外部链接',
|
||||||
icon: 'mdi:link-variant',
|
// icon: 'mdi:link-variant',
|
||||||
order: 4,
|
// order: 4,
|
||||||
},
|
// },
|
||||||
children: [
|
// children: [
|
||||||
{
|
// {
|
||||||
name: 'LinkGithubSrc',
|
// name: 'LinkGithubSrc',
|
||||||
path: 'https://github.com/zclzone/vue-naive-admin',
|
// path: 'https://github.com/zclzone/vue-naive-admin',
|
||||||
meta: {
|
// meta: {
|
||||||
title: '源码 - github',
|
// title: '源码 - github',
|
||||||
icon: 'mdi:github',
|
// icon: 'mdi:github',
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
name: 'LinkGiteeSrc',
|
// name: 'LinkGiteeSrc',
|
||||||
path: 'https://gitee.com/zclzone/vue-naive-admin',
|
// path: 'https://gitee.com/zclzone/vue-naive-admin',
|
||||||
meta: {
|
// meta: {
|
||||||
title: '源码 - gitee',
|
// title: '源码 - gitee',
|
||||||
icon: 'simple-icons:gitee',
|
// icon: 'simple-icons:gitee',
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
name: 'LinkDocs',
|
// name: 'LinkDocs',
|
||||||
path: 'https://zclzone.github.io/vue-naive-admin-docs',
|
// path: 'https://zclzone.github.io/vue-naive-admin-docs',
|
||||||
meta: {
|
// meta: {
|
||||||
title: '文档 - vuepress',
|
// title: '文档 - vuepress',
|
||||||
icon: 'mdi:vuejs',
|
// icon: 'mdi:vuejs',
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
},
|
// },
|
||||||
]
|
]
|
||||||
|
|
||||||
export const NOT_FOUND_ROUTE = {
|
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 './permission'
|
||||||
export * from './tags'
|
export * from './tags'
|
||||||
export * from './user'
|
export * from './user'
|
||||||
|
export * from './goods'
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { defineStore } from 'pinia'
|
|||||||
import { resetRouter } from '@/router'
|
import { resetRouter } from '@/router'
|
||||||
import { useTagsStore, usePermissionStore } from '@/store'
|
import { useTagsStore, usePermissionStore } from '@/store'
|
||||||
import { removeToken, toLogin } from '@/utils'
|
import { removeToken, toLogin } from '@/utils'
|
||||||
import api from '@/api'
|
// import api from '@/api'
|
||||||
|
|
||||||
export const useUserStore = defineStore('user', {
|
export const useUserStore = defineStore('user', {
|
||||||
state() {
|
state() {
|
||||||
@@ -26,14 +26,18 @@ export const useUserStore = defineStore('user', {
|
|||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
async getUserInfo() {
|
async getUserInfo() {
|
||||||
try {
|
const typeMer = localStorage.getItem('type')
|
||||||
const res = await api.getUser()
|
this.userInfo = {
|
||||||
const { id, name, avatar, role } = res.data
|
role: [typeMer],
|
||||||
this.userInfo = { id, name, avatar, role }
|
|
||||||
return Promise.resolve(res.data)
|
|
||||||
} catch (error) {
|
|
||||||
return Promise.reject(error)
|
|
||||||
}
|
}
|
||||||
|
// 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() {
|
async logout() {
|
||||||
const { resetTags } = useTagsStore()
|
const { resetTags } = useTagsStore()
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { lStorage } from '@/utils'
|
import { lStorage } from '@/utils'
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
|
|
||||||
const TOKEN_CODE = 'access_token'
|
const TOKEN_CODE = 'mer_token'
|
||||||
const DURATION = 6 * 60 * 60
|
const DURATION = 6 * 60 * 60
|
||||||
|
|
||||||
export function getToken() {
|
export function getToken() {
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export function reqReject(error) {
|
|||||||
export function resResolve(response) {
|
export function resResolve(response) {
|
||||||
// TODO: 处理不同的 response.headers
|
// TODO: 处理不同的 response.headers
|
||||||
const { data, status, config, statusText } = response
|
const { data, status, config, statusText } = response
|
||||||
if (data?.code !== 0) {
|
if (data?.code !== 200) {
|
||||||
const code = data?.code ?? status
|
const code = data?.code ?? status
|
||||||
|
|
||||||
/** 根据code处理对应的操作,并返回处理后的message */
|
/** 根据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',
|
path: '/error-page',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/error-page/404',
|
redirect: '/error-page/404',
|
||||||
|
isHidden: true,
|
||||||
meta: {
|
meta: {
|
||||||
title: '错误页',
|
title: '错误页',
|
||||||
icon: 'mdi:alert-circle-outline',
|
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'
|
import { request } from '@/utils'
|
||||||
|
|
||||||
export default {
|
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"
|
v-model:value="loginInfo.name"
|
||||||
autofocus
|
autofocus
|
||||||
class="h-50 items-center pl-10 text-16"
|
class="h-50 items-center pl-10 text-16"
|
||||||
placeholder="admin"
|
placeholder="请输入账号"
|
||||||
:maxlength="20"
|
:maxlength="20"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
class="h-50 items-center pl-10 text-16"
|
class="h-50 items-center pl-10 text-16"
|
||||||
type="password"
|
type="password"
|
||||||
show-password-on="mousedown"
|
show-password-on="mousedown"
|
||||||
placeholder="123456"
|
placeholder="请输入密码"
|
||||||
:maxlength="20"
|
:maxlength="20"
|
||||||
@keypress.enter="handleLogin"
|
@keypress.enter="handleLogin"
|
||||||
/>
|
/>
|
||||||
@@ -99,9 +99,10 @@ async function handleLogin() {
|
|||||||
try {
|
try {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
$message.loading('正在验证...')
|
$message.loading('正在验证...')
|
||||||
const res = await api.login({ name, password: password.toString() })
|
const res = await api.login({ phone: name, password: password.toString() })
|
||||||
$message.success('登录成功')
|
$message.success('登录成功')
|
||||||
setToken(res.data.token)
|
setToken(res.data.token)
|
||||||
|
window.localStorage.setItem('type', res.data.type)
|
||||||
if (isRemember.value) {
|
if (isRemember.value) {
|
||||||
lStorage.set('loginInfo', { name, password })
|
lStorage.set('loginInfo', { name, password })
|
||||||
} else {
|
} 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 text-16>Hello, {{ userStore.name }}</p>
|
||||||
<p mt-5 text-12 op-60>今天又是元气满满的一天</p>
|
<p mt-5 text-12 op-60>今天又是元气满满的一天</p>
|
||||||
</div>
|
</div>
|
||||||
<div ml-auto flex items-center>
|
<!-- <div ml-auto flex items-center>
|
||||||
<n-statistic label="待办" :value="4">
|
<n-statistic label="待办" :value="4">
|
||||||
<template #suffix>/ 10</template>
|
<template #suffix>/ 10</template>
|
||||||
</n-statistic>
|
</n-statistic>
|
||||||
@@ -22,11 +22,11 @@
|
|||||||
<img alt="forks" src="https://badgen.net/github/forks/zclzone/vue-naive-admin" />
|
<img alt="forks" src="https://badgen.net/github/forks/zclzone/vue-naive-admin" />
|
||||||
</a>
|
</a>
|
||||||
</n-statistic>
|
</n-statistic>
|
||||||
</div>
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
</n-card>
|
</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>
|
<template #header-extra>
|
||||||
<n-button text type="primary">更多</n-button>
|
<n-button text type="primary">更多</n-button>
|
||||||
</template>
|
</template>
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
<div h-0 w-300></div>
|
<div h-0 w-300></div>
|
||||||
<div h-0 w-300></div>
|
<div h-0 w-300></div>
|
||||||
</div>
|
</div>
|
||||||
</n-card>
|
</n-card> -->
|
||||||
</div>
|
</div>
|
||||||
</AppPage>
|
</AppPage>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user