create-unibest 4.0.2 → 4.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,145 @@
1
+ import type { TabBar } from '@uni-helper/vite-plugin-uni-pages'
2
+ import type { CustomTabBarItem, NativeTabBarItem } from './types'
3
+
4
+ /**
5
+ * tabbar 选择的策略,更详细的介绍见 tabbar.md 文件
6
+ * 0: 'NO_TABBAR' `无 tabbar`
7
+ * 1: 'NATIVE_TABBAR' `原生 tabbar`
8
+ * 2: 'CUSTOM_TABBAR' `自定义 tabbar`
9
+ *
10
+ * 温馨提示:本文件的任何代码更改了之后,都需要重新运行,否则 pages.json 不会更新导致配置不生效
11
+ */
12
+ export const TABBAR_STRATEGY_MAP = {
13
+ NO_TABBAR: 0,
14
+ NATIVE_TABBAR: 1,
15
+ CUSTOM_TABBAR: 2,
16
+ }
17
+
18
+ // TODO: 1/3. 通过这里切换使用tabbar的策略
19
+ // 如果是使用 NO_TABBAR(0),nativeTabbarList 和 customTabbarList 都不生效
20
+ // 如果是使用 NATIVE_TABBAR(1),只需要配置 nativeTabbarList,customTabbarList 不生效
21
+ // 如果是使用 CUSTOM_TABBAR(2),只需要配置 customTabbarList,nativeTabbarList 不生效
22
+ export const selectedTabbarStrategy = TABBAR_STRATEGY_MAP.CUSTOM_TABBAR
23
+
24
+ // TODO: 2/3. 使用 NATIVE_TABBAR 时,更新下面的 tabbar 配置
25
+ export const nativeTabbarList: NativeTabBarItem[] = [
26
+ {
27
+ iconPath: 'static/tabbar/home.png',
28
+ selectedIconPath: 'static/tabbar/homeHL.png',
29
+ pagePath: 'pages/index/index',
30
+ text: '%tabbar.home%',
31
+ },
32
+ {
33
+ iconPath: 'static/tabbar/personal.png',
34
+ selectedIconPath: 'static/tabbar/personalHL.png',
35
+ pagePath: 'pages/me/me',
36
+ text: '%tabbar.me%',
37
+ },
38
+ ]
39
+
40
+ // TODO: 3/3. 使用 CUSTOM_TABBAR 时,更新下面的 tabbar 配置
41
+ // 如果需要配置鼓包,需要在 'tabbar/store.ts' 里面设置,最后在 `tabbar/index.vue` 里面更改鼓包的图片
42
+ export const customTabbarList: CustomTabBarItem[] = [
43
+ {
44
+ text: '%tabbar.home%',
45
+ pagePath: 'pages/index/index',
46
+ // 注意 unocss 图标需要如下处理:(二选一)
47
+ // 1)在fg-tabbar.vue页面上引入一下并注释掉(见tabbar/index.vue代码第2行)
48
+ // 2)配置到 unocss.config.ts 的 safelist 中
49
+ iconType: 'unocss',
50
+ icon: 'i-carbon-home',
51
+ // badge: 'dot',
52
+ },
53
+ // 鼓包配置示例(2025-12-31)
54
+ // 中间鼓包tabbarItem配置:通常是扫描按钮、发布按钮、更多按钮等,点击触发业务逻辑
55
+ // {
56
+ // pagePath: 'pages/me/me',
57
+ // text: '我的',
58
+ // // 1)在fg-tabbar.vue页面上引入一下并注释掉(见tabbar/index.vue代码第2行)
59
+ // // 2)配置到 unocss.config.ts 的 safelist 中
60
+ // iconType: 'image',
61
+ // icon: '/static/tabbar/scan.png',
62
+ // isBulge: true,
63
+ // },
64
+ {
65
+ pagePath: 'pages/i18n/index',
66
+ text: '%i18n.title%',
67
+ iconType: 'unocss',
68
+ icon: 'i-carbon-ibm-watson-language-translator',
69
+ // badge: 10,
70
+ },
71
+ {
72
+ pagePath: 'pages/me/me',
73
+ text: '%tabbar.me%',
74
+ iconType: 'unocss',
75
+ icon: 'i-carbon-user',
76
+ // badge: 10,
77
+ },
78
+
79
+ // 其他类型演示
80
+ // 1、uiLib
81
+ // {
82
+ // pagePath: 'pages/index/index',
83
+ // text: '首页',
84
+ // iconType: 'uiLib',
85
+ // icon: 'home',
86
+ // },
87
+ // 2、iconfont
88
+ // {
89
+ // pagePath: 'pages/index/index',
90
+ // text: '首页',
91
+ // // 注意 iconfont 图标需要额外加上 'iconfont',如下
92
+ // iconType: 'iconfont',
93
+ // icon: 'iconfont icon-my',
94
+ // },
95
+ // 3、image
96
+ // {
97
+ // pagePath: 'pages/index/index',
98
+ // text: '首页',
99
+ // // 使用 ‘image’时,需要配置 icon + iconActive 2张图片
100
+ // iconType: 'image',
101
+ // icon: '/static/tabbar/home.png',
102
+ // iconActive: '/static/tabbar/homeHL.png',
103
+ // },
104
+ ]
105
+
106
+ /**
107
+ * 是否启用 tabbar 缓存
108
+ * NATIVE_TABBAR(1) 和 CUSTOM_TABBAR(2) 时,需要tabbar缓存
109
+ */
110
+ export const tabbarCacheEnable
111
+ = [TABBAR_STRATEGY_MAP.NATIVE_TABBAR, TABBAR_STRATEGY_MAP.CUSTOM_TABBAR].includes(selectedTabbarStrategy)
112
+
113
+ /**
114
+ * 是否启用自定义 tabbar
115
+ * CUSTOM_TABBAR(2) 时,启用自定义tabbar
116
+ */
117
+ export const customTabbarEnable = [TABBAR_STRATEGY_MAP.CUSTOM_TABBAR].includes(selectedTabbarStrategy)
118
+
119
+ /**
120
+ * 是否需要隐藏原生 tabbar
121
+ * CUSTOM_TABBAR(2) 时,需要隐藏原生tabbar
122
+ */
123
+ export const needHideNativeTabbar = selectedTabbarStrategy === TABBAR_STRATEGY_MAP.CUSTOM_TABBAR
124
+
125
+ const _tabbarList = customTabbarEnable ? customTabbarList.map(item => ({ text: item.text, pagePath: item.pagePath })) : nativeTabbarList
126
+ export const tabbarList = customTabbarEnable ? customTabbarList : nativeTabbarList
127
+
128
+ // NATIVE_TABBAR(1) 时,显示原生Tabbar,在i18n的情况下需要 setTabbarItem (框架已经处理)
129
+ export const isNativeTabbar = selectedTabbarStrategy === TABBAR_STRATEGY_MAP.NATIVE_TABBAR
130
+
131
+ const _tabbar: TabBar = {
132
+ // 只有微信小程序支持 custom。App 和 H5 不生效
133
+ custom: selectedTabbarStrategy === TABBAR_STRATEGY_MAP.CUSTOM_TABBAR,
134
+ color: '#999999',
135
+ selectedColor: '#018d71',
136
+ backgroundColor: '#F8F8F8',
137
+ borderStyle: 'black',
138
+ height: '50px',
139
+ fontSize: '10px',
140
+ iconWidth: '24px',
141
+ spacing: '3px',
142
+ list: _tabbarList as unknown as TabBar['list'],
143
+ }
144
+
145
+ export const tabBar = tabbarCacheEnable ? _tabbar : undefined
@@ -0,0 +1,29 @@
1
+ import { t } from '@/locale'
2
+ import { isCurrentPageTabbar } from '@/utils'
3
+ import { isNativeTabbar, tabbarList } from './config'
4
+
5
+ // h5 中一直可以生效,小程序里面默认是无法动态切换的,这里借助vue模板自带响应式的方式
6
+ // 直接替换 %xxx% 为 t('xxx')即可
7
+ export function getI18nText(key: string) {
8
+ // 获取 %xxx% 中的 xxx
9
+ const match = key.match(/%(.+?)%/)
10
+ if (match) {
11
+ key = match[1]
12
+ }
13
+ console.log('设置多语言:', key)
14
+ return t(key)
15
+ }
16
+
17
+ export function setTabbarItem() {
18
+ // 只有使用原生Tabbar才需要 setTabbarItem
19
+ // 而且只有当前页是tabbar页才能设置
20
+ console.log('设置多语言:setTabBarItem', isNativeTabbar, isCurrentPageTabbar())
21
+ if (isNativeTabbar && isCurrentPageTabbar()) {
22
+ tabbarList.forEach((item, index) => {
23
+ uni.setTabBarItem({
24
+ index,
25
+ text: getI18nText(item.text),
26
+ })
27
+ })
28
+ }
29
+ }
@@ -0,0 +1,140 @@
1
+ <script setup lang="ts">
2
+ // i-carbon-code
3
+ import { customTabbarEnable, needHideNativeTabbar, tabbarCacheEnable } from './config'
4
+ import { setTabbarItem } from './i18n'
5
+ import { tabbarList, tabbarStore } from './store'
6
+ import TabbarItem from './TabbarItem.vue'
7
+
8
+ // #ifdef MP-WEIXIN
9
+ // 将自定义节点设置成虚拟的(去掉自定义组件包裹层),更加接近Vue组件的表现,能更好的使用flex属性
10
+ defineOptions({
11
+ virtualHost: true,
12
+ })
13
+ // #endif
14
+
15
+ /**
16
+ * 中间的鼓包tabbarItem的点击事件
17
+ */
18
+ function handleClickBulge() {
19
+ uni.showToast({
20
+ title: '点击了中间的鼓包tabbarItem',
21
+ icon: 'none',
22
+ })
23
+ }
24
+
25
+ function handleClick(index: number) {
26
+ // 点击原来的不做操作
27
+ if (index === tabbarStore.curIdx) {
28
+ return
29
+ }
30
+ if (tabbarList[index].isBulge) {
31
+ handleClickBulge()
32
+ return
33
+ }
34
+ const url = tabbarList[index].pagePath
35
+ tabbarStore.setCurIdx(index)
36
+ if (tabbarCacheEnable) {
37
+ uni.switchTab({ url })
38
+ }
39
+ else {
40
+ uni.navigateTo({ url })
41
+ }
42
+ }
43
+ // #ifndef MP-WEIXIN || MP-ALIPAY
44
+ // 因为有了 custom:true, 微信里面不需要多余的hide操作
45
+ onLoad(() => {
46
+ // 解决原生 tabBar 未隐藏导致有2个 tabBar 的问题
47
+ needHideNativeTabbar
48
+ && uni.hideTabBar({
49
+ fail(err) {
50
+ console.log('hideTabBar fail: ', err)
51
+ },
52
+ success(res) {
53
+ // console.log('hideTabBar success: ', res)
54
+ },
55
+ })
56
+ })
57
+ // #endif
58
+
59
+ // #ifdef MP-ALIPAY
60
+ onMounted(() => {
61
+ // 解决支付宝自定义tabbar 未隐藏导致有2个 tabBar 的问题; 注意支付宝很特别,需要在 onMounted 钩子调用
62
+ customTabbarEnable // 另外,支付宝里面,只要是 customTabbar 都需要隐藏
63
+ && uni.hideTabBar({
64
+ fail(err) {
65
+ console.log('hideTabBar fail: ', err)
66
+ },
67
+ success(res) {
68
+ // console.log('hideTabBar success: ', res)
69
+ },
70
+ })
71
+ })
72
+ // #endif
73
+ const activeColor = 'var(--wot-color-theme, #1890ff)'
74
+ const inactiveColor = '#666'
75
+ function getColorByIndex(index: number) {
76
+ return tabbarStore.curIdx === index ? activeColor : inactiveColor
77
+ }
78
+
79
+ // 注意,上面处理的是自定义tabbar,下面处理的是原生tabbar,参考:https://unibest.tech/base/10-i18n
80
+ onShow(() => {
81
+ setTabbarItem()
82
+ })
83
+ </script>
84
+
85
+ <template>
86
+ <view v-if="customTabbarEnable" class="h-50px pb-safe">
87
+ <view class="border-and-fixed bg-white" @touchmove.stop.prevent>
88
+ <view class="h-50px flex items-center">
89
+ <view
90
+ v-for="(item, index) in tabbarList" :key="index"
91
+ class="flex flex-1 flex-col items-center justify-center"
92
+ :style="{ color: getColorByIndex(index) }"
93
+ @click="handleClick(index)"
94
+ >
95
+ <view v-if="item.isBulge" class="relative">
96
+ <!-- 中间一个鼓包tabbarItem的处理 -->
97
+ <view class="bulge">
98
+ <TabbarItem :item="item" :index="index" class="text-center" is-bulge />
99
+ </view>
100
+ </view>
101
+ <TabbarItem v-else :item="item" :index="index" class="relative px-3 text-center" />
102
+ </view>
103
+ </view>
104
+
105
+ <view class="pb-safe" />
106
+ </view>
107
+ </view>
108
+ </template>
109
+
110
+ <style scoped lang="scss">
111
+ .border-and-fixed {
112
+ position: fixed;
113
+ bottom: 0;
114
+ left: 0;
115
+ right: 0;
116
+ z-index: 1000;
117
+ border-top: 1px solid #eee;
118
+ box-sizing: border-box;
119
+ }
120
+ // 中间鼓包的样式
121
+ .bulge {
122
+ position: absolute;
123
+ top: -20px;
124
+ left: 50%;
125
+ transform-origin: top center;
126
+ transform: translateX(-50%) scale(0.5) translateY(-33%);
127
+ display: flex;
128
+ justify-content: center;
129
+ align-items: center;
130
+ width: 250rpx;
131
+ height: 250rpx;
132
+ border-radius: 50%;
133
+ background-color: #fff;
134
+ box-shadow: inset 0 0 0 1px #fefefe;
135
+
136
+ &:active {
137
+ // opacity: 0.8;
138
+ }
139
+ }
140
+ </style>
@@ -0,0 +1,8 @@
1
+ export {}
2
+
3
+ declare module 'vue' {
4
+ interface ComponentCustomProperties {
5
+ $t: (key: string, opt?: Record<string, any>) => string
6
+ $tm: (key: string, opt?: Record<string, any>) => [] | { [p: string]: any }
7
+ }
8
+ }
@@ -0,0 +1,10 @@
1
+ import { t } from '@/locale/index'
2
+
3
+ /** 非vue 文件使用 i18n */
4
+ export function testI18n() {
5
+ // 下面同样生效
6
+ uni.showModal({
7
+ title: 'i18n 测试',
8
+ content: t('i18n.title'),
9
+ })
10
+ }
@@ -0,0 +1,179 @@
1
+ import type { PageMetaDatum, SubPackages } from '@uni-helper/vite-plugin-uni-pages'
2
+ import { isMpWeixin } from '@uni-helper/uni-env'
3
+ import { pages, subPackages } from '@/pages.json'
4
+ import { isPageTabbar } from '@/tabbar/store'
5
+
6
+ export type PageInstance = Page.PageInstance<AnyObject, object> & { $page: Page.PageInstance<AnyObject, object> & { fullPath: string } }
7
+
8
+ export function getLastPage() {
9
+ // getCurrentPages() 至少有1个元素,所以不再额外判断
10
+ // const lastPage = getCurrentPages().at(-1)
11
+ // 上面那个在低版本安卓中打包会报错,所以改用下面这个【虽然我加了 src/interceptions/prototype.ts,但依然报错】
12
+ const pages = getCurrentPages()
13
+ return pages[pages.length - 1] as PageInstance
14
+ }
15
+
16
+ /**
17
+ * 获取当前页面路由的 path 路径和 redirectPath 路径
18
+ * path 如 '/pages/login/login'
19
+ * redirectPath 如 '/pages/demo/base/route-interceptor'
20
+ */
21
+ export function currRoute() {
22
+ const lastPage = getLastPage() as PageInstance
23
+ if (!lastPage) {
24
+ return {
25
+ path: '',
26
+ query: {},
27
+ }
28
+ }
29
+ const currRoute = lastPage.$page
30
+ // console.log('lastPage.$page:', currRoute)
31
+ // console.log('lastPage.$page.fullpath:', currRoute.fullPath)
32
+ // console.log('lastPage.$page.options:', currRoute.options)
33
+ // console.log('lastPage.options:', (lastPage as any).options)
34
+ // 经过多端测试,只有 fullPath 靠谱,其他都不靠谱
35
+ const { fullPath } = currRoute
36
+ // console.log(fullPath)
37
+ // eg: /pages/login/login?redirect=%2Fpages%2Fdemo%2Fbase%2Froute-interceptor (小程序)
38
+ // eg: /pages/login/login?redirect=%2Fpages%2Froute-interceptor%2Findex%3Fname%3Dfeige%26age%3D30(h5)
39
+ return parseUrlToObj(fullPath)
40
+ }
41
+
42
+ export function ensureDecodeURIComponent(url: string) {
43
+ if (url.startsWith('%')) {
44
+ return ensureDecodeURIComponent(decodeURIComponent(url))
45
+ }
46
+ return url
47
+ }
48
+ /**
49
+ * 解析 url 得到 path 和 query
50
+ * 比如输入url: /pages/login/login?redirect=%2Fpages%2Fdemo%2Fbase%2Froute-interceptor
51
+ * 输出: {path: /pages/login/login, query: {redirect: /pages/demo/base/route-interceptor}}
52
+ */
53
+ export function parseUrlToObj(url: string) {
54
+ const [path, queryStr] = url.split('?')
55
+ // console.log(path, queryStr)
56
+
57
+ if (!queryStr) {
58
+ return {
59
+ path,
60
+ query: {},
61
+ }
62
+ }
63
+ const query: Record<string, string> = {}
64
+ queryStr.split('&').forEach((item) => {
65
+ const [key, value] = item.split('=')
66
+ // console.log(key, value)
67
+ query[key] = ensureDecodeURIComponent(value) // 这里需要统一 decodeURIComponent 一下,可以兼容h5和微信y
68
+ })
69
+ return { path, query }
70
+ }
71
+ /**
72
+ * 得到所有的需要登录的 pages,包括主包和分包的
73
+ * 这里设计得通用一点,可以传递 key 作为判断依据,默认是 excludeLoginPath, 与 route-block 配对使用
74
+ * 如果没有传 key,则表示所有的 pages,如果传递了 key, 则表示通过 key 过滤
75
+ */
76
+ export function getAllPages(key?: string) {
77
+ // 这里处理主包
78
+ const mainPages = (pages as PageMetaDatum[])
79
+ .filter(page => !key || page[key])
80
+ .map(page => ({
81
+ ...page,
82
+ path: `/${page.path}`,
83
+ }))
84
+
85
+ // 这里处理分包
86
+ const subPages: PageMetaDatum[] = []
87
+ ;(subPackages as SubPackages).forEach((subPageObj) => {
88
+ // console.log(subPageObj)
89
+ const { root } = subPageObj
90
+
91
+ subPageObj.pages
92
+ .filter(page => !key || page[key])
93
+ .forEach((page) => {
94
+ subPages.push({
95
+ ...page,
96
+ path: `/${root}/${page.path}`,
97
+ })
98
+ })
99
+ })
100
+ const result = [...mainPages, ...subPages]
101
+ // console.log(`getAllPages by ${key} result: `, result)
102
+ return result
103
+ }
104
+
105
+ export function getCurrentPageI18nKey() {
106
+ const routeObj = currRoute()
107
+
108
+ let currPage = (pages as PageMetaDatum[]).find(page => `/${page.path}` === routeObj.path)
109
+ if (!currPage) {
110
+ // 在主包中找不到对应的页面,则在分包中找
111
+ const allSubPages: PageMetaDatum[] = []
112
+ subPackages?.forEach((config) => {
113
+ config.pages?.forEach((cur) => {
114
+ allSubPages.push({
115
+ ...cur,
116
+ path: `/${config.root}/${cur.path}`,
117
+ })
118
+ })
119
+ })
120
+ currPage = allSubPages.find(page => page.path === routeObj.path)
121
+ if (!currPage) {
122
+ console.warn('路由不正确')
123
+ return ''
124
+ }
125
+ }
126
+ console.log(currPage)
127
+ console.log(currPage.style.navigationBarTitleText)
128
+ return currPage.style?.navigationBarTitleText || ''
129
+ }
130
+
131
+ export function isCurrentPageTabbar() {
132
+ const { path } = currRoute()
133
+ return isPageTabbar(path)
134
+ }
135
+
136
+ /**
137
+ * 根据微信小程序当前环境,判断应该获取的 baseUrl
138
+ */
139
+ export function getEnvBaseUrl() {
140
+ // 请求基准地址
141
+ let baseUrl = import.meta.env.VITE_SERVER_BASEURL
142
+
143
+ // # 有些同学可能需要在微信小程序里面根据 develop、trial、release 分别设置上传地址,参考代码如下。
144
+ const VITE_SERVER_BASEURL__WEIXIN_DEVELOP = 'https://ukw0y1.laf.run'
145
+ const VITE_SERVER_BASEURL__WEIXIN_TRIAL = 'https://ukw0y1.laf.run'
146
+ const VITE_SERVER_BASEURL__WEIXIN_RELEASE = 'https://ukw0y1.laf.run'
147
+
148
+ // 微信小程序端环境区分
149
+ if (isMpWeixin) {
150
+ const {
151
+ miniProgram: { envVersion },
152
+ } = uni.getAccountInfoSync()
153
+
154
+ switch (envVersion) {
155
+ case 'develop':
156
+ baseUrl = VITE_SERVER_BASEURL__WEIXIN_DEVELOP || baseUrl
157
+ break
158
+ case 'trial':
159
+ baseUrl = VITE_SERVER_BASEURL__WEIXIN_TRIAL || baseUrl
160
+ break
161
+ case 'release':
162
+ baseUrl = VITE_SERVER_BASEURL__WEIXIN_RELEASE || baseUrl
163
+ break
164
+ }
165
+ }
166
+
167
+ return baseUrl
168
+ }
169
+
170
+ /**
171
+ * 是否是双token模式
172
+ */
173
+ export const isDoubleTokenMode = import.meta.env.VITE_AUTH_MODE === 'double'
174
+
175
+ /**
176
+ * 首页路径,通过 page.json 里面的 type 为 home 的页面获取,如果没有,则默认是第一个页面
177
+ * 通常为 /pages/index/index
178
+ */
179
+ export const HOME_PAGE = `/${(pages as PageMetaDatum[]).find(page => page.type === 'home')?.path || (pages as PageMetaDatum[])[0].path}`
@@ -0,0 +1,9 @@
1
+ import type { FeatureContext } from '../../packages/cli/src/features/interface'
2
+
3
+ export async function preApply(ctx: FeatureContext) {
4
+ console.log(`[i18n] Pre-apply for ${ctx.projectPath}`)
5
+ }
6
+
7
+ export async function postApply(ctx: FeatureContext) {
8
+ console.log(`[i18n] Post-apply for ${ctx.projectPath}`)
9
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "@unibest/feature-i18n",
3
+ "version": "1.0.0",
4
+ "description": "unibest i18n feature",
5
+ "dependencies": {
6
+ "dayjs": "^1.11.0",
7
+ "vue-i18n": "^9.0.0"
8
+ }
9
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "type": "object",
4
+ "properties": {
5
+ "locales": {
6
+ "type": "array",
7
+ "items": { "type": "string" },
8
+ "default": ["zh-Hans", "en"],
9
+ "description": "支持的语言列表"
10
+ }
11
+ },
12
+ "required": []
13
+ }
@@ -0,0 +1,20 @@
1
+ # 登录页
2
+ 需要输入账号、密码/验证码的登录页。
3
+
4
+ ## 适用性
5
+
6
+ 本页面主要用于 `h5` 和 `APP`。
7
+
8
+ 小程序通常有平台的登录方式 `uni.login` 通常用不到登录页,所以不适用于 `小程序`。(即默认情况下,小程序环境是不会走登录拦截逻辑的。)
9
+
10
+ 但是如果您的小程序也需要现实的 `登录页` 那也是可以使用的。
11
+
12
+ 在 `src/router/config.ts` 中有一个变量 `LOGIN_PAGE_ENABLE_IN_MP` 来控制是否在小程序中使用 `H5的登录页`。
13
+
14
+ 更多信息请看 `src/router` 文件夹的内容。
15
+
16
+ ## 登录跳转
17
+
18
+ 目前登录的跳转逻辑主要在 `src/router/interceptor.ts` 和 `src/pages/login/login.vue` 里面,默认会在登录后自动重定向到来源/配置的页面。
19
+
20
+ 如果与您的业务不符,您可以自行修改。
@@ -0,0 +1,44 @@
1
+ <script lang="ts" setup>
2
+ import { useTokenStore } from '@/store/token'
3
+
4
+ definePage({
5
+ style: {
6
+ navigationBarTitleText: '登录',
7
+ },
8
+ })
9
+
10
+ const tokenStore = useTokenStore()
11
+ async function doLogin() {
12
+ if (tokenStore.hasLogin) {
13
+ uni.navigateBack()
14
+ return
15
+ }
16
+ try {
17
+ // 调用登录接口
18
+ await tokenStore.login({
19
+ username: '菲鸽',
20
+ password: '123456',
21
+ })
22
+ uni.navigateBack()
23
+ }
24
+ catch (error) {
25
+ console.log('登录失败', error)
26
+ }
27
+ }
28
+ </script>
29
+
30
+ <template>
31
+ <view class="login">
32
+ <!-- 本页面是非MP的登录页,主要用于 h5 和 APP -->
33
+ <view class="text-center">
34
+ 登录页
35
+ </view>
36
+ <button class="mt-4 w-40 text-center" @click="doLogin">
37
+ 点击模拟登录
38
+ </button>
39
+ </view>
40
+ </template>
41
+
42
+ <style lang="scss" scoped>
43
+ //
44
+ </style>
@@ -0,0 +1,34 @@
1
+ <script lang="ts" setup>
2
+ import { LOGIN_PAGE } from '@/router/config'
3
+
4
+ definePage({
5
+ style: {
6
+ navigationBarTitleText: '注册',
7
+ },
8
+ })
9
+
10
+ function doRegister() {
11
+ uni.showToast({
12
+ title: '注册成功',
13
+ })
14
+ // 注册成功后跳转到登录页
15
+ uni.navigateTo({
16
+ url: LOGIN_PAGE,
17
+ })
18
+ }
19
+ </script>
20
+
21
+ <template>
22
+ <view class="login">
23
+ <view class="text-center">
24
+ 注册页
25
+ </view>
26
+ <button class="mt-4 w-40 text-center" @click="doRegister">
27
+ 点击模拟注册
28
+ </button>
29
+ </view>
30
+ </template>
31
+
32
+ <style lang="scss" scoped>
33
+ //
34
+ </style>