create-pubinfo 2.0.0-beta.9 → 2.0.0-rc.1
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.
- package/dist/index.js +352 -306
- package/package.json +13 -13
- package/templates/pubinfo-template/.browserslistrc +5 -0
- package/templates/pubinfo-template/.editorconfig +10 -0
- package/templates/pubinfo-template/.env +5 -0
- package/templates/pubinfo-template/.env.development +6 -0
- package/templates/pubinfo-template/.env.production +10 -0
- package/templates/pubinfo-template/_gitignore +37 -0
- package/templates/pubinfo-template/_npmrc +5 -0
- package/templates/pubinfo-template/commitlint.config.js +66 -0
- package/templates/pubinfo-template/eslint.config.ts +3 -0
- package/templates/pubinfo-template/index.html +47 -0
- package/templates/pubinfo-template/openapi.config.ts +33 -0
- package/templates/pubinfo-template/package.json +53 -0
- package/templates/pubinfo-template/pubinfo.config.ts +9 -0
- package/templates/pubinfo-template/public/browser_upgrade/chrome.png +0 -0
- package/templates/pubinfo-template/public/browser_upgrade/edge.png +0 -0
- package/templates/pubinfo-template/public/browser_upgrade/index.css +49 -0
- package/templates/pubinfo-template/public/loading.css +92 -0
- package/templates/pubinfo-template/src/App.vue +7 -0
- package/templates/pubinfo-template/src/api/modules/auth/index.ts +3 -0
- package/templates/pubinfo-template/src/api/modules/auth/renzhengfuwu.ts +145 -0
- package/templates/pubinfo-template/src/api/modules/auth/typings.d.ts +97 -0
- package/templates/pubinfo-template/src/api/request.ts +125 -0
- package/templates/pubinfo-template/src/assets/icons/logo.svg +1 -0
- package/templates/pubinfo-template/src/assets/icons/process-management.svg +1 -0
- package/templates/pubinfo-template/src/assets/icons/workbench.svg +1 -0
- package/templates/pubinfo-template/src/assets/images/login-bg.webp +0 -0
- package/templates/pubinfo-template/src/assets/images/login-bg_dark.webp +0 -0
- package/templates/pubinfo-template/src/assets/images/login-small.png +0 -0
- package/templates/pubinfo-template/src/assets/images/login-small_dark.webp +0 -0
- package/templates/pubinfo-template/src/components/UIProvider/index.vue +51 -0
- package/templates/pubinfo-template/src/layouts/index.vue +38 -0
- package/templates/pubinfo-template/src/main.ts +22 -0
- package/templates/pubinfo-template/src/modules/auth.ts +20 -0
- package/templates/pubinfo-template/src/modules/rbac.ts +11 -0
- package/templates/pubinfo-template/src/routes/index.ts +71 -0
- package/templates/pubinfo-template/src/routes/modules/demo/breadcrumb.example.ts +62 -0
- package/templates/pubinfo-template/src/routes/modules/demo/link.ts +15 -0
- package/templates/pubinfo-template/src/routes/modules/demo/multilevel.menu.example.ts +68 -0
- package/templates/pubinfo-template/src/routes/modules/demo/other.page.ts +37 -0
- package/templates/pubinfo-template/src/routes/modules/demo/single.ts +14 -0
- package/templates/pubinfo-template/src/settings.ts +8 -0
- package/templates/pubinfo-template/src/stores/index.ts +2 -0
- package/templates/pubinfo-template/src/stores/modules/conter.ts +16 -0
- package/templates/pubinfo-template/src/views/demo/breadcrumb_example/detail1.vue +11 -0
- package/templates/pubinfo-template/src/views/demo/breadcrumb_example/detail2.vue +11 -0
- package/templates/pubinfo-template/src/views/demo/breadcrumb_example/list1.vue +11 -0
- package/templates/pubinfo-template/src/views/demo/breadcrumb_example/list2.vue +11 -0
- package/templates/pubinfo-template/src/views/demo/multilevel_menu_example/level2/level3/page1.vue +11 -0
- package/templates/pubinfo-template/src/views/demo/multilevel_menu_example/level2/level3/page2.vue +11 -0
- package/templates/pubinfo-template/src/views/demo/multilevel_menu_example/level2/page.vue +11 -0
- package/templates/pubinfo-template/src/views/demo/multilevel_menu_example/page.vue +11 -0
- package/templates/pubinfo-template/src/views/demo/other_page/des.vue +13 -0
- package/templates/pubinfo-template/src/views/demo/other_page/index.vue +25 -0
- package/templates/pubinfo-template/src/views/demo/preview-empty/index.vue +17 -0
- package/templates/pubinfo-template/src/views/demo/single/index.vue +13 -0
- package/templates/pubinfo-template/src/views/system/index.vue +5 -0
- package/templates/pubinfo-template/src/views/system/login/components/LoginForm.vue +29 -0
- package/templates/pubinfo-template/src/views/system/login/components/LoginWithPhone.vue +213 -0
- package/templates/pubinfo-template/src/views/system/login/components/PasswordLogin.vue +194 -0
- package/templates/pubinfo-template/src/views/system/login/components/Savephone.vue +17 -0
- package/templates/pubinfo-template/src/views/system/login/components/Useragreement.vue +26 -0
- package/templates/pubinfo-template/src/views/system/login/composables.ts +84 -0
- package/templates/pubinfo-template/src/views/system/login/index.vue +147 -0
- package/templates/pubinfo-template/stylelint.config.js +3 -0
- package/templates/pubinfo-template/tsconfig.json +3 -0
- package/templates/pubinfo-template/uno.config.ts +17 -0
- package/dist/index.cjs +0 -364
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { defineStore } from 'pinia';
|
|
2
|
+
import { computed, ref } from 'vue';
|
|
3
|
+
|
|
4
|
+
export const useCounterStore = defineStore('counter', () => {
|
|
5
|
+
const count = ref(0);
|
|
6
|
+
const doubleCount = computed(() => count.value * 2);
|
|
7
|
+
function increment() {
|
|
8
|
+
count.value++;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
count,
|
|
13
|
+
doubleCount,
|
|
14
|
+
increment,
|
|
15
|
+
};
|
|
16
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { PageMain } from 'pubinfo';
|
|
3
|
+
|
|
4
|
+
defineOptions({
|
|
5
|
+
name: 'OtherPage',
|
|
6
|
+
});
|
|
7
|
+
/* =============================================
|
|
8
|
+
= 逻辑代码 =
|
|
9
|
+
============================================= */
|
|
10
|
+
const router = useRouter();
|
|
11
|
+
function jump() {
|
|
12
|
+
router.push({
|
|
13
|
+
name: 'OtherPageDetail',
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<PageMain>
|
|
20
|
+
列表页
|
|
21
|
+
<a-button type="primary" @click="jump">
|
|
22
|
+
点击跳转入详情页
|
|
23
|
+
</a-button>
|
|
24
|
+
</PageMain>
|
|
25
|
+
</template>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/* =============================================
|
|
3
|
+
= Vue SFC Options 配置 =
|
|
4
|
+
============================================= */
|
|
5
|
+
defineOptions({
|
|
6
|
+
name: 'PreviewEmpty',
|
|
7
|
+
});
|
|
8
|
+
/* =============================================
|
|
9
|
+
= 逻辑代码 =
|
|
10
|
+
============================================= */
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<template>
|
|
14
|
+
<div>
|
|
15
|
+
空白展示页面
|
|
16
|
+
</div>
|
|
17
|
+
</template>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { useLoginTabs } from '../composables';
|
|
3
|
+
|
|
4
|
+
defineOptions({
|
|
5
|
+
name: 'LoginFrom',
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
const { tabs, initialTab, changeActiveTab } = useLoginTabs();
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<template>
|
|
12
|
+
<div class="flex flex-col w-456px [background:transparent]">
|
|
13
|
+
<div class="flex flex-row overflow-hidden border border-solid border-[#e7e8e9] rounded-1">
|
|
14
|
+
<div
|
|
15
|
+
v-for="(tab, index) in tabs"
|
|
16
|
+
:key="tab.title"
|
|
17
|
+
class="flex flex-row items-center justify-center h-10 text-base cursor-pointer rounded"
|
|
18
|
+
:class="[initialTab === index ? 'text-[#2f6bff] bg-[#ecf1fd]' : 'text-[#8a8e92] ']"
|
|
19
|
+
:style="{ width: `${100 / tabs.length}%` }"
|
|
20
|
+
@click="changeActiveTab(index)"
|
|
21
|
+
>
|
|
22
|
+
{{ tab.title }}
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
<div class="relative min-h-350px">
|
|
26
|
+
<component :is="tabs[initialTab].component" :key="tabs[initialTab].title" :name="tabs[initialTab].title" />
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
</template>
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { SelectProps } from 'ant-design-vue';
|
|
3
|
+
import type { FormInstance, Rule } from 'ant-design-vue/es/form';
|
|
4
|
+
import { useToggle } from '@vueuse/core';
|
|
5
|
+
import { message } from 'ant-design-vue';
|
|
6
|
+
import { useCountdown } from '../composables';
|
|
7
|
+
import Savephone from './Savephone.vue';
|
|
8
|
+
|
|
9
|
+
defineOptions({
|
|
10
|
+
name: 'LoginWithPhone',
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
interface FormState {
|
|
14
|
+
phone: string
|
|
15
|
+
verify: string
|
|
16
|
+
checked: false
|
|
17
|
+
}
|
|
18
|
+
const [verifyDisabled, setVerifyDisabled] = useToggle(true);
|
|
19
|
+
const phoneForm = ref<FormInstance>();
|
|
20
|
+
const { count, start, isStart } = useCountdown();
|
|
21
|
+
const regionCode = ref<number>(0);
|
|
22
|
+
const router = useRouter();
|
|
23
|
+
const route = useRoute();
|
|
24
|
+
|
|
25
|
+
const formState = reactive<FormState>({
|
|
26
|
+
phone: '',
|
|
27
|
+
verify: '',
|
|
28
|
+
checked: false,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const rules: Record<string, Rule[]> = {
|
|
32
|
+
phone: [
|
|
33
|
+
{
|
|
34
|
+
validator: checkPhoneIsCorrect,
|
|
35
|
+
whitespace: true,
|
|
36
|
+
trigger: 'change',
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
verify: [
|
|
40
|
+
{
|
|
41
|
+
required: true,
|
|
42
|
+
whitespace: true,
|
|
43
|
+
message: '请输入验证码',
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const regionCodeOptins: SelectProps['options'] = [
|
|
49
|
+
{
|
|
50
|
+
value: 0,
|
|
51
|
+
label: '+86 (中国大陆)',
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
value: 1,
|
|
55
|
+
label: '+852 (香港行政区)',
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
value: 2,
|
|
59
|
+
label: '+853 (澳门行政区)',
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
value: 3,
|
|
63
|
+
label: '+886 (台湾省)',
|
|
64
|
+
},
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
async function checkPhoneIsCorrect(_rule: Rule, value: string) {
|
|
68
|
+
function reject(area: string) {
|
|
69
|
+
setVerifyDisabled(true);
|
|
70
|
+
return Promise.reject(new Error(`请输入正确的${area}手机号`));
|
|
71
|
+
}
|
|
72
|
+
if (!value) {
|
|
73
|
+
setVerifyDisabled(true);
|
|
74
|
+
return Promise.reject(new Error(`请输入手机号`));
|
|
75
|
+
}
|
|
76
|
+
switch (regionCode.value) {
|
|
77
|
+
// 中国大陆
|
|
78
|
+
case 0:
|
|
79
|
+
if (!/^1[3-9]\d{9}$/.test(value)) {
|
|
80
|
+
return reject('中国大陆');
|
|
81
|
+
}
|
|
82
|
+
break;
|
|
83
|
+
// 香港特别行政区
|
|
84
|
+
case 1:
|
|
85
|
+
if (!/^([569])\d{7}$/.test(value)) {
|
|
86
|
+
return reject('香港特别行政区');
|
|
87
|
+
}
|
|
88
|
+
break;
|
|
89
|
+
// 澳门特别行政区
|
|
90
|
+
case 2:
|
|
91
|
+
if (!/^6\d{7}$/.test(value)) {
|
|
92
|
+
return reject('澳门特别行政区');
|
|
93
|
+
}
|
|
94
|
+
break;
|
|
95
|
+
// 台湾省
|
|
96
|
+
case 3:
|
|
97
|
+
if (!/^9\d{8}$/.test(value)) {
|
|
98
|
+
return reject('台湾省');
|
|
99
|
+
}
|
|
100
|
+
break;
|
|
101
|
+
default:
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
setVerifyDisabled(false);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async function areaChange() {
|
|
108
|
+
if (!formState.phone) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
phoneForm.value?.validateFields('phone');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async function sendVerifyCode() {
|
|
115
|
+
message.success('验证码已发送,请注意查收');
|
|
116
|
+
start();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async function submit() {
|
|
120
|
+
try {
|
|
121
|
+
await phoneForm.value?.validate();
|
|
122
|
+
|
|
123
|
+
// TODO 实现手机号登录逻辑
|
|
124
|
+
|
|
125
|
+
if (formState.checked) {
|
|
126
|
+
localStorage.setItem('pubinfo_web_savedPhone', formState.phone);
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
localStorage.removeItem('pubinfo_web_savedPhone');
|
|
130
|
+
}
|
|
131
|
+
message.success('登录成功');
|
|
132
|
+
router.push(route.query.redirect?.toString() ?? '/');
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
onMounted(() => {
|
|
139
|
+
const phone = localStorage.getItem('pubinfo_web_savedPhone');
|
|
140
|
+
if (phone) {
|
|
141
|
+
formState.phone = phone;
|
|
142
|
+
setVerifyDisabled(false);
|
|
143
|
+
formState.checked = true as any;
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
</script>
|
|
147
|
+
|
|
148
|
+
<template>
|
|
149
|
+
<div class="phone-form" mt-40px>
|
|
150
|
+
<a-form
|
|
151
|
+
ref="phoneForm"
|
|
152
|
+
:model="formState"
|
|
153
|
+
autocomplete="off"
|
|
154
|
+
:rules="rules"
|
|
155
|
+
@finish="submit"
|
|
156
|
+
>
|
|
157
|
+
<a-form-item name="phone">
|
|
158
|
+
<a-input-group compact>
|
|
159
|
+
<a-form-item-rest>
|
|
160
|
+
<a-select
|
|
161
|
+
v-model:value="regionCode"
|
|
162
|
+
size="large"
|
|
163
|
+
style="width: 35%;"
|
|
164
|
+
:options="regionCodeOptins"
|
|
165
|
+
@change="areaChange"
|
|
166
|
+
/>
|
|
167
|
+
</a-form-item-rest>
|
|
168
|
+
<a-input
|
|
169
|
+
v-model:value="formState.phone"
|
|
170
|
+
allow-clear
|
|
171
|
+
size="large"
|
|
172
|
+
placeholder="请输入手机号"
|
|
173
|
+
style="width: 65%;"
|
|
174
|
+
/>
|
|
175
|
+
</a-input-group>
|
|
176
|
+
</a-form-item>
|
|
177
|
+
|
|
178
|
+
<a-form-item name="verify">
|
|
179
|
+
<a-input
|
|
180
|
+
v-model:value="formState.verify"
|
|
181
|
+
allow-clear
|
|
182
|
+
size="large"
|
|
183
|
+
placeholder="请输入验证码"
|
|
184
|
+
>
|
|
185
|
+
<template #suffix>
|
|
186
|
+
<a-button
|
|
187
|
+
size="small"
|
|
188
|
+
type="link"
|
|
189
|
+
:disabled="verifyDisabled"
|
|
190
|
+
>
|
|
191
|
+
<span v-if="!isStart" @click="sendVerifyCode">获取短信验证码</span>
|
|
192
|
+
<span v-else text="#8A8E92">{{ count }}秒后重新获取</span>
|
|
193
|
+
</a-button>
|
|
194
|
+
</template>
|
|
195
|
+
</a-input>
|
|
196
|
+
</a-form-item>
|
|
197
|
+
<a-form-item>
|
|
198
|
+
<Savephone v-model:checked="formState.checked" />
|
|
199
|
+
</a-form-item>
|
|
200
|
+
<a-form-item>
|
|
201
|
+
<a-button
|
|
202
|
+
class="h-48px!"
|
|
203
|
+
block
|
|
204
|
+
type="primary"
|
|
205
|
+
html-type="submit"
|
|
206
|
+
:disabled="!formState.checked"
|
|
207
|
+
>
|
|
208
|
+
登录
|
|
209
|
+
</a-button>
|
|
210
|
+
</a-form-item>
|
|
211
|
+
</a-form>
|
|
212
|
+
</div>
|
|
213
|
+
</template>
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { FormInstance, Rule } from 'ant-design-vue/es/form';
|
|
3
|
+
import type { UnwrapRef } from 'vue';
|
|
4
|
+
import { useToggle } from '@vueuse/core';
|
|
5
|
+
import { message, Modal } from 'ant-design-vue';
|
|
6
|
+
import { RESPONSE_CODE, useUserStore } from 'pubinfo';
|
|
7
|
+
import { useCaptchas, useFocusElement } from '../composables';
|
|
8
|
+
import Useragreement from './Useragreement.vue';
|
|
9
|
+
|
|
10
|
+
defineOptions({
|
|
11
|
+
name: 'PasswordLogin',
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
interface FormState {
|
|
15
|
+
account: string
|
|
16
|
+
password: string
|
|
17
|
+
captchas: string
|
|
18
|
+
captchaHash: string
|
|
19
|
+
checked: boolean
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface HttpError {
|
|
23
|
+
code: RESPONSE_CODE
|
|
24
|
+
data: any
|
|
25
|
+
hint: string
|
|
26
|
+
msg: string
|
|
27
|
+
success: boolean
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function isHttpError(error: unknown): error is HttpError {
|
|
31
|
+
return (error as HttpError).code !== undefined;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const userStore = useUserStore();
|
|
35
|
+
const { send, captcha, captchaHash } = useCaptchas();
|
|
36
|
+
const router = useRouter();
|
|
37
|
+
const route = useRoute();
|
|
38
|
+
const { focusElementDataId } = useFocusElement();
|
|
39
|
+
|
|
40
|
+
const loginForm = ref<FormInstance | null>(null);
|
|
41
|
+
const formState: UnwrapRef<FormState> = reactive({
|
|
42
|
+
account: '',
|
|
43
|
+
password: '',
|
|
44
|
+
captchas: '',
|
|
45
|
+
checked: true,
|
|
46
|
+
captchaHash,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const rules: Record<string, Rule[]> = {
|
|
50
|
+
account: [{ required: true, whitespace: true, message: '请输入账号' }],
|
|
51
|
+
password: [{ required: true, whitespace: true, message: '请输入密码' }],
|
|
52
|
+
captchas: [{ required: true, whitespace: true, message: '请输入验证码' }],
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const [loading, setLoading] = useToggle(false);
|
|
56
|
+
|
|
57
|
+
async function onSubmit() {
|
|
58
|
+
if (loading.value) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
setLoading(true);
|
|
62
|
+
try {
|
|
63
|
+
await loginForm.value?.validate();
|
|
64
|
+
await userStore.login(formState);
|
|
65
|
+
message.success('登录成功');
|
|
66
|
+
router.push(route.query.redirect?.toString() ?? '/');
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
if (isHttpError(error)) {
|
|
70
|
+
const code = error.code;
|
|
71
|
+
switch (code) {
|
|
72
|
+
case RESPONSE_CODE.LOGINNAME_PASSWORD_WRONG:
|
|
73
|
+
case RESPONSE_CODE.CODE_OVERTIME:
|
|
74
|
+
case RESPONSE_CODE.CODE_WRONG:
|
|
75
|
+
send();
|
|
76
|
+
break;
|
|
77
|
+
case RESPONSE_CODE.CHANGE_INIT_PASSWORD:
|
|
78
|
+
case RESPONSE_CODE.PASSWORD_EXPIRED:
|
|
79
|
+
createChangePasswordModal(error.msg, error?.data?.accessToken);
|
|
80
|
+
break;
|
|
81
|
+
default:
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
finally {
|
|
87
|
+
setLoading(false);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function createChangePasswordModal(msg: string, token: string) {
|
|
92
|
+
Modal.confirm({
|
|
93
|
+
title: '提示',
|
|
94
|
+
content() {
|
|
95
|
+
return msg;
|
|
96
|
+
},
|
|
97
|
+
okText: '修改密码',
|
|
98
|
+
cancelText: '暂不登录',
|
|
99
|
+
onOk() {
|
|
100
|
+
router.push({
|
|
101
|
+
name: 'ChangePassword',
|
|
102
|
+
params: {
|
|
103
|
+
changePassWordToken: token,
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
</script>
|
|
110
|
+
|
|
111
|
+
<template>
|
|
112
|
+
<div class="mt-10">
|
|
113
|
+
<AForm ref="loginForm" :model="formState" :rules="rules" @finish="onSubmit">
|
|
114
|
+
<a-form-item name="account">
|
|
115
|
+
<a-input
|
|
116
|
+
v-model:value="formState.account"
|
|
117
|
+
allow-clear
|
|
118
|
+
size="large"
|
|
119
|
+
placeholder="请输入登录账号"
|
|
120
|
+
data-id="account"
|
|
121
|
+
>
|
|
122
|
+
<template #prefix>
|
|
123
|
+
<PubinfoIcon v-if="focusElementDataId === 'account'" name="i-solar-user-bold" color="#1578FF" />
|
|
124
|
+
<PubinfoIcon v-else name="i-solar-user-broken" color="#AFB0B2" />
|
|
125
|
+
</template>
|
|
126
|
+
</a-input>
|
|
127
|
+
</a-form-item>
|
|
128
|
+
<a-form-item name="password">
|
|
129
|
+
<a-input-password
|
|
130
|
+
v-model:value="formState.password"
|
|
131
|
+
allow-clear
|
|
132
|
+
size="large"
|
|
133
|
+
placeholder="请输入登录密码"
|
|
134
|
+
visibility-toggle
|
|
135
|
+
data-id="password"
|
|
136
|
+
>
|
|
137
|
+
<template #prefix>
|
|
138
|
+
<PubinfoIcon v-if="focusElementDataId === 'password'" name="i-solar-lock-password-unlocked-bold" color="#1578FF" />
|
|
139
|
+
<PubinfoIcon v-else name="i-solar-lock-password-unlocked-broken" color="#AFB0B2" />
|
|
140
|
+
</template>
|
|
141
|
+
</a-input-password>
|
|
142
|
+
</a-form-item>
|
|
143
|
+
<a-form-item name="captchas">
|
|
144
|
+
<a-input
|
|
145
|
+
v-model:value="formState.captchas"
|
|
146
|
+
size="large"
|
|
147
|
+
allow-clear
|
|
148
|
+
placeholder="请输入验证码"
|
|
149
|
+
data-id="captchas"
|
|
150
|
+
>
|
|
151
|
+
<template #prefix>
|
|
152
|
+
<PubinfoIcon v-if="focusElementDataId === 'captchas'" name="i-solar-shield-check-bold" color="#1578FF" />
|
|
153
|
+
<PubinfoIcon v-else name="i-solar-shield-check-broken" color="#AFB0B2" />
|
|
154
|
+
</template>
|
|
155
|
+
<template #addonAfter>
|
|
156
|
+
<div
|
|
157
|
+
w-100px
|
|
158
|
+
h-38px
|
|
159
|
+
cursor-pointer
|
|
160
|
+
@click="send"
|
|
161
|
+
>
|
|
162
|
+
<img :src="captcha">
|
|
163
|
+
</div>
|
|
164
|
+
</template>
|
|
165
|
+
</a-input>
|
|
166
|
+
</a-form-item>
|
|
167
|
+
<a-form-item>
|
|
168
|
+
<Useragreement v-model:checked="formState.checked" />
|
|
169
|
+
</a-form-item>
|
|
170
|
+
<!-- 登录 -->
|
|
171
|
+
<a-form-item>
|
|
172
|
+
<div w-full h-48px>
|
|
173
|
+
<a-button
|
|
174
|
+
class="h-48px!"
|
|
175
|
+
type="primary"
|
|
176
|
+
html-type="submit"
|
|
177
|
+
block
|
|
178
|
+
:disabled="!formState.checked"
|
|
179
|
+
:loading="loading"
|
|
180
|
+
>
|
|
181
|
+
登录
|
|
182
|
+
</a-button>
|
|
183
|
+
</div>
|
|
184
|
+
</a-form-item>
|
|
185
|
+
</AForm>
|
|
186
|
+
</div>
|
|
187
|
+
</template>
|
|
188
|
+
|
|
189
|
+
<style scoped>
|
|
190
|
+
:deep(.ant-input-group-addon) {
|
|
191
|
+
padding: 0 !important;
|
|
192
|
+
overflow: hidden;
|
|
193
|
+
}
|
|
194
|
+
</style>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
defineOptions({
|
|
3
|
+
name: 'Savephone',
|
|
4
|
+
});
|
|
5
|
+
|
|
6
|
+
const checked = defineModel(
|
|
7
|
+
'checked',
|
|
8
|
+
{
|
|
9
|
+
type: Boolean, default: false,
|
|
10
|
+
});
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<template>
|
|
14
|
+
<a-checkbox v-model:checked="checked">
|
|
15
|
+
记住手机号
|
|
16
|
+
</a-checkbox>
|
|
17
|
+
</template>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
defineOptions({
|
|
3
|
+
name: 'Useragreement',
|
|
4
|
+
});
|
|
5
|
+
|
|
6
|
+
const checked = defineModel(
|
|
7
|
+
'checked',
|
|
8
|
+
{
|
|
9
|
+
type: Boolean, default: true,
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
function jumpUseragreementPage() {
|
|
13
|
+
// 暂未实现用户协议、隐私政策
|
|
14
|
+
}
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<template>
|
|
18
|
+
<a-checkbox v-model:checked="checked">
|
|
19
|
+
我已阅读并同意<span
|
|
20
|
+
hover:underline
|
|
21
|
+
decoration-2
|
|
22
|
+
text="#1578FF"
|
|
23
|
+
@click.prevent="jumpUseragreementPage"
|
|
24
|
+
>用户协议、隐私政策</span>
|
|
25
|
+
</a-checkbox>
|
|
26
|
+
</template>
|