@h-ai/cli 0.1.0-alpha.18 → 0.1.0-alpha.20
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/{chunk-BPO34NRL.js → chunk-3BBXDQ4Y.js} +5 -5
- package/dist/chunk-3BBXDQ4Y.js.map +1 -0
- package/dist/cli-config-templates-IGGO7P45.js +5 -0
- package/dist/{cli-config-templates-JCS7T3NU.js.map → cli-config-templates-IGGO7P45.js.map} +1 -1
- package/dist/index.js +67 -39
- package/dist/index.js.map +1 -1
- package/dist/{src-N4NPS7AG.js → src-QNEJJ3BV.js} +261 -103
- package/dist/src-QNEJJ3BV.js.map +1 -0
- package/package.json +2 -2
- package/templates/apps/admin/messages/en-US.json +5 -0
- package/templates/apps/admin/messages/zh-CN.json +5 -0
- package/templates/apps/admin/src/routes/+layout.svelte.hbs +5 -5
- package/templates/apps/admin/src/routes/+page.svelte.hbs +32 -12
- package/templates/apps/admin/src/routes/admin/+layout.svelte.hbs +37 -20
- package/templates/apps/admin/src/routes/admin/+page.svelte.hbs +33 -24
- package/templates/apps/admin/src/routes/admin/settings/+page.svelte.hbs +16 -13
- package/templates/apps/android-app/src/lib/api.ts.hbs +5 -4
- package/templates/apps/android-app/src/lib/capacitor.ts +1 -1
- package/templates/apps/android-app/src/routes/+layout.svelte.hbs +11 -10
- package/templates/apps/android-app/src/routes/+page.svelte.hbs +17 -6
- package/templates/apps/fullstack/packages/{{projectName}}-serv/README.md.hbs +4 -1
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_core.yml.hbs +14 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_serv.yml.hbs +13 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/index.ts.hbs +3 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server-app.ts.hbs +23 -3
- package/templates/apps/h5/messages/en-US.json +3 -0
- package/templates/apps/h5/messages/zh-CN.json +3 -0
- package/templates/apps/h5/src/routes/+layout.svelte.hbs +30 -29
- package/templates/apps/h5/src/routes/+page.svelte.hbs +17 -6
- package/templates/apps/h5/src/routes/discover/+page.svelte.hbs +17 -6
- package/templates/apps/h5/src/routes/profile/+page.svelte.hbs +17 -6
- package/templates/apps/website/src/routes/+layout.svelte.hbs +35 -26
- package/templates/apps/website/src/routes/+page.svelte.hbs +28 -10
- package/templates/apps/website/src/routes/about/+page.svelte.hbs +11 -6
- package/templates/apps/website/src/routes/contact/+page.svelte.hbs +37 -34
- package/templates/apps/website/src/routes/services/+page.svelte.hbs +27 -40
- package/templates/base/package.json.hbs +30 -24
- package/templates/base/src/app.html.hbs +4 -0
- package/templates/base/src/hooks.server.ts.hbs +17 -7
- package/templates/base/src/lib/server/init.ts.hbs +20 -12
- package/templates/base/static/favicon.png +0 -0
- package/templates/base/tests/scaffold.test.ts.hbs +9 -1
- package/templates/base/vite.config.ts.hbs +3 -3
- package/templates/features/iam/routes-admin/(auth)/+layout.svelte.hbs +5 -5
- package/templates/features/iam/routes-admin/(auth)/auth/login/+page.svelte.hbs +34 -32
- package/templates/features/iam/routes-admin/(auth)/auth/register/+page.svelte.hbs +46 -48
- package/templates/features/iam/routes-h5/auth/login/+page.svelte.hbs +35 -31
- package/templates/features/iam/routes-h5/auth/register/+page.svelte.hbs +41 -38
- package/templates/features/payment/routes/api/v1/payment/create/+server.ts +15 -7
- package/templates/features/payment/routes/api/v1/payment/notify/[provider]/+server.ts +1 -2
- package/templates/skills/AGENTS.md +11 -1
- package/templates/skills/CLAUDE.md +2 -1
- package/templates/skills/copilot-instructions.md +22 -6
- package/templates/skills/hai-ai/SKILL.md +115 -646
- package/templates/skills/hai-ai/reference.md +197 -0
- package/templates/skills/hai-api-client/SKILL.md +7 -1
- package/templates/skills/hai-app-create/SKILL.md +1 -1
- package/templates/skills/hai-app-review/SKILL.md +1 -1
- package/templates/skills/hai-audit/SKILL.md +7 -2
- package/templates/skills/hai-cache/SKILL.md +2 -0
- package/templates/skills/hai-capacitor/SKILL.md +11 -9
- package/templates/skills/hai-core/SKILL.md +4 -1
- package/templates/skills/hai-crypto/SKILL.md +42 -8
- package/templates/skills/hai-deploy/SKILL.md +12 -9
- package/templates/skills/hai-iam/SKILL.md +2 -0
- package/templates/skills/hai-kit/SKILL.md +14 -5
- package/templates/skills/hai-payment/SKILL.md +5 -0
- package/templates/skills/hai-reach/SKILL.md +3 -1
- package/templates/skills/hai-reldb/SKILL.md +2 -0
- package/templates/skills/hai-scheduler/SKILL.md +2 -0
- package/templates/skills/hai-serv/SKILL.md +5 -0
- package/templates/skills/hai-storage/SKILL.md +10 -1
- package/templates/skills/hai-ui/SKILL.md +25 -11
- package/templates/skills/hai-vecdb/SKILL.md +8 -1
- package/dist/chunk-BPO34NRL.js.map +0 -1
- package/dist/cli-config-templates-JCS7T3NU.js +0 -5
- package/dist/src-N4NPS7AG.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "{{projectName}}",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.20",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "{{#if_eq appType 'admin'}}Enterprise management system built with hai Agent Framework{{/if_eq}}{{#if_eq appType 'website'}}Enterprise website built with hai Agent Framework{{/if_eq}}{{#if_eq appType 'h5'}}Mobile H5 app built with hai Agent Framework{{/if_eq}}{{#if_eq appType 'api'}}REST API service built with hai Agent Framework{{/if_eq}}{{#if_eq appType 'android-app'}}Android app built with hai Agent Framework{{/if_eq}}",
|
|
6
6
|
"keywords": ["hai", "sveltekit", "svelte5", "{{appType}}"],
|
|
@@ -22,36 +22,42 @@
|
|
|
22
22
|
"clean": "rimraf .svelte-kit build .turbo"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@h-ai/core": "^0.1.0-alpha.
|
|
26
|
-
"@h-ai/kit": "^0.1.0-alpha.
|
|
27
|
-
"@h-ai/ui": "^0.1.0-alpha.
|
|
28
|
-
"@h-ai/reldb": "^0.1.0-alpha.
|
|
29
|
-
"@h-ai/cache": "^0.1.0-alpha.
|
|
30
|
-
"@h-ai/iam": "^0.1.0-alpha.
|
|
31
|
-
"@h-ai/crypto": "^0.1.0-alpha.
|
|
32
|
-
"@h-ai/storage": "^0.1.0-alpha.
|
|
33
|
-
"@h-ai/ai": "^0.1.0-alpha.
|
|
34
|
-
"@h-ai/audit": "^0.1.0-alpha.
|
|
35
|
-
"@h-ai/reach": "^0.1.0-alpha.
|
|
36
|
-
"@h-ai/payment": "^0.1.0-alpha.
|
|
37
|
-
"@h-ai/vecdb": "^0.1.0-alpha.
|
|
38
|
-
"@h-ai/datapipe": "^0.1.0-alpha.
|
|
39
|
-
"@h-ai/scheduler": "^0.1.0-alpha.
|
|
40
|
-
"@h-ai/deploy": "^0.1.0-alpha.
|
|
41
|
-
"@h-ai/api-client": "^0.1.0-alpha.
|
|
42
|
-
"@h-ai/capacitor": "^0.1.0-alpha.
|
|
43
|
-
"@h-ai/api-client": "^0.1.0-alpha.
|
|
44
|
-
"@h-ai/capacitor": "^0.1.0-alpha.
|
|
25
|
+
"@h-ai/core": "^0.1.0-alpha.20",
|
|
26
|
+
"@h-ai/kit": "^0.1.0-alpha.20"{{#if hasUi}},
|
|
27
|
+
"@h-ai/ui": "^0.1.0-alpha.20"{{/if}}{{#if features.db}},
|
|
28
|
+
"@h-ai/reldb": "^0.1.0-alpha.20"{{/if}}{{#if features.cache}},
|
|
29
|
+
"@h-ai/cache": "^0.1.0-alpha.20"{{/if}}{{#if features.iam}},
|
|
30
|
+
"@h-ai/iam": "^0.1.0-alpha.20"{{/if}}{{#if features.crypto}},
|
|
31
|
+
"@h-ai/crypto": "^0.1.0-alpha.20"{{/if}}{{#if features.storage}},
|
|
32
|
+
"@h-ai/storage": "^0.1.0-alpha.20"{{/if}}{{#if features.ai}},
|
|
33
|
+
"@h-ai/ai": "^0.1.0-alpha.20"{{/if}}{{#if features.audit}},
|
|
34
|
+
"@h-ai/audit": "^0.1.0-alpha.20"{{/if}}{{#if features.reach}},
|
|
35
|
+
"@h-ai/reach": "^0.1.0-alpha.20"{{/if}}{{#if features.payment}},
|
|
36
|
+
"@h-ai/payment": "^0.1.0-alpha.20"{{/if}}{{#if features.vecdb}},
|
|
37
|
+
"@h-ai/vecdb": "^0.1.0-alpha.20"{{/if}}{{#if features.datapipe}},
|
|
38
|
+
"@h-ai/datapipe": "^0.1.0-alpha.20"{{/if}}{{#if features.scheduler}},
|
|
39
|
+
"@h-ai/scheduler": "^0.1.0-alpha.20"{{/if}}{{#if features.deploy}},
|
|
40
|
+
"@h-ai/deploy": "^0.1.0-alpha.20"{{/if}}{{#if features.api-client}},
|
|
41
|
+
"@h-ai/api-client": "^0.1.0-alpha.20"{{/if}}{{#if features.capacitor}},
|
|
42
|
+
"@h-ai/capacitor": "^0.1.0-alpha.20"{{/if}}{{#if isCapacitorApp}}{{#unless features.api-client}},
|
|
43
|
+
"@h-ai/api-client": "^0.1.0-alpha.20"{{/unless}}{{#unless features.capacitor}},
|
|
44
|
+
"@h-ai/capacitor": "^0.1.0-alpha.20"{{/unless}}{{/if}},
|
|
45
45
|
"zod": "^4.4.3"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@antfu/eslint-config": "^9.0.0",
|
|
49
49
|
"@playwright/test": "^1.60.0",
|
|
50
50
|
{{#if isCapacitorApp}}
|
|
51
|
-
|
|
52
|
-
"@capacitor/
|
|
53
|
-
"@capacitor/
|
|
51
|
+
"@aparajita/capacitor-secure-storage": "^8.0.0",
|
|
52
|
+
"@capacitor/app": "^8.0.1",
|
|
53
|
+
"@capacitor/camera": "^8.0.2",
|
|
54
|
+
"@capacitor/cli": "^8.3.4",
|
|
55
|
+
"@capacitor/core": "^8.3.4",
|
|
56
|
+
"@capacitor/android": "^8.3.4",
|
|
57
|
+
"@capacitor/device": "^8.0.1",
|
|
54
58
|
"@capacitor/preferences": "^8.0.1",
|
|
59
|
+
"@capacitor/push-notifications": "^8.0.2",
|
|
60
|
+
"@capacitor/status-bar": "^8.0.1",
|
|
55
61
|
"@sveltejs/adapter-static": "^3.0.10",
|
|
56
62
|
{{else}}
|
|
57
63
|
{{#if_eq appType 'api'}}
|
|
@@ -5,18 +5,18 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import type { Handle } from '@sveltejs/kit'
|
|
8
|
+
{{#if hasI18n}}
|
|
9
|
+
import { paraglideMiddleware } from '$lib/paraglide/server.js'
|
|
10
|
+
{{/if}}
|
|
8
11
|
import { initApp } from '$lib/server/init.js'
|
|
9
12
|
import { core } from '@h-ai/core'
|
|
10
|
-
import { kit } from '@h-ai/kit'
|
|
11
|
-
{{#if features.iam}}
|
|
12
|
-
import { iam } from '@h-ai/iam'
|
|
13
|
-
{{/if}}
|
|
14
13
|
{{#if features.crypto}}
|
|
15
14
|
import { crypto } from '@h-ai/crypto'
|
|
16
15
|
{{/if}}
|
|
17
|
-
{{#if
|
|
18
|
-
import {
|
|
16
|
+
{{#if features.iam}}
|
|
17
|
+
import { iam } from '@h-ai/iam'
|
|
19
18
|
{{/if}}
|
|
19
|
+
import { kit } from '@h-ai/kit'
|
|
20
20
|
|
|
21
21
|
{{#if features.crypto}}
|
|
22
22
|
// 初始化加密模块(同步)
|
|
@@ -85,7 +85,17 @@ const haiHandle = kit.createHandle({
|
|
|
85
85
|
auth: {
|
|
86
86
|
verifyToken: async (token) => {
|
|
87
87
|
const result = await iam.auth.verifyToken(token)
|
|
88
|
-
|
|
88
|
+
if (!result.success)
|
|
89
|
+
return null
|
|
90
|
+
const session = result.data
|
|
91
|
+
// 映射为 kit 的 SessionData 形态(携带守卫所需的核心字段)
|
|
92
|
+
return {
|
|
93
|
+
userId: session.userId,
|
|
94
|
+
username: session.username,
|
|
95
|
+
roles: session.roles,
|
|
96
|
+
permissions: session.permissions,
|
|
97
|
+
data: session.data,
|
|
98
|
+
}
|
|
89
99
|
},
|
|
90
100
|
operations: iam.auth,
|
|
91
101
|
loginUrl: '/auth/login',
|
|
@@ -27,31 +27,39 @@
|
|
|
27
27
|
{{/if}}
|
|
28
28
|
*/
|
|
29
29
|
|
|
30
|
-
{{#if features.
|
|
31
|
-
import {
|
|
32
|
-
{{/if}}
|
|
33
|
-
import { core } from '@h-ai/core'
|
|
34
|
-
{{#if features.db}}
|
|
35
|
-
import { reldb, ReldbConfigSchema } from '@h-ai/reldb'
|
|
30
|
+
{{#if features.ai}}
|
|
31
|
+
import type { AIConfigInput } from '@h-ai/ai'
|
|
36
32
|
{{/if}}
|
|
37
33
|
{{#if features.iam}}
|
|
38
34
|
import type { IamConfigSettingsInput } from '@h-ai/iam'
|
|
39
|
-
|
|
35
|
+
{{/if}}
|
|
36
|
+
{{#if features.reach}}
|
|
37
|
+
import type { ReachConfigInput } from '@h-ai/reach'
|
|
40
38
|
{{/if}}
|
|
41
39
|
{{#if features.storage}}
|
|
42
40
|
import type { StorageConfigInput } from '@h-ai/storage'
|
|
43
|
-
import { storage, StorageConfigSchema } from '@h-ai/storage'
|
|
44
41
|
{{/if}}
|
|
45
42
|
{{#if features.ai}}
|
|
46
|
-
import type { AIConfigInput } from '@h-ai/ai'
|
|
47
43
|
import { ai } from '@h-ai/ai'
|
|
48
44
|
{{/if}}
|
|
45
|
+
{{#if features.audit}}
|
|
46
|
+
import { audit } from '@h-ai/audit'
|
|
47
|
+
{{/if}}
|
|
48
|
+
{{#if features.cache}}
|
|
49
|
+
import { cache, CacheConfigSchema } from '@h-ai/cache'
|
|
50
|
+
{{/if}}
|
|
51
|
+
import { core } from '@h-ai/core'
|
|
52
|
+
{{#if features.iam}}
|
|
53
|
+
import { iam } from '@h-ai/iam'
|
|
54
|
+
{{/if}}
|
|
49
55
|
{{#if features.reach}}
|
|
50
|
-
import type { ReachConfigInput } from '@h-ai/reach'
|
|
51
56
|
import { reach } from '@h-ai/reach'
|
|
52
57
|
{{/if}}
|
|
53
|
-
{{#if features.
|
|
54
|
-
import {
|
|
58
|
+
{{#if features.db}}
|
|
59
|
+
import { reldb, ReldbConfigSchema } from '@h-ai/reldb'
|
|
60
|
+
{{/if}}
|
|
61
|
+
{{#if features.storage}}
|
|
62
|
+
import { storage, StorageConfigSchema } from '@h-ai/storage'
|
|
55
63
|
{{/if}}
|
|
56
64
|
|
|
57
65
|
{{#if features.db}}
|
|
Binary file
|
|
@@ -22,6 +22,14 @@ describe('generated scaffold', () => {
|
|
|
22
22
|
|
|
23
23
|
it('renders the app shell locale marker', async () => {
|
|
24
24
|
const appHtml = await readFile(join(rootDir, 'src/app.html'), 'utf-8')
|
|
25
|
-
expect(appHtml).toContain('lang="{{#if hasI18n}}%lang%{{else}}{{defaultLocale}}{{/if}}"')
|
|
25
|
+
expect(appHtml).toContain('lang="{{#if hasI18n}}{{#if isCapacitorApp}}{{defaultLocale}}{{else}}%lang%{{/if}}{{else}}{{defaultLocale}}{{/if}}"')
|
|
26
26
|
})
|
|
27
|
+
{{#unless isCapacitorApp}}
|
|
28
|
+
|
|
29
|
+
it('ships an application config loaded at startup', async () => {
|
|
30
|
+
const coreConfig = await readFile(join(rootDir, 'config/_core.yml'), 'utf-8')
|
|
31
|
+
expect(coreConfig).toContain('name: {{projectName}}')
|
|
32
|
+
expect(coreConfig).toContain('defaultLocale: {{defaultLocale}}')
|
|
33
|
+
})
|
|
34
|
+
{{/unless}}
|
|
27
35
|
})
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import path from 'node:path'
|
|
5
5
|
import process from 'node:process'
|
|
6
|
+
{{#if hasI18n}}
|
|
7
|
+
import { paraglideVitePlugin } from '@inlang/paraglide-js'
|
|
8
|
+
{{/if}}
|
|
6
9
|
import { sveltekit } from '@sveltejs/kit/vite'
|
|
7
10
|
{{#if hasUi}}
|
|
8
11
|
import tailwindcss from '@tailwindcss/vite'
|
|
9
12
|
{{/if}}
|
|
10
|
-
{{#if hasI18n}}
|
|
11
|
-
import { paraglideVitePlugin } from '@inlang/paraglide-js'
|
|
12
|
-
{{/if}}
|
|
13
13
|
import { defineConfig, loadEnv } from 'vite'
|
|
14
14
|
|
|
15
15
|
export default defineConfig(({ mode }) => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{{!-- 认证布局(登录/注册共用) --}}
|
|
2
|
-
<script lang=
|
|
2
|
+
<script lang='ts'>
|
|
3
3
|
/**
|
|
4
4
|
* 认证布局(登录/注册共用)
|
|
5
5
|
*/
|
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
children: Snippet
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
const { children }: Props = $props()
|
|
13
13
|
</script>
|
|
14
14
|
|
|
15
|
-
<div class=
|
|
16
|
-
<div class=
|
|
17
|
-
<div class=
|
|
15
|
+
<div class='min-h-screen flex items-center justify-center bg-base-200'>
|
|
16
|
+
<div class='card w-full max-w-md bg-base-100 shadow-xl'>
|
|
17
|
+
<div class='card-body'>
|
|
18
18
|
{@render children()}
|
|
19
19
|
</div>
|
|
20
20
|
</div>
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
{{!-- Admin 登录页面 --}}
|
|
2
|
-
<script lang=
|
|
2
|
+
<script lang='ts'>
|
|
3
3
|
/**
|
|
4
4
|
* 登录页面
|
|
5
5
|
*/
|
|
6
|
+
import { resolve } from '$app/paths'
|
|
6
7
|
{{#if hasI18n}}
|
|
7
8
|
import * as m from '$lib/paraglide/messages'
|
|
8
9
|
{{/if}}
|
|
10
|
+
import { Alert, Button, FormField, Input } from '@h-ai/ui'
|
|
9
11
|
|
|
10
12
|
let username = $state('')
|
|
11
13
|
let password = $state('')
|
|
12
14
|
let error = $state('')
|
|
13
15
|
let loading = $state(false)
|
|
14
16
|
|
|
15
|
-
async function handleLogin() {
|
|
17
|
+
async function handleLogin(event: SubmitEvent) {
|
|
18
|
+
event.preventDefault()
|
|
16
19
|
error = ''
|
|
17
20
|
loading = true
|
|
18
21
|
try {
|
|
@@ -24,20 +27,23 @@
|
|
|
24
27
|
const data = await res.json()
|
|
25
28
|
if (data.success) {
|
|
26
29
|
window.location.href = '/admin'
|
|
27
|
-
}
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
28
32
|
{{#if hasI18n}}
|
|
29
33
|
error = data.error?.message || m.auth_login_failed()
|
|
30
34
|
{{else}}
|
|
31
35
|
error = data.error?.message || '登录失败'
|
|
32
36
|
{{/if}}
|
|
33
37
|
}
|
|
34
|
-
}
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
35
40
|
{{#if hasI18n}}
|
|
36
41
|
error = m.auth_error_network()
|
|
37
42
|
{{else}}
|
|
38
43
|
error = '网络错误'
|
|
39
44
|
{{/if}}
|
|
40
|
-
}
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
41
47
|
loading = false
|
|
42
48
|
}
|
|
43
49
|
}
|
|
@@ -52,47 +58,43 @@
|
|
|
52
58
|
</svelte:head>
|
|
53
59
|
|
|
54
60
|
{{#if hasI18n}}
|
|
55
|
-
<h2 class=
|
|
61
|
+
<h2 class='text-2xl font-bold text-center mb-6'>{m.auth_login_title()}</h2>
|
|
56
62
|
{{else}}
|
|
57
|
-
<h2 class=
|
|
63
|
+
<h2 class='text-2xl font-bold text-center mb-6'>登录</h2>
|
|
58
64
|
{{/if}}
|
|
59
65
|
|
|
60
66
|
{#if error}
|
|
61
|
-
<
|
|
62
|
-
<span>{error}</span>
|
|
63
|
-
</div>
|
|
67
|
+
<Alert variant='error' class='mb-4'>{error}</Alert>
|
|
64
68
|
{/if}
|
|
65
69
|
|
|
66
|
-
<form onsubmit={
|
|
67
|
-
<div class="form-control">
|
|
68
|
-
{{#if hasI18n}}
|
|
69
|
-
<label class="label" for="username"><span class="label-text">{m.auth_label_username()}</span></label>
|
|
70
|
-
{{else}}
|
|
71
|
-
<label class="label" for="username"><span class="label-text">用户名</span></label>
|
|
72
|
-
{{/if}}
|
|
73
|
-
<input id="username" type="text" class="input input-bordered w-full" bind:value={username} required />
|
|
74
|
-
</div>
|
|
75
|
-
<div class="form-control">
|
|
76
|
-
{{#if hasI18n}}
|
|
77
|
-
<label class="label" for="password"><span class="label-text">{m.auth_label_password()}</span></label>
|
|
78
|
-
{{else}}
|
|
79
|
-
<label class="label" for="password"><span class="label-text">密码</span></label>
|
|
80
|
-
{{/if}}
|
|
81
|
-
<input id="password" type="password" class="input input-bordered w-full" bind:value={password} required />
|
|
82
|
-
</div>
|
|
83
|
-
<button type="submit" class="btn btn-primary w-full" disabled={loading}>
|
|
70
|
+
<form onsubmit={handleLogin} class='space-y-4'>
|
|
84
71
|
{{#if hasI18n}}
|
|
72
|
+
<FormField label={m.auth_label_username()} required>
|
|
73
|
+
<Input id='username' type='text' bind:value={username} required />
|
|
74
|
+
</FormField>
|
|
75
|
+
<FormField label={m.auth_label_password()} required>
|
|
76
|
+
<Input id='password' type='password' bind:value={password} required />
|
|
77
|
+
</FormField>
|
|
78
|
+
<Button type='submit' variant='primary' loading={loading} class='w-full'>
|
|
85
79
|
{loading ? m.auth_login_loading() : m.auth_login_submit()}
|
|
80
|
+
</Button>
|
|
86
81
|
{{else}}
|
|
82
|
+
<FormField label='用户名' required>
|
|
83
|
+
<Input id='username' type='text' bind:value={username} required />
|
|
84
|
+
</FormField>
|
|
85
|
+
<FormField label='密码' required>
|
|
86
|
+
<Input id='password' type='password' bind:value={password} required />
|
|
87
|
+
</FormField>
|
|
88
|
+
<Button type='submit' variant='primary' loading={loading} class='w-full'>
|
|
87
89
|
{loading ? '登录中...' : '登录'}
|
|
90
|
+
</Button>
|
|
88
91
|
{{/if}}
|
|
89
|
-
</button>
|
|
90
92
|
</form>
|
|
91
93
|
|
|
92
|
-
<div class=
|
|
94
|
+
<div class='text-center mt-4'>
|
|
93
95
|
{{#if hasI18n}}
|
|
94
|
-
<a href=
|
|
96
|
+
<a href={resolve('/auth/register', {})} class='link link-primary text-sm'>{m.auth_login_to_register()}</a>
|
|
95
97
|
{{else}}
|
|
96
|
-
<a href=
|
|
98
|
+
<a href={resolve('/auth/register', {})} class='link link-primary text-sm'>没有账号?立即注册</a>
|
|
97
99
|
{{/if}}
|
|
98
100
|
</div>
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
{{!-- Admin 注册页面 --}}
|
|
2
|
-
<script lang=
|
|
2
|
+
<script lang='ts'>
|
|
3
3
|
/**
|
|
4
4
|
* 注册页面
|
|
5
5
|
*/
|
|
6
|
+
import { resolve } from '$app/paths'
|
|
6
7
|
{{#if hasI18n}}
|
|
7
8
|
import * as m from '$lib/paraglide/messages'
|
|
8
9
|
{{/if}}
|
|
10
|
+
import { Alert, Button, FormField, Input } from '@h-ai/ui'
|
|
9
11
|
|
|
10
12
|
let username = $state('')
|
|
11
13
|
let email = $state('')
|
|
@@ -14,7 +16,8 @@
|
|
|
14
16
|
let error = $state('')
|
|
15
17
|
let loading = $state(false)
|
|
16
18
|
|
|
17
|
-
async function handleRegister() {
|
|
19
|
+
async function handleRegister(event: SubmitEvent) {
|
|
20
|
+
event.preventDefault()
|
|
18
21
|
error = ''
|
|
19
22
|
if (password !== confirmPassword) {
|
|
20
23
|
{{#if hasI18n}}
|
|
@@ -34,20 +37,23 @@
|
|
|
34
37
|
const data = await res.json()
|
|
35
38
|
if (data.success) {
|
|
36
39
|
window.location.href = '/auth/login'
|
|
37
|
-
}
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
38
42
|
{{#if hasI18n}}
|
|
39
43
|
error = data.error?.message || m.auth_register_failed()
|
|
40
44
|
{{else}}
|
|
41
45
|
error = data.error?.message || '注册失败'
|
|
42
46
|
{{/if}}
|
|
43
47
|
}
|
|
44
|
-
}
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
45
50
|
{{#if hasI18n}}
|
|
46
51
|
error = m.auth_error_network()
|
|
47
52
|
{{else}}
|
|
48
53
|
error = '网络错误'
|
|
49
54
|
{{/if}}
|
|
50
|
-
}
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
51
57
|
loading = false
|
|
52
58
|
}
|
|
53
59
|
}
|
|
@@ -62,63 +68,55 @@
|
|
|
62
68
|
</svelte:head>
|
|
63
69
|
|
|
64
70
|
{{#if hasI18n}}
|
|
65
|
-
<h2 class=
|
|
71
|
+
<h2 class='text-2xl font-bold text-center mb-6'>{m.auth_register_title()}</h2>
|
|
66
72
|
{{else}}
|
|
67
|
-
<h2 class=
|
|
73
|
+
<h2 class='text-2xl font-bold text-center mb-6'>注册</h2>
|
|
68
74
|
{{/if}}
|
|
69
75
|
|
|
70
76
|
{#if error}
|
|
71
|
-
<
|
|
72
|
-
<span>{error}</span>
|
|
73
|
-
</div>
|
|
77
|
+
<Alert variant='error' class='mb-4'>{error}</Alert>
|
|
74
78
|
{/if}
|
|
75
79
|
|
|
76
|
-
<form onsubmit={
|
|
77
|
-
<div class="form-control">
|
|
78
|
-
{{#if hasI18n}}
|
|
79
|
-
<label class="label" for="username"><span class="label-text">{m.auth_label_username()}</span></label>
|
|
80
|
-
{{else}}
|
|
81
|
-
<label class="label" for="username"><span class="label-text">用户名</span></label>
|
|
82
|
-
{{/if}}
|
|
83
|
-
<input id="username" type="text" class="input input-bordered w-full" bind:value={username} required />
|
|
84
|
-
</div>
|
|
85
|
-
<div class="form-control">
|
|
86
|
-
{{#if hasI18n}}
|
|
87
|
-
<label class="label" for="email"><span class="label-text">{m.auth_label_email()}</span></label>
|
|
88
|
-
{{else}}
|
|
89
|
-
<label class="label" for="email"><span class="label-text">邮箱</span></label>
|
|
90
|
-
{{/if}}
|
|
91
|
-
<input id="email" type="email" class="input input-bordered w-full" bind:value={email} required />
|
|
92
|
-
</div>
|
|
93
|
-
<div class="form-control">
|
|
94
|
-
{{#if hasI18n}}
|
|
95
|
-
<label class="label" for="password"><span class="label-text">{m.auth_label_password()}</span></label>
|
|
96
|
-
{{else}}
|
|
97
|
-
<label class="label" for="password"><span class="label-text">密码</span></label>
|
|
98
|
-
{{/if}}
|
|
99
|
-
<input id="password" type="password" class="input input-bordered w-full" bind:value={password} required />
|
|
100
|
-
</div>
|
|
101
|
-
<div class="form-control">
|
|
102
|
-
{{#if hasI18n}}
|
|
103
|
-
<label class="label" for="confirmPassword"><span class="label-text">{m.auth_label_confirm_password()}</span></label>
|
|
104
|
-
{{else}}
|
|
105
|
-
<label class="label" for="confirmPassword"><span class="label-text">确认密码</span></label>
|
|
106
|
-
{{/if}}
|
|
107
|
-
<input id="confirmPassword" type="password" class="input input-bordered w-full" bind:value={confirmPassword} required />
|
|
108
|
-
</div>
|
|
109
|
-
<button type="submit" class="btn btn-primary w-full" disabled={loading}>
|
|
80
|
+
<form onsubmit={handleRegister} class='space-y-4'>
|
|
110
81
|
{{#if hasI18n}}
|
|
82
|
+
<FormField label={m.auth_label_username()} required>
|
|
83
|
+
<Input id='username' type='text' bind:value={username} required />
|
|
84
|
+
</FormField>
|
|
85
|
+
<FormField label={m.auth_label_email()} required>
|
|
86
|
+
<Input id='email' type='email' bind:value={email} required />
|
|
87
|
+
</FormField>
|
|
88
|
+
<FormField label={m.auth_label_password()} required>
|
|
89
|
+
<Input id='password' type='password' bind:value={password} required />
|
|
90
|
+
</FormField>
|
|
91
|
+
<FormField label={m.auth_label_confirm_password()} required>
|
|
92
|
+
<Input id='confirmPassword' type='password' bind:value={confirmPassword} required />
|
|
93
|
+
</FormField>
|
|
94
|
+
<Button type='submit' variant='primary' loading={loading} class='w-full'>
|
|
111
95
|
{loading ? m.auth_register_loading() : m.auth_register_submit()}
|
|
96
|
+
</Button>
|
|
112
97
|
{{else}}
|
|
98
|
+
<FormField label='用户名' required>
|
|
99
|
+
<Input id='username' type='text' bind:value={username} required />
|
|
100
|
+
</FormField>
|
|
101
|
+
<FormField label='邮箱' required>
|
|
102
|
+
<Input id='email' type='email' bind:value={email} required />
|
|
103
|
+
</FormField>
|
|
104
|
+
<FormField label='密码' required>
|
|
105
|
+
<Input id='password' type='password' bind:value={password} required />
|
|
106
|
+
</FormField>
|
|
107
|
+
<FormField label='确认密码' required>
|
|
108
|
+
<Input id='confirmPassword' type='password' bind:value={confirmPassword} required />
|
|
109
|
+
</FormField>
|
|
110
|
+
<Button type='submit' variant='primary' loading={loading} class='w-full'>
|
|
113
111
|
{loading ? '注册中...' : '注册'}
|
|
112
|
+
</Button>
|
|
114
113
|
{{/if}}
|
|
115
|
-
</button>
|
|
116
114
|
</form>
|
|
117
115
|
|
|
118
|
-
<div class=
|
|
116
|
+
<div class='text-center mt-4'>
|
|
119
117
|
{{#if hasI18n}}
|
|
120
|
-
<a href=
|
|
118
|
+
<a href={resolve('/auth/login', {})} class='link link-primary text-sm'>{m.auth_register_to_login()}</a>
|
|
121
119
|
{{else}}
|
|
122
|
-
<a href=
|
|
120
|
+
<a href={resolve('/auth/login', {})} class='link link-primary text-sm'>已有账号?立即登录</a>
|
|
123
121
|
{{/if}}
|
|
124
122
|
</div>
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
{{!-- H5 登录页面 --}}
|
|
2
|
-
<script lang=
|
|
2
|
+
<script lang='ts'>
|
|
3
3
|
/**
|
|
4
4
|
* H5 登录页面
|
|
5
5
|
*/
|
|
6
|
+
import { resolve } from '$app/paths'
|
|
6
7
|
{{#if hasI18n}}
|
|
7
8
|
import * as m from '$lib/paraglide/messages'
|
|
8
9
|
{{/if}}
|
|
10
|
+
import { Alert, Button, FormField, Input } from '@h-ai/ui'
|
|
9
11
|
|
|
10
12
|
let username = $state('')
|
|
11
13
|
let password = $state('')
|
|
12
14
|
let error = $state('')
|
|
13
15
|
let loading = $state(false)
|
|
14
16
|
|
|
15
|
-
async function handleLogin() {
|
|
17
|
+
async function handleLogin(event: SubmitEvent) {
|
|
18
|
+
event.preventDefault()
|
|
16
19
|
error = ''
|
|
17
20
|
loading = true
|
|
18
21
|
try {
|
|
@@ -24,20 +27,23 @@
|
|
|
24
27
|
const data = await res.json()
|
|
25
28
|
if (data.success) {
|
|
26
29
|
window.location.href = '/'
|
|
27
|
-
}
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
28
32
|
{{#if hasI18n}}
|
|
29
33
|
error = data.error?.message || m.auth_login_failed()
|
|
30
34
|
{{else}}
|
|
31
35
|
error = data.error?.message || '登录失败'
|
|
32
36
|
{{/if}}
|
|
33
37
|
}
|
|
34
|
-
}
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
35
40
|
{{#if hasI18n}}
|
|
36
41
|
error = m.auth_error_network()
|
|
37
42
|
{{else}}
|
|
38
43
|
error = '网络错误'
|
|
39
44
|
{{/if}}
|
|
40
|
-
}
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
41
47
|
loading = false
|
|
42
48
|
}
|
|
43
49
|
}
|
|
@@ -51,48 +57,46 @@
|
|
|
51
57
|
{{/if}}
|
|
52
58
|
</svelte:head>
|
|
53
59
|
|
|
54
|
-
<div class=
|
|
60
|
+
<div class='p-4 pt-12 space-y-4'>
|
|
55
61
|
{{#if hasI18n}}
|
|
56
|
-
<h1 class=
|
|
62
|
+
<h1 class='text-2xl font-black tracking-tight text-center'>{m.auth_login_title()}</h1>
|
|
57
63
|
{{else}}
|
|
58
|
-
<h1 class=
|
|
64
|
+
<h1 class='text-2xl font-black tracking-tight text-center'>登录</h1>
|
|
59
65
|
{{/if}}
|
|
60
66
|
|
|
61
67
|
{#if error}
|
|
62
|
-
<
|
|
63
|
-
<span>{error}</span>
|
|
64
|
-
</div>
|
|
68
|
+
<Alert variant='error'>{error}</Alert>
|
|
65
69
|
{/if}
|
|
66
70
|
|
|
67
|
-
<form onsubmit={
|
|
68
|
-
<div class="form-control">
|
|
69
|
-
{{#if hasI18n}}
|
|
70
|
-
<input type="text" placeholder={m.auth_label_username()} class="input input-bordered w-full" bind:value={username} required />
|
|
71
|
-
{{else}}
|
|
72
|
-
<input type="text" placeholder="用户名" class="input input-bordered w-full" bind:value={username} required />
|
|
73
|
-
{{/if}}
|
|
74
|
-
</div>
|
|
75
|
-
<div class="form-control">
|
|
76
|
-
{{#if hasI18n}}
|
|
77
|
-
<input type="password" placeholder={m.auth_label_password()} class="input input-bordered w-full" bind:value={password} required />
|
|
78
|
-
{{else}}
|
|
79
|
-
<input type="password" placeholder="密码" class="input input-bordered w-full" bind:value={password} required />
|
|
80
|
-
{{/if}}
|
|
81
|
-
</div>
|
|
82
|
-
<button type="submit" class="btn btn-primary w-full" disabled={loading}>
|
|
71
|
+
<form onsubmit={handleLogin} class='space-y-4'>
|
|
83
72
|
{{#if hasI18n}}
|
|
73
|
+
<FormField label={m.auth_label_username()} required>
|
|
74
|
+
<Input id='username' type='text' bind:value={username} required />
|
|
75
|
+
</FormField>
|
|
76
|
+
<FormField label={m.auth_label_password()} required>
|
|
77
|
+
<Input id='password' type='password' bind:value={password} required />
|
|
78
|
+
</FormField>
|
|
79
|
+
<Button type='submit' variant='primary' loading={loading} class='w-full'>
|
|
84
80
|
{loading ? m.auth_login_loading() : m.auth_login_submit()}
|
|
81
|
+
</Button>
|
|
85
82
|
{{else}}
|
|
83
|
+
<FormField label='用户名' required>
|
|
84
|
+
<Input id='username' type='text' bind:value={username} required />
|
|
85
|
+
</FormField>
|
|
86
|
+
<FormField label='密码' required>
|
|
87
|
+
<Input id='password' type='password' bind:value={password} required />
|
|
88
|
+
</FormField>
|
|
89
|
+
<Button type='submit' variant='primary' loading={loading} class='w-full'>
|
|
86
90
|
{loading ? '登录中...' : '登录'}
|
|
91
|
+
</Button>
|
|
87
92
|
{{/if}}
|
|
88
|
-
</button>
|
|
89
93
|
</form>
|
|
90
94
|
|
|
91
|
-
<div class=
|
|
95
|
+
<div class='text-center'>
|
|
92
96
|
{{#if hasI18n}}
|
|
93
|
-
<a href=
|
|
97
|
+
<a href={resolve('/auth/register', {})} class='link link-primary text-sm'>{m.auth_login_to_register()}</a>
|
|
94
98
|
{{else}}
|
|
95
|
-
<a href=
|
|
99
|
+
<a href={resolve('/auth/register', {})} class='link link-primary text-sm'>没有账号?立即注册</a>
|
|
96
100
|
{{/if}}
|
|
97
101
|
</div>
|
|
98
102
|
</div>
|