create-young-proj 1.4.0 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +32 -0
- package/package.json +1 -1
- package/template-nuxt-admin/README.md +1 -1
- package/template-nuxt-admin/nuxt.config.ts +4 -5
- package/template-nuxt-admin/package.json +0 -1
- package/template-nuxt-admin/server/plugins/env.ts +8 -0
- package/template-nuxt-admin/yarn.lock +0 -5
- package/template-nuxt-mobile/.nvmrc +1 -0
- package/{template-vue-mobile → template-nuxt-mobile}/.vscode/extensions.json +5 -3
- package/template-nuxt-mobile/.vscode/settings.json +39 -0
- package/{template-vue-mobile → template-nuxt-mobile}/Dockerfile +12 -13
- package/template-nuxt-mobile/README.md +90 -0
- package/template-nuxt-mobile/_gitignore +26 -0
- package/template-nuxt-mobile/_npmrc +2 -0
- package/template-nuxt-mobile/_nvmrc +1 -0
- package/template-nuxt-mobile/app.vue +79 -0
- package/template-nuxt-mobile/boot.mjs +17 -0
- package/template-nuxt-mobile/components/young/CodeInput.vue +72 -0
- package/template-nuxt-mobile/composables/api.ts +57 -0
- package/template-nuxt-mobile/composables/apis/get.ts +22 -0
- package/template-nuxt-mobile/composables/apis/index.ts +8 -0
- package/template-nuxt-mobile/composables/apis/post.ts +39 -0
- package/template-nuxt-mobile/composables/share.ts +22 -0
- package/template-nuxt-mobile/composables/user.ts +48 -0
- package/template-nuxt-mobile/composables/utils.ts +80 -0
- package/template-nuxt-mobile/config/.devrc +2 -0
- package/template-nuxt-mobile/env.d.ts +65 -0
- package/template-nuxt-mobile/error.vue +69 -0
- package/template-nuxt-mobile/eslint.config.js +33 -0
- package/template-nuxt-mobile/layouts/blank.vue +11 -0
- package/template-nuxt-mobile/layouts/default.vue +32 -0
- package/template-nuxt-mobile/layouts/tabbar.vue +29 -0
- package/template-nuxt-mobile/middleware/auth.global.ts +34 -0
- package/template-nuxt-mobile/nuxt.config.ts +78 -0
- package/template-nuxt-mobile/package.json +40 -0
- package/template-nuxt-mobile/pages/base/login.vue +124 -0
- package/template-nuxt-mobile/pages/base/resetPasswd.vue +84 -0
- package/template-nuxt-mobile/pages/index.vue +22 -0
- package/template-nuxt-mobile/pages/my.vue +18 -0
- package/template-nuxt-mobile/pages/sub/[id].vue +21 -0
- package/template-nuxt-mobile/public/favicon.ico +0 -0
- package/template-nuxt-mobile/public/robots.txt +2 -0
- package/template-nuxt-mobile/server/plugins/init.ts +94 -0
- package/template-nuxt-mobile/server/routes/get/env.ts +13 -0
- package/template-nuxt-mobile/server/tsconfig.json +3 -0
- package/template-nuxt-mobile/server/utils/index.ts +12 -0
- package/template-nuxt-mobile/server/utils/proxy.ts +59 -0
- package/template-nuxt-mobile/tsconfig.json +4 -0
- package/template-nuxt-mobile/typings/system.d.ts +22 -0
- package/template-nuxt-mobile/uno.config.ts +40 -0
- package/template-nuxt-mobile/utils/tool.ts +153 -0
- package/template-nuxt-mobile/yarn.lock +7737 -0
- package/template-nuxt-website/README.md +3 -1
- package/template-nuxt-website/nuxt.config.ts +4 -5
- package/template-vitepress/Dockerfile +6 -2
- package/template-vue-mobile/.vscode/base.code-snippets +0 -24
- package/template-vue-mobile/.vscode/settings.json +0 -7
- package/template-vue-mobile/README.md +0 -71
- package/template-vue-mobile/_env +0 -6
- package/template-vue-mobile/_gitignore +0 -30
- package/template-vue-mobile/boot.mjs +0 -16
- package/template-vue-mobile/build/custom-plugin.ts +0 -30
- package/template-vue-mobile/build/index.ts +0 -7
- package/template-vue-mobile/build/plugins.ts +0 -68
- package/template-vue-mobile/config/.devrc +0 -2
- package/template-vue-mobile/index.html +0 -25
- package/template-vue-mobile/nitro.config.ts +0 -19
- package/template-vue-mobile/package.json +0 -48
- package/template-vue-mobile/plugins/env.ts +0 -26
- package/template-vue-mobile/public/vite.svg +0 -1
- package/template-vue-mobile/rome.json +0 -24
- package/template-vue-mobile/routes/[...all].ts +0 -11
- package/template-vue-mobile/routes/get/env.ts +0 -25
- package/template-vue-mobile/src/App.vue +0 -29
- package/template-vue-mobile/src/auto-components.d.ts +0 -24
- package/template-vue-mobile/src/auto-imports.d.ts +0 -289
- package/template-vue-mobile/src/components/Init.vue +0 -36
- package/template-vue-mobile/src/global.d.ts +0 -7
- package/template-vue-mobile/src/hooks/useVerifyCode.ts +0 -46
- package/template-vue-mobile/src/layouts/blank.vue +0 -9
- package/template-vue-mobile/src/layouts/default.vue +0 -27
- package/template-vue-mobile/src/layouts/sub.vue +0 -20
- package/template-vue-mobile/src/main.ts +0 -35
- package/template-vue-mobile/src/modules/1-router.ts +0 -40
- package/template-vue-mobile/src/modules/2-pinia.ts +0 -10
- package/template-vue-mobile/src/modules/3-net.ts +0 -46
- package/template-vue-mobile/src/modules/4-auth.ts +0 -64
- package/template-vue-mobile/src/views/[...all_404].vue +0 -557
- package/template-vue-mobile/src/views/base/login.vue +0 -110
- package/template-vue-mobile/src/views/base/resetPasswd.vue +0 -88
- package/template-vue-mobile/src/views/index.vue +0 -18
- package/template-vue-mobile/src/views/my.vue +0 -15
- package/template-vue-mobile/src/views/sub.vue +0 -18
- package/template-vue-mobile/src/vite-env.d.ts +0 -43
- package/template-vue-mobile/tsconfig.json +0 -21
- package/template-vue-mobile/tsconfig.node.json +0 -9
- package/template-vue-mobile/unocss.config.ts +0 -47
- package/template-vue-mobile/vite.config.ts +0 -32
- package/template-vue-mobile/yarn.lock +0 -4395
- /package/{template-vue-mobile → template-nuxt-mobile}/config/.onlinerc +0 -0
- /package/{template-vue-mobile → template-nuxt-mobile}/config/.testrc +0 -0
@@ -0,0 +1,48 @@
|
|
1
|
+
/*
|
2
|
+
* @Author: zhangyang
|
3
|
+
* @Date: 2023-06-21 12:03:42
|
4
|
+
* @LastEditTime: 2023-11-07 16:41:48
|
5
|
+
* @Description:
|
6
|
+
*/
|
7
|
+
export const useUserStore = defineStore('useUserStore', () => {
|
8
|
+
const cookie = useLocalStorage<UserLoginRes>('token', {} as UserLoginRes)
|
9
|
+
|
10
|
+
const avatar = computed(() => cookie.value?.headimgurl)
|
11
|
+
const nick = computed(() => cookie.value?.nickname)
|
12
|
+
const userId = computed(() => cookie.value?.uuid)
|
13
|
+
const token = computed(() => {
|
14
|
+
if (!validateToken())
|
15
|
+
removeToken()
|
16
|
+
|
17
|
+
return cookie.value?.token
|
18
|
+
})
|
19
|
+
const hasLogin = computed(() => !!token.value)
|
20
|
+
|
21
|
+
const SaveFlag = useLocalStorage('n天免登', true)
|
22
|
+
const Exptime = useLocalStorage('token过期时间', 0)
|
23
|
+
|
24
|
+
function validateToken() {
|
25
|
+
const now = Date.now()
|
26
|
+
const exp = Exptime.value
|
27
|
+
return now < exp
|
28
|
+
}
|
29
|
+
|
30
|
+
function removeToken() {
|
31
|
+
cookie.value = undefined
|
32
|
+
}
|
33
|
+
|
34
|
+
return {
|
35
|
+
cookie,
|
36
|
+
hasLogin,
|
37
|
+
avatar,
|
38
|
+
nick,
|
39
|
+
token,
|
40
|
+
SaveFlag,
|
41
|
+
Exptime,
|
42
|
+
removeToken,
|
43
|
+
userId,
|
44
|
+
}
|
45
|
+
})
|
46
|
+
|
47
|
+
if (import.meta.hot)
|
48
|
+
import.meta.hot.accept(acceptHMRUpdate(useUserStore, import.meta.hot))
|
@@ -0,0 +1,80 @@
|
|
1
|
+
/*
|
2
|
+
* @Author: zhangyang
|
3
|
+
* @Date: 2022-08-12 16:31:53
|
4
|
+
* @LastEditTime: 2023-11-07 18:01:33
|
5
|
+
* @Description:
|
6
|
+
*/
|
7
|
+
import { createVNode, render } from 'vue'
|
8
|
+
|
9
|
+
export function goDownload(android?: string, ios?: string) {
|
10
|
+
const { isApple } = useDevice()
|
11
|
+
if (isApple)
|
12
|
+
ios && window.open(ios)
|
13
|
+
|
14
|
+
else
|
15
|
+
android && window.open(android)
|
16
|
+
}
|
17
|
+
|
18
|
+
export function closeWindow() {
|
19
|
+
if (process.server)
|
20
|
+
return
|
21
|
+
|
22
|
+
// @ts-expect-error
|
23
|
+
if (typeof WeixinJSBridge !== 'undefined') {
|
24
|
+
// @ts-expect-error 微信浏览器关闭窗口
|
25
|
+
WeixinJSBridge.call('closeWindow')
|
26
|
+
}
|
27
|
+
|
28
|
+
// @ts-expect-error
|
29
|
+
if (typeof AlipayJSBridge !== 'undefined') {
|
30
|
+
// @ts-expect-error 支付宝浏览器关闭窗口
|
31
|
+
AlipayJSBridge.call('popWindow')
|
32
|
+
}
|
33
|
+
// 其他关闭窗口
|
34
|
+
window.close()
|
35
|
+
}
|
36
|
+
|
37
|
+
export async function showLoading() {
|
38
|
+
if (process.server)
|
39
|
+
return
|
40
|
+
|
41
|
+
showLoadingToast({
|
42
|
+
message: '加载中...',
|
43
|
+
forbidClick: true,
|
44
|
+
})
|
45
|
+
}
|
46
|
+
|
47
|
+
export function hideLoading() {
|
48
|
+
if (process.server)
|
49
|
+
return
|
50
|
+
|
51
|
+
closeToast()
|
52
|
+
}
|
53
|
+
/**
|
54
|
+
* 异步插入组件
|
55
|
+
* @param El 组件实例
|
56
|
+
*/
|
57
|
+
export function injectComponent(El: ReturnType<typeof defineComponent>) {
|
58
|
+
if (process.server)
|
59
|
+
return false
|
60
|
+
|
61
|
+
const appendTo = document.createElement('div')
|
62
|
+
|
63
|
+
const onDestroy = () => {
|
64
|
+
try {
|
65
|
+
render(null, appendTo)
|
66
|
+
}
|
67
|
+
catch (error) {
|
68
|
+
console.info('remove child error', error)
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
const vnode = createVNode(El, {
|
73
|
+
onDestroy,
|
74
|
+
})
|
75
|
+
render(vnode, appendTo)
|
76
|
+
|
77
|
+
appendTo.firstElementChild && document.body.appendChild(appendTo.firstElementChild)
|
78
|
+
|
79
|
+
return onDestroy
|
80
|
+
}
|
@@ -0,0 +1,65 @@
|
|
1
|
+
/*
|
2
|
+
* @Author: zhangyang
|
3
|
+
* @Date: 2023-05-26 11:50:06
|
4
|
+
* @LastEditTime: 2023-11-29 17:21:16
|
5
|
+
* @Description:
|
6
|
+
*/
|
7
|
+
/**
|
8
|
+
* 环境变量
|
9
|
+
*/
|
10
|
+
interface ImportMetaEnv {
|
11
|
+
/**
|
12
|
+
* 微信公众号 appid,用于网页授权登录,SDK 签名等
|
13
|
+
*/
|
14
|
+
VITE_WECHAT_APPID: string
|
15
|
+
|
16
|
+
/**
|
17
|
+
* 默认标题
|
18
|
+
*/
|
19
|
+
VITE_TITLE: string
|
20
|
+
|
21
|
+
/**
|
22
|
+
* 调试控制台
|
23
|
+
*/
|
24
|
+
VITE_VCONSOLE?: boolean
|
25
|
+
};
|
26
|
+
|
27
|
+
declare interface Window {
|
28
|
+
/**
|
29
|
+
* 注入到前端使用的环境变量
|
30
|
+
*/
|
31
|
+
__YOUNG_ENV__: ImportMetaEnv
|
32
|
+
};
|
33
|
+
|
34
|
+
declare module '#app' {
|
35
|
+
interface PageMeta {
|
36
|
+
/**
|
37
|
+
* 顶部标题
|
38
|
+
*/
|
39
|
+
title?: string
|
40
|
+
/**
|
41
|
+
* 不受 container 的宽度限制
|
42
|
+
*/
|
43
|
+
full?: boolean
|
44
|
+
/**
|
45
|
+
* main 背景色
|
46
|
+
*/
|
47
|
+
bgColor?: string
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
/**
|
52
|
+
* 路由元数据类型扩展
|
53
|
+
*/
|
54
|
+
declare module 'vue-router' {
|
55
|
+
interface RouteMeta {
|
56
|
+
/**
|
57
|
+
* 页面标题
|
58
|
+
*/
|
59
|
+
title: string
|
60
|
+
/**
|
61
|
+
* 默认需要登录,显示设置为 false 则无需登录
|
62
|
+
*/
|
63
|
+
auth?: boolean
|
64
|
+
}
|
65
|
+
}
|
@@ -0,0 +1,69 @@
|
|
1
|
+
<!--
|
2
|
+
* @Author: zhangyang
|
3
|
+
* @Date: 2023-06-12 15:00:07
|
4
|
+
* @LastEditTime: 2023-10-30 14:34:37
|
5
|
+
* @Description:
|
6
|
+
-->
|
7
|
+
<script lang="ts" setup>
|
8
|
+
import type { NuxtError } from '#app'
|
9
|
+
|
10
|
+
const props = defineProps<{
|
11
|
+
error: NuxtError
|
12
|
+
}>()
|
13
|
+
|
14
|
+
let timer: NodeJS.Timeout
|
15
|
+
|
16
|
+
const i = ref(5)
|
17
|
+
|
18
|
+
function clear() {
|
19
|
+
clearError()
|
20
|
+
clearInterval(timer)
|
21
|
+
location.replace('/')
|
22
|
+
}
|
23
|
+
|
24
|
+
onMounted(() => {
|
25
|
+
if (process.server)
|
26
|
+
return
|
27
|
+
|
28
|
+
const isDev = process.dev || window.__YOUNG_ENV__
|
29
|
+
? !!window.__YOUNG_ENV__.VITE_VCONSOLE
|
30
|
+
: location.href.includes('-dev-')
|
31
|
+
|| location.href.includes('-test-')
|
32
|
+
|
33
|
+
console.log(props.error)
|
34
|
+
if (isDev) {
|
35
|
+
console.log('开发模式,不自动清理')
|
36
|
+
const srcEl = document.createElement('script')
|
37
|
+
srcEl.src = '//g2021-cdn.laiyouxi.com/image/21Store/admin-img/vconsole.min.js'
|
38
|
+
document.body.appendChild(srcEl)
|
39
|
+
// @ts-expect-error
|
40
|
+
// eslint-disable-next-line no-new
|
41
|
+
new VConsole()
|
42
|
+
console.log(props.error)
|
43
|
+
return
|
44
|
+
}
|
45
|
+
timer = setInterval(() => {
|
46
|
+
i.value--
|
47
|
+
if (i.value === 0)
|
48
|
+
clear()
|
49
|
+
}, 1e3)
|
50
|
+
})
|
51
|
+
</script>
|
52
|
+
|
53
|
+
<template>
|
54
|
+
<div class="flex w-full h-full flex-col justify-center items-center">
|
55
|
+
<div class="text-5xl my-6">
|
56
|
+
{{ error.statusCode }}
|
57
|
+
</div>
|
58
|
+
<div class="text-lg my-2">
|
59
|
+
{{ error.statusMessage || error.message || '出错啦~' }}
|
60
|
+
</div>
|
61
|
+
|
62
|
+
<div class="mb-2">
|
63
|
+
{{ i }}s 后自动跳转首页
|
64
|
+
</div>
|
65
|
+
<ElButton @click="clear">
|
66
|
+
立即返回首页
|
67
|
+
</ElButton>
|
68
|
+
</div>
|
69
|
+
</template>
|
@@ -0,0 +1,33 @@
|
|
1
|
+
/*
|
2
|
+
* @Author: zhangyang
|
3
|
+
* @Date: 2023-11-01 10:13:50
|
4
|
+
* @LastEditTime: 2023-11-01 11:11:55
|
5
|
+
* @Description:
|
6
|
+
*/
|
7
|
+
import antfu from '@antfu/eslint-config'
|
8
|
+
|
9
|
+
export default antfu({
|
10
|
+
overrides: {
|
11
|
+
vue: {
|
12
|
+
'vue/valid-v-model': 'off',
|
13
|
+
},
|
14
|
+
typescript: {
|
15
|
+
'ts/no-use-before-define': 'off',
|
16
|
+
'ts/no-unused-vars': 'off',
|
17
|
+
'ts/ban-types': 'off',
|
18
|
+
'ts/ban-ts-comment': 'off',
|
19
|
+
},
|
20
|
+
},
|
21
|
+
rules: {
|
22
|
+
'no-console': 'off',
|
23
|
+
'node/prefer-global/process': 'off',
|
24
|
+
'unused-imports/no-unused-vars': 'off',
|
25
|
+
'no-throw-literal': 'off',
|
26
|
+
'antfu/consistent-list-newline': 'off',
|
27
|
+
'style/jsx-indent': 'off',
|
28
|
+
},
|
29
|
+
}, {
|
30
|
+
ignores: [
|
31
|
+
'public',
|
32
|
+
],
|
33
|
+
})
|
@@ -0,0 +1,32 @@
|
|
1
|
+
<!--
|
2
|
+
* @Author: zhangyang
|
3
|
+
* @Date: 2023-09-27 14:15:48
|
4
|
+
* @LastEditTime: 2023-11-29 17:19:17
|
5
|
+
* @Description:
|
6
|
+
-->
|
7
|
+
<script lang="ts" setup>
|
8
|
+
const route = useRoute()
|
9
|
+
const title = computed(() => route.meta.title || import.meta.env.VITE_TITLE)
|
10
|
+
|
11
|
+
const router = useRouter()
|
12
|
+
function backFn() {
|
13
|
+
if (history.length === 1) {
|
14
|
+
console.log('扫码直接进入, 返回直接回首页')
|
15
|
+
router.replace('/')
|
16
|
+
}
|
17
|
+
else {
|
18
|
+
router.back()
|
19
|
+
}
|
20
|
+
}
|
21
|
+
</script>
|
22
|
+
|
23
|
+
<template>
|
24
|
+
<div lg="max-w-800px mx-auto">
|
25
|
+
<VanNavBar :border="false" left-arrow @click-left="backFn">
|
26
|
+
<template #title>
|
27
|
+
<span class="text-[#FFFFFF] text-16px font-700">{{ title }}</span>
|
28
|
+
</template>
|
29
|
+
</VanNavBar>
|
30
|
+
<NuxtPage v-bind="$attrs" />
|
31
|
+
</div>
|
32
|
+
</template>
|
@@ -0,0 +1,29 @@
|
|
1
|
+
<!--
|
2
|
+
* @Author: zhangyang
|
3
|
+
* @Date: 2023-11-29 17:11:40
|
4
|
+
* @LastEditTime: 2023-11-29 17:15:39
|
5
|
+
* @Description:
|
6
|
+
-->
|
7
|
+
<script lang="ts" setup>
|
8
|
+
const route = useRoute()
|
9
|
+
const title = computed(() => route.meta.title || import.meta.env.VITE_TITLE)
|
10
|
+
</script>
|
11
|
+
|
12
|
+
<template>
|
13
|
+
<div lg="max-w-800px mx-auto">
|
14
|
+
<VanNavBar :border="false">
|
15
|
+
<template #title>
|
16
|
+
<span class="text-[#FFFFFF] text-16px font-700">{{ title }}</span>
|
17
|
+
</template>
|
18
|
+
</VanNavBar>
|
19
|
+
<NuxtPage v-bind="$attrs" />
|
20
|
+
<VanTabbar route lg="!left-50% transform max-w-800px -translate-x-50%">
|
21
|
+
<VanTabbarItem to="/" icon="home-o">
|
22
|
+
<span>首页</span>
|
23
|
+
</VanTabbarItem>
|
24
|
+
<VanTabbarItem to="/my" icon="user-o">
|
25
|
+
<span>我的</span>
|
26
|
+
</VanTabbarItem>
|
27
|
+
</VanTabbar>
|
28
|
+
</div>
|
29
|
+
</template>
|
@@ -0,0 +1,34 @@
|
|
1
|
+
/*
|
2
|
+
* @Author: zhangyang
|
3
|
+
* @Date: 2023-11-29 17:22:28
|
4
|
+
* @LastEditTime: 2023-11-29 17:56:58
|
5
|
+
* @Description:
|
6
|
+
*/
|
7
|
+
export default defineNuxtRouteMiddleware(async (to, from) => {
|
8
|
+
if (to.matched.length === 0)
|
9
|
+
throw createError({ message: '页面不存在', statusCode: 404 })
|
10
|
+
|
11
|
+
const { hasLogin } = storeToRefs(useUserStore())
|
12
|
+
console.log('🚀 ~ file: auth.global.ts:12 ~ defineNuxtRouteMiddleware ~ hasLogin:', hasLogin.value)
|
13
|
+
|
14
|
+
const changeTitle = () => {
|
15
|
+
document.title = (to.meta.title as string) || window.__YOUNG_ENV__.VITE_TITLE
|
16
|
+
}
|
17
|
+
|
18
|
+
// 页面无需登录
|
19
|
+
if (to.meta.auth === false || hasLogin.value) {
|
20
|
+
changeTitle()
|
21
|
+
return
|
22
|
+
}
|
23
|
+
|
24
|
+
if (!hasLogin.value && to.path !== '/base/login') {
|
25
|
+
// 页面需要登录,但是未登录
|
26
|
+
showNotify({
|
27
|
+
message: '未登录或登录过期,请重新登录',
|
28
|
+
type: 'danger',
|
29
|
+
})
|
30
|
+
return navigateTo(`/base/login?redirect=${encodeURIComponent(to.fullPath)}`, {
|
31
|
+
replace: true,
|
32
|
+
})
|
33
|
+
}
|
34
|
+
})
|
@@ -0,0 +1,78 @@
|
|
1
|
+
/*
|
2
|
+
* @Author: zhangyang
|
3
|
+
* @Date: 2023-09-21 15:57:55
|
4
|
+
* @LastEditTime: 2023-11-29 16:51:03
|
5
|
+
* @Description:
|
6
|
+
*/
|
7
|
+
import { resolve } from 'node:path'
|
8
|
+
|
9
|
+
// https://nuxt.com/docs/api/configuration/nuxt-config
|
10
|
+
export default defineNuxtConfig({
|
11
|
+
ssr: false,
|
12
|
+
app: {
|
13
|
+
head: {
|
14
|
+
htmlAttrs: {
|
15
|
+
lang: 'zh-CN',
|
16
|
+
},
|
17
|
+
viewport: 'width=device-width,initial-scale=1.0,user-scalable=no,shrink-to-fit=no',
|
18
|
+
meta: [
|
19
|
+
{ name: 'theme-color', content: '#ffffff' },
|
20
|
+
{ name: 'screen-orientation', content: 'portrait' },
|
21
|
+
{ name: 'x5-orientation', content: 'portrait' },
|
22
|
+
{ name: 'renderer', content: 'webkit' },
|
23
|
+
{ name: 'mobile-web-app-capable', content: 'yes' },
|
24
|
+
{ name: 'creator', content: 'BluesYoung-web' },
|
25
|
+
{ 'http-equiv': 'X-UA-Compatible', 'content': 'IE=edge,chrome=1' },
|
26
|
+
{ id: 'viewportMeta', name: 'viewport', content: 'maximum-scale=1.0,minimum-scale=1.0,user-scalable=0,width=device-width,initial-scale=1.0' },
|
27
|
+
{ name: 'format-detection', content: 'telephone=no,email=no,date=no,address=no' },
|
28
|
+
],
|
29
|
+
script: [
|
30
|
+
{
|
31
|
+
innerHTML: `
|
32
|
+
this.globalThis || (this.globalThis = this);
|
33
|
+
window.onerror = function(e) {
|
34
|
+
console.log(e)
|
35
|
+
window.alert('您的浏览器版本过低,请尝试使用其他浏览器或将浏览器升级至最新版本后重试!');
|
36
|
+
}
|
37
|
+
`,
|
38
|
+
},
|
39
|
+
],
|
40
|
+
link: [
|
41
|
+
{ rel: 'icon', type: 'image/png', href: '/favicon.ico' },
|
42
|
+
{ rel: 'apple-touch-icon', type: 'image/png', href: '/favicon.ico' },
|
43
|
+
{ rel: 'apple-touch-icon-precomposed', type: 'image/png', href: '/favicon.ico' },
|
44
|
+
],
|
45
|
+
},
|
46
|
+
},
|
47
|
+
devtools: { enabled: false },
|
48
|
+
modules: [
|
49
|
+
'@nuxtjs/device',
|
50
|
+
'@pinia/nuxt',
|
51
|
+
'@unocss/nuxt',
|
52
|
+
'@vueuse/nuxt',
|
53
|
+
'@element-plus/nuxt',
|
54
|
+
'@vant/nuxt',
|
55
|
+
],
|
56
|
+
unocss: {
|
57
|
+
// 默认的 @unocss/reset/tailwind.css 会造成 element 样式异常
|
58
|
+
// 手动注入 @unocss/reset/tailwind-compat.css
|
59
|
+
preflight: false,
|
60
|
+
},
|
61
|
+
|
62
|
+
nitro: {
|
63
|
+
output: {
|
64
|
+
dir: resolve(__dirname, './dist'),
|
65
|
+
},
|
66
|
+
sourceMap: false,
|
67
|
+
minify: true,
|
68
|
+
},
|
69
|
+
|
70
|
+
vite: {
|
71
|
+
build: {
|
72
|
+
sourcemap: false,
|
73
|
+
// 兼容旧浏览器
|
74
|
+
target: ['chrome58'],
|
75
|
+
cssTarget: ['chrome58'],
|
76
|
+
},
|
77
|
+
},
|
78
|
+
})
|
@@ -0,0 +1,40 @@
|
|
1
|
+
{
|
2
|
+
"name": "template-nuxt-mobile",
|
3
|
+
"type": "module",
|
4
|
+
"version": "0.0.0",
|
5
|
+
"private": true,
|
6
|
+
"scripts": {
|
7
|
+
"build": "nuxt build",
|
8
|
+
"dev": "nuxt dev",
|
9
|
+
"generate": "nuxt generate",
|
10
|
+
"preview": "nuxt preview",
|
11
|
+
"postinstall": "nuxt prepare",
|
12
|
+
"lint": "eslint .",
|
13
|
+
"lint:fix": "eslint . --fix"
|
14
|
+
},
|
15
|
+
"dependencies": {
|
16
|
+
"@bluesyoung/http": "^1.2.0",
|
17
|
+
"@bluesyoung/logger": "^0.0.1",
|
18
|
+
"@bluesyoung/utils": "^0.2.1",
|
19
|
+
"c12": "^1.4.2",
|
20
|
+
"http-proxy": "^1.18.1"
|
21
|
+
},
|
22
|
+
"devDependencies": {
|
23
|
+
"@antfu/eslint-config": "^1.1.0",
|
24
|
+
"@bluesyoung/ui-vue3": "^0.1.1",
|
25
|
+
"@bluesyoung/ui-vue3-element-plus": "^1.3.7",
|
26
|
+
"@element-plus/nuxt": "^1.0.6",
|
27
|
+
"@iconify/json": "^2.2.135",
|
28
|
+
"@nuxtjs/device": "^3.1.1",
|
29
|
+
"@pinia/nuxt": "^0.5.1",
|
30
|
+
"@unocss/nuxt": "^0.57.1",
|
31
|
+
"@vant/nuxt": "^1.0.3",
|
32
|
+
"@vueuse/nuxt": "^10.5.0",
|
33
|
+
"element-plus": "^2.3.14",
|
34
|
+
"eslint": "^8.51.0",
|
35
|
+
"nuxt": "3.5.1",
|
36
|
+
"sass": "^1.69.5",
|
37
|
+
"typescript": "^5.2.2",
|
38
|
+
"vant": "^4.7.3"
|
39
|
+
}
|
40
|
+
}
|
@@ -0,0 +1,124 @@
|
|
1
|
+
<!--
|
2
|
+
* @Author: zhangyang
|
3
|
+
* @Date: 2023-11-29 16:30:21
|
4
|
+
* @LastEditTime: 2023-11-30 09:41:00
|
5
|
+
* @Description:
|
6
|
+
-->
|
7
|
+
<script lang="ts" setup>
|
8
|
+
import { isMobile } from '@bluesyoung/utils'
|
9
|
+
import type { FormInstance } from 'vant'
|
10
|
+
|
11
|
+
definePageMeta({
|
12
|
+
title: '登录',
|
13
|
+
layout: 'blank',
|
14
|
+
auth: false,
|
15
|
+
})
|
16
|
+
|
17
|
+
const formRef = ref<FormInstance>()
|
18
|
+
const router = useRouter()
|
19
|
+
const route = useRoute()
|
20
|
+
const isPass = ref(true)
|
21
|
+
const form = ref<LoginForm>({ tel: '', passwd: '' })
|
22
|
+
|
23
|
+
const isReaded = ref(true)
|
24
|
+
const showPopup = ref(false)
|
25
|
+
const popupContent = ref(`<h1>我是用户协议</h1>`)
|
26
|
+
|
27
|
+
enum ProtoType {
|
28
|
+
用户协议,
|
29
|
+
隐私政策,
|
30
|
+
}
|
31
|
+
|
32
|
+
function read(type: ProtoType) {
|
33
|
+
if (type === ProtoType.用户协议)
|
34
|
+
popupContent.value = `<h1>我是用户协议</h1>`
|
35
|
+
|
36
|
+
else
|
37
|
+
popupContent.value = `<h1>我是隐私政策</h1>`
|
38
|
+
|
39
|
+
showPopup.value = true
|
40
|
+
}
|
41
|
+
const [showPass, toggle] = useToggle(false)
|
42
|
+
|
43
|
+
watch(() => isPass.value, () => form.value.passwd = '')
|
44
|
+
|
45
|
+
const { cookie, Exptime, hasLogin } = storeToRefs(useUserStore())
|
46
|
+
|
47
|
+
async function loginHandler() {
|
48
|
+
try {
|
49
|
+
await formRef.value?.validate()
|
50
|
+
if (!isReaded.value) {
|
51
|
+
showToast('请先同意服务协议!')
|
52
|
+
return
|
53
|
+
}
|
54
|
+
const data = await apis.post.login(form.value)
|
55
|
+
console.log('🚀 ~ file: login.vue:55 ~ loginHandler ~ data:', data)
|
56
|
+
if (data) {
|
57
|
+
cookie.value = data
|
58
|
+
// 三天后过期
|
59
|
+
Exptime.value = Date.now() + 1000 * 60 * 60 * 24 * 3
|
60
|
+
showSuccessToast('登录成功!')
|
61
|
+
|
62
|
+
nextTick(() => {
|
63
|
+
if (route.query.redirect)
|
64
|
+
navigateTo({ path: route.query.redirect as string })
|
65
|
+
else
|
66
|
+
navigateTo('/')
|
67
|
+
})
|
68
|
+
}
|
69
|
+
}
|
70
|
+
catch (error) {
|
71
|
+
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
onMounted(() => {
|
76
|
+
hasLogin.value && navigateTo('/', {
|
77
|
+
replace: true,
|
78
|
+
})
|
79
|
+
})
|
80
|
+
</script>
|
81
|
+
|
82
|
+
<template>
|
83
|
+
<VanNavBar title="登录" safe-area-inset-bottom />
|
84
|
+
<div v-bind="$attrs" class="w-full h-full mt-10">
|
85
|
+
<VanForm ref="formRef">
|
86
|
+
<VanCellGroup inset>
|
87
|
+
<VanField
|
88
|
+
v-model.trim="form.tel" maxlength="11" placeholder="手机号" :rules="[
|
89
|
+
{ required: true, message: '请填写手机号' },
|
90
|
+
{ validator: isMobile, message: '请输入合法的手机号' },
|
91
|
+
]"
|
92
|
+
/>
|
93
|
+
<VanField
|
94
|
+
v-if="isPass" v-model.trim="form.passwd" placeholder="密码" :type="showPass ? 'password' : 'text'"
|
95
|
+
:rules="[{ required: true, message: '请填写密码' }]"
|
96
|
+
>
|
97
|
+
<template #right-icon>
|
98
|
+
<VanIcon :name="!showPass ? 'eye' : 'closed-eye'" @click="toggle(!showPass)" />
|
99
|
+
</template>
|
100
|
+
</VanField>
|
101
|
+
<YoungCodeInput v-else v-model.trim="form.passwd" :tel="form.tel" placeholder="验证码" :rules="[{ required: true, message: '请填写验证码' }]" />
|
102
|
+
</VanCellGroup>
|
103
|
+
<VanCheckbox v-model="isReaded" shape="square" icon-size="small" class="p-4">
|
104
|
+
我已阅读并同意
|
105
|
+
<span class=" text-purple-500" @click.prevent="read(ProtoType.用户协议)">用户协议</span>
|
106
|
+
与
|
107
|
+
<span class=" text-purple-500" @click.prevent="read(ProtoType.隐私政策)">隐私政策</span>
|
108
|
+
</VanCheckbox>
|
109
|
+
<div class="m-4">
|
110
|
+
<VanButton block type="primary" @click="loginHandler">
|
111
|
+
登录
|
112
|
+
</VanButton>
|
113
|
+
</div>
|
114
|
+
<div class="flex justify-between p-4">
|
115
|
+
<span v-if="isPass" class="text-purple-500 cursor-pointer" @click.prevent="isPass = false">短信登录</span>
|
116
|
+
<span v-if="isPass" class="text-purple-500 cursor-pointer" @click.prevent="$router.push('/base/resetPasswd')">找回密码</span>
|
117
|
+
<span v-else class="text-purple-500 cursor-pointer" @click.prevent="isPass = true">密码登录</span>
|
118
|
+
</div>
|
119
|
+
</VanForm>
|
120
|
+
<VanPopup v-model:show="showPopup" position="center" :style="{ height: '80%', width: '90%', overflow: 'auto' }">
|
121
|
+
<div v-html="popupContent" />
|
122
|
+
</VanPopup>
|
123
|
+
</div>
|
124
|
+
</template>
|