docs(README.md): 项目文档修改
This commit is contained in:
parent
e2f24f5429
commit
21d61b7a06
636
README.md
636
README.md
|
|
@ -1,623 +1,49 @@
|
|||
## 技术栈官网
|
||||
[](https://gitee.com/wangjiabin-x/uh5)
|
||||

|
||||
[](https://github.com/hxrui/youlai-mall/stargazers)
|
||||
[](https://github.com/hxrui/youlai-mall/blob/master/LICENSE)
|
||||

|
||||

|
||||

|
||||
|
||||
- vue3: https://v3.cn.vuejs.org/guide/introduction.html
|
||||
**线上预览地址:** http://www.youlai.tech
|
||||
|
||||
- vite2: https://cn.vitejs.dev/guide/
|
||||
#### 项目预览
|
||||
|
||||
- element-plus: https://element-plus.gitee.io/zh-CN/component/button.html
|
||||
|  |  |
|
||||
| ------------------------------------------------------------ | ------------------------------------------------------------ |
|
||||
| |  |
|
||||
|
||||
- vue-router4 : https://next.router.vuejs.org/zh/introduction.html
|
||||
|
||||
- ~~vuex4:https://next.vuex.vuejs.org/zh/index.html~~ (pinia替代)
|
||||
|
||||
- pinia: https://pinia.vuejs.org
|
||||
|
||||
#### 技术栈
|
||||
|
||||
## Vite项目构建
|
||||
- **前端技术栈:** vue3、vite2、element-plus、typescript、vue-element-admin
|
||||
|
||||
Vite是一种新型前端构建工具,能够显著提升前端开发体验。
|
||||
|
||||
[Vite 官方中文文档](https://cn.vitejs.dev/ )
|
||||
#### 项目地址
|
||||
|
||||
项目构建命令:
|
||||
| 项目名称 | 源码地址 |项目名称 | 源码地址 |
|
||||
| ---------- | ------------------------------------------------------------ |---------- | ------------------------------------------------------------ |
|
||||
| 微服务后台 | [youlai-mall](https://gitee.com/youlaitech/youlai-mall) | 微信小程序 | [youlai-mall-weapp](https://gitee.com/youlaitech/youlai-mall-weapp) |
|
||||
| 管理前端 | [youlai-mall-admin](https://gitee.com/youlaitech/youlai-mall-admin) |APP应用 | [youlai-mall-app](https://gitee.com/youlaitech/youlai-mall-app) |
|
||||
|
||||
```shell
|
||||
npm init vite@latest vue3-element-admin --template vue-ts
|
||||
cd vue3-element-admin
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
访问本地: http://localhost:3000
|
||||
#### 项目启动
|
||||
|
||||
## vue-router
|
||||
1. 本机安装Node环境
|
||||
2. npm install
|
||||
3. npm run dev
|
||||
4. 访问 http://localhost:9527
|
||||
|
||||
```text
|
||||
npm install vue-router@next
|
||||
```
|
||||
#### 项目文档
|
||||
|
||||
src 下创建 router/interface.ts
|
||||
[项目文档地址](https://www.cnblogs.com/haoxianrui/)
|
||||
|
||||
```typescript
|
||||
import {createRouter, createWebHashHistory, RouteRecordRaw} from 'vue-router'
|
||||
import HelloWord from '../components/HelloWorld.vue'
|
||||
|
||||
const routes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: '',
|
||||
redirect: (_) => {
|
||||
return {path: '/home'}
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/home',
|
||||
name: 'HelloWord',
|
||||
component: HelloWord
|
||||
}
|
||||
]
|
||||
#### 联系信息
|
||||
因为微信交流群满200人只能通过邀请进入,如果想进入交流群学习可添加以下开发人员,备注“**有来**“由其拉进群。
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
routes: routes
|
||||
})
|
||||
|
||||
export default router
|
||||
```
|
||||
|
||||
**参考文档:**
|
||||
|
||||
- [路由的 hash 模式和 history 模式的区别](https://www.cnblogs.com/GGbondLearn/p/12239651.html)
|
||||
|
||||
## pinia
|
||||
|
||||
```shell
|
||||
npm install pinia
|
||||
```
|
||||
|
||||
src 下创建 store/index.ts
|
||||
|
||||
```typescript
|
||||
import { createPinia } from "pinia";
|
||||
const store = createPinia();
|
||||
export { store };
|
||||
```
|
||||
main.ts
|
||||
|
||||
```typescript
|
||||
import {createApp} from 'vue'
|
||||
import App from './App.vue'
|
||||
import router from "./router";
|
||||
import '@/styles/index.scss'
|
||||
import { store } from "./store";
|
||||
import ElementPlus from 'element-plus'
|
||||
import 'element-plus/theme-chalk/index.css'
|
||||
import locale from 'element-plus/lib/locale/lang/zh-cn'
|
||||
import 'virtual:svg-icons-register';
|
||||
|
||||
|
||||
// @see https://blog.csdn.net/qq_37213281/article/details/121422027
|
||||
import * as ElIconModules from '@element-plus/icons'
|
||||
import '@/permission'
|
||||
|
||||
|
||||
import Pagination from '@/components/Pagination/index.vue'
|
||||
import {listDictsByCode} from '@/api/system/dict'
|
||||
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
// 统一注册el-icon图标
|
||||
// @link https://blog.csdn.net/Alloom/article/details/119415984
|
||||
for (let iconName in ElIconModules) {
|
||||
app.component(iconName, (ElIconModules as any)[iconName])
|
||||
}
|
||||
|
||||
// 全局方法
|
||||
app.config.globalProperties.$listDictsByCode = listDictsByCode
|
||||
app.component('Pagination', Pagination) // 全局组件
|
||||
.use(store)
|
||||
.use(router)
|
||||
.use(ElementPlus, {locale})
|
||||
.mount('#app')
|
||||
|
||||
```
|
||||
|
||||
|
||||
## element-plus
|
||||
|
||||
```shell
|
||||
npm install element-plus
|
||||
```
|
||||
|
||||
## main.ts
|
||||
|
||||
```typescript
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import router from "./router";
|
||||
import {store,key} from './store'
|
||||
|
||||
import ElementPlus from 'element-plus'
|
||||
import 'element-plus/dist/index.css'
|
||||
|
||||
const app=createApp(App)
|
||||
app
|
||||
.use(router)
|
||||
.use(store,key)
|
||||
.use(ElementPlus)
|
||||
.mount('#app')
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Vite 设置路径别名
|
||||
|
||||
#### 安装 @types/node
|
||||
|
||||
```shell
|
||||
npm install --save-dev @types/node
|
||||
```
|
||||
|
||||
或者简写
|
||||
|
||||
```shell
|
||||
npm i -D @types/node
|
||||
```
|
||||
|
||||
#### vite.config.ts
|
||||
|
||||
```typescript
|
||||
import {defineConfig} from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
// 在 ts 模块中加载 node 核心模块需要安装 node 的类型补充模块: npm i -D @types/node
|
||||
import path from 'path'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
resolve: {
|
||||
// Vite2设置别名路径方式一
|
||||
/**
|
||||
alias:{
|
||||
|
||||
"/@":path.resolve("./src"),
|
||||
},
|
||||
**/
|
||||
|
||||
// Vite2设置别名路径方式二
|
||||
alias: [
|
||||
{
|
||||
find: "@",
|
||||
replacement: path.resolve("./src")
|
||||
},
|
||||
{
|
||||
find: "@image",
|
||||
replacement: path.resolve("./src/assets/images")
|
||||
},
|
||||
{
|
||||
find: "@/router",
|
||||
replacement: path.resolve("./src/router")
|
||||
},
|
||||
{
|
||||
find: "@/store",
|
||||
replacement: path.resolve("./src/store")
|
||||
},
|
||||
{
|
||||
find: "@/api",
|
||||
replacement: path.resolve("./src/api")
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
#### tsconfig.json
|
||||
|
||||
TS配置别名路径,否则使用别名路径会报错,下面关键配置 `baseUrl` 、`paths` 和 `include`
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
...
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"@": ["src"],
|
||||
"@*": ["src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Vite 环境变量配置
|
||||
|
||||
**官方环境变量配置文档:** https://cn.vitejs.dev/guide/env-and-mode.html
|
||||
|
||||
#### 配置文件
|
||||
|
||||
在项目根目录分别添加 `开发环境配置` 、 `生产环境配置`和`模拟环境配置`文件
|
||||
|
||||
开发环境配置:`.env.development`
|
||||
|
||||
```properties
|
||||
# 开发环境变量 注意:变量必须以 VITE_ 为前缀才能暴露给外部读取
|
||||
VITE_APP_TITLE = '管理系统'
|
||||
VITE_APP_PORT = 3000
|
||||
VITE_APP_BASE_API = '/dev-api'
|
||||
```
|
||||
|
||||
|
||||
生产环境配置:`.env.production`
|
||||
|
||||
```properties
|
||||
# 生产环境变量
|
||||
VITE_APP_TITLE = '管理系统'
|
||||
VITE_APP_PORT = 3000
|
||||
VITE_APP_BASE_API = '/prod-api'
|
||||
```
|
||||
|
||||
|
||||
模拟环境配置:`.env.staging`
|
||||
|
||||
```properties
|
||||
# 模拟环境变量
|
||||
VITE_APP_TITLE = '管理系统'
|
||||
VITE_APP_PORT = 3000
|
||||
VITE_APP_BASE_API = '/stage-api'
|
||||
```
|
||||
|
||||
#### 环境变量智能提示
|
||||
|
||||
`src/env.d.ts` 添加以下配置
|
||||
|
||||
```typescript
|
||||
// 环境变量智能提示
|
||||
interface ImportMetaEnv {
|
||||
VITE_APP_TITLE: string,
|
||||
VITE_APP_PORT: string,
|
||||
VITE_APP_BASE_API: string
|
||||
}
|
||||
```
|
||||
|
||||
## 生产打包配置
|
||||
|
||||
#### package.json
|
||||
|
||||
```json
|
||||
"scripts": {
|
||||
"dev": "vite serve --mode development",
|
||||
"build:prod": "vue-tsc --noEmit && vite build --mode production",
|
||||
"serve": "vite preview"
|
||||
}
|
||||
```
|
||||
|
||||
#### tsconfig.json
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
...
|
||||
"skipLibCheck": true // element-plus 生产打包报错,通过此配置修改 TS 不对第三方依赖类型检查
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
执行 `npm run build:prod` 命令打包,生成的打包文件在项目根目录 `dist` 目录下
|
||||
|
||||
|
||||
|
||||
## axios 封装
|
||||
|
||||
#### 安装axios
|
||||
|
||||
```
|
||||
npm i axios
|
||||
```
|
||||
|
||||
#### 缓存工具类
|
||||
|
||||
**src/utils/storage.ts**
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* window.localStorage 浏览器永久缓存
|
||||
*/
|
||||
export const Local = {
|
||||
// 设置永久缓存
|
||||
set(key: string, val: any) {
|
||||
window.localStorage.setItem(key, JSON.stringify(val));
|
||||
},
|
||||
// 获取永久缓存
|
||||
get(key: string) {
|
||||
let json: any = window.localStorage.getItem(key);
|
||||
return JSON.parse(json);
|
||||
},
|
||||
// 移除永久缓存
|
||||
remove(key: string) {
|
||||
window.localStorage.removeItem(key);
|
||||
},
|
||||
// 移除全部永久缓存
|
||||
clear() {
|
||||
window.localStorage.clear();
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* window.sessionStorage 浏览器临时缓存
|
||||
*/
|
||||
export const Session = {
|
||||
// 设置临时缓存
|
||||
set(key: string, val: any) {
|
||||
window.sessionStorage.setItem(key, JSON.stringify(val));
|
||||
},
|
||||
// 获取临时缓存
|
||||
get(key: string) {
|
||||
let json: any = window.sessionStorage.getItem(key);
|
||||
return JSON.parse(json);
|
||||
},
|
||||
// 移除临时缓存
|
||||
remove(key: string) {
|
||||
window.sessionStorage.removeItem(key);
|
||||
},
|
||||
// 移除全部临时缓存
|
||||
clear() {
|
||||
window.sessionStorage.clear();
|
||||
}
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### 创建axios实例
|
||||
|
||||
**src/utils/request.ts**
|
||||
|
||||
```typescript
|
||||
import axios from "axios";
|
||||
import {ElMessage, ElMessageBox} from "element-plus";
|
||||
import {Session} from "@/utils/storage";
|
||||
|
||||
|
||||
// 创建 axios 实例
|
||||
const service = axios.create({
|
||||
baseURL: import.meta.env.VITE_BASE_API as any,
|
||||
timeout: 50000,
|
||||
headers: {'Content-Type': 'application/json;charset=utf-8'}
|
||||
})
|
||||
|
||||
// 请求拦截器
|
||||
service.interceptors.request.use(
|
||||
(config) => {
|
||||
if (!config?.headers) {
|
||||
throw new Error(`Expected 'config' and 'config.headers' not to be undefined`);
|
||||
}
|
||||
if (Session.get('token')) {
|
||||
config.headers.Authorization = `${Session.get('token')}`;
|
||||
}
|
||||
|
||||
}, (error) => {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
)
|
||||
|
||||
// 响应拦截器
|
||||
service.interceptors.response.use(
|
||||
({data}) => {
|
||||
// 对响应数据做点什么
|
||||
const {code, msg} = data;
|
||||
if (code === '00000') {
|
||||
return data;
|
||||
} else {
|
||||
ElMessage({
|
||||
message: msg || '系统出错',
|
||||
type: 'error'
|
||||
})
|
||||
return Promise.reject(new Error(msg || 'Error'))
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
const {code, msg} = error.response.data
|
||||
if (code === 'A0230') { // token 过期
|
||||
Session.clear(); // 清除浏览器全部临时缓存
|
||||
window.location.href = '/'; // 跳转登录页
|
||||
ElMessageBox.alert('当前页面已失效,请重新登录', '提示', {})
|
||||
.then(() => {
|
||||
})
|
||||
.catch(() => {
|
||||
});
|
||||
}
|
||||
return Promise.reject(new Error(msg || 'Error'))
|
||||
}
|
||||
);
|
||||
|
||||
// 导出 axios 实例
|
||||
export default service
|
||||
```
|
||||
|
||||
|
||||
|
||||
## HelloWorld.vue
|
||||
|
||||
```typescript
|
||||
<template>
|
||||
<el-input v-model="num"/>
|
||||
<el-button @click="handleClick">点击+1</el-button>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {defineComponent, computed} from 'vue'
|
||||
import {useStore} from '@/store';
|
||||
|
||||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
const store = useStore()
|
||||
const num = computed(()=>{
|
||||
return store.state.count
|
||||
})
|
||||
const handleClick = () => {
|
||||
store.commit('increment')
|
||||
}
|
||||
return {
|
||||
num,
|
||||
handleClick
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
## App.vue
|
||||
|
||||
```typescript
|
||||
|
||||
<template>
|
||||
<img alt="Vue logo" src="./assets/logo.png" />
|
||||
<router-view/>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
#app {
|
||||
font-family: Avenir, Helvetica, Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-align: center;
|
||||
color: #2c3e50;
|
||||
margin-top: 60px;
|
||||
}
|
||||
</style>
|
||||
|
||||
```
|
||||
|
||||
## SVG图标
|
||||
|
||||
- [使用手册(详细)](https://github.com/anncwb/vite-plugin-svg-icons/blob/main/README.zh_CN.md)
|
||||
|
||||
1. 安装
|
||||
|
||||
```
|
||||
npm i vite-plugin-svg-icons -D
|
||||
```
|
||||
2. 配置插件
|
||||
|
||||
源码坐标:[vite.config.ts](vite.config.ts)
|
||||
|
||||
```
|
||||
viteSvgIcons({
|
||||
// 指定需要缓存的图标文件夹
|
||||
iconDirs: [path.resolve(process.cwd(), 'src/assets/icons/svg')],
|
||||
// 指定symbolId格式
|
||||
symbolId: 'icon-[dir]-[name]',
|
||||
})
|
||||
```
|
||||
3. 组件封装
|
||||
|
||||
源码坐标:[src/components/SvgIcon/index.vue](src/components/SvgIcon/index.vue)
|
||||
|
||||
|
||||
4. 使用示例
|
||||
|
||||
源码坐标:[src/components/IconSelect/index.vue](src/components/IconSelect/index.vue)
|
||||
|
||||
|
||||
## 跨域处理
|
||||
|
||||
vite.config.ts 跨域配置
|
||||
|
||||
```
|
||||
// 本地反向代理解决浏览器跨域限制
|
||||
server: {
|
||||
host: 'localhost',
|
||||
port: Number(env.VITE_APP_PORT),
|
||||
open: true, // 运行自动打开浏览器
|
||||
proxy: {
|
||||
[env.VITE_APP_BASE_API]: {
|
||||
target: 'http://localhost:9999',
|
||||
changeOrigin: true,
|
||||
rewrite: path => path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '')
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## NProgress 进度条
|
||||
|
||||
1. 安装
|
||||
```
|
||||
npm install --save nprogress
|
||||
```
|
||||
|
||||
2. 使用案例
|
||||
|
||||
源码坐标:[permission.ts](src/permission.ts)
|
||||
```
|
||||
import NProgress from 'nprogress';
|
||||
import 'nprogress/nprogress.css'
|
||||
NProgress.configure({showSpinner: false}) // 进度环显示/隐藏
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
NProgress.start()
|
||||
...
|
||||
})
|
||||
|
||||
router.afterEach(() => {
|
||||
NProgress.done()
|
||||
})
|
||||
```
|
||||
|
||||
## 富文本编辑器 wangEditor
|
||||
|
||||
- [官方文档](https://www.wangeditor.com/v5/)
|
||||
|
||||
- [Vue3 使用](https://www.wangeditor.com/v5/guide/for-frame.html#vue3)
|
||||
|
||||
- [Vue3 示例](https://github.com/wangfupeng1988/vue3-wangeditor-demo)
|
||||
|
||||
1. 安装
|
||||
```
|
||||
# 安装 editor
|
||||
npm install @wangeditor/editor --save
|
||||
|
||||
# 安装 Vue3 组件
|
||||
npm install @wangeditor/editor-for-vue@next --save
|
||||
```
|
||||
|
||||
2. 组件封装
|
||||
|
||||
- 源码坐标:[src/components/WangEditor/index.vue](src/components/WangEditor/index.vue)
|
||||
|
||||
- wangEditor自定义图片上传
|
||||
```aidl
|
||||
const editorConfig = {
|
||||
placeholder: '请输入内容...',
|
||||
MENU_CONF: {
|
||||
uploadImage: {
|
||||
async customUpload(file, insertFn) {
|
||||
uploadFile(file).then(response => {
|
||||
const url = response.data
|
||||
insertFn(url)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
3. 使用示例
|
||||
|
||||
源码坐标:[src/views/pms/goods/components/GoodsInfo.vue](src/views/pms/goods/components/GoodsInfo.vue)
|
||||
|
||||
|
||||
## 列表排序 sortablejs
|
||||
|
||||
1. 安装
|
||||
```
|
||||
npm install sortablejs --save
|
||||
```
|
||||
|  |  |  | .png) |
|
||||
| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
|
||||
|  |  |  |  |## 联系信息
|
||||
|
|
|
|||
|
|
@ -109,8 +109,6 @@ import {listMembersWithPage} from '@/api/ums/member'
|
|||
|
||||
import {reactive, ref, onMounted, toRefs} from 'vue'
|
||||
import {ElTable, ElMessage, ElMessageBox} from 'element-plus'
|
||||
import {listCascadeCategories} from "@api/pms/category";
|
||||
import {listGoodsWithPage} from "@api/pms/goods";
|
||||
|
||||
const state = reactive({
|
||||
// 遮罩层
|
||||
|
|
|
|||
Loading…
Reference in New Issue