feat: 创建项目,首次提交
@ -0,0 +1,3 @@
|
|||||||
|
module.exports = {
|
||||||
|
extends: ['@commitlint/config-conventional'],
|
||||||
|
}
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
# API 和 HTTP 请求规范
|
||||||
|
|
||||||
|
## HTTP 请求封装
|
||||||
|
- 可以使用 `简单http` 或者 `alova` 或者 `@tanstack/vue-query` 进行请求管理
|
||||||
|
- HTTP 配置在 [src/http/](mdc:src/http/) 目录下
|
||||||
|
- `简单http` - [src/http/http.ts](mdc:src/http/http.ts)
|
||||||
|
- `alova` - [src/http/alova.ts](mdc:src/http/alova.ts)
|
||||||
|
- `vue-query` - [src/http/vue-query.ts](mdc:src/http/vue-query.ts)
|
||||||
|
- 请求拦截器在 [src/http/interceptor.ts](mdc:src/http/interceptor.ts)
|
||||||
|
- 支持请求重试、缓存、错误处理
|
||||||
|
|
||||||
|
## API 接口规范
|
||||||
|
- API 接口定义在 [src/api/](mdc:src/api/) 目录下
|
||||||
|
- 按功能模块组织 API 文件
|
||||||
|
- 使用 TypeScript 定义请求和响应类型
|
||||||
|
- 支持 `简单http`、`alova` 和 `vue-query` 三种请求方式
|
||||||
|
|
||||||
|
|
||||||
|
## 示例代码结构
|
||||||
|
```typescript
|
||||||
|
// API 接口定义
|
||||||
|
export interface LoginParams {
|
||||||
|
username: string
|
||||||
|
password: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LoginResponse {
|
||||||
|
token: string
|
||||||
|
userInfo: UserInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
// alova 方式
|
||||||
|
export const login = (params: LoginParams) =>
|
||||||
|
http.Post<LoginResponse>('/api/login', params)
|
||||||
|
|
||||||
|
// vue-query 方式
|
||||||
|
export const useLogin = () => {
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (params: LoginParams) =>
|
||||||
|
http.post<LoginResponse>('/api/login', params)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 错误处理
|
||||||
|
- 统一错误处理在拦截器中配置
|
||||||
|
- 支持网络错误、业务错误、认证错误等
|
||||||
|
- 自动处理 token 过期和刷新
|
||||||
|
---
|
||||||
|
globs: src/api/*.ts,src/http/*.ts
|
||||||
|
---
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
# 开发工作流程
|
||||||
|
|
||||||
|
## 项目启动
|
||||||
|
1. 安装依赖:`pnpm install`
|
||||||
|
2. 开发环境:
|
||||||
|
- H5: `pnpm dev` 或 `pnpm dev:h5`
|
||||||
|
- 微信小程序: `pnpm dev:mp`
|
||||||
|
- 支付宝小程序: `pnpm dev:mp-alipay`
|
||||||
|
- APP: `pnpm dev:app`
|
||||||
|
|
||||||
|
## 代码规范
|
||||||
|
- 使用 ESLint 进行代码检查:`pnpm lint`
|
||||||
|
- 自动修复代码格式:`pnpm lint:fix`
|
||||||
|
- 使用 eslint 格式化代码
|
||||||
|
- 遵循 TypeScript 严格模式
|
||||||
|
|
||||||
|
## 构建和部署
|
||||||
|
- H5 构建:`pnpm build:h5`
|
||||||
|
- 微信小程序构建:`pnpm build:mp`
|
||||||
|
- 支付宝小程序构建:`pnpm build:mp-alipay`
|
||||||
|
- APP 构建:`pnpm build:app`
|
||||||
|
- 类型检查:`pnpm type-check`
|
||||||
|
|
||||||
|
## 开发工具
|
||||||
|
- 推荐使用 VSCode 编辑器
|
||||||
|
- 安装 Vue 和 TypeScript 相关插件
|
||||||
|
- 使用 uni-app 开发者工具调试小程序
|
||||||
|
- 使用 HBuilderX 调试 APP
|
||||||
|
|
||||||
|
## 调试技巧
|
||||||
|
- 使用 console.log 和 uni.showToast 调试
|
||||||
|
- 利用 Vue DevTools 调试组件状态
|
||||||
|
- 使用网络面板调试 API 请求
|
||||||
|
- 平台差异测试和兼容性检查
|
||||||
|
|
||||||
|
## 性能优化
|
||||||
|
- 使用懒加载和代码分割
|
||||||
|
- 优化图片和静态资源
|
||||||
|
- 减少不必要的重渲染
|
||||||
|
- 合理使用缓存策略
|
||||||
|
---
|
||||||
|
description: 开发工作流程和最佳实践指南
|
||||||
|
---
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
# 样式和 CSS 开发规范
|
||||||
|
|
||||||
|
## UnoCSS 原子化 CSS
|
||||||
|
- 项目使用 UnoCSS 作为原子化 CSS 框架
|
||||||
|
- 配置在 [uno.config.ts](mdc:uno.config.ts)
|
||||||
|
- 支持预设和自定义规则
|
||||||
|
- 优先使用原子化类名,减少自定义 CSS
|
||||||
|
|
||||||
|
## SCSS 规范
|
||||||
|
- 使用 SCSS 预处理器
|
||||||
|
- 样式文件使用 `lang="scss"` 和 `scoped` 属性
|
||||||
|
- 遵循 BEM 命名规范
|
||||||
|
- 使用变量和混入提高复用性
|
||||||
|
|
||||||
|
## 样式组织
|
||||||
|
- 全局样式在 [src/style/](mdc:src/style/) 目录下
|
||||||
|
- 组件样式使用 scoped 作用域
|
||||||
|
- 图标字体在 [src/style/iconfont.css](mdc:src/style/iconfont.css)
|
||||||
|
- 主题变量在 [src/uni_modules/uni-scss/](mdc:src/uni_modules/uni-scss/) 目录下
|
||||||
|
|
||||||
|
## 示例代码结构
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<view class="container flex flex-col items-center p-4">
|
||||||
|
<text class="title text-lg font-bold mb-2">标题</text>
|
||||||
|
<view class="content bg-gray-100 rounded-lg p-3">
|
||||||
|
<!-- 内容 -->
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.container {
|
||||||
|
min-height: 100vh;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 600rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
## 响应式设计
|
||||||
|
- 使用 rpx 单位适配不同屏幕
|
||||||
|
- 支持横屏和竖屏布局
|
||||||
|
- 使用 flexbox 和 grid 布局
|
||||||
|
- 考虑不同平台的样式差异
|
||||||
|
---
|
||||||
|
globs: *.vue,*.scss,*.css
|
||||||
|
---
|
||||||
@ -0,0 +1,62 @@
|
|||||||
|
# uni-app 开发规范
|
||||||
|
|
||||||
|
## 页面开发
|
||||||
|
- 页面文件放在 [src/pages/](mdc:src/pages/) 目录下
|
||||||
|
- 使用约定式路由,文件名即路由路径
|
||||||
|
- 页面配置在仅需要在 宏`definePage` 中配置标题等内容即可,会自动生成到 `pages.json` 中
|
||||||
|
|
||||||
|
## 组件开发
|
||||||
|
- 组件文件放在 [src/components/](mdc:src/components/) 或者 [src/pages/xx/components/](mdc:src/pages/xx/components/) 目录下
|
||||||
|
- 使用 uni-app 内置组件和第三方组件库
|
||||||
|
- 支持 wot-ui\uview-pro\uv-ui\sard-ui\uview-plus 等多种第三方组件库 和 z-paging 组件
|
||||||
|
- 自定义组件遵循 uni-app 组件规范
|
||||||
|
|
||||||
|
## 平台适配
|
||||||
|
- 使用条件编译处理平台差异
|
||||||
|
- 支持 H5、小程序、APP 多平台
|
||||||
|
- 注意各平台的 API 差异
|
||||||
|
- 使用 uni.xxx API 替代原生 API
|
||||||
|
|
||||||
|
## 示例代码结构
|
||||||
|
```vue
|
||||||
|
<script setup lang="ts">
|
||||||
|
// #ifdef H5
|
||||||
|
import { h5Api } from '@/utils/h5'
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
import { mpApi } from '@/utils/mp'
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
// #ifdef H5
|
||||||
|
h5Api.showToast('H5 平台')
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
mpApi.showToast('微信小程序')
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<view class="page">
|
||||||
|
<!-- uni-app 组件 -->
|
||||||
|
<button @click="handleClick">点击</button>
|
||||||
|
|
||||||
|
<!-- 条件渲染 -->
|
||||||
|
<!-- #ifdef H5 -->
|
||||||
|
<view>H5 特有内容</view>
|
||||||
|
<!-- #endif -->
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 生命周期
|
||||||
|
- 使用 uni-app 页面生命周期
|
||||||
|
- onLoad、onShow、onReady、onHide、onUnload
|
||||||
|
- 组件生命周期遵循 Vue3 规范
|
||||||
|
- 注意页面栈和导航管理
|
||||||
|
---
|
||||||
|
globs: src/pages/*.vue,src/components/*.vue
|
||||||
|
---
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
categories:
|
||||||
|
- title: 🚀 新功能
|
||||||
|
labels: [feat, feature]
|
||||||
|
- title: 🛠️ 修复
|
||||||
|
labels: [fix, bugfix]
|
||||||
|
- title: 💅 样式
|
||||||
|
labels: [style]
|
||||||
|
- title: 📄 文档
|
||||||
|
labels: [docs]
|
||||||
|
- title: ⚡️ 性能
|
||||||
|
labels: [perf]
|
||||||
|
- title: 🧪 测试
|
||||||
|
labels: [test]
|
||||||
|
- title: ♻️ 重构
|
||||||
|
labels: [refactor]
|
||||||
|
- title: 📦 构建
|
||||||
|
labels: [build]
|
||||||
|
- title: 🚨 补丁
|
||||||
|
labels: [patch, hotfix]
|
||||||
|
- title: 🌐 发布
|
||||||
|
labels: [release, publish]
|
||||||
|
- title: 🔧 流程
|
||||||
|
labels: [ci, cd, workflow]
|
||||||
|
- title: ⚙️ 配置
|
||||||
|
labels: [config, chore]
|
||||||
|
- title: 📁 文件
|
||||||
|
labels: [file]
|
||||||
|
- title: 🎨 格式化
|
||||||
|
labels: [format]
|
||||||
|
- title: 🔀 其他
|
||||||
|
labels: [other, misc]
|
||||||
@ -0,0 +1,188 @@
|
|||||||
|
name: Auto Merge Main to Other Branches
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
workflow_dispatch: # 手动触发
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# merge-to-release:
|
||||||
|
# name: Merge main into release
|
||||||
|
# runs-on: ubuntu-latest
|
||||||
|
# steps:
|
||||||
|
# - name: Checkout repository
|
||||||
|
# uses: actions/checkout@v4
|
||||||
|
# with:
|
||||||
|
# fetch-depth: 0
|
||||||
|
# token: ${{ secrets.GH_TOKEN_AUTO_MERGE }}
|
||||||
|
|
||||||
|
# - name: Merge main into release
|
||||||
|
# run: |
|
||||||
|
# git config user.name "GitHub Actions"
|
||||||
|
# git config user.email "actions@github.com"
|
||||||
|
# git checkout release
|
||||||
|
# git merge main --no-ff -m "Auto merge main into release"
|
||||||
|
# git push origin release
|
||||||
|
|
||||||
|
merge-to-i18n:
|
||||||
|
name: Merge main into i18n
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
token: ${{ secrets.GH_TOKEN_AUTO_MERGE }}
|
||||||
|
|
||||||
|
- name: Merge main into i18n
|
||||||
|
run: |
|
||||||
|
git config user.name "GitHub Actions"
|
||||||
|
git config user.email "actions@github.com"
|
||||||
|
git checkout i18n
|
||||||
|
git merge main --no-ff -m "Auto merge main into i18n"
|
||||||
|
git push origin i18n
|
||||||
|
|
||||||
|
merge-to-base-sard-ui:
|
||||||
|
name: Merge main into base-sard-ui
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
token: ${{ secrets.GH_TOKEN_AUTO_MERGE }}
|
||||||
|
|
||||||
|
- name: Merge main into base-sard-ui
|
||||||
|
run: |
|
||||||
|
git config user.name "GitHub Actions"
|
||||||
|
git config user.email "actions@github.com"
|
||||||
|
git checkout base-sard-ui
|
||||||
|
git merge main --no-ff -m "Auto merge main into base-sard-ui"
|
||||||
|
git push origin base-sard-ui
|
||||||
|
|
||||||
|
merge-to-base-uv-ui:
|
||||||
|
name: Merge main into base-uv-ui
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
token: ${{ secrets.GH_TOKEN_AUTO_MERGE }}
|
||||||
|
|
||||||
|
- name: Merge main into base-uv-ui
|
||||||
|
run: |
|
||||||
|
git config user.name "GitHub Actions"
|
||||||
|
git config user.email "actions@github.com"
|
||||||
|
git checkout base-uv-ui
|
||||||
|
git merge main --no-ff -m "Auto merge main into base-uv-ui"
|
||||||
|
git push origin base-uv-ui
|
||||||
|
|
||||||
|
merge-to-base-uview-pro:
|
||||||
|
name: Merge main into base-uview-pro
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
token: ${{ secrets.GH_TOKEN_AUTO_MERGE }}
|
||||||
|
|
||||||
|
- name: Merge main into base-uview-pro
|
||||||
|
run: |
|
||||||
|
git config user.name "GitHub Actions"
|
||||||
|
git config user.email "actions@github.com"
|
||||||
|
git checkout base-uview-pro
|
||||||
|
git merge main --no-ff -m "Auto merge main into base-uview-pro"
|
||||||
|
git push origin base-uview-pro
|
||||||
|
|
||||||
|
merge-to-base-uview-plus:
|
||||||
|
name: Merge main into base-uview-plus
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
token: ${{ secrets.GH_TOKEN_AUTO_MERGE }}
|
||||||
|
|
||||||
|
- name: Merge main into base-uview-plus
|
||||||
|
run: |
|
||||||
|
git config user.name "GitHub Actions"
|
||||||
|
git config user.email "actions@github.com"
|
||||||
|
git checkout base-uview-plus
|
||||||
|
git merge main --no-ff -m "Auto merge main into base-uview-plus"
|
||||||
|
git push origin base-uview-plus
|
||||||
|
|
||||||
|
# merge-to-base-tm-ui:
|
||||||
|
# name: Merge main into base-tm-ui
|
||||||
|
# runs-on: ubuntu-latest
|
||||||
|
# steps:
|
||||||
|
# - name: Checkout repository
|
||||||
|
# uses: actions/checkout@v4
|
||||||
|
# with:
|
||||||
|
# fetch-depth: 0
|
||||||
|
# token: ${{ secrets.GH_TOKEN_AUTO_MERGE }}
|
||||||
|
|
||||||
|
# - name: Merge main into base-tm-ui
|
||||||
|
# run: |
|
||||||
|
# git config user.name "GitHub Actions"
|
||||||
|
# git config user.email "actions@github.com"
|
||||||
|
# git checkout base-tm-ui
|
||||||
|
# git merge main --no-ff -m "Auto merge main into base-tm-ui"
|
||||||
|
# git push origin base-tm-ui
|
||||||
|
|
||||||
|
merge-to-base-skiyee-ui:
|
||||||
|
name: Merge main into base-skiyee-ui
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
token: ${{ secrets.GH_TOKEN_AUTO_MERGE }}
|
||||||
|
|
||||||
|
- name: Merge main into base-skiyee-ui
|
||||||
|
run: |
|
||||||
|
git config user.name "GitHub Actions"
|
||||||
|
git config user.email "actions@github.com"
|
||||||
|
git checkout base-skiyee-ui
|
||||||
|
git merge main --no-ff -m "Auto merge main into base-skiyee-ui"
|
||||||
|
git push origin base-skiyee-ui
|
||||||
|
|
||||||
|
merge-to-main-v4:
|
||||||
|
name: Merge main into main-v4
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
token: ${{ secrets.GH_TOKEN_AUTO_MERGE }}
|
||||||
|
|
||||||
|
- name: Merge main into main-v4
|
||||||
|
run: |
|
||||||
|
git config user.name "GitHub Actions"
|
||||||
|
git config user.email "actions@github.com"
|
||||||
|
git checkout main-v4
|
||||||
|
git merge main --no-ff -m "Auto merge main into main-v4"
|
||||||
|
git push origin main-v4
|
||||||
|
|
||||||
|
merge-to-i18n-v4:
|
||||||
|
name: Merge main into i18n-v4
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
token: ${{ secrets.GH_TOKEN_AUTO_MERGE }}
|
||||||
|
|
||||||
|
- name: Merge main into i18n-v4
|
||||||
|
run: |
|
||||||
|
git config user.name "GitHub Actions"
|
||||||
|
git config user.email "actions@github.com"
|
||||||
|
git checkout i18n-v4
|
||||||
|
git merge main --no-ff -m "Auto merge main into i18n-v4"
|
||||||
|
git push origin i18n-v4
|
||||||
@ -0,0 +1,119 @@
|
|||||||
|
name: Auto Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pull-requests: read
|
||||||
|
issues: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Install yq
|
||||||
|
run: sudo snap install yq
|
||||||
|
|
||||||
|
- name: Generate changelog
|
||||||
|
id: changelog
|
||||||
|
env:
|
||||||
|
CONFIG_FILE: .github/release.yml
|
||||||
|
run: |
|
||||||
|
# 解析配置文件
|
||||||
|
declare -A category_map
|
||||||
|
while IFS=";" read -r title labels; do
|
||||||
|
for label in $labels; do
|
||||||
|
category_map[$label]="$title"
|
||||||
|
done
|
||||||
|
done < <(yq -o=tsv '.categories[] | [.title, (.labels | join(" "))] | join(";")' $CONFIG_FILE)
|
||||||
|
# 获取版本范围
|
||||||
|
mapfile -t tags < <(git tag -l --sort=-version:refname)
|
||||||
|
current_tag=${tags[0]}
|
||||||
|
previous_tag=${tags[1]:-}
|
||||||
|
if [[ -z "$previous_tag" ]]; then
|
||||||
|
commit_range="$current_tag"
|
||||||
|
echo "首次发布版本: $current_tag"
|
||||||
|
else
|
||||||
|
commit_range="$previous_tag..$current_tag"
|
||||||
|
echo "版本范围: $commit_range"
|
||||||
|
fi
|
||||||
|
# 获取所有符合规范的提交
|
||||||
|
commits=$(git log --pretty=format:"%s|%h" "$commit_range")
|
||||||
|
# 生成分类日志
|
||||||
|
declare -A log_entries
|
||||||
|
while IFS="|" read -r subject hash; do
|
||||||
|
# type=$(echo "$subject" | cut -d':' -f1 | tr -d ' ')
|
||||||
|
type=$(echo "$subject" | sed -E 's/^([[:alnum:]]+)(\(.*\))?:.*/\1/' | tr -d ' ')
|
||||||
|
found=0
|
||||||
|
for label in "${!category_map[@]}"; do
|
||||||
|
if [[ "$type" == "$label" ]]; then
|
||||||
|
entry="- ${subject} (${hash:0:7})"
|
||||||
|
log_entries[${category_map[$label]}]+="$entry"$'\n'
|
||||||
|
found=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [[ $found -eq 0 ]]; then
|
||||||
|
entry="- ${subject} (${hash:0:7})"
|
||||||
|
log_entries["其他"]+="$entry"$'\n'
|
||||||
|
fi
|
||||||
|
done <<< "$commits"
|
||||||
|
|
||||||
|
# 统计提交数量
|
||||||
|
commit_count=$(git log --oneline "$commit_range" | wc -l)
|
||||||
|
# 统计受影响的文件数量
|
||||||
|
file_count=$(git diff --name-only "$commit_range" | wc -l)
|
||||||
|
# 统计贡献者信息
|
||||||
|
contributor_stats=$(git shortlog -sn "$commit_range")
|
||||||
|
contributor_notes=""
|
||||||
|
while IFS= read -r line; do
|
||||||
|
commits=$(echo "$line" | awk '{print $1}')
|
||||||
|
name=$(echo "$line" | awk '{$1=""; print $0}' | sed 's/^ //')
|
||||||
|
contributor_notes+="- @${name} (${commits} commits)\n"
|
||||||
|
done <<< "$contributor_stats"
|
||||||
|
# 构建输出内容
|
||||||
|
release_notes="## 版本更新日志 ($current_tag)\n\n"
|
||||||
|
while IFS= read -r category; do
|
||||||
|
if [[ -n "${log_entries[$category]}" ]]; then
|
||||||
|
release_notes+="### $category\n${log_entries[$category]}\n"
|
||||||
|
fi
|
||||||
|
done < <(yq '.categories[].title' $CONFIG_FILE)
|
||||||
|
# 构建输出内容
|
||||||
|
release_notes="## 版本更新日志 ($current_tag)\n\n"
|
||||||
|
current_date=$(date +"%Y-%m-%d")
|
||||||
|
# 添加发布日期和下载统计信息
|
||||||
|
release_notes+=" ### 📅 发布日期: ${current_date}\n"
|
||||||
|
while IFS= read -r category; do
|
||||||
|
if [[ -n "${log_entries[$category]}" ]]; then
|
||||||
|
release_notes+="### $category\n${log_entries[$category]}\n"
|
||||||
|
fi
|
||||||
|
done < <(yq '.categories[].title' $CONFIG_FILE)
|
||||||
|
|
||||||
|
# 添加统计信息
|
||||||
|
release_notes+="### 📊 统计信息\n"
|
||||||
|
release_notes+="- 本次发布包含 ${commit_count} 个提交\n"
|
||||||
|
release_notes+="- 影响 ${file_count} 个文件\n\n"
|
||||||
|
# 添加贡献者信息
|
||||||
|
release_notes+="### 👥 贡献者\n"
|
||||||
|
release_notes+="感谢这些优秀的贡献者(按提交次数排序):\n"
|
||||||
|
release_notes+="${contributor_notes}\n"
|
||||||
|
release_notes+="---\n"
|
||||||
|
# 写入文件
|
||||||
|
echo -e "$release_notes" > changelog.md
|
||||||
|
echo "生成日志内容:"
|
||||||
|
cat changelog.md
|
||||||
|
- name: Create Release
|
||||||
|
uses: ncipollo/release-action@v1
|
||||||
|
with:
|
||||||
|
generateReleaseNotes: false
|
||||||
|
bodyFile: changelog.md
|
||||||
|
tag: ${{ github.ref_name }}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
npx --no-install commitlint --edit "$1"
|
||||||
@ -0,0 +1 @@
|
|||||||
|
npx lint-staged --allow-empty
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
# registry = https://registry.npmjs.org
|
||||||
|
registry = https://registry.npmmirror.com
|
||||||
|
|
||||||
|
strict-peer-dependencies=false
|
||||||
|
auto-install-peers=true
|
||||||
|
shamefully-hoist=true
|
||||||
|
ignore-workspace-root-check=true
|
||||||
|
install-workspace-root=true
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"vue.volar",
|
||||||
|
"esbenp.prettier-vscode",
|
||||||
|
"dbaeumer.vscode-eslint",
|
||||||
|
"antfu.unocss",
|
||||||
|
"antfu.iconify",
|
||||||
|
"evils.uniapp-vscode",
|
||||||
|
"uni-helper.uni-helper-vscode",
|
||||||
|
"uni-helper.uni-app-schemas-vscode",
|
||||||
|
"uni-helper.uni-highlight-vscode",
|
||||||
|
"uni-helper.uni-ui-snippets-vscode",
|
||||||
|
"uni-helper.uni-app-snippets-vscode",
|
||||||
|
"streetsidesoftware.code-spell-checker",
|
||||||
|
"christian-kohler.path-intellisense"
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -0,0 +1,96 @@
|
|||||||
|
{
|
||||||
|
// 配置语言的文件关联
|
||||||
|
"files.associations": {
|
||||||
|
"pages.json": "jsonc", // pages.json 可以写注释
|
||||||
|
"manifest.json": "jsonc" // manifest.json 可以写注释
|
||||||
|
},
|
||||||
|
|
||||||
|
"stylelint.enable": false, // 禁用 stylelint
|
||||||
|
"css.validate": false, // 禁用 CSS 内置验证
|
||||||
|
"scss.validate": false, // 禁用 SCSS 内置验证
|
||||||
|
"less.validate": false, // 禁用 LESS 内置验证
|
||||||
|
|
||||||
|
"typescript.tsdk": "node_modules\\typescript\\lib",
|
||||||
|
"explorer.fileNesting.enabled": true,
|
||||||
|
"explorer.fileNesting.expand": false,
|
||||||
|
"explorer.fileNesting.patterns": {
|
||||||
|
"README.md": "index.html,favicon.ico,robots.txt,CHANGELOG.md",
|
||||||
|
"docker.md": "Dockerfile,docker*.md,nginx*,.dockerignore",
|
||||||
|
"pages.config.ts": "manifest.config.ts,openapi-ts-request.config.ts",
|
||||||
|
"package.json": "tsconfig.json,pnpm-lock.yaml,pnpm-workspace.yaml,LICENSE,.gitattributes,.gitignore,.gitpod.yml,CNAME,.npmrc,.browserslistrc",
|
||||||
|
"eslint.config.mjs": ".commitlintrc.*,.prettier*,.editorconfig,.commitlint.cjs,.eslint*"
|
||||||
|
},
|
||||||
|
|
||||||
|
// Disable the default formatter, use eslint instead
|
||||||
|
"prettier.enable": false,
|
||||||
|
"editor.formatOnSave": false,
|
||||||
|
|
||||||
|
// Auto fix
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.fixAll.eslint": "explicit",
|
||||||
|
"source.organizeImports": "never"
|
||||||
|
},
|
||||||
|
|
||||||
|
// Silent the stylistic rules in you IDE, but still auto fix them
|
||||||
|
"eslint.rules.customizations": [
|
||||||
|
{ "rule": "style/*", "severity": "off", "fixable": true },
|
||||||
|
{ "rule": "format/*", "severity": "off", "fixable": true },
|
||||||
|
{ "rule": "*-indent", "severity": "off", "fixable": true },
|
||||||
|
{ "rule": "*-spacing", "severity": "off", "fixable": true },
|
||||||
|
{ "rule": "*-spaces", "severity": "off", "fixable": true },
|
||||||
|
{ "rule": "*-order", "severity": "off", "fixable": true },
|
||||||
|
{ "rule": "*-dangle", "severity": "off", "fixable": true },
|
||||||
|
{ "rule": "*-newline", "severity": "off", "fixable": true },
|
||||||
|
{ "rule": "*quotes", "severity": "off", "fixable": true },
|
||||||
|
{ "rule": "*semi", "severity": "off", "fixable": true }
|
||||||
|
],
|
||||||
|
|
||||||
|
// Enable eslint for all supported languages
|
||||||
|
"eslint.validate": [
|
||||||
|
"javascript",
|
||||||
|
"javascriptreact",
|
||||||
|
"typescript",
|
||||||
|
"typescriptreact",
|
||||||
|
"vue",
|
||||||
|
"html",
|
||||||
|
"markdown",
|
||||||
|
"json",
|
||||||
|
"jsonc",
|
||||||
|
"yaml",
|
||||||
|
"toml",
|
||||||
|
"xml",
|
||||||
|
"gql",
|
||||||
|
"graphql",
|
||||||
|
"astro",
|
||||||
|
"svelte",
|
||||||
|
"css",
|
||||||
|
"less",
|
||||||
|
"scss",
|
||||||
|
"pcss",
|
||||||
|
"postcss"
|
||||||
|
],
|
||||||
|
"cSpell.words": [
|
||||||
|
"alova",
|
||||||
|
"Aplipay",
|
||||||
|
"attributify",
|
||||||
|
"chooseavatar",
|
||||||
|
"climblee",
|
||||||
|
"commitlint",
|
||||||
|
"dcloudio",
|
||||||
|
"iconfont",
|
||||||
|
"oxlint",
|
||||||
|
"qrcode",
|
||||||
|
"refresherrefresh",
|
||||||
|
"scrolltolower",
|
||||||
|
"tabbar",
|
||||||
|
"Toutiao",
|
||||||
|
"uniapp",
|
||||||
|
"unibest",
|
||||||
|
"unocss",
|
||||||
|
"uview",
|
||||||
|
"uvui",
|
||||||
|
"Wechat",
|
||||||
|
"WechatMiniprogram",
|
||||||
|
"Weixin"
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -0,0 +1,77 @@
|
|||||||
|
{
|
||||||
|
// Place your unibest 工作区 snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and
|
||||||
|
// description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope
|
||||||
|
// is left empty or omitted, the snippet gets applied to all languages. The prefix is what is
|
||||||
|
// used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
|
||||||
|
// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders.
|
||||||
|
// Placeholders with the same ids are connected.
|
||||||
|
// Example:
|
||||||
|
// "Print to console": {
|
||||||
|
// "scope": "javascript,typescript",
|
||||||
|
// "prefix": "log",
|
||||||
|
// "body": [
|
||||||
|
// "console.log('$1');",
|
||||||
|
// "$2"
|
||||||
|
// ],
|
||||||
|
// "description": "Log output to console"
|
||||||
|
// }
|
||||||
|
"Print unibest Vue3 SFC": {
|
||||||
|
"scope": "vue",
|
||||||
|
"prefix": "v3",
|
||||||
|
"body": [
|
||||||
|
"<script lang=\"ts\" setup>",
|
||||||
|
"definePage({",
|
||||||
|
" style: {",
|
||||||
|
" navigationBarTitleText: '$1',",
|
||||||
|
" },",
|
||||||
|
"})",
|
||||||
|
"</script>\n",
|
||||||
|
"<template>",
|
||||||
|
" <view class=\"\">$3</view>",
|
||||||
|
"</template>\n",
|
||||||
|
"<style lang=\"scss\" scoped>",
|
||||||
|
"//$4",
|
||||||
|
"</style>\n",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"Print unibest style": {
|
||||||
|
"scope": "vue",
|
||||||
|
"prefix": "st",
|
||||||
|
"body": [
|
||||||
|
"<style lang=\"scss\" scoped>",
|
||||||
|
"//",
|
||||||
|
"</style>\n"
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"Print unibest script": {
|
||||||
|
"scope": "vue",
|
||||||
|
"prefix": "sc",
|
||||||
|
"body": [
|
||||||
|
"<script lang=\"ts\" setup>",
|
||||||
|
"//$1",
|
||||||
|
"</script>\n"
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"Print unibest script with definePage": {
|
||||||
|
"scope": "vue",
|
||||||
|
"prefix": "scdp",
|
||||||
|
"body": [
|
||||||
|
"<script lang=\"ts\" setup>",
|
||||||
|
"definePage({",
|
||||||
|
" style: {",
|
||||||
|
" navigationBarTitleText: '$1',",
|
||||||
|
" },",
|
||||||
|
"})",
|
||||||
|
"</script>\n"
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"Print unibest template": {
|
||||||
|
"scope": "vue",
|
||||||
|
"prefix": "te",
|
||||||
|
"body": [
|
||||||
|
"<template>",
|
||||||
|
" <view class=\"\">$1</view>",
|
||||||
|
"</template>\n"
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2025 菲鸽
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
# 参考代码
|
||||||
|
|
||||||
|
部分代码片段,供参考。
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
# 依赖目录
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# 版本控制
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
|
||||||
|
# 构建产物
|
||||||
|
/dist
|
||||||
|
|
||||||
|
# 开发工具配置
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
.trae/
|
||||||
|
.cursor/
|
||||||
|
|
||||||
|
# 其他配置文件
|
||||||
|
.github/
|
||||||
|
.husky/
|
||||||
|
|
||||||
|
# 日志文件
|
||||||
|
logs/
|
||||||
|
|
||||||
|
# 缓存文件
|
||||||
|
.cache/
|
||||||
|
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
|
||||||
|
# 操作系统文件
|
||||||
|
.DS_Store
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
# 变量必须以 VITE_ 为前缀才能暴露给外部读取
|
||||||
|
NODE_ENV = 'development'
|
||||||
|
# 是否去除console 和 debugger
|
||||||
|
VITE_DELETE_CONSOLE = false
|
||||||
|
# 是否开启sourcemap
|
||||||
|
VITE_SHOW_SOURCEMAP = false
|
||||||
|
|
||||||
|
# 后台请求地址
|
||||||
|
# VITE_SERVER_BASEURL = 'https://dev.xxx.com'
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
# 变量必须以 VITE_ 为前缀才能暴露给外部读取
|
||||||
|
NODE_ENV = 'production'
|
||||||
|
# 是否去除console 和 debugger
|
||||||
|
VITE_DELETE_CONSOLE = true
|
||||||
|
# 是否开启sourcemap
|
||||||
|
VITE_SHOW_SOURCEMAP = false
|
||||||
|
|
||||||
|
# 后台请求地址
|
||||||
|
# VITE_SERVER_BASEURL = 'https://prod.xxx.com'
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
# 变量必须以 VITE_ 为前缀才能暴露给外部读取
|
||||||
|
NODE_ENV = 'development'
|
||||||
|
# 是否去除console 和 debugger
|
||||||
|
VITE_DELETE_CONSOLE = false
|
||||||
|
# 是否开启sourcemap
|
||||||
|
VITE_SHOW_SOURCEMAP = false
|
||||||
|
|
||||||
|
# 后台请求地址
|
||||||
|
# VITE_SERVER_BASEURL = 'https://test.xxx.com'
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
import uniHelper from '@uni-helper/eslint-config'
|
||||||
|
|
||||||
|
export default uniHelper({
|
||||||
|
unocss: true,
|
||||||
|
vue: true,
|
||||||
|
markdown: false,
|
||||||
|
ignores: [
|
||||||
|
// 忽略uni_modules目录
|
||||||
|
'**/uni_modules/',
|
||||||
|
// 忽略原生插件目录
|
||||||
|
'**/nativeplugins/',
|
||||||
|
'dist',
|
||||||
|
// unplugin-auto-import 生成的类型文件,每次提交都改变,所以加入这里吧,与 .gitignore 配合使用
|
||||||
|
'auto-import.d.ts',
|
||||||
|
// vite-plugin-uni-pages 生成的类型文件,每次切换分支都一堆不同的,所以直接 .gitignore
|
||||||
|
'uni-pages.d.ts',
|
||||||
|
// 插件生成的文件
|
||||||
|
'src/pages.json',
|
||||||
|
'src/manifest.json',
|
||||||
|
// 忽略自动生成文件
|
||||||
|
'src/service/**',
|
||||||
|
],
|
||||||
|
// https://eslint-config.antfu.me/rules
|
||||||
|
rules: {
|
||||||
|
'no-useless-return': 'off',
|
||||||
|
'no-console': 'off',
|
||||||
|
'no-unused-vars': 'off',
|
||||||
|
'vue/no-unused-refs': 'off',
|
||||||
|
'unused-imports/no-unused-vars': 'off',
|
||||||
|
'eslint-comments/no-unlimited-disable': 'off',
|
||||||
|
'jsdoc/check-param-names': 'off',
|
||||||
|
'jsdoc/require-returns-description': 'off',
|
||||||
|
'ts/no-empty-object-type': 'off',
|
||||||
|
'no-extend-native': 'off',
|
||||||
|
'ts/no-require-imports': 'off',
|
||||||
|
'import/first': 'off',
|
||||||
|
'vue/singleline-html-element-content-newline': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
externalIgnores: ['text'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
// vue SFC 调换顺序改这里
|
||||||
|
'vue/block-order': ['error', {
|
||||||
|
order: [['script', 'template'], 'style'],
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
formatters: {
|
||||||
|
/**
|
||||||
|
* Format CSS, LESS, SCSS files, also the `<style>` blocks in Vue
|
||||||
|
* By default uses Prettier
|
||||||
|
*/
|
||||||
|
css: true,
|
||||||
|
/**
|
||||||
|
* Format HTML files
|
||||||
|
* By default uses Prettier
|
||||||
|
*/
|
||||||
|
html: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
After Width: | Height: | Size: 14 KiB |
@ -0,0 +1,26 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html build-time="%BUILD_TIME%">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon" />
|
||||||
|
<script>
|
||||||
|
var coverSupport =
|
||||||
|
'CSS' in window &&
|
||||||
|
typeof CSS.supports === 'function' &&
|
||||||
|
(CSS.supports('top: env(a)') || CSS.supports('top: constant(a)'))
|
||||||
|
document.write(
|
||||||
|
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
|
||||||
|
(coverSupport ? ', viewport-fit=cover' : '') +
|
||||||
|
'" />',
|
||||||
|
)
|
||||||
|
</script>
|
||||||
|
<title>%VITE_APP_TITLE%</title>
|
||||||
|
<!--preload-links-->
|
||||||
|
<!--app-context-->
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="app"><!--app-html--></div>
|
||||||
|
<script type="module" src="/src/main.ts"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
import type { GenerateServiceProps } from 'openapi-ts-request'
|
||||||
|
|
||||||
|
export default [
|
||||||
|
{
|
||||||
|
schemaPath: 'https://ukw0y1.laf.run/unibest-opapi-test.json',
|
||||||
|
serversPath: './src/service',
|
||||||
|
requestLibPath: `import request from '@/http/vue-query';\n import { CustomRequestOptions } from '@/http/types';`,
|
||||||
|
requestOptionsType: 'CustomRequestOptions',
|
||||||
|
isGenReactQuery: false,
|
||||||
|
reactQueryMode: 'vue',
|
||||||
|
isGenJavaScript: false,
|
||||||
|
},
|
||||||
|
] as GenerateServiceProps[]
|
||||||
@ -0,0 +1,194 @@
|
|||||||
|
{
|
||||||
|
"name": "pest_uni",
|
||||||
|
"type": "module",
|
||||||
|
"version": "3.18.8",
|
||||||
|
"unibest-version": "3.18.8",
|
||||||
|
"update-time": "2025-10-13",
|
||||||
|
"packageManager": "pnpm@10.10.0",
|
||||||
|
"description": "unibest - 最好的 uniapp 开发模板",
|
||||||
|
"generate-time": "用户创建项目时生成",
|
||||||
|
"author": {
|
||||||
|
"name": "feige996",
|
||||||
|
"zhName": "菲鸽",
|
||||||
|
"email": "1020103647@qq.com",
|
||||||
|
"github": "https://github.com/feige996",
|
||||||
|
"gitee": "https://gitee.com/feige996"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"homepage": "https://unibest.tech",
|
||||||
|
"repository": "https://github.com/feige996/unibest",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/feige996/unibest/issues",
|
||||||
|
"url-old": "https://github.com/codercup/unibest/issues"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20",
|
||||||
|
"pnpm": ">=9"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"preinstall": "npx only-allow pnpm",
|
||||||
|
"uvm": "npx @dcloudio/uvm@latest",
|
||||||
|
"uvm-rm": "node ./scripts/postupgrade.js",
|
||||||
|
"postuvm": "echo upgrade uni-app success!",
|
||||||
|
"dev:app": "uni -p app",
|
||||||
|
"dev:app:test": "uni -p app --mode test",
|
||||||
|
"dev:app:prod": "uni -p app --mode production",
|
||||||
|
"dev:app-android": "uni -p app-android",
|
||||||
|
"dev:app-ios": "uni -p app-ios",
|
||||||
|
"dev:custom": "uni -p",
|
||||||
|
"dev": "uni",
|
||||||
|
"dev:test": "uni --mode test",
|
||||||
|
"dev:prod": "uni --mode production",
|
||||||
|
"dev:h5": "uni",
|
||||||
|
"dev:h5:test": "uni --mode test",
|
||||||
|
"dev:h5:prod": "uni --mode production",
|
||||||
|
"dev:h5:ssr": "uni --ssr",
|
||||||
|
"dev:mp": "uni -p mp-weixin",
|
||||||
|
"dev:mp:test": "uni -p mp-weixin --mode test",
|
||||||
|
"dev:mp:prod": "uni -p mp-weixin --mode production",
|
||||||
|
"dev:mp-alipay": "uni -p mp-alipay",
|
||||||
|
"dev:mp-baidu": "uni -p mp-baidu",
|
||||||
|
"dev:mp-jd": "uni -p mp-jd",
|
||||||
|
"dev:mp-kuaishou": "uni -p mp-kuaishou",
|
||||||
|
"dev:mp-lark": "uni -p mp-lark",
|
||||||
|
"dev:mp-qq": "uni -p mp-qq",
|
||||||
|
"dev:mp-toutiao": "uni -p mp-toutiao",
|
||||||
|
"dev:mp-weixin": "uni -p mp-weixin",
|
||||||
|
"dev:mp-xhs": "uni -p mp-xhs",
|
||||||
|
"dev:quickapp-webview": "uni -p quickapp-webview",
|
||||||
|
"dev:quickapp-webview-huawei": "uni -p quickapp-webview-huawei",
|
||||||
|
"dev:quickapp-webview-union": "uni -p quickapp-webview-union",
|
||||||
|
"build:app": "uni build -p app",
|
||||||
|
"build:app:test": "uni build -p app --mode test",
|
||||||
|
"build:app:prod": "uni build -p app --mode production",
|
||||||
|
"build:app-android": "uni build -p app-android",
|
||||||
|
"build:app-ios": "uni build -p app-ios",
|
||||||
|
"build:custom": "uni build -p",
|
||||||
|
"build:h5": "uni build",
|
||||||
|
"build:h5:test": "uni build --mode test",
|
||||||
|
"build:h5:prod": "uni build --mode production",
|
||||||
|
"build": "uni build",
|
||||||
|
"build:test": "uni build --mode test",
|
||||||
|
"build:prod": "uni build --mode production",
|
||||||
|
"build:h5:ssr": "uni build --ssr",
|
||||||
|
"build:mp-alipay": "uni build -p mp-alipay",
|
||||||
|
"build:mp": "uni build -p mp-weixin",
|
||||||
|
"build:mp:test": "uni build -p mp-weixin --mode test",
|
||||||
|
"build:mp:prod": "uni build -p mp-weixin --mode production",
|
||||||
|
"build:mp-baidu": "uni build -p mp-baidu",
|
||||||
|
"build:mp-jd": "uni build -p mp-jd",
|
||||||
|
"build:mp-kuaishou": "uni build -p mp-kuaishou",
|
||||||
|
"build:mp-lark": "uni build -p mp-lark",
|
||||||
|
"build:mp-qq": "uni build -p mp-qq",
|
||||||
|
"build:mp-toutiao": "uni build -p mp-toutiao",
|
||||||
|
"build:mp-weixin": "uni build -p mp-weixin",
|
||||||
|
"build:mp-xhs": "uni build -p mp-xhs",
|
||||||
|
"build:quickapp-webview": "uni build -p quickapp-webview",
|
||||||
|
"build:quickapp-webview-huawei": "uni build -p quickapp-webview-huawei",
|
||||||
|
"build:quickapp-webview-union": "uni build -p quickapp-webview-union",
|
||||||
|
"type-check": "vue-tsc --noEmit",
|
||||||
|
"openapi": "openapi-ts",
|
||||||
|
"init-husky": "git init && husky",
|
||||||
|
"init-baseFile": "node ./scripts/create-base-files.js",
|
||||||
|
"prepare": "pnpm init-husky & pnpm init-baseFile",
|
||||||
|
"lint": "eslint",
|
||||||
|
"lint:fix": "eslint --fix"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@alova/adapter-uniapp": "^2.0.14",
|
||||||
|
"@alova/shared": "^1.3.1",
|
||||||
|
"@dcloudio/uni-app": "3.0.0-4070620250821001",
|
||||||
|
"@dcloudio/uni-app-harmony": "3.0.0-4070620250821001",
|
||||||
|
"@dcloudio/uni-app-plus": "3.0.0-4070620250821001",
|
||||||
|
"@dcloudio/uni-components": "3.0.0-4070620250821001",
|
||||||
|
"@dcloudio/uni-h5": "3.0.0-4070620250821001",
|
||||||
|
"@dcloudio/uni-mp-alipay": "3.0.0-4070620250821001",
|
||||||
|
"@dcloudio/uni-mp-baidu": "3.0.0-4070620250821001",
|
||||||
|
"@dcloudio/uni-mp-harmony": "3.0.0-4070620250821001",
|
||||||
|
"@dcloudio/uni-mp-jd": "3.0.0-4070620250821001",
|
||||||
|
"@dcloudio/uni-mp-kuaishou": "3.0.0-4070620250821001",
|
||||||
|
"@dcloudio/uni-mp-lark": "3.0.0-4070620250821001",
|
||||||
|
"@dcloudio/uni-mp-qq": "3.0.0-4070620250821001",
|
||||||
|
"@dcloudio/uni-mp-toutiao": "3.0.0-4070620250821001",
|
||||||
|
"@dcloudio/uni-mp-weixin": "3.0.0-4070620250821001",
|
||||||
|
"@dcloudio/uni-mp-xhs": "3.0.0-4070620250821001",
|
||||||
|
"@dcloudio/uni-quickapp-webview": "3.0.0-4070620250821001",
|
||||||
|
"@qiun/ucharts": "2.5.0-20230101",
|
||||||
|
"abortcontroller-polyfill": "^1.7.8",
|
||||||
|
"alova": "^3.3.3",
|
||||||
|
"dayjs": "1.11.10",
|
||||||
|
"js-cookie": "^3.0.5",
|
||||||
|
"pinia": "2.0.36",
|
||||||
|
"pinia-plugin-persistedstate": "3.2.1",
|
||||||
|
"vue": "^3.4.21",
|
||||||
|
"vue-i18n": "^9.14.5",
|
||||||
|
"vue-router": "4.5.1",
|
||||||
|
"wot-design-uni": "^1.12.4",
|
||||||
|
"z-paging": "2.8.7"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@commitlint/cli": "^19.8.1",
|
||||||
|
"@commitlint/config-conventional": "^19.8.1",
|
||||||
|
"@dcloudio/types": "^3.4.8",
|
||||||
|
"@dcloudio/uni-automator": "3.0.0-4070620250821001",
|
||||||
|
"@dcloudio/uni-cli-shared": "3.0.0-4070620250821001",
|
||||||
|
"@dcloudio/uni-stacktracey": "3.0.0-4070620250821001",
|
||||||
|
"@dcloudio/vite-plugin-uni": "3.0.0-4070620250821001",
|
||||||
|
"@esbuild/darwin-arm64": "0.20.2",
|
||||||
|
"@esbuild/darwin-x64": "0.20.2",
|
||||||
|
"@iconify-json/carbon": "^1.2.4",
|
||||||
|
"@rollup/rollup-darwin-x64": "^4.28.0",
|
||||||
|
"@types/node": "^20.17.9",
|
||||||
|
"@uni-helper/eslint-config": "0.5.0",
|
||||||
|
"@uni-helper/plugin-uni": "0.1.0",
|
||||||
|
"@uni-helper/uni-env": "0.1.8",
|
||||||
|
"@uni-helper/uni-types": "1.0.0-alpha.6",
|
||||||
|
"@uni-helper/unocss-preset-uni": "0.2.11",
|
||||||
|
"@uni-helper/vite-plugin-uni-components": "0.2.3",
|
||||||
|
"@uni-helper/vite-plugin-uni-layouts": "0.1.11",
|
||||||
|
"@uni-helper/vite-plugin-uni-manifest": "0.2.8",
|
||||||
|
"@uni-helper/vite-plugin-uni-pages": "0.3.19",
|
||||||
|
"@uni-helper/vite-plugin-uni-platform": "0.0.5",
|
||||||
|
"@uni-ku/bundle-optimizer": "v1.3.15-beta.2",
|
||||||
|
"@uni-ku/root": "1.4.1",
|
||||||
|
"@unocss/eslint-plugin": "^66.2.3",
|
||||||
|
"@unocss/preset-legacy-compat": "66.0.0",
|
||||||
|
"@vue/runtime-core": "^3.4.21",
|
||||||
|
"@vue/tsconfig": "^0.1.3",
|
||||||
|
"autoprefixer": "^10.4.20",
|
||||||
|
"cross-env": "^10.0.0",
|
||||||
|
"eslint": "^9.31.0",
|
||||||
|
"eslint-plugin-format": "^1.0.1",
|
||||||
|
"husky": "^9.1.7",
|
||||||
|
"lint-staged": "^15.2.10",
|
||||||
|
"miniprogram-api-typings": "^4.1.0",
|
||||||
|
"openapi-ts-request": "^1.6.7",
|
||||||
|
"postcss": "^8.4.49",
|
||||||
|
"postcss-html": "^1.8.0",
|
||||||
|
"postcss-scss": "^4.0.9",
|
||||||
|
"rollup-plugin-visualizer": "^6.0.3",
|
||||||
|
"sass": "1.77.8",
|
||||||
|
"std-env": "^3.9.0",
|
||||||
|
"typescript": "~5.8.0",
|
||||||
|
"unocss": "66.0.0",
|
||||||
|
"unplugin-auto-import": "^20.0.0",
|
||||||
|
"vite": "5.2.8",
|
||||||
|
"vite-plugin-restart": "^1.0.0",
|
||||||
|
"vue-tsc": "^3.0.6"
|
||||||
|
},
|
||||||
|
"pnpm": {
|
||||||
|
"overrides": {
|
||||||
|
"unconfig": "7.3.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overrides": {
|
||||||
|
"unconfig": "7.3.2"
|
||||||
|
},
|
||||||
|
"resolutions": {
|
||||||
|
"bin-wrapper": "npm:bin-wrapper-china",
|
||||||
|
"unconfig": "7.3.2"
|
||||||
|
},
|
||||||
|
"lint-staged": {
|
||||||
|
"*": "eslint --fix"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* @Author: chris
|
||||||
|
* @Date: 2025-10-20 10:45:46
|
||||||
|
* @LastEditors: chris
|
||||||
|
* @LastEditTime: 2025-10-20 11:40:32
|
||||||
|
*/
|
||||||
|
import { defineUniPages } from '@uni-helper/vite-plugin-uni-pages'
|
||||||
|
import { tabBar } from './src/tabbar/config'
|
||||||
|
|
||||||
|
export default defineUniPages({
|
||||||
|
globalStyle: {
|
||||||
|
navigationStyle: 'default',
|
||||||
|
navigationBarTitleText: '果园',
|
||||||
|
navigationBarBackgroundColor: '#f8f8f8',
|
||||||
|
navigationBarTextStyle: 'black',
|
||||||
|
backgroundColor: '#FFFFFF',
|
||||||
|
},
|
||||||
|
easycom: {
|
||||||
|
autoscan: true,
|
||||||
|
custom: {
|
||||||
|
'^fg-(.*)': '@/components/fg-$1/fg-$1.vue',
|
||||||
|
'^wd-(.*)': 'wot-design-uni/components/wd-$1/wd-$1.vue',
|
||||||
|
'^(?!z-paging-refresh|z-paging-load-more)z-paging(.*)':
|
||||||
|
'z-paging/components/z-paging$1/z-paging$1.vue',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// tabbar 的配置统一在 “./src/tabbar/config.ts” 文件中
|
||||||
|
tabBar: tabBar as any,
|
||||||
|
})
|
||||||
@ -0,0 +1,83 @@
|
|||||||
|
import { exec } from 'node:child_process'
|
||||||
|
import fs from 'node:fs'
|
||||||
|
import path from 'node:path'
|
||||||
|
import process from 'node:process'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开开发者工具
|
||||||
|
*/
|
||||||
|
function _openDevTools() {
|
||||||
|
const platform = process.platform // darwin, win32, linux
|
||||||
|
const { UNI_PLATFORM } = process.env // mp-weixin, mp-alipay
|
||||||
|
|
||||||
|
const uniPlatformText = UNI_PLATFORM === 'mp-weixin' ? '微信小程序' : UNI_PLATFORM === 'mp-alipay' ? '支付宝小程序' : '小程序'
|
||||||
|
|
||||||
|
// 项目路径(构建输出目录)
|
||||||
|
const projectPath = path.resolve(process.cwd(), `dist/dev/${UNI_PLATFORM}`)
|
||||||
|
|
||||||
|
// 检查构建输出目录是否存在
|
||||||
|
if (!fs.existsSync(projectPath)) {
|
||||||
|
console.log(`❌ ${uniPlatformText}构建目录不存在:`, projectPath)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`🚀 正在打开${uniPlatformText}开发者工具...`)
|
||||||
|
|
||||||
|
// 根据不同操作系统执行不同命令
|
||||||
|
let command = ''
|
||||||
|
|
||||||
|
if (platform === 'darwin') {
|
||||||
|
// macOS
|
||||||
|
if (UNI_PLATFORM === 'mp-weixin') {
|
||||||
|
command = `/Applications/wechatwebdevtools.app/Contents/MacOS/cli -o "${projectPath}"`
|
||||||
|
}
|
||||||
|
else if (UNI_PLATFORM === 'mp-alipay') {
|
||||||
|
command = `/Applications/小程序开发者工具.app/Contents/MacOS/小程序开发者工具 --p "${projectPath}"`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (platform === 'win32' || platform === 'win64') {
|
||||||
|
// Windows
|
||||||
|
if (UNI_PLATFORM === 'mp-weixin') {
|
||||||
|
command = `"C:\\Program Files (x86)\\Tencent\\微信web开发者工具\\cli.bat" -o "${projectPath}"`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Linux 或其他系统
|
||||||
|
console.log('❌ 当前系统不支持自动打开微信开发者工具')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
exec(command, (error, stdout, stderr) => {
|
||||||
|
if (error) {
|
||||||
|
console.log(`❌ 打开${uniPlatformText}开发者工具失败:`, error.message)
|
||||||
|
console.log(`💡 请确保${uniPlatformText}开发者工具服务端口已启用`)
|
||||||
|
console.log(`💡 可以手动打开${uniPlatformText}开发者工具并导入项目:`, projectPath)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stderr) {
|
||||||
|
console.log('⚠️ 警告:', stderr)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`✅ ${uniPlatformText}开发者工具已打开`)
|
||||||
|
|
||||||
|
if (stdout) {
|
||||||
|
console.log(stdout)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function openDevTools() {
|
||||||
|
// 首次构建标记
|
||||||
|
let isFirstBuild = true
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: 'uni-devtools',
|
||||||
|
writeBundle() {
|
||||||
|
if (isFirstBuild && process.env.UNI_PLATFORM?.includes('mp')) {
|
||||||
|
isFirstBuild = false
|
||||||
|
_openDevTools()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,101 @@
|
|||||||
|
// # 执行 `pnpm upgrade` 后会升级 `uniapp` 相关依赖
|
||||||
|
// # 在升级完后,会自动添加很多无用依赖,这需要删除以减小依赖包体积
|
||||||
|
// # 只需要执行下面的命令即可
|
||||||
|
|
||||||
|
import { exec } from 'node:child_process'
|
||||||
|
import { promisify } from 'node:util'
|
||||||
|
|
||||||
|
// 日志控制开关,设置为 true 可以启用所有日志输出
|
||||||
|
const FG_LOG_ENABLE = true
|
||||||
|
|
||||||
|
// 将 exec 转换为返回 Promise 的函数
|
||||||
|
const execPromise = promisify(exec)
|
||||||
|
|
||||||
|
// 定义要执行的命令
|
||||||
|
const dependencies = [
|
||||||
|
'@dcloudio/uni-app-harmony',
|
||||||
|
// TODO: 如果不需要某个平台的小程序,请手动删除或注释掉
|
||||||
|
'@dcloudio/uni-mp-alipay',
|
||||||
|
'@dcloudio/uni-mp-baidu',
|
||||||
|
'@dcloudio/uni-mp-jd',
|
||||||
|
'@dcloudio/uni-mp-kuaishou',
|
||||||
|
'@dcloudio/uni-mp-lark',
|
||||||
|
'@dcloudio/uni-mp-qq',
|
||||||
|
'@dcloudio/uni-mp-toutiao',
|
||||||
|
'@dcloudio/uni-mp-xhs',
|
||||||
|
'@dcloudio/uni-quickapp-webview',
|
||||||
|
// i18n模板要注释掉下面的
|
||||||
|
'vue-i18n',
|
||||||
|
]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 带开关的日志输出函数
|
||||||
|
* @param {string} message 日志消息
|
||||||
|
* @param {string} type 日志类型 (log, error)
|
||||||
|
*/
|
||||||
|
function log(message, type = 'log') {
|
||||||
|
if (FG_LOG_ENABLE) {
|
||||||
|
if (type === 'error') {
|
||||||
|
console.error(message)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.log(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 卸载单个依赖包
|
||||||
|
* @param {string} dep 依赖包名
|
||||||
|
* @returns {Promise<boolean>} 是否成功卸载
|
||||||
|
*/
|
||||||
|
async function uninstallDependency(dep) {
|
||||||
|
try {
|
||||||
|
log(`开始卸载依赖: ${dep}`)
|
||||||
|
const { stdout, stderr } = await execPromise(`pnpm un ${dep}`)
|
||||||
|
if (stdout) {
|
||||||
|
log(`stdout [${dep}]: ${stdout}`)
|
||||||
|
}
|
||||||
|
if (stderr) {
|
||||||
|
log(`stderr [${dep}]: ${stderr}`, 'error')
|
||||||
|
}
|
||||||
|
log(`成功卸载依赖: ${dep}`)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
// 单个依赖卸载失败不影响其他依赖
|
||||||
|
log(`卸载依赖 ${dep} 失败: ${error.message}`, 'error')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 串行卸载所有依赖包
|
||||||
|
*/
|
||||||
|
async function uninstallAllDependencies() {
|
||||||
|
log(`开始串行卸载 ${dependencies.length} 个依赖包...`)
|
||||||
|
|
||||||
|
let successCount = 0
|
||||||
|
let failedCount = 0
|
||||||
|
|
||||||
|
// 串行执行所有卸载命令
|
||||||
|
for (const dep of dependencies) {
|
||||||
|
const success = await uninstallDependency(dep)
|
||||||
|
if (success) {
|
||||||
|
successCount++
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
failedCount++
|
||||||
|
}
|
||||||
|
|
||||||
|
// 为了避免命令执行过快导致的问题,添加短暂延迟
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 100))
|
||||||
|
}
|
||||||
|
|
||||||
|
log(`卸载操作完成: 成功 ${successCount} 个, 失败 ${failedCount} 个`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行串行卸载
|
||||||
|
uninstallAllDependencies().catch((err) => {
|
||||||
|
log(`串行卸载过程中出现未捕获的错误: ${err}`, 'error')
|
||||||
|
})
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
import { API_DOMAINS, http } from '@/http/alova'
|
||||||
|
|
||||||
|
export interface IFoo {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function foo() {
|
||||||
|
return http.Get<IFoo>('/foo', {
|
||||||
|
params: {
|
||||||
|
name: '菲鸽',
|
||||||
|
page: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
},
|
||||||
|
meta: { domain: API_DOMAINS.SECONDARY }, // 用于切换请求地址
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -0,0 +1,74 @@
|
|||||||
|
import type { Ref } from 'vue'
|
||||||
|
import { onMounted, ref } from 'vue'
|
||||||
|
|
||||||
|
interface UseScrollOptions<T> {
|
||||||
|
fetchData: (page: number, pageSize: number) => Promise<T[]>
|
||||||
|
pageSize?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UseScrollReturn<T> {
|
||||||
|
list: Ref<T[]>
|
||||||
|
loading: Ref<boolean>
|
||||||
|
finished: Ref<boolean>
|
||||||
|
error: Ref<any>
|
||||||
|
refresh: () => Promise<void>
|
||||||
|
loadMore: () => Promise<void>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useScroll<T>({
|
||||||
|
fetchData,
|
||||||
|
pageSize = 10,
|
||||||
|
}: UseScrollOptions<T>): UseScrollReturn<T> {
|
||||||
|
const list = ref<T[]>([]) as Ref<T[]>
|
||||||
|
const loading = ref(false)
|
||||||
|
const finished = ref(false)
|
||||||
|
const error = ref<any>(null)
|
||||||
|
const page = ref(1)
|
||||||
|
|
||||||
|
const loadData = async () => {
|
||||||
|
if (loading.value || finished.value)
|
||||||
|
return
|
||||||
|
|
||||||
|
loading.value = true
|
||||||
|
error.value = null
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = await fetchData(page.value, pageSize)
|
||||||
|
if (data.length < pageSize) {
|
||||||
|
finished.value = true
|
||||||
|
}
|
||||||
|
list.value.push(...data)
|
||||||
|
page.value++
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
error.value = err
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const refresh = async () => {
|
||||||
|
page.value = 1
|
||||||
|
finished.value = false
|
||||||
|
list.value = []
|
||||||
|
await loadData()
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadMore = async () => {
|
||||||
|
await loadData()
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
refresh()
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
list,
|
||||||
|
loading,
|
||||||
|
finished,
|
||||||
|
error,
|
||||||
|
refresh,
|
||||||
|
loadMore,
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
import type { CustomRequestOptions } from '@/http/types'
|
||||||
|
import { http } from './http'
|
||||||
|
|
||||||
|
/*
|
||||||
|
* openapi-ts-request 工具的 request 跨客户端适配方法
|
||||||
|
*/
|
||||||
|
export default function request<T = unknown>(
|
||||||
|
url: string,
|
||||||
|
options: Omit<CustomRequestOptions, 'url'> & {
|
||||||
|
params?: Record<string, unknown>
|
||||||
|
headers?: Record<string, unknown>
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
const requestOptions = {
|
||||||
|
url,
|
||||||
|
...options,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.params) {
|
||||||
|
requestOptions.query = requestOptions.params
|
||||||
|
delete requestOptions.params
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.headers) {
|
||||||
|
requestOptions.header = options.headers
|
||||||
|
delete requestOptions.headers
|
||||||
|
}
|
||||||
|
|
||||||
|
return http<T>(requestOptions)
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
const testUniLayoutExposedData = ref('testUniLayoutExposedData')
|
||||||
|
defineExpose({
|
||||||
|
testUniLayoutExposedData,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<slot />
|
||||||
|
</template>
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
import { createSSRApp } from 'vue'
|
||||||
|
import App from './App.vue'
|
||||||
|
import { requestInterceptor } from './http/interceptor'
|
||||||
|
import { routeInterceptor } from './router/interceptor'
|
||||||
|
|
||||||
|
import store from './store'
|
||||||
|
import '@/style/index.scss'
|
||||||
|
import 'virtual:uno.css'
|
||||||
|
|
||||||
|
export function createApp() {
|
||||||
|
const app = createSSRApp(App)
|
||||||
|
app.use(store)
|
||||||
|
app.use(routeInterceptor)
|
||||||
|
app.use(requestInterceptor)
|
||||||
|
|
||||||
|
return {
|
||||||
|
app,
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
# 404 页面
|
||||||
|
|
||||||
|
`404页面` 只有在路由不存在时才会显示,如果您不需要可以删除该页面。但是建议保留。
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
# 登录页
|
||||||
|
需要输入账号、密码/验证码的登录页。
|
||||||
|
|
||||||
|
## 适用性
|
||||||
|
|
||||||
|
本页面主要用于 `h5` 和 `APP`。
|
||||||
|
|
||||||
|
小程序通常有平台的登录方式 `uni.login` 通常用不到登录页,所以不适用于 `小程序`。(即默认情况下,小程序环境是不会走登录拦截逻辑的。)
|
||||||
|
|
||||||
|
但是如果您的小程序也需要现实的 `登录页` 那也是可以使用的。
|
||||||
|
|
||||||
|
在 `src/router/config.ts` 中有一个变量 `LOGIN_PAGE_ENABLE_IN_MP` 来控制是否在小程序中使用 `H5的登录页`。
|
||||||
|
|
||||||
|
更多信息请看 `src/router` 文件夹的内容。
|
||||||
|
|
||||||
|
## 登录跳转
|
||||||
|
|
||||||
|
目前登录的跳转逻辑主要在 `src/router/interceptor.ts` 和 `src/pages/login/login.vue` 里面,默认会在登录后自动重定向到来源/配置的页面。
|
||||||
|
|
||||||
|
如果与您的业务不符,您可以自行修改。
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { LOGIN_PAGE } from '@/router/config'
|
||||||
|
|
||||||
|
definePage({
|
||||||
|
style: {
|
||||||
|
navigationBarTitleText: '注册',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
function doRegister() {
|
||||||
|
uni.showToast({
|
||||||
|
title: '注册成功',
|
||||||
|
})
|
||||||
|
// 注册成功后跳转到登录页
|
||||||
|
uni.navigateTo({
|
||||||
|
url: LOGIN_PAGE,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<view class="login">
|
||||||
|
<view class="text-center">
|
||||||
|
注册页
|
||||||
|
</view>
|
||||||
|
<button class="mt-4 w-40 text-center" @click="doRegister">
|
||||||
|
点击模拟注册
|
||||||
|
</button>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
//
|
||||||
|
</style>
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { useRequest } from 'alova/client'
|
||||||
|
import { foo } from '@/api/foo-alova'
|
||||||
|
|
||||||
|
definePage({
|
||||||
|
style: {
|
||||||
|
navigationBarTitleText: 'Alova 演示',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const initialData = undefined
|
||||||
|
|
||||||
|
const { loading, data, send } = useRequest(foo, {
|
||||||
|
initialData,
|
||||||
|
immediate: true,
|
||||||
|
})
|
||||||
|
console.log(data)
|
||||||
|
function reset() {
|
||||||
|
data.value = initialData
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<view class="p-6 text-center">
|
||||||
|
<button type="primary" size="mini" class="my-6 w-160px" @click="send">
|
||||||
|
发送请求
|
||||||
|
</button>
|
||||||
|
<view class="h-16">
|
||||||
|
<view v-if="loading">
|
||||||
|
loading...
|
||||||
|
</view>
|
||||||
|
<block v-else>
|
||||||
|
<view class="text-xl">
|
||||||
|
请求数据如下
|
||||||
|
</view>
|
||||||
|
<view class="text-green leading-8">
|
||||||
|
{{ JSON.stringify(data) }}
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
|
||||||
|
<view class="text-red">
|
||||||
|
{{ data?.id }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<button type="default" size="mini" class="my-6 w-160px" @click="reset">
|
||||||
|
重置数据
|
||||||
|
</button>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
//
|
||||||
|
</style>
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import type { UserItem } from '@/service'
|
||||||
|
import { infoUsingGet, listAllUsingGet } from '@/service'
|
||||||
|
|
||||||
|
const loading = ref(false)
|
||||||
|
const error = ref<Error | null>(null)
|
||||||
|
const data = ref<UserItem>()
|
||||||
|
|
||||||
|
// openapi 请求示例
|
||||||
|
async function getUserInfo() {
|
||||||
|
try {
|
||||||
|
loading.value = true
|
||||||
|
const res = await infoUsingGet({})
|
||||||
|
console.log(res)
|
||||||
|
data.value = res
|
||||||
|
error.value = null
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
error.value = err as Error
|
||||||
|
data.value = null
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// openapi + useRequest 请求示例
|
||||||
|
const { data: data2, loading: loading2, run } = useRequest(() => listAllUsingGet({}), {
|
||||||
|
immediate: false,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<view class="p-6 text-center">
|
||||||
|
<view class="my-4 text-center">
|
||||||
|
1)直接使用 openapi 生成的请求
|
||||||
|
</view>
|
||||||
|
<view class="my-4 text-center">
|
||||||
|
<button type="primary" size="mini" class="w-160px" @click="getUserInfo">
|
||||||
|
发送请求
|
||||||
|
</button>
|
||||||
|
<view class="text-xl">
|
||||||
|
请求数据如下
|
||||||
|
</view>
|
||||||
|
<view class="text-green leading-8">
|
||||||
|
{{ JSON.stringify(data) }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="my-4 text-center">
|
||||||
|
2)直接使用 openapi + useRequest 生成的请求
|
||||||
|
</view>
|
||||||
|
<view class="my-4 flex items-center gap-2 text-center">
|
||||||
|
<button type="primary" size="mini" class="w-160px" @click="run">
|
||||||
|
发送请求
|
||||||
|
</button>
|
||||||
|
</view>
|
||||||
|
<view class="text-xl">
|
||||||
|
请求数据如下
|
||||||
|
</view>
|
||||||
|
<view class="text-green leading-8">
|
||||||
|
{{ JSON.stringify(data2) }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import type { IFooItem } from '@/api/foo'
|
||||||
|
import { getFooAPI } from '@/api/foo'
|
||||||
|
|
||||||
|
const recommendUrl = ref('http://laf.run/signup?code=ohaOgIX')
|
||||||
|
|
||||||
|
// const initialData = {
|
||||||
|
// name: 'initialData',
|
||||||
|
// id: '1234',
|
||||||
|
// }
|
||||||
|
const initialData = undefined
|
||||||
|
const { loading, error, data, run } = useRequest<IFooItem>(() => getFooAPI('菲鸽'), {
|
||||||
|
immediate: true,
|
||||||
|
initialData,
|
||||||
|
})
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
data.value = initialData
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<view class="p-6 text-center">
|
||||||
|
<view class="my-2 text-center">
|
||||||
|
<button type="primary" size="mini" class="w-160px" @click="run">
|
||||||
|
发送请求
|
||||||
|
</button>
|
||||||
|
</view>
|
||||||
|
<view class="h-16">
|
||||||
|
<view v-if="loading">
|
||||||
|
loading...
|
||||||
|
</view>
|
||||||
|
<block v-else>
|
||||||
|
<view class="text-xl">
|
||||||
|
请求数据如下
|
||||||
|
</view>
|
||||||
|
<view class="text-green leading-8">
|
||||||
|
{{ JSON.stringify(data) }}
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
<view class="my-6 text-center">
|
||||||
|
<button type="warn" size="mini" class="w-160px" :disabled="!data" @click="reset">
|
||||||
|
重置数据
|
||||||
|
</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
// code here
|
||||||
|
import RequestComp from './components/request.vue'
|
||||||
|
|
||||||
|
definePage({
|
||||||
|
style: {
|
||||||
|
navigationBarTitleText: '分包页面',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
function gotoScroll() {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages-sub/demo/scroll',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<view class="text-center">
|
||||||
|
<view class="m-8">
|
||||||
|
http://localhost:9000/#/pages-sub/demo/index
|
||||||
|
</view>
|
||||||
|
<view class="my-4 text-green-500">
|
||||||
|
分包页面demo
|
||||||
|
</view>
|
||||||
|
<view class="text-blue-500">
|
||||||
|
分包页面里面的components示例
|
||||||
|
</view>
|
||||||
|
<button class="my-4" type="primary" size="mini" @click="gotoScroll">
|
||||||
|
跳转到上拉刷新和下拉加载更多
|
||||||
|
</button>
|
||||||
|
<view>
|
||||||
|
<RequestComp />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
//
|
||||||
|
</style>
|
||||||
@ -0,0 +1,169 @@
|
|||||||
|
<!--
|
||||||
|
* @Author: chris
|
||||||
|
* @Date: 2025-10-21 11:42:40
|
||||||
|
* @LastEditors: chris
|
||||||
|
* @LastEditTime: 2025-10-22 10:26:02
|
||||||
|
-->
|
||||||
|
<script setup name="line-chart">
|
||||||
|
import LEchart from '@/uni_modules/lime-echart_1.0.5/components/l-echart/l-echart.vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
echarts: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
chartData: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({
|
||||||
|
dates: ['10/1', '10/2', '10/3', '10/4', '10/5', '10/6', '10/7'],
|
||||||
|
values: [42, 49, 56, 32, 71, 33, 22],
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const lineChartRef = ref(null)
|
||||||
|
let lineChart = null
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
nextTick(async () => {
|
||||||
|
await initChart()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (lineChart)
|
||||||
|
lineChart.dispose()
|
||||||
|
})
|
||||||
|
|
||||||
|
async function initChart() {
|
||||||
|
if (!lineChartRef.value || !props.echarts)
|
||||||
|
return
|
||||||
|
lineChart = await lineChartRef.value.init(props.echarts)
|
||||||
|
refreshChart()
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshChart() {
|
||||||
|
if (!lineChart)
|
||||||
|
return
|
||||||
|
lineChart.showLoading()
|
||||||
|
lineChart.setOption(createOptions())
|
||||||
|
lineChart.hideLoading()
|
||||||
|
}
|
||||||
|
|
||||||
|
function createOptions() {
|
||||||
|
const gradient = new props.echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||||
|
{ offset: 0, color: 'rgba(77, 171, 247, 0.5)' },
|
||||||
|
{ offset: 1, color: 'rgba(77, 171, 247, 0.1)' },
|
||||||
|
])
|
||||||
|
|
||||||
|
const option = {
|
||||||
|
title: {
|
||||||
|
text: '7天虫情数量趋势',
|
||||||
|
top: '2%',
|
||||||
|
textStyle: {
|
||||||
|
color: '#333',
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
},
|
||||||
|
left: 'center',
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
backgroundColor: 'rgba(0, 0, 0, 0.7)',
|
||||||
|
borderColor: '#333',
|
||||||
|
textStyle: {
|
||||||
|
color: '#fff',
|
||||||
|
},
|
||||||
|
formatter: (params) => {
|
||||||
|
const data = params[0]
|
||||||
|
return `虫情数量: ${Math.round(data.value)}`
|
||||||
|
},
|
||||||
|
axisPointer: {
|
||||||
|
type: 'cross',
|
||||||
|
label: {
|
||||||
|
backgroundColor: '#6a7985',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: '3%',
|
||||||
|
right: '3%',
|
||||||
|
bottom: '3%',
|
||||||
|
top: '20%',
|
||||||
|
containLabel: true,
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
boundaryGap: false,
|
||||||
|
data: props.chartData.dates,
|
||||||
|
axisLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: '#464646',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
color: '#ddd',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
type: 'value',
|
||||||
|
name: '数量',
|
||||||
|
nameTextStyle: {
|
||||||
|
color: '#ddd',
|
||||||
|
},
|
||||||
|
min: 0,
|
||||||
|
max: 'dataMax + 50',
|
||||||
|
axisLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: '#464646',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
color: '#ddd',
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: '#2a2a2a',
|
||||||
|
type: 'dashed',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '虫情数量',
|
||||||
|
type: 'line',
|
||||||
|
data: props.chartData.values,
|
||||||
|
smooth: true,
|
||||||
|
symbol: 'circle',
|
||||||
|
symbolSize: 6,
|
||||||
|
itemStyle: {
|
||||||
|
color: '#4dabf7',
|
||||||
|
},
|
||||||
|
areaStyle: {
|
||||||
|
color: gradient,
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
focus: 'series',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
return option
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<view class="line-chart">
|
||||||
|
<l-echart id="lineChart" ref="lineChartRef" type="2d" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.line-chart {
|
||||||
|
width: 100%;
|
||||||
|
height: 300px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,157 @@
|
|||||||
|
<!--
|
||||||
|
* @Author: chris
|
||||||
|
* @Date: 2025-10-21 11:42:40
|
||||||
|
* @LastEditors: chris
|
||||||
|
* @LastEditTime: 2025-10-22 10:26:22
|
||||||
|
-->
|
||||||
|
<script setup name="pie-chart">
|
||||||
|
import LEchart from '@/uni_modules/lime-echart_1.0.5/components/l-echart/l-echart.vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
echarts: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
chartData: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({
|
||||||
|
datas: [
|
||||||
|
{
|
||||||
|
name: '红蜘蛛',
|
||||||
|
value: 100,
|
||||||
|
itemStyle: {
|
||||||
|
color: '#ffa502',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '蚜虫',
|
||||||
|
value: 170,
|
||||||
|
itemStyle: {
|
||||||
|
color: '#ff6b6b',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '果蝇',
|
||||||
|
value: 140,
|
||||||
|
itemStyle: {
|
||||||
|
color: '#5f27cd',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '其他',
|
||||||
|
value: 300,
|
||||||
|
itemStyle: {
|
||||||
|
color: '#54a0ff',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const pieChartRef = ref(null)
|
||||||
|
let pieChart = null
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await initChart()
|
||||||
|
})
|
||||||
|
async function initChart() {
|
||||||
|
if (!pieChartRef.value)
|
||||||
|
return
|
||||||
|
pieChart = await pieChartRef.value.init(props.echarts)
|
||||||
|
refreshChart()
|
||||||
|
}
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (pieChart)
|
||||||
|
pieChart.dispose()
|
||||||
|
})
|
||||||
|
|
||||||
|
function refreshChart() {
|
||||||
|
if (!pieChart)
|
||||||
|
return
|
||||||
|
pieChart.showLoading()
|
||||||
|
pieChart.setOption(createOptions())
|
||||||
|
pieChart.hideLoading()
|
||||||
|
}
|
||||||
|
|
||||||
|
function createOptions() {
|
||||||
|
const options = {
|
||||||
|
title: {
|
||||||
|
text: '虫情分布状况',
|
||||||
|
top: '2%',
|
||||||
|
textStyle: {
|
||||||
|
color: '#333',
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
},
|
||||||
|
left: 'center',
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'item',
|
||||||
|
backgroundColor: 'rgba(0, 0, 0, 0.7)',
|
||||||
|
borderColor: '#333',
|
||||||
|
textStyle: {
|
||||||
|
color: '#fff',
|
||||||
|
},
|
||||||
|
formatter: '{b}: {c} ({d}%)',
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
bottom: '3%',
|
||||||
|
left: 'center',
|
||||||
|
textStyle: {
|
||||||
|
color: '#333',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '虫情分布',
|
||||||
|
type: 'pie',
|
||||||
|
radius: ['40%', '70%'],
|
||||||
|
// center: ['35%', '50%'],
|
||||||
|
// top: '3%',
|
||||||
|
// left: '3%',
|
||||||
|
// right: '3%',
|
||||||
|
// bottom: '3%',
|
||||||
|
avoidLabelOverlap: false,
|
||||||
|
itemStyle: {
|
||||||
|
borderRadius: 10,
|
||||||
|
borderColor: '#fff',
|
||||||
|
borderWidth: 2,
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
show: false,
|
||||||
|
position: 'center',
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
fontSize: '16',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
// color: 'red',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
labelLine: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
data: props.chartData.datas,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
return options
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<view class="pie-chart">
|
||||||
|
<l-echart id="pieChart" ref="pieChartRef" type="2d" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.pie-chart {
|
||||||
|
width: 100%;
|
||||||
|
height: 300px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* @Author: chris
|
||||||
|
* @Date: 2025-10-22 09:16:37
|
||||||
|
* @LastEditors: chris
|
||||||
|
* @LastEditTime: 2025-10-22 09:16:48
|
||||||
|
*/
|
||||||
|
export const pestTypeDict = {
|
||||||
|
蚜虫: {
|
||||||
|
color: '#ff6b6b',
|
||||||
|
},
|
||||||
|
红蜘蛛: {
|
||||||
|
color: '#ffa502',
|
||||||
|
},
|
||||||
|
果蝇: {
|
||||||
|
color: '#5f27cd',
|
||||||
|
},
|
||||||
|
菜青虫: {
|
||||||
|
color: '#10ac84',
|
||||||
|
},
|
||||||
|
其他: {
|
||||||
|
color: '#54a0ff',
|
||||||
|
},
|
||||||
|
}
|
||||||
@ -0,0 +1,129 @@
|
|||||||
|
<!--
|
||||||
|
* @Author: chris
|
||||||
|
* @Date: 2025-10-17 11:52:06
|
||||||
|
* @LastEditors: chris
|
||||||
|
* @LastEditTime: 2025-10-22 14:16:01
|
||||||
|
-->
|
||||||
|
<script setup>
|
||||||
|
const echarts = require('../../uni_modules/lime-echart_1.0.5/static/echarts.min2.js')
|
||||||
|
|
||||||
|
import LineChart from './components/lineChart.vue'
|
||||||
|
import PieChart from './components/pieChart.vue'
|
||||||
|
|
||||||
|
definePage({
|
||||||
|
style: {
|
||||||
|
navigationBarTitleText: '虫情监测',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const { proxy } = getCurrentInstance()
|
||||||
|
const query = uni.createSelectorQuery().in(proxy)
|
||||||
|
|
||||||
|
const chartSize = ref({
|
||||||
|
lineChart: {
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
},
|
||||||
|
pieChart: {
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
// await getChartCanvasSize('lineChart')
|
||||||
|
// await getChartCanvasSize('pieChart')
|
||||||
|
})
|
||||||
|
|
||||||
|
async function getCanvasSize(id) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
query.select(`#${id}`).boundingClientRect((info) => {
|
||||||
|
resolve(info)
|
||||||
|
}).exec()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getChartCanvasSize(id) {
|
||||||
|
const { width = 0, height = 0 } = await getCanvasSize(id)
|
||||||
|
chartSize.value[id].width = width
|
||||||
|
chartSize.value[id].height = height
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<view class="pest-monitor-page">
|
||||||
|
<wd-card class="pest-info-card">
|
||||||
|
<view class="pest-total-title">
|
||||||
|
<view class="title-text">
|
||||||
|
虫害总数(近7天)
|
||||||
|
</view>
|
||||||
|
<view class="update-time">
|
||||||
|
更新时间: {{ '2023-10-17 11:52:06' }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="pest-total-count">
|
||||||
|
{{ 12345 }}
|
||||||
|
</view>
|
||||||
|
</wd-card>
|
||||||
|
|
||||||
|
<!-- 折线图区域 -->
|
||||||
|
<wd-card class="chart-card">
|
||||||
|
<!-- <view class="chart-title">
|
||||||
|
近7天虫害趋势
|
||||||
|
</view> -->
|
||||||
|
<!-- <l-echart id="lineChart" ref="lineChartRef" class="chart" /> -->
|
||||||
|
<line-chart id="lineChart" :echarts="echarts" />
|
||||||
|
</wd-card>
|
||||||
|
|
||||||
|
<!-- 饼图区域 -->
|
||||||
|
<wd-card class="chart-card">
|
||||||
|
<!-- <view class="chart-title">
|
||||||
|
虫害类型分布
|
||||||
|
</view> -->
|
||||||
|
<pie-chart id="pieChart" :echarts="echarts" />
|
||||||
|
</wd-card>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
$bg-color: #f5f7fa;
|
||||||
|
|
||||||
|
.pest-monitor-page {
|
||||||
|
@apply py-15px min-h-[100vh];
|
||||||
|
background-color: $bg-color;
|
||||||
|
|
||||||
|
> .wd-card {
|
||||||
|
@apply p-15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pest-info-card {
|
||||||
|
.pest-total-title {
|
||||||
|
@apply flex flex-col items-center justify-between mb-20px;
|
||||||
|
|
||||||
|
.title-text {
|
||||||
|
@apply text-20px font-bold tracking-[4px] mb-2px;
|
||||||
|
color: $-color-theme;
|
||||||
|
}
|
||||||
|
.update-time {
|
||||||
|
@apply text-12px;
|
||||||
|
color: $-color-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pest-total-count {
|
||||||
|
@apply text-center font-size-20px font-600;
|
||||||
|
color: $-color-warning;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-card {
|
||||||
|
.chart-title {
|
||||||
|
@apply mb-20px font-bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart {
|
||||||
|
@apply w-[100%] h-[300px];
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
// @ts-ignore
|
||||||
|
export * from './types';
|
||||||
|
|
||||||
|
export * from './listAll';
|
||||||
|
export * from './info';
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
// @ts-ignore
|
||||||
|
import request from '@/http/vue-query';
|
||||||
|
import { CustomRequestOptions } from '@/http/types';
|
||||||
|
|
||||||
|
import * as API from './types';
|
||||||
|
|
||||||
|
/** 用户信息 GET /user/info */
|
||||||
|
export async function infoUsingGet({
|
||||||
|
options,
|
||||||
|
}: {
|
||||||
|
options?: CustomRequestOptions;
|
||||||
|
}) {
|
||||||
|
return request<API.UserItem>('/user/info', {
|
||||||
|
method: 'GET',
|
||||||
|
...(options || {}),
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
// @ts-ignore
|
||||||
|
import request from '@/http/vue-query';
|
||||||
|
import { CustomRequestOptions } from '@/http/types';
|
||||||
|
|
||||||
|
import * as API from './types';
|
||||||
|
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
|
||||||
|
|
||||||
|
/** 用户列表 GET /user/listAll */
|
||||||
|
export async function listAllUsingGet({
|
||||||
|
options,
|
||||||
|
}: {
|
||||||
|
options?: CustomRequestOptions;
|
||||||
|
}) {
|
||||||
|
return request<API.UserItem[]>('/user/listAll', {
|
||||||
|
method: 'GET',
|
||||||
|
...(options || {}),
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
// @ts-ignore
|
||||||
|
|
||||||
|
export type InfoUsingGetResponse = {
|
||||||
|
code: number;
|
||||||
|
msg: string;
|
||||||
|
data: UserItem;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type InfoUsingGetResponses = {
|
||||||
|
200: InfoUsingGetResponse;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ListAllUsingGetResponse = {
|
||||||
|
code: number;
|
||||||
|
msg: string;
|
||||||
|
data: UserItem[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ListAllUsingGetResponses = {
|
||||||
|
200: ListAllUsingGetResponse;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type UserItem = {
|
||||||
|
userId: number;
|
||||||
|
username: string;
|
||||||
|
nickname: string;
|
||||||
|
avatar: string;
|
||||||
|
};
|
||||||
|
After Width: | Height: | Size: 58 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 574 B |