Merge branch 'main' into i18n

This commit is contained in:
feige996 2025-06-21 15:15:33 +08:00
commit b154a44987
21 changed files with 6016 additions and 2127 deletions

View File

@ -1,14 +1,14 @@
name: Auto Merge Base to Other Branches
name: Auto Merge Main to Other Branches
on:
push:
branches:
- base
- main
workflow_dispatch: # 手动触发
jobs:
merge-to-i18n:
name: Merge base into i18n
name: Merge main into i18n
runs-on: ubuntu-latest
steps:
- name: Checkout repository
@ -17,46 +17,10 @@ jobs:
fetch-depth: 0
token: ${{ secrets.GH_TOKEN_AUTO_MERGE }}
- name: Merge base into i18n
- name: Merge main into i18n
run: |
git config user.name "GitHub Actions"
git config user.email "actions@github.com"
git checkout i18n
git merge base --no-ff -m "Auto merge base into i18n"
git merge main --no-ff -m "Auto merge main into i18n"
git push origin i18n
merge-to-tabbar:
name: Merge base into tabbar
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GH_TOKEN_AUTO_MERGE }}
- name: Merge base into tabbar
run: |
git config user.name "GitHub Actions"
git config user.email "actions@github.com"
git checkout tabbar
git merge base --no-ff -m "Auto merge base into tabbar"
git push origin tabbar
merge-to-spa:
name: Merge base into spa
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GH_TOKEN_AUTO_MERGE }}
- name: Merge base into spa
run: |
git config user.name "GitHub Actions"
git config user.email "actions@github.com"
git checkout spa
git merge base --no-ff -m "Auto merge base into spa"
git push origin spa

View File

@ -1,3 +1,5 @@
node_modules
# unplugin-auto-import 生成的类型文件,每次提交都改变,所以加入这里吧,与 .gitignore 配合使用
auto-import.d.ts

View File

@ -70,13 +70,13 @@
## 📦 运行(支持热更新)
- web平台 `pnpm dev:h5`, 然后打开 [http://localhost:9000/](http://localhost:9000/)。
- weixin平台`pnpm dev:mp-weixin` 然后打开微信开发者工具,导入本地文件夹,选择本项目的`dist/dev/mp-weixin` 文件。
- weixin平台`pnpm dev:mp` 然后打开微信开发者工具,导入本地文件夹,选择本项目的`dist/dev/mp-weixin` 文件。
- APP平台`pnpm dev:app`, 然后打开 `HBuilderX`,导入刚刚生成的`dist/dev/app` 文件夹,选择运行到模拟器(开发时优先使用),或者运行的安卓/ios基座。
## 🔗 发布
- web平台 `pnpm build:h5`,打包后的文件在 `dist/build/h5`可以放到web服务器如nginx运行。如果最终不是放在根目录可以在 `manifest.config.ts` 文件的 `h5.router.base` 属性进行修改。
- weixin平台`pnpm build:mp-weixin`, 打包后的文件在 `dist/build/mp-weixin`,然后通过微信开发者工具导入,并点击右上角的“上传”按钮进行上传。
- weixin平台`pnpm build:mp`, 打包后的文件在 `dist/build/mp-weixin`,然后通过微信开发者工具导入,并点击右上角的“上传”按钮进行上传。
- APP平台`pnpm build:app`, 然后打开 `HBuilderX`,导入刚刚生成的`dist/build/app` 文件夹,选择发行 - APP云打包。
## 📄 License

View File

@ -1,7 +1,7 @@
{
"name": "unibest",
"type": "commonjs",
"version": "2.13.1",
"version": "2.14.0",
"description": "unibest - 最好的 uniapp 开发模板",
"update-time": "2025-06-17",
"author": {
@ -125,8 +125,8 @@
"@dcloudio/uni-cli-shared": "3.0.0-4060620250520001",
"@dcloudio/uni-stacktracey": "3.0.0-4060620250520001",
"@dcloudio/vite-plugin-uni": "3.0.0-4060620250520001",
"@esbuild/darwin-arm64": "0.25.5",
"@esbuild/darwin-x64": "0.25.5",
"@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",

View File

@ -1,4 +1,5 @@
import { defineUniPages } from '@uni-helper/vite-plugin-uni-pages'
import { tabBar } from './src/layouts/fg-tabbar/tabbarList'
export default defineUniPages({
globalStyle: {
@ -17,29 +18,6 @@ export default defineUniPages({
'z-paging/components/z-paging$1/z-paging$1.vue',
},
},
// 如果不需要tabBar推荐使用 spa 模板。pnpm create xxx -t spa
tabBar: {
color: '#999999',
selectedColor: '#018d71',
backgroundColor: '#F8F8F8',
borderStyle: 'black',
height: '50px',
fontSize: '10px',
iconWidth: '24px',
spacing: '3px',
list: [
{
iconPath: 'static/tabbar/home.png',
selectedIconPath: 'static/tabbar/homeHL.png',
pagePath: 'pages/index/index',
text: '%tabbar.home%',
},
{
iconPath: 'static/tabbar/example.png',
selectedIconPath: 'static/tabbar/exampleHL.png',
pagePath: 'pages/about/about',
text: '%tabbar.about%',
},
],
},
// tabbar 的配置统一在 “./src/layouts/fg-tabbar/tabbarList.ts” 文件中
tabBar: tabBar as any,
})

View File

@ -0,0 +1,13 @@
diff --git a/dist/uni-h5.es.js b/dist/uni-h5.es.js
index 7421bad97d94ad34a3d4d94292a9ee9071430662..19c6071ee4036ceb8d1cfa09030e471c002d2cda 100644
--- a/dist/uni-h5.es.js
+++ b/dist/uni-h5.es.js
@@ -23410,7 +23410,7 @@ function useShowTabBar(emit2) {
const tabBar2 = useTabBar();
const showTabBar2 = computed(() => route.meta.isTabBar && tabBar2.shown);
updateCssVar({
- "--tab-bar-height": tabBar2.height
+ "--tab-bar-height": tabBar2?.height || 0
});
return showTabBar2;
}

6363
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

2
pnpm-workspace.yaml Normal file
View File

@ -0,0 +1,2 @@
patchedDependencies:
'@dcloudio/uni-h5': patches/@dcloudio__uni-h5.patch

View File

@ -37,19 +37,21 @@ export default function useUpload<T extends TfileType>(options: TOptions<T> = {}
count: 1,
success: (res: any) => {
console.log('File selected successfully:', res)
// h5中res:{errMsg: "chooseImage:ok", tempFilePaths: "blob:http://localhost:9000/f74ab6b8-a14d-4cb6-a10d-fcf4511a0de5", tempFiles: [File]}
// h5的File有一下字段{name: "girl.jpeg", size: 48976, type: "image/jpeg"}
// 小程序中res:{errMsg: "chooseImage:ok", tempFiles: [{fileType: "image", size: 48976, tempFilePath: "http://tmp/5iG1WpIxTaJf3ece38692a337dc06df7eb69ecb49c6b.jpeg"}]}
// h5中res:{errMsg: "chooseImage:ok", tempFilePaths: "blob:http://localhost:9000/f74ab6b8-a14d-4cb6-a10d-fcf4511a0de5", tempFiles: [File]}
// h5的File有以下字段{name: "girl.jpeg", size: 48976, type: "image/jpeg"}
// App中res:{errMsg: "chooseImage:ok", tempFilePaths: "file:///Users/feige/xxx/gallery/1522437259-compressed-IMG_0006.jpg", tempFiles: [File]}
// App的File有以下字段{path: "file:///Users/feige/xxx/gallery/1522437259-compressed-IMG_0006.jpg", size: 48976}
let tempFilePath = ''
let size = 0
// #ifdef H5
tempFilePath = res.tempFilePaths[0]
size = res.tempFiles[0].size
// #endif
// #ifdef MP-WEIXIN
tempFilePath = res.tempFiles[0].tempFilePath
size = res.tempFiles[0].size
// #endif
// #ifndef MP-WEIXIN
tempFilePath = res.tempFilePaths[0]
size = res.tempFiles[0].size
// #endif
handleFileChoose({ tempFilePath, size })
},
fail: (err: any) => {

View File

@ -0,0 +1,68 @@
<template>
<wd-tabbar
v-if="customTabbarEnable"
fixed
v-model="tabbarStore.curIdx"
bordered
safeAreaInsetBottom
placeholder
@change="selectTabBar"
>
<block v-for="(item, idx) in tabbarList" :key="item.path">
<wd-tabbar-item
v-if="item.iconType === 'wot'"
:title="item.text"
:icon="item.icon"
></wd-tabbar-item>
<wd-tabbar-item
v-else-if="item.iconType === 'unocss' || item.iconType === 'iconfont'"
:title="item.text"
>
<template #icon>
<view
h-40rpx
w-40rpx
:class="[item.icon, idx === tabbarStore.curIdx ? 'is-active' : 'is-inactive']"
></view>
</template>
</wd-tabbar-item>
<wd-tabbar-item v-else-if="item.iconType === 'local'" :title="item.text">
<template #icon>
<image :src="item.icon" h-40rpx w-40rpx />
</template>
</wd-tabbar-item>
</block>
</wd-tabbar>
</template>
<script setup lang="ts">
// 'i-carbon-code',
import { tabbarList as _tabBarList, cacheTabbarEnable, selectedTabbarStrategy } from './tabbarList'
import { tabbarStore } from './tabbar'
const customTabbarEnable = selectedTabbarStrategy === 1 || selectedTabbarStrategy === 2
/** tabbarList 里面的 path 从 pages.config.ts 得到 */
const tabbarList = _tabBarList.map((item) => ({ ...item, path: `/${item.pagePath}` }))
function selectTabBar({ value: index }: { value: number }) {
const url = tabbarList[index].path
tabbarStore.setCurIdx(index)
if (cacheTabbarEnable) {
uni.switchTab({ url })
} else {
uni.navigateTo({ url })
}
}
onLoad(() => {
// tabBar 2 tabBar
const hideRedundantTabbarEnable = selectedTabbarStrategy === 1
hideRedundantTabbarEnable &&
uni.hideTabBar({
fail(err) {
console.log('hideTabBar fail: ', err)
},
success(res) {
console.log('hideTabBar success: ', res)
},
})
})
</script>

View File

@ -0,0 +1,16 @@
# tabbar 说明
tabbar 分为4种情况
- 完全原生tabbar使用 switchTab 切换 tabbartabbar页面有缓存。
- 优势原生自带的tabbar最先渲染有缓存。
- 劣势只能使用2组图片来切换选中和非选中状态修改颜色只能重新换图片或者用iconfont
- 半自定义tabbar使用 switchTab 切换 tabbartabbar页面有缓存。使用了第三方UI库的 tabbar 组件,并隐藏了原生 tabbar 的显示。
- 优势:可以随意配置自己想要的 svg icon切换字体颜色方便。有缓存。可以实现各种花里胡哨的动效等。
- 劣势首次点击tababr会闪烁。
- 全自定义tabbar使用 navigateTo 切换tabbartabbar页面无缓存。使用了第三方UI库的 tabbar 组件。
- 优势:可以随意配置自己想要的 svg icon切换字体颜色方便。可以实现各种花里胡哨的动效等。
- 劣势首次点击tababr会闪烁无缓存。
- 无tabbar只有一个页面入口底部无tabbar显示常用语临时活动页。
> 注意:花里胡哨的效果需要自己实现,本模版不提供。

View File

@ -0,0 +1,11 @@
/**
* tabbar storageSync tabbar
* 使reactive简单状态 pinia
*/
export const tabbarStore = reactive({
curIdx: uni.getStorageSync('app-tabbar-index') || 0,
setCurIdx(idx: number) {
this.curIdx = idx
uni.setStorageSync('app-tabbar-index', idx)
},
})

View File

@ -0,0 +1,65 @@
/**
* tabbar tabbar.md
* 0: 'NATIVE_TABBAR'
* 2: 'FULL_CUSTOM_TABBAR'
* 1: 'HALF_CUSTOM_TABBAR'
* 3: 'NO_TABBAR'
*
* pages.json
*/
// TODO通过这里切换使用tabbar的策略
export const selectedTabbarStrategy = 0
// 0 和 1 时需要tabbar缓存
export const cacheTabbarEnable = selectedTabbarStrategy < 2
// selectedTabbarStrategy==0 时,需要填 iconPath 和 selectedIconPath
// selectedTabbarStrategy==1 or 2 时,需要填 icon 和 iconType
// selectedTabbarStrategy==3 时tabbarList 不生效
export const tabbarList = [
{
iconPath: 'static/tabbar/home.png',
selectedIconPath: 'static/tabbar/homeHL.png',
pagePath: 'pages/index/index',
text: '首页',
icon: 'home',
iconType: 'wot',
},
{
iconPath: 'static/tabbar/example.png',
selectedIconPath: 'static/tabbar/exampleHL.png',
pagePath: 'pages/about/about',
text: '关于',
icon: 'i-carbon-code',
// 注意 unocss 的图标需要在 页面上引入一下,或者配置到 unocss.config.ts 的 safelist 中
iconType: 'unocss',
},
// {
// pagePath: 'pages/my/index',
// text: '我的',
// icon: '/static/logo.svg',
// iconType: 'local',
// },
// {
// pagePath: 'pages/mine/index',
// text: '我的',
// icon: 'iconfont icon-my',
// iconType: 'iconfont',
// },
]
const _tabbar = {
color: '#999999',
selectedColor: '#018d71',
backgroundColor: '#F8F8F8',
borderStyle: 'black',
height: '50px',
fontSize: '10px',
iconWidth: '24px',
spacing: '3px',
list: tabbarList,
}
// 0和1 需要显示底部的tabbar的各种配置以利用缓存
export const tabBar = cacheTabbarEnable ? _tabbar : undefined

19
src/layouts/tabbar.vue Normal file
View File

@ -0,0 +1,19 @@
<template>
<wd-config-provider :themeVars="themeVars">
<slot />
<fg-tabbar />
<wd-toast />
<wd-message-box />
</wd-config-provider>
</template>
<script lang="ts" setup>
import FgTabbar from './fg-tabbar/fg-tabbar.vue'
import type { ConfigProviderThemeVars } from 'wot-design-uni'
const themeVars: ConfigProviderThemeVars = {
// colorTheme: 'red',
// buttonPrimaryBgColor: '#07c160',
// buttonPrimaryColor: '#07c160',
}
</script>

View File

@ -38,11 +38,11 @@
}
]
},
"__esModule": true,
"pages": [
{
"path": "pages/index/index",
"type": "home",
"layout": "tabbar",
"style": {
"navigationStyle": "custom",
"navigationBarTitleText": "首页"
@ -51,6 +51,7 @@
{
"path": "pages/about/about",
"type": "page",
"layout": "tabbar",
"style": {
"navigationBarTitleText": "关于"
}

View File

@ -1,5 +1,6 @@
<route lang="json5">
{
layout: 'tabbar',
style: {
navigationBarTitleText: '关于',
},
@ -7,6 +8,7 @@
</route>
<template>
<view>
<view
class="bg-white overflow-hidden pt-2 px-4"
:style="{ marginTop: safeAreaInsets?.top + 'px' }"
@ -15,6 +17,11 @@
鸽友们好我是
<text class="text-red-500">菲鸽</text>
</view>
<!-- <button @click="toSubPage()">去分包</button> -->
<view class="test-css">测试 scss 样式</view>
<RequestComp />
<UploadComp />
</view>
<RequestComp />
<UploadComp />
</view>
@ -37,6 +44,7 @@ const toSubPage = () => {
// console.log('oxlint')
// }
// testOxlint('oxlint')
console.log('about')
</script>
<style lang="scss" scoped>

View File

@ -14,8 +14,8 @@
<template v-else>
<view class="m-2">上传后返回的接口数据</view>
<view class="m-2">{{ data }}</view>
<view class="h-80 w-full">
<image v-if="data" :src="data.url" mode="scaleToFill" />
<view v-if="data" class="h-80 w-full">
<image :src="data.url" mode="scaleToFill" />
</view>
</template>
</view>

View File

@ -1,17 +1,16 @@
<!-- 使用 type="home" 属性设置首页其他页面不需要设置默认为page推荐使用json5更强大且允许注释 -->
<route lang="json5" type="home">
{
layout: 'tabbar',
style: {
// 'custom' 'default'
navigationStyle: 'custom',
navigationBarTitleText: '首页',
},
}
</route>
<template>
<view
class="bg-white overflow-hidden pt-2 px-4"
:style="{ marginTop: safeAreaInsets?.top + 'px' }"
>
<view class="bg-white pt-2 px-4" :style="{ marginTop: safeAreaInsets?.top + 'px' }">
<view class="mt-12">
<image src="/static/logo.svg" alt="" class="w-28 h-28 block mx-auto" />
</view>
@ -68,4 +67,6 @@ const description = ref(
onLoad(() => {
console.log('项目作者:', author.value)
})
console.log('index')
</script>

View File

@ -1,4 +1,4 @@
// @import './iconfont.css';
@import './iconfont.css';
.test {
// 可以通过 @apply 多个样式封装整体样式

View File

@ -1,9 +1,6 @@
import pagesConfig from '@/pages.json'
import { pages, subPackages } from '@/pages.json'
import { isMpWeixin } from './platform'
const { pages, subPackages, tabBar = { list: [] } } = { ...pagesConfig }
export const tabBarList = tabBar.list
export const getLastPage = () => {
// getCurrentPages() 至少有1个元素所以不再额外判断
// const lastPage = getCurrentPages().at(-1)
@ -12,38 +9,6 @@ export const getLastPage = () => {
return pages[pages.length - 1]
}
/** 判断当前页面是否是 tabbar 页 */
export const getIsTabbar = () => {
try {
const lastPage = getLastPage()
const currPath = lastPage?.route
return Boolean(tabBar?.list?.some((item) => item.pagePath === currPath))
} catch {
return false
}
}
/**
* tabbar
* @param path
* @returns true: tabbar false: tabbar
*/
export const isTableBar = (path: string) => {
if (!tabBar) {
return false
}
if (!tabBar.list.length) {
// 通常有 tabBar 的话list 不能有空且至少有2个元素这里其实不用处理
return false
}
// 这里需要处理一下 path因为 tabBar 中的 pagePath 是不带 /pages 前缀的
if (path.startsWith('/')) {
path = path.substring(1)
}
return !!tabBar.list.find((e) => e.pagePath === path)
}
/**
* path redirectPath
* path '/pages/login/index'

View File

@ -39,6 +39,7 @@ export default defineConfig({
center: 'flex justify-center items-center',
},
],
safelist: [],
rules: [
[
'p-safe',