init project
This commit is contained in:
29
.gitignore
vendored
Normal file
29
.gitignore
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
# uni-app
|
||||
unpackage
|
||||
.hbuilderx
|
||||
|
||||
21
App.vue
Normal file
21
App.vue
Normal file
@@ -0,0 +1,21 @@
|
||||
<script setup>
|
||||
import { onLaunch, onShow, onHide } from '@dcloudio/uni-app'
|
||||
|
||||
onLaunch(() => {
|
||||
console.log('App Launch')
|
||||
})
|
||||
|
||||
onShow(() => {
|
||||
console.log('App Show')
|
||||
})
|
||||
|
||||
onHide(() => {
|
||||
console.log('App Hide')
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
/*每个页面公共css */
|
||||
@import '@/styles/common.scss';
|
||||
</style>
|
||||
|
||||
136
README.md
Normal file
136
README.md
Normal file
@@ -0,0 +1,136 @@
|
||||
# nl-uniapp
|
||||
|
||||
基于 Vue3 + Vite + Ant Design Vue 的 uni-app 项目模板
|
||||
|
||||
## 技术栈
|
||||
|
||||
- **框架**: Vue 3
|
||||
- **构建工具**: Vite
|
||||
- **UI组件库**: Ant Design Vue 4.x
|
||||
- **状态管理**: Pinia
|
||||
- **HTTP请求**: Axios (已封装)
|
||||
- **样式预处理**: Sass/SCSS
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
nl-uniapp/
|
||||
├── pages/ # 页面目录
|
||||
│ └── index/ # 首页
|
||||
├── src/
|
||||
│ ├── api/ # API接口
|
||||
│ │ └── index.js # 接口定义
|
||||
│ ├── stores/ # Pinia状态管理
|
||||
│ │ └── user.js # 用户状态
|
||||
│ ├── utils/ # 工具函数
|
||||
│ │ └── request.js # axios封装
|
||||
│ └── styles/ # 样式文件
|
||||
│ ├── common.scss # 公共样式
|
||||
│ └── variables.scss # 样式变量
|
||||
├── static/ # 静态资源
|
||||
├── App.vue # 应用入口
|
||||
├── main.js # 主入口文件
|
||||
├── pages.json # 页面配置
|
||||
├── manifest.json # 应用配置
|
||||
├── vite.config.js # Vite配置
|
||||
└── package.json # 项目配置
|
||||
```
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 安装依赖
|
||||
|
||||
```bash
|
||||
npm install
|
||||
# 或
|
||||
yarn install
|
||||
# 或
|
||||
pnpm install
|
||||
```
|
||||
|
||||
### 开发运行
|
||||
|
||||
```bash
|
||||
# H5
|
||||
npm run dev:h5
|
||||
|
||||
# 微信小程序
|
||||
npm run dev:mp-weixin
|
||||
|
||||
# 支付宝小程序
|
||||
npm run dev:mp-alipay
|
||||
|
||||
# 其他平台...
|
||||
```
|
||||
|
||||
### 构建打包
|
||||
|
||||
```bash
|
||||
# H5
|
||||
npm run build:h5
|
||||
|
||||
# 微信小程序
|
||||
npm run build:mp-weixin
|
||||
|
||||
# 其他平台...
|
||||
```
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 1. Axios封装
|
||||
|
||||
已封装好的axios请求工具,位于 `src/utils/request.js`,包含:
|
||||
|
||||
- 请求/响应拦截器
|
||||
- 自动添加token
|
||||
- 统一错误处理
|
||||
- Loading状态管理
|
||||
- 支持GET、POST、PUT、DELETE、文件上传等方法
|
||||
|
||||
使用示例:
|
||||
|
||||
```javascript
|
||||
import { api } from '@/api'
|
||||
|
||||
// GET请求
|
||||
const res = await api.getList({ page: 1 })
|
||||
|
||||
// POST请求
|
||||
const res = await api.create({ name: '测试' })
|
||||
```
|
||||
|
||||
### 2. 状态管理
|
||||
|
||||
使用Pinia进行状态管理,示例store位于 `src/stores/user.js`
|
||||
|
||||
### 3. API接口管理
|
||||
|
||||
所有API接口统一管理在 `src/api/index.js`,方便维护和调用
|
||||
|
||||
### 4. 样式系统
|
||||
|
||||
- 支持SCSS预处理器
|
||||
- 统一的样式变量定义
|
||||
- 公共样式类
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **Ant Design Vue兼容性**: Ant Design Vue主要针对H5端,在小程序端可能不完全兼容,建议:
|
||||
- H5端使用Ant Design Vue组件
|
||||
- 小程序端使用uni-app原生组件或uni-ui组件库
|
||||
|
||||
2. **API配置**: 请在 `src/utils/request.js` 中修改 `baseURL` 为你的实际API地址
|
||||
|
||||
3. **Token管理**: Token会自动从store中获取并添加到请求头,请确保正确设置token
|
||||
|
||||
## 开发建议
|
||||
|
||||
1. 页面开发时,优先使用uni-app原生组件以保证跨平台兼容性
|
||||
2. 样式使用rpx单位以适配不同屏幕尺寸
|
||||
3. API请求统一使用封装好的request工具
|
||||
4. 状态管理使用Pinia,避免直接使用localStorage
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
11
env.example
Normal file
11
env.example
Normal file
@@ -0,0 +1,11 @@
|
||||
# 环境变量配置示例
|
||||
# 复制此文件为 .env.development 和 .env.production 并修改相应配置
|
||||
|
||||
# 开发环境
|
||||
VITE_APP_BASE_API=/api
|
||||
VITE_APP_TITLE=nl-uniapp
|
||||
|
||||
# 生产环境
|
||||
# VITE_APP_BASE_API=https://your-api-domain.com
|
||||
# VITE_APP_TITLE=nl-uniapp
|
||||
|
||||
17
index.html
Normal file
17
index.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<title>nl-uniapp</title>
|
||||
<script>
|
||||
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || CSS.supports('top: constant(a)'))
|
||||
document.write('<meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0' + (coverSupport ? ',viewport-fit=cover' : '') + '" />')
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
18
main.js
Normal file
18
main.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import { createSSRApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import Antd from 'ant-design-vue'
|
||||
import 'ant-design-vue/dist/reset.css'
|
||||
import { createPinia } from 'pinia'
|
||||
|
||||
export function createApp() {
|
||||
const app = createSSRApp(App)
|
||||
const pinia = createPinia()
|
||||
|
||||
app.use(pinia)
|
||||
app.use(Antd)
|
||||
|
||||
return {
|
||||
app
|
||||
}
|
||||
}
|
||||
|
||||
116
manifest.json
Normal file
116
manifest.json
Normal file
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"name": "nl-uniapp",
|
||||
"appid": "__UNI__NLUNAPP",
|
||||
"description": "uniapp项目",
|
||||
"versionName": "1.0.0",
|
||||
"versionCode": "100",
|
||||
"transformPx": false,
|
||||
"app-plus": {
|
||||
"usingComponents": true,
|
||||
"nvueStyleCompiler": "uni-app",
|
||||
"compilerVersion": 3,
|
||||
"splashscreen": {
|
||||
"alwaysShowBeforeRender": true,
|
||||
"waiting": true,
|
||||
"autoclose": true,
|
||||
"delay": 0
|
||||
},
|
||||
"modules": {},
|
||||
"distribute": {
|
||||
"android": {
|
||||
"permissions": [
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
|
||||
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
|
||||
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
|
||||
]
|
||||
},
|
||||
"ios": {},
|
||||
"sdkConfigs": {}
|
||||
}
|
||||
},
|
||||
"quickapp": {},
|
||||
"mp-weixin": {
|
||||
"appid": "",
|
||||
"setting": {
|
||||
"urlCheck": false,
|
||||
"es6": true,
|
||||
"enhance": true,
|
||||
"postcss": true,
|
||||
"preloadBackgroundData": false,
|
||||
"minified": true,
|
||||
"newFeature": false,
|
||||
"coverView": true,
|
||||
"nodeModules": false,
|
||||
"autoAudits": false,
|
||||
"showShadowRootInWxmlPanel": true,
|
||||
"scopeDataCheck": false,
|
||||
"uglifyFileName": false,
|
||||
"checkInvalidKey": true,
|
||||
"checkSiteMap": true,
|
||||
"uploadWithSourceMap": true,
|
||||
"compileHotReLoad": false,
|
||||
"lazyloadPlaceholderEnable": false,
|
||||
"useMultiFrameRuntime": true,
|
||||
"useApiHook": true,
|
||||
"useApiHostProcess": true,
|
||||
"babelSetting": {
|
||||
"ignore": [],
|
||||
"disablePlugins": [],
|
||||
"outputPath": ""
|
||||
},
|
||||
"enableEngineNative": false,
|
||||
"useIsolateContext": true,
|
||||
"userConfirmedBundleSwitch": false,
|
||||
"packNpmManually": false,
|
||||
"packNpmRelationList": [],
|
||||
"minifyWXSS": true,
|
||||
"showES6CompileOption": false,
|
||||
"minifyWXML": true,
|
||||
"useStaticServer": true
|
||||
},
|
||||
"usingComponents": true,
|
||||
"permission": {
|
||||
"scope.userLocation": {
|
||||
"desc": "你的位置信息将用于小程序位置接口的效果展示"
|
||||
}
|
||||
},
|
||||
"optimization": {
|
||||
"subPackages": true
|
||||
}
|
||||
},
|
||||
"mp-alipay": {
|
||||
"usingComponents": true
|
||||
},
|
||||
"mp-baidu": {
|
||||
"usingComponents": true
|
||||
},
|
||||
"mp-toutiao": {
|
||||
"usingComponents": true
|
||||
},
|
||||
"uniStatistics": {
|
||||
"enable": false
|
||||
},
|
||||
"vueVersion": "3",
|
||||
"h5": {
|
||||
"devServer": {
|
||||
"port": 3000,
|
||||
"disableHostCheck": true
|
||||
},
|
||||
"router": {
|
||||
"mode": "hash"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
66
package.json
Normal file
66
package.json
Normal file
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"name": "nl-uniapp",
|
||||
"version": "1.0.0",
|
||||
"description": "uniapp项目 - Vue3 + Vite + Ant Design Vue",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"install": "npm install",
|
||||
"dev:h5": "uni",
|
||||
"dev:mp-weixin": "uni -p mp-weixin",
|
||||
"dev:mp-alipay": "uni -p mp-alipay",
|
||||
"dev:mp-baidu": "uni -p mp-baidu",
|
||||
"dev:mp-toutiao": "uni -p mp-toutiao",
|
||||
"dev:mp-qq": "uni -p mp-qq",
|
||||
"dev:mp-kuaishou": "uni -p mp-kuaishou",
|
||||
"dev:mp-lark": "uni -p mp-lark",
|
||||
"dev:quickapp-webview": "uni -p quickapp-webview",
|
||||
"dev:quickapp-webview-huawei": "uni -p quickapp-webview-huawei",
|
||||
"dev:quickapp-webview-union": "uni -p quickapp-webview-union",
|
||||
"build:h5": "uni build",
|
||||
"build:mp-weixin": "uni build -p mp-weixin",
|
||||
"build:mp-alipay": "uni build -p mp-alipay",
|
||||
"build:mp-baidu": "uni build -p mp-baidu",
|
||||
"build:mp-toutiao": "uni build -p mp-toutiao",
|
||||
"build:mp-qq": "uni build -p mp-qq",
|
||||
"build:mp-kuaishou": "uni build -p mp-kuaishou",
|
||||
"build:mp-lark": "uni build -p mp-lark",
|
||||
"build:quickapp-webview": "uni build -p quickapp-webview",
|
||||
"build:quickapp-webview-huawei": "uni build -p quickapp-webview-huawei",
|
||||
"build:quickapp-webview-union": "uni build -p quickapp-webview-union"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dcloudio/uni-app": "^3.0.0",
|
||||
"@dcloudio/uni-app-plus": "^3.0.0",
|
||||
"@dcloudio/uni-components": "^3.0.0",
|
||||
"@dcloudio/uni-h5": "^3.0.0",
|
||||
"@dcloudio/uni-mp-alipay": "^3.0.0",
|
||||
"@dcloudio/uni-mp-baidu": "^3.0.0",
|
||||
"@dcloudio/uni-mp-kuaishou": "^3.0.0",
|
||||
"@dcloudio/uni-mp-lark": "^3.0.0",
|
||||
"@dcloudio/uni-mp-qq": "^3.0.0",
|
||||
"@dcloudio/uni-mp-toutiao": "^3.0.0",
|
||||
"@dcloudio/uni-mp-weixin": "^3.0.0",
|
||||
"@dcloudio/uni-quickapp-webview": "^3.0.0",
|
||||
"ant-design-vue": "^4.0.0",
|
||||
"axios": "^1.6.0",
|
||||
"pinia": "^2.1.0",
|
||||
"vue": "^3.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@dcloudio/types": "^3.4.0",
|
||||
"@dcloudio/uni-automator": "^3.0.0",
|
||||
"@dcloudio/uni-cli-shared": "^3.0.0",
|
||||
"@dcloudio/vite-plugin-uni": "^3.0.0",
|
||||
"@vitejs/plugin-vue": "^4.5.0",
|
||||
"sass": "^1.69.0",
|
||||
"vite": "^5.0.0"
|
||||
},
|
||||
"browserslist": [
|
||||
"Android >= 4.4",
|
||||
"ios >= 9"
|
||||
],
|
||||
"uni-app": {
|
||||
"scripts": {}
|
||||
}
|
||||
}
|
||||
|
||||
37
pages.json
Normal file
37
pages.json
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"easycom": {
|
||||
"autoscan": true,
|
||||
"custom": {
|
||||
"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"
|
||||
}
|
||||
},
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/index/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "首页"
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalStyle": {
|
||||
"navigationBarTextStyle": "black",
|
||||
"navigationBarTitleText": "nl-uniapp",
|
||||
"navigationBarBackgroundColor": "#F8F8F8",
|
||||
"backgroundColor": "#F8F8F8"
|
||||
},
|
||||
"tabBar": {
|
||||
"color": "#7A7E83",
|
||||
"selectedColor": "#3cc51f",
|
||||
"borderStyle": "black",
|
||||
"backgroundColor": "#ffffff",
|
||||
"list": [
|
||||
{
|
||||
"pagePath": "pages/index/index",
|
||||
"iconPath": "static/tab-home.png",
|
||||
"selectedIconPath": "static/tab-home-current.png",
|
||||
"text": "首页"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
291
pages/index/index.vue
Normal file
291
pages/index/index.vue
Normal file
@@ -0,0 +1,291 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<!-- H5端使用Ant Design Vue组件 -->
|
||||
<!-- #ifdef H5 -->
|
||||
<a-card title="欢迎使用 nl-uniapp" :bordered="false">
|
||||
<a-space direction="vertical" :size="16" style="width: 100%">
|
||||
<a-typography-title :level="3">项目信息</a-typography-title>
|
||||
|
||||
<a-descriptions :column="1" bordered>
|
||||
<a-descriptions-item label="框架">Vue 3</a-descriptions-item>
|
||||
<a-descriptions-item label="构建工具">Vite</a-descriptions-item>
|
||||
<a-descriptions-item label="UI组件库">Ant Design Vue</a-descriptions-item>
|
||||
<a-descriptions-item label="状态管理">Pinia</a-descriptions-item>
|
||||
<a-descriptions-item label="HTTP请求">Axios</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
|
||||
<a-divider />
|
||||
|
||||
<a-space direction="vertical" :size="12" style="width: 100%">
|
||||
<a-typography-title :level="4">功能演示</a-typography-title>
|
||||
|
||||
<a-button type="primary" block @click="handleGetRequest" :loading="loading">
|
||||
测试GET请求
|
||||
</a-button>
|
||||
|
||||
<a-button type="primary" block @click="handlePostRequest" :loading="loading">
|
||||
测试POST请求
|
||||
</a-button>
|
||||
|
||||
<a-button type="default" block @click="handleShowMessage">
|
||||
显示消息提示
|
||||
</a-button>
|
||||
</a-space>
|
||||
|
||||
<a-divider />
|
||||
|
||||
<a-alert
|
||||
message="提示"
|
||||
description="这是一个基于 Vue3 + Vite + Ant Design Vue 的 uniapp 项目模板"
|
||||
type="info"
|
||||
show-icon
|
||||
/>
|
||||
</a-space>
|
||||
</a-card>
|
||||
<!-- #endif -->
|
||||
|
||||
<!-- 小程序端使用uni-app原生组件 -->
|
||||
<!-- #ifndef H5 -->
|
||||
<view class="card">
|
||||
<view class="title">欢迎使用 nl-uniapp</view>
|
||||
|
||||
<view class="info-section">
|
||||
<view class="info-title">项目信息</view>
|
||||
<view class="info-item">
|
||||
<text class="label">框架:</text>
|
||||
<text class="value">Vue 3</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">构建工具:</text>
|
||||
<text class="value">Vite</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">UI组件库:</text>
|
||||
<text class="value">Ant Design Vue</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">状态管理:</text>
|
||||
<text class="value">Pinia</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">HTTP请求:</text>
|
||||
<text class="value">Axios</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="divider"></view>
|
||||
|
||||
<view class="demo-section">
|
||||
<view class="demo-title">功能演示</view>
|
||||
<button class="btn btn-primary" @click="handleGetRequest" :loading="loading">
|
||||
测试GET请求
|
||||
</button>
|
||||
<button class="btn btn-primary" @click="handlePostRequest" :loading="loading">
|
||||
测试POST请求
|
||||
</button>
|
||||
<button class="btn btn-default" @click="handleShowMessage">
|
||||
显示消息提示
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<view class="divider"></view>
|
||||
|
||||
<view class="alert">
|
||||
<text class="alert-title">提示</text>
|
||||
<text class="alert-desc">这是一个基于 Vue3 + Vite + Ant Design Vue 的 uniapp 项目模板</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { api } from '@/api'
|
||||
// #ifdef H5
|
||||
import { message } from 'ant-design-vue'
|
||||
// #endif
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
// GET请求示例
|
||||
const handleGetRequest = async () => {
|
||||
try {
|
||||
loading.value = true
|
||||
const res = await api.getList({ page: 1, pageSize: 10 })
|
||||
console.log('GET请求成功:', res)
|
||||
// #ifdef H5
|
||||
message.success('GET请求成功,请查看控制台')
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
uni.showToast({
|
||||
title: 'GET请求成功',
|
||||
icon: 'success'
|
||||
})
|
||||
// #endif
|
||||
} catch (error) {
|
||||
console.error('GET请求失败:', error)
|
||||
// #ifdef H5
|
||||
message.error('GET请求失败')
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
uni.showToast({
|
||||
title: 'GET请求失败',
|
||||
icon: 'none'
|
||||
})
|
||||
// #endif
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// POST请求示例
|
||||
const handlePostRequest = async () => {
|
||||
try {
|
||||
loading.value = true
|
||||
const res = await api.create({ name: '测试数据', value: '123' })
|
||||
console.log('POST请求成功:', res)
|
||||
// #ifdef H5
|
||||
message.success('POST请求成功,请查看控制台')
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
uni.showToast({
|
||||
title: 'POST请求成功',
|
||||
icon: 'success'
|
||||
})
|
||||
// #endif
|
||||
} catch (error) {
|
||||
console.error('POST请求失败:', error)
|
||||
// #ifdef H5
|
||||
message.error('POST请求失败')
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
uni.showToast({
|
||||
title: 'POST请求失败',
|
||||
icon: 'none'
|
||||
})
|
||||
// #endif
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 消息提示示例
|
||||
const handleShowMessage = () => {
|
||||
// #ifdef H5
|
||||
message.info('这是一个消息提示')
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
uni.showToast({
|
||||
title: '这是一个消息提示',
|
||||
icon: 'none'
|
||||
})
|
||||
// #endif
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.container {
|
||||
padding: 16px;
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
// 小程序端样式
|
||||
.card {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 24px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 24px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.info-section {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.info-title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
padding: 12px 0;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
|
||||
.label {
|
||||
color: #666;
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
.value {
|
||||
color: #333;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.divider {
|
||||
height: 1px;
|
||||
background-color: #e8e8e8;
|
||||
margin: 24px 0;
|
||||
}
|
||||
|
||||
.demo-section {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.demo-title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 100%;
|
||||
margin-bottom: 12px;
|
||||
padding: 12px;
|
||||
border-radius: 4px;
|
||||
font-size: 16px;
|
||||
|
||||
&.btn-primary {
|
||||
background-color: #1890ff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&.btn-default {
|
||||
background-color: #fff;
|
||||
color: #333;
|
||||
border: 1px solid #d9d9d9;
|
||||
}
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: 12px;
|
||||
background-color: #e6f7ff;
|
||||
border: 1px solid #91d5ff;
|
||||
border-radius: 4px;
|
||||
|
||||
.alert-title {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
margin-bottom: 8px;
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.alert-desc {
|
||||
display: block;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
77
src/api/index.js
Normal file
77
src/api/index.js
Normal file
@@ -0,0 +1,77 @@
|
||||
import request from '@/utils/request'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
|
||||
// 获取token的辅助函数
|
||||
function getToken() {
|
||||
try {
|
||||
const userStore = useUserStore()
|
||||
return userStore.getToken() || ''
|
||||
} catch (e) {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
// 示例API接口
|
||||
export const api = {
|
||||
// 获取用户信息
|
||||
getUserInfo() {
|
||||
return request.get('/user/info')
|
||||
},
|
||||
|
||||
// 登录
|
||||
login(data) {
|
||||
return request.post('/user/login', data)
|
||||
},
|
||||
|
||||
// 退出登录
|
||||
logout() {
|
||||
return request.post('/user/logout')
|
||||
},
|
||||
|
||||
// 获取列表数据
|
||||
getList(params) {
|
||||
return request.get('/list', params)
|
||||
},
|
||||
|
||||
// 创建数据
|
||||
create(data) {
|
||||
return request.post('/create', data)
|
||||
},
|
||||
|
||||
// 更新数据
|
||||
update(id, data) {
|
||||
return request.put(`/update/${id}`, data)
|
||||
},
|
||||
|
||||
// 删除数据
|
||||
delete(id) {
|
||||
return request.delete(`/delete/${id}`)
|
||||
},
|
||||
|
||||
// 上传文件
|
||||
uploadFile(filePath) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const baseURL = import.meta.env.VITE_APP_BASE_API || (process.env.NODE_ENV === 'development' ? '/api' : 'https://your-api-domain.com')
|
||||
uni.uploadFile({
|
||||
url: baseURL + '/upload',
|
||||
filePath: filePath,
|
||||
name: 'file',
|
||||
header: {
|
||||
Authorization: `Bearer ${getToken()}`
|
||||
},
|
||||
success: (res) => {
|
||||
try {
|
||||
const data = JSON.parse(res.data)
|
||||
resolve(data)
|
||||
} catch (e) {
|
||||
resolve(res.data)
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
25
src/components/README.md
Normal file
25
src/components/README.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# 组件目录
|
||||
|
||||
此目录用于存放自定义组件。
|
||||
|
||||
## 使用方式
|
||||
|
||||
在页面中引入组件:
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<view>
|
||||
<custom-component />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import CustomComponent from '@/components/CustomComponent.vue'
|
||||
</script>
|
||||
```
|
||||
|
||||
## 组件命名规范
|
||||
|
||||
- 组件文件名使用 PascalCase(大驼峰命名)
|
||||
- 组件名与文件名保持一致
|
||||
|
||||
55
src/stores/user.js
Normal file
55
src/stores/user.js
Normal file
@@ -0,0 +1,55 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
|
||||
export const useUserStore = defineStore('user', () => {
|
||||
const token = ref('')
|
||||
const userInfo = ref(null)
|
||||
|
||||
// 设置token
|
||||
function setToken(val) {
|
||||
token.value = val
|
||||
// 可以同时存储到本地
|
||||
uni.setStorageSync('token', val)
|
||||
}
|
||||
|
||||
// 获取token
|
||||
function getToken() {
|
||||
if (!token.value) {
|
||||
token.value = uni.getStorageSync('token') || ''
|
||||
}
|
||||
return token.value
|
||||
}
|
||||
|
||||
// 设置用户信息
|
||||
function setUserInfo(info) {
|
||||
userInfo.value = info
|
||||
uni.setStorageSync('userInfo', info)
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
function getUserInfo() {
|
||||
if (!userInfo.value) {
|
||||
userInfo.value = uni.getStorageSync('userInfo') || null
|
||||
}
|
||||
return userInfo.value
|
||||
}
|
||||
|
||||
// 退出登录
|
||||
function logout() {
|
||||
token.value = ''
|
||||
userInfo.value = null
|
||||
uni.removeStorageSync('token')
|
||||
uni.removeStorageSync('userInfo')
|
||||
}
|
||||
|
||||
return {
|
||||
token,
|
||||
userInfo,
|
||||
setToken,
|
||||
getToken,
|
||||
setUserInfo,
|
||||
getUserInfo,
|
||||
logout
|
||||
}
|
||||
})
|
||||
|
||||
122
src/styles/common.scss
Normal file
122
src/styles/common.scss
Normal file
@@ -0,0 +1,122 @@
|
||||
/* 全局样式 */
|
||||
page {
|
||||
background-color: #f5f5f5;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* 通用容器 */
|
||||
.container {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
/* 通用卡片 */
|
||||
.card {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
/* 通用按钮 */
|
||||
.btn {
|
||||
padding: 12px 24px;
|
||||
border-radius: 4px;
|
||||
border: none;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
|
||||
&.btn-primary {
|
||||
background-color: #1890ff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&.btn-success {
|
||||
background-color: #52c41a;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&.btn-warning {
|
||||
background-color: #faad14;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&.btn-error {
|
||||
background-color: #f5222d;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
/* 通用文本 */
|
||||
.text-primary {
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.text-success {
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
.text-warning {
|
||||
color: #faad14;
|
||||
}
|
||||
|
||||
.text-error {
|
||||
color: #f5222d;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* 通用布局 */
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.flex-center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.flex-between {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.flex-column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* 通用间距 */
|
||||
.mt-xs { margin-top: 4px; }
|
||||
.mt-sm { margin-top: 8px; }
|
||||
.mt-md { margin-top: 16px; }
|
||||
.mt-lg { margin-top: 24px; }
|
||||
|
||||
.mb-xs { margin-bottom: 4px; }
|
||||
.mb-sm { margin-bottom: 8px; }
|
||||
.mb-md { margin-bottom: 16px; }
|
||||
.mb-lg { margin-bottom: 24px; }
|
||||
|
||||
.ml-xs { margin-left: 4px; }
|
||||
.ml-sm { margin-left: 8px; }
|
||||
.ml-md { margin-left: 16px; }
|
||||
.ml-lg { margin-left: 24px; }
|
||||
|
||||
.mr-xs { margin-right: 4px; }
|
||||
.mr-sm { margin-right: 8px; }
|
||||
.mr-md { margin-right: 16px; }
|
||||
.mr-lg { margin-right: 24px; }
|
||||
|
||||
.p-xs { padding: 4px; }
|
||||
.p-sm { padding: 8px; }
|
||||
.p-md { padding: 16px; }
|
||||
.p-lg { padding: 24px; }
|
||||
|
||||
34
src/styles/variables.scss
Normal file
34
src/styles/variables.scss
Normal file
@@ -0,0 +1,34 @@
|
||||
// 主题颜色
|
||||
$primary-color: #1890ff;
|
||||
$success-color: #52c41a;
|
||||
$warning-color: #faad14;
|
||||
$error-color: #f5222d;
|
||||
$info-color: #1890ff;
|
||||
|
||||
// 文字颜色
|
||||
$text-color: #333333;
|
||||
$text-color-secondary: #666666;
|
||||
$text-color-disabled: #999999;
|
||||
|
||||
// 背景颜色
|
||||
$bg-color: #ffffff;
|
||||
$bg-color-secondary: #f5f5f5;
|
||||
|
||||
// 边框颜色
|
||||
$border-color: #e8e8e8;
|
||||
$border-radius: 4px;
|
||||
|
||||
// 间距
|
||||
$spacing-xs: 4px;
|
||||
$spacing-sm: 8px;
|
||||
$spacing-md: 16px;
|
||||
$spacing-lg: 24px;
|
||||
$spacing-xl: 32px;
|
||||
|
||||
// 字体大小
|
||||
$font-size-xs: 12px;
|
||||
$font-size-sm: 14px;
|
||||
$font-size-md: 16px;
|
||||
$font-size-lg: 18px;
|
||||
$font-size-xl: 20px;
|
||||
|
||||
164
src/utils/index.js
Normal file
164
src/utils/index.js
Normal file
@@ -0,0 +1,164 @@
|
||||
/**
|
||||
* 工具函数集合
|
||||
*/
|
||||
|
||||
/**
|
||||
* 格式化日期
|
||||
* @param {Date|string|number} date 日期
|
||||
* @param {string} format 格式,默认 'YYYY-MM-DD HH:mm:ss'
|
||||
* @returns {string} 格式化后的日期字符串
|
||||
*/
|
||||
export function formatDate(date, format = 'YYYY-MM-DD HH:mm:ss') {
|
||||
const d = new Date(date)
|
||||
const year = d.getFullYear()
|
||||
const month = String(d.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(d.getDate()).padStart(2, '0')
|
||||
const hour = String(d.getHours()).padStart(2, '0')
|
||||
const minute = String(d.getMinutes()).padStart(2, '0')
|
||||
const second = String(d.getSeconds()).padStart(2, '0')
|
||||
|
||||
return format
|
||||
.replace('YYYY', year)
|
||||
.replace('MM', month)
|
||||
.replace('DD', day)
|
||||
.replace('HH', hour)
|
||||
.replace('mm', minute)
|
||||
.replace('ss', second)
|
||||
}
|
||||
|
||||
/**
|
||||
* 防抖函数
|
||||
* @param {Function} func 要防抖的函数
|
||||
* @param {number} wait 等待时间(毫秒)
|
||||
* @returns {Function} 防抖后的函数
|
||||
*/
|
||||
export function debounce(func, wait = 300) {
|
||||
let timeout
|
||||
return function executedFunction(...args) {
|
||||
const later = () => {
|
||||
clearTimeout(timeout)
|
||||
func(...args)
|
||||
}
|
||||
clearTimeout(timeout)
|
||||
timeout = setTimeout(later, wait)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 节流函数
|
||||
* @param {Function} func 要节流的函数
|
||||
* @param {number} limit 时间限制(毫秒)
|
||||
* @returns {Function} 节流后的函数
|
||||
*/
|
||||
export function throttle(func, limit = 300) {
|
||||
let inThrottle
|
||||
return function executedFunction(...args) {
|
||||
if (!inThrottle) {
|
||||
func(...args)
|
||||
inThrottle = true
|
||||
setTimeout(() => (inThrottle = false), limit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 深拷贝
|
||||
* @param {any} obj 要拷贝的对象
|
||||
* @returns {any} 拷贝后的对象
|
||||
*/
|
||||
export function deepClone(obj) {
|
||||
if (obj === null || typeof obj !== 'object') return obj
|
||||
if (obj instanceof Date) return new Date(obj.getTime())
|
||||
if (obj instanceof Array) return obj.map(item => deepClone(item))
|
||||
if (typeof obj === 'object') {
|
||||
const clonedObj = {}
|
||||
for (const key in obj) {
|
||||
if (obj.hasOwnProperty(key)) {
|
||||
clonedObj[key] = deepClone(obj[key])
|
||||
}
|
||||
}
|
||||
return clonedObj
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成唯一ID
|
||||
* @returns {string} 唯一ID
|
||||
*/
|
||||
export function generateId() {
|
||||
return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储数据到本地
|
||||
* @param {string} key 键名
|
||||
* @param {any} value 值
|
||||
*/
|
||||
export function setStorage(key, value) {
|
||||
try {
|
||||
uni.setStorageSync(key, value)
|
||||
} catch (e) {
|
||||
console.error('存储数据失败:', e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从本地获取数据
|
||||
* @param {string} key 键名
|
||||
* @param {any} defaultValue 默认值
|
||||
* @returns {any} 存储的值
|
||||
*/
|
||||
export function getStorage(key, defaultValue = null) {
|
||||
try {
|
||||
const value = uni.getStorageSync(key)
|
||||
return value !== '' ? value : defaultValue
|
||||
} catch (e) {
|
||||
console.error('获取数据失败:', e)
|
||||
return defaultValue
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除本地存储
|
||||
* @param {string} key 键名
|
||||
*/
|
||||
export function removeStorage(key) {
|
||||
try {
|
||||
uni.removeStorageSync(key)
|
||||
} catch (e) {
|
||||
console.error('删除数据失败:', e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示提示消息
|
||||
* @param {string} title 提示内容
|
||||
* @param {string} icon 图标类型
|
||||
* @param {number} duration 显示时长
|
||||
*/
|
||||
export function showToast(title, icon = 'none', duration = 2000) {
|
||||
uni.showToast({
|
||||
title,
|
||||
icon,
|
||||
duration
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示加载提示
|
||||
* @param {string} title 提示内容
|
||||
*/
|
||||
export function showLoading(title = '加载中...') {
|
||||
uni.showLoading({
|
||||
title,
|
||||
mask: true
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 隐藏加载提示
|
||||
*/
|
||||
export function hideLoading() {
|
||||
uni.hideLoading()
|
||||
}
|
||||
|
||||
205
src/utils/request.js
Normal file
205
src/utils/request.js
Normal file
@@ -0,0 +1,205 @@
|
||||
import axios from 'axios'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
|
||||
// 创建axios实例
|
||||
const service = axios.create({
|
||||
baseURL: import.meta.env.VITE_APP_BASE_API || (process.env.NODE_ENV === 'development' ? '/api' : 'https://your-api-domain.com'),
|
||||
timeout: 10000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json;charset=UTF-8'
|
||||
}
|
||||
})
|
||||
|
||||
// 请求拦截器
|
||||
service.interceptors.request.use(
|
||||
config => {
|
||||
// 在发送请求之前做些什么
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 添加token
|
||||
if (userStore.token) {
|
||||
config.headers.Authorization = `Bearer ${userStore.token}`
|
||||
}
|
||||
|
||||
// 显示loading(可根据需要自定义)
|
||||
if (config.showLoading !== false) {
|
||||
uni.showLoading({
|
||||
title: '加载中...',
|
||||
mask: true
|
||||
})
|
||||
}
|
||||
|
||||
return config
|
||||
},
|
||||
error => {
|
||||
// 对请求错误做些什么
|
||||
uni.hideLoading()
|
||||
console.error('请求错误:', error)
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
// 响应拦截器
|
||||
service.interceptors.response.use(
|
||||
response => {
|
||||
// 隐藏loading
|
||||
uni.hideLoading()
|
||||
|
||||
const res = response.data
|
||||
|
||||
// 如果返回的状态码为200,说明接口请求成功,可以正常拿到数据
|
||||
// 否则的话抛出错误
|
||||
if (res.code !== undefined && res.code !== 200) {
|
||||
// 根据不同的错误码,做相应的处理
|
||||
handleError(res.code, res.message || '请求失败')
|
||||
|
||||
// 返回一个reject的Promise,让错误信息能够被catch到
|
||||
return Promise.reject(new Error(res.message || '请求失败'))
|
||||
} else {
|
||||
// 返回成功的数据
|
||||
return res
|
||||
}
|
||||
},
|
||||
error => {
|
||||
// 隐藏loading
|
||||
uni.hideLoading()
|
||||
|
||||
// 对响应错误做点什么
|
||||
console.error('响应错误:', error)
|
||||
|
||||
if (error.response) {
|
||||
// 服务器返回了错误状态码
|
||||
const { status, data } = error.response
|
||||
|
||||
switch (status) {
|
||||
case 401:
|
||||
// 未授权,清除token并跳转到登录页
|
||||
handleError(401, '未授权,请重新登录')
|
||||
try {
|
||||
const userStore = useUserStore()
|
||||
userStore.logout()
|
||||
// 注意:如果登录页面不存在,请注释掉下面的跳转
|
||||
// uni.reLaunch({
|
||||
// url: '/pages/login/login'
|
||||
// })
|
||||
} catch (e) {
|
||||
console.error('退出登录失败:', e)
|
||||
}
|
||||
break
|
||||
case 403:
|
||||
handleError(403, '拒绝访问')
|
||||
break
|
||||
case 404:
|
||||
handleError(404, '请求错误,未找到该资源')
|
||||
break
|
||||
case 500:
|
||||
handleError(500, '服务器错误')
|
||||
break
|
||||
default:
|
||||
handleError(status, data?.message || `连接错误${status}`)
|
||||
}
|
||||
} else if (error.request) {
|
||||
// 请求已经发出,但没有收到响应
|
||||
handleError(-1, '网络连接失败,请检查网络')
|
||||
} else {
|
||||
// 发送请求时出了点问题
|
||||
handleError(-1, error.message || '请求失败')
|
||||
}
|
||||
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
// 错误处理函数
|
||||
function handleError(code, message) {
|
||||
// 可以根据不同的错误码做不同的处理
|
||||
uni.showToast({
|
||||
title: message,
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
})
|
||||
}
|
||||
|
||||
// 封装请求方法
|
||||
const request = {
|
||||
/**
|
||||
* GET请求
|
||||
* @param {string} url 请求地址
|
||||
* @param {object} params 请求参数
|
||||
* @param {object} config 请求配置
|
||||
*/
|
||||
get(url, params = {}, config = {}) {
|
||||
return service({
|
||||
method: 'get',
|
||||
url,
|
||||
params,
|
||||
...config
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* POST请求
|
||||
* @param {string} url 请求地址
|
||||
* @param {object} data 请求数据
|
||||
* @param {object} config 请求配置
|
||||
*/
|
||||
post(url, data = {}, config = {}) {
|
||||
return service({
|
||||
method: 'post',
|
||||
url,
|
||||
data,
|
||||
...config
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* PUT请求
|
||||
* @param {string} url 请求地址
|
||||
* @param {object} data 请求数据
|
||||
* @param {object} config 请求配置
|
||||
*/
|
||||
put(url, data = {}, config = {}) {
|
||||
return service({
|
||||
method: 'put',
|
||||
url,
|
||||
data,
|
||||
...config
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* DELETE请求
|
||||
* @param {string} url 请求地址
|
||||
* @param {object} params 请求参数
|
||||
* @param {object} config 请求配置
|
||||
*/
|
||||
delete(url, params = {}, config = {}) {
|
||||
return service({
|
||||
method: 'delete',
|
||||
url,
|
||||
params,
|
||||
...config
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
* @param {string} url 请求地址
|
||||
* @param {FormData} formData 表单数据
|
||||
* @param {object} config 请求配置
|
||||
*/
|
||||
upload(url, formData, config = {}) {
|
||||
return service({
|
||||
method: 'post',
|
||||
url,
|
||||
data: formData,
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
},
|
||||
...config
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default request
|
||||
|
||||
3
static/.gitkeep
Normal file
3
static/.gitkeep
Normal file
@@ -0,0 +1,3 @@
|
||||
# 静态资源目录
|
||||
# 请在此目录放置图片、字体等静态资源
|
||||
|
||||
26
tsconfig.json
Normal file
26
tsconfig.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"skipLibCheck": true,
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "preserve",
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
|
||||
11
tsconfig.node.json
Normal file
11
tsconfig.node.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.js"]
|
||||
}
|
||||
|
||||
36
vite.config.js
Normal file
36
vite.config.js
Normal file
@@ -0,0 +1,36 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import uni from '@dcloudio/vite-plugin-uni'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import path from 'path'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
vue(),
|
||||
uni()
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, 'src')
|
||||
}
|
||||
},
|
||||
css: {
|
||||
preprocessorOptions: {
|
||||
scss: {
|
||||
additionalData: `@import "@/styles/variables.scss";`
|
||||
}
|
||||
}
|
||||
},
|
||||
server: {
|
||||
port: 3000,
|
||||
open: true,
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://localhost:8080',
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/api/, '')
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user