@coze-arch/cli 0.0.1-alpha.77c1b0 → 0.0.1-alpha.7d92f8
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/lib/__templates__/expo/.cozeproj/scripts/deploy_build.sh +25 -18
- package/lib/__templates__/expo/.cozeproj/scripts/deploy_run.sh +28 -46
- package/lib/__templates__/expo/_npmrc +1 -1
- package/lib/__templates__/expo/client/contexts/AuthContext.tsx +14 -107
- package/lib/__templates__/expo/client/screens/home/index.tsx +1 -4
- package/lib/__templates__/expo/client/screens/home/styles.ts +1 -273
- package/lib/__templates__/expo/client/scripts/install-missing-deps.js +36 -12
- package/lib/__templates__/expo/client/utils/index.ts +1 -2
- package/lib/__templates__/expo/metro.config.js +15 -15
- package/lib/__templates__/expo/package.json +13 -3
- package/lib/__templates__/expo/pnpm-lock.yaml +134 -7
- package/lib/__templates__/expo/src/index.ts +2 -2
- package/lib/__templates__/expo/template.config.js +1 -1
- package/lib/__templates__/nextjs/.coze +3 -3
- package/lib/__templates__/nextjs/README.md +341 -19
- package/lib/__templates__/nextjs/_npmrc +1 -1
- package/lib/__templates__/nextjs/components.json +21 -0
- package/lib/__templates__/nextjs/package.json +54 -1
- package/lib/__templates__/nextjs/pnpm-lock.yaml +7947 -1523
- package/lib/__templates__/nextjs/scripts/dev.sh +9 -27
- package/lib/__templates__/nextjs/src/app/globals.css +99 -8
- package/lib/__templates__/nextjs/src/app/layout.tsx +18 -18
- package/lib/__templates__/nextjs/src/components/ui/accordion.tsx +66 -0
- package/lib/__templates__/nextjs/src/components/ui/alert-dialog.tsx +157 -0
- package/lib/__templates__/nextjs/src/components/ui/alert.tsx +66 -0
- package/lib/__templates__/nextjs/src/components/ui/aspect-ratio.tsx +11 -0
- package/lib/__templates__/nextjs/src/components/ui/avatar.tsx +53 -0
- package/lib/__templates__/nextjs/src/components/ui/badge.tsx +46 -0
- package/lib/__templates__/nextjs/src/components/ui/breadcrumb.tsx +109 -0
- package/lib/__templates__/nextjs/src/components/ui/button-group.tsx +83 -0
- package/lib/__templates__/nextjs/src/components/ui/button.tsx +62 -0
- package/lib/__templates__/nextjs/src/components/ui/calendar.tsx +220 -0
- package/lib/__templates__/nextjs/src/components/ui/card.tsx +92 -0
- package/lib/__templates__/nextjs/src/components/ui/carousel.tsx +241 -0
- package/lib/__templates__/nextjs/src/components/ui/chart.tsx +357 -0
- package/lib/__templates__/nextjs/src/components/ui/checkbox.tsx +32 -0
- package/lib/__templates__/nextjs/src/components/ui/collapsible.tsx +33 -0
- package/lib/__templates__/nextjs/src/components/ui/command.tsx +184 -0
- package/lib/__templates__/nextjs/src/components/ui/context-menu.tsx +252 -0
- package/lib/__templates__/nextjs/src/components/ui/dialog.tsx +143 -0
- package/lib/__templates__/nextjs/src/components/ui/drawer.tsx +135 -0
- package/lib/__templates__/nextjs/src/components/ui/dropdown-menu.tsx +257 -0
- package/lib/__templates__/nextjs/src/components/ui/empty.tsx +104 -0
- package/lib/__templates__/nextjs/src/components/ui/field.tsx +248 -0
- package/lib/__templates__/nextjs/src/components/ui/form.tsx +167 -0
- package/lib/__templates__/nextjs/src/components/ui/hover-card.tsx +44 -0
- package/lib/__templates__/nextjs/src/components/ui/input-group.tsx +170 -0
- package/lib/__templates__/nextjs/src/components/ui/input-otp.tsx +77 -0
- package/lib/__templates__/nextjs/src/components/ui/input.tsx +21 -0
- package/lib/__templates__/nextjs/src/components/ui/item.tsx +193 -0
- package/lib/__templates__/nextjs/src/components/ui/kbd.tsx +28 -0
- package/lib/__templates__/nextjs/src/components/ui/label.tsx +24 -0
- package/lib/__templates__/nextjs/src/components/ui/menubar.tsx +276 -0
- package/lib/__templates__/nextjs/src/components/ui/navigation-menu.tsx +168 -0
- package/lib/__templates__/nextjs/src/components/ui/pagination.tsx +127 -0
- package/lib/__templates__/nextjs/src/components/ui/popover.tsx +48 -0
- package/lib/__templates__/nextjs/src/components/ui/progress.tsx +31 -0
- package/lib/__templates__/nextjs/src/components/ui/radio-group.tsx +45 -0
- package/lib/__templates__/nextjs/src/components/ui/resizable.tsx +56 -0
- package/lib/__templates__/nextjs/src/components/ui/scroll-area.tsx +58 -0
- package/lib/__templates__/nextjs/src/components/ui/select.tsx +190 -0
- package/lib/__templates__/nextjs/src/components/ui/separator.tsx +28 -0
- package/lib/__templates__/nextjs/src/components/ui/sheet.tsx +139 -0
- package/lib/__templates__/nextjs/src/components/ui/sidebar.tsx +726 -0
- package/lib/__templates__/nextjs/src/components/ui/skeleton.tsx +13 -0
- package/lib/__templates__/nextjs/src/components/ui/slider.tsx +63 -0
- package/lib/__templates__/nextjs/src/components/ui/sonner.tsx +40 -0
- package/lib/__templates__/nextjs/src/components/ui/spinner.tsx +16 -0
- package/lib/__templates__/nextjs/src/components/ui/switch.tsx +31 -0
- package/lib/__templates__/nextjs/src/components/ui/table.tsx +116 -0
- package/lib/__templates__/nextjs/src/components/ui/tabs.tsx +66 -0
- package/lib/__templates__/nextjs/src/components/ui/textarea.tsx +18 -0
- package/lib/__templates__/nextjs/src/components/ui/toggle-group.tsx +83 -0
- package/lib/__templates__/nextjs/src/components/ui/toggle.tsx +47 -0
- package/lib/__templates__/nextjs/src/components/ui/tooltip.tsx +61 -0
- package/lib/__templates__/nextjs/src/hooks/use-mobile.ts +19 -0
- package/lib/__templates__/nextjs/src/lib/utils.ts +6 -0
- package/lib/__templates__/nextjs/template.config.js +2 -2
- package/lib/__templates__/templates.json +6 -37
- package/lib/__templates__/vite/.coze +3 -3
- package/lib/__templates__/vite/README.md +204 -26
- package/lib/__templates__/vite/_npmrc +1 -1
- package/lib/__templates__/vite/package.json +1 -1
- package/lib/__templates__/vite/pnpm-lock.yaml +120 -120
- package/lib/__templates__/vite/scripts/dev.sh +7 -26
- package/lib/__templates__/vite/template.config.js +11 -2
- package/lib/__templates__/vite/vite.config.ts +6 -3
- package/lib/cli.js +426 -249
- package/package.json +5 -3
- package/lib/__templates__/react-rsbuild/.coze +0 -11
- package/lib/__templates__/react-rsbuild/.vscode/settings.json +0 -121
- package/lib/__templates__/react-rsbuild/README.md +0 -61
- package/lib/__templates__/react-rsbuild/_gitignore +0 -97
- package/lib/__templates__/react-rsbuild/_npmrc +0 -22
- package/lib/__templates__/react-rsbuild/package.json +0 -31
- package/lib/__templates__/react-rsbuild/pnpm-lock.yaml +0 -997
- package/lib/__templates__/react-rsbuild/rsbuild.config.ts +0 -13
- package/lib/__templates__/react-rsbuild/scripts/build.sh +0 -14
- package/lib/__templates__/react-rsbuild/scripts/dev.sh +0 -51
- package/lib/__templates__/react-rsbuild/scripts/start.sh +0 -15
- package/lib/__templates__/react-rsbuild/src/App.tsx +0 -60
- package/lib/__templates__/react-rsbuild/src/index.css +0 -21
- package/lib/__templates__/react-rsbuild/src/index.html +0 -12
- package/lib/__templates__/react-rsbuild/src/index.tsx +0 -16
- package/lib/__templates__/react-rsbuild/tailwind.config.js +0 -9
- package/lib/__templates__/react-rsbuild/template.config.js +0 -54
- package/lib/__templates__/react-rsbuild/tsconfig.json +0 -17
- package/lib/__templates__/rsbuild/.coze +0 -11
- package/lib/__templates__/rsbuild/.vscode/settings.json +0 -7
- package/lib/__templates__/rsbuild/README.md +0 -61
- package/lib/__templates__/rsbuild/_gitignore +0 -97
- package/lib/__templates__/rsbuild/_npmrc +0 -22
- package/lib/__templates__/rsbuild/package.json +0 -24
- package/lib/__templates__/rsbuild/pnpm-lock.yaml +0 -888
- package/lib/__templates__/rsbuild/rsbuild.config.ts +0 -12
- package/lib/__templates__/rsbuild/scripts/build.sh +0 -14
- package/lib/__templates__/rsbuild/scripts/dev.sh +0 -51
- package/lib/__templates__/rsbuild/scripts/start.sh +0 -15
- package/lib/__templates__/rsbuild/src/index.css +0 -21
- package/lib/__templates__/rsbuild/src/index.html +0 -12
- package/lib/__templates__/rsbuild/src/index.ts +0 -5
- package/lib/__templates__/rsbuild/src/main.ts +0 -65
- package/lib/__templates__/rsbuild/tailwind.config.js +0 -9
- package/lib/__templates__/rsbuild/template.config.js +0 -56
- package/lib/__templates__/rsbuild/tsconfig.json +0 -16
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
if [ -z "${BASH_VERSION:-}" ]; then exec /usr/bin/env bash "$0" "$@"; fi
|
|
3
3
|
set -euo pipefail
|
|
4
4
|
ROOT_DIR="$(pwd)"
|
|
5
|
+
PREVIEW_DIR="${COZE_PREVIEW_DIR:-$ROOT_DIR}"
|
|
5
6
|
LOG_DIR="${COZE_LOG_DIR:-$ROOT_DIR/logs}"
|
|
6
7
|
LOG_FILE="$LOG_DIR/app.log"
|
|
7
8
|
mkdir -p "$LOG_DIR"
|
|
@@ -29,19 +30,25 @@ check_command() {
|
|
|
29
30
|
write_log() {
|
|
30
31
|
local level="${1:-INFO}"
|
|
31
32
|
local msg="${2:-}"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
33
|
+
node -e '
|
|
34
|
+
const fs=require("fs");
|
|
35
|
+
const path=process.argv[1];
|
|
36
|
+
const level=(process.argv[2]||"").toUpperCase();
|
|
37
|
+
let msg=String(process.argv[3]||"");
|
|
38
|
+
const ts=Date.now();
|
|
39
|
+
const dt=new Date();
|
|
40
|
+
const parts=new Intl.DateTimeFormat("en-GB",{timeZone:"Asia/Shanghai",year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:false}).formatToParts(dt);
|
|
41
|
+
const o={};
|
|
42
|
+
for(const p of parts){o[p.type]=p.value}
|
|
43
|
+
const dt_str=`${o.year}-${o.month}-${o.day} ${o.hour}:${o.minute}:${o.second}`;
|
|
44
|
+
msg=msg.replace(/\\n/g,"\n");
|
|
45
|
+
msg=`${dt_str} [${level}] ${msg}`;
|
|
46
|
+
const record=JSON.stringify({level, message: msg, timestamp: ts},null,0);
|
|
47
|
+
const fd=fs.openSync(path,"a");
|
|
48
|
+
fs.writeSync(fd, record+"\n", null, "utf8");
|
|
49
|
+
fs.fsyncSync(fd);
|
|
50
|
+
fs.closeSync(fd);
|
|
51
|
+
' "$LOG_FILE" "$level" "$msg"
|
|
45
52
|
|
|
46
53
|
case "$level" in
|
|
47
54
|
INFO) info "$msg" ;;
|
|
@@ -55,16 +62,16 @@ PY
|
|
|
55
62
|
write_log "INFO" "==================== 开始构建 ===================="
|
|
56
63
|
|
|
57
64
|
write_log "INFO" "检查根目录 pre_install.py"
|
|
58
|
-
if [ -f "$
|
|
59
|
-
write_log "INFO" "执行:python $
|
|
60
|
-
python "$
|
|
65
|
+
if [ -f "$PREVIEW_DIR/pre_install.py" ]; then
|
|
66
|
+
write_log "INFO" "执行:python $PREVIEW_DIR/pre_install.py"
|
|
67
|
+
python "$PREVIEW_DIR/pre_install.py" || write_log "ERROR" "pre_install.py 执行失败"
|
|
61
68
|
fi
|
|
62
69
|
|
|
63
70
|
write_log "INFO" "开始执行构建脚本(build_dev.sh)..."
|
|
64
71
|
write_log "INFO" "正在检查依赖命令是否存在..."
|
|
65
72
|
# 检查核心命令
|
|
66
|
-
check_command "pip"
|
|
67
|
-
check_command "python"
|
|
73
|
+
# check_command "pip"
|
|
74
|
+
# check_command "python"
|
|
68
75
|
check_command "pnpm"
|
|
69
76
|
check_command "npm"
|
|
70
77
|
|
|
@@ -4,7 +4,7 @@ LOG_FILE="$LOG_DIR/app.log"
|
|
|
4
4
|
mkdir -p "$LOG_DIR"
|
|
5
5
|
|
|
6
6
|
# ==================== 配置项 ====================
|
|
7
|
-
#
|
|
7
|
+
# Server 服务配置
|
|
8
8
|
SERVER_HOST="0.0.0.0"
|
|
9
9
|
SERVER_PORT="9091"
|
|
10
10
|
# Expo 项目配置
|
|
@@ -97,19 +97,25 @@ ensure_port() {
|
|
|
97
97
|
write_log() {
|
|
98
98
|
local level="${1:-INFO}"
|
|
99
99
|
local msg="${2:-}"
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
100
|
+
node -e '
|
|
101
|
+
const fs=require("fs");
|
|
102
|
+
const path=process.argv[1];
|
|
103
|
+
const level=(process.argv[2]||"").toUpperCase();
|
|
104
|
+
let msg=String(process.argv[3]||"");
|
|
105
|
+
const ts=Date.now();
|
|
106
|
+
msg=msg.replace(/\\n/g,"\n");
|
|
107
|
+
const dt=new Date();
|
|
108
|
+
const parts=new Intl.DateTimeFormat("en-GB",{timeZone:"Asia/Shanghai",year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:false}).formatToParts(dt);
|
|
109
|
+
const o={};
|
|
110
|
+
for(const p of parts){o[p.type]=p.value}
|
|
111
|
+
const dt_str=`${o.year}-${o.month}-${o.day} ${o.hour}:${o.minute}:${o.second}`;
|
|
112
|
+
msg=`${dt_str} [${level}] ${msg}`;
|
|
113
|
+
const record=JSON.stringify({level, message: msg, timestamp: ts},null,0);
|
|
114
|
+
const fd=fs.openSync(path,"a");
|
|
115
|
+
fs.writeSync(fd, record+"\n", null, "utf8");
|
|
116
|
+
fs.fsyncSync(fd);
|
|
117
|
+
fs.closeSync(fd);
|
|
118
|
+
' "$LOG_FILE" "$level" "$msg"
|
|
113
119
|
case "$level" in
|
|
114
120
|
INFO) echo -e "\033[32m[INFO] $msg\033[0m" ;;
|
|
115
121
|
WARN) echo -e "\033[33m[WARN] $msg\033[0m" ;;
|
|
@@ -157,7 +163,7 @@ write_log "INFO" "==================== 开始启动 ===================="
|
|
|
157
163
|
write_log "INFO" "开始执行服务启动脚本(start_dev.sh)..."
|
|
158
164
|
write_log "INFO" "正在检查依赖命令和目录是否存在..."
|
|
159
165
|
# 检查核心命令
|
|
160
|
-
check_command "python"
|
|
166
|
+
# check_command "python"
|
|
161
167
|
check_command "npm"
|
|
162
168
|
check_command "pnpm"
|
|
163
169
|
check_command "lsof"
|
|
@@ -169,39 +175,15 @@ mkdir -p logs
|
|
|
169
175
|
ensure_port SERVER_PORT "$SERVER_PORT"
|
|
170
176
|
ensure_port EXPO_PORT "$EXPO_PORT"
|
|
171
177
|
|
|
172
|
-
# ====================
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
if [ -n "${COZE_WORKLOAD_IDENTITY_API_KEY:-}" ]; then
|
|
179
|
-
export OPENAI_API_KEY="$COZE_WORKLOAD_IDENTITY_API_KEY"
|
|
180
|
-
fi
|
|
181
|
-
if [ -n "${OPENAI_API_KEY:-}" ]; then
|
|
182
|
-
export ARK_API_KEY="$OPENAI_API_KEY"
|
|
183
|
-
fi
|
|
184
|
-
|
|
185
|
-
if [ -n "${COZE_INTEGRATION_BASE_URL:-}" ]; then
|
|
186
|
-
_base="${COZE_INTEGRATION_BASE_URL%/}"
|
|
187
|
-
export default_llm_base_url="${_base}/api/v3"
|
|
178
|
+
# ==================== 启动 Server 服务 ====================
|
|
179
|
+
write_log "INFO" "检查 Nginx 端口 (5000)..."
|
|
180
|
+
if is_port_free 5000; then
|
|
181
|
+
write_log "INFO" "端口 5000 未被占用,正在启动 Nginx..."
|
|
182
|
+
service nginx start
|
|
188
183
|
else
|
|
189
|
-
|
|
184
|
+
write_log "INFO" "端口 5000 已被占用,跳过 Nginx 启动"
|
|
190
185
|
fi
|
|
191
186
|
|
|
192
|
-
if [ -n "${PGDATABASE_URL:-}" ]; then
|
|
193
|
-
_pg="${PGDATABASE_URL}"
|
|
194
|
-
case "${_pg}" in
|
|
195
|
-
postgresql://*)
|
|
196
|
-
_pg="postgresql+asyncpg://${_pg#postgresql://}"
|
|
197
|
-
;;
|
|
198
|
-
esac
|
|
199
|
-
_pg="${_pg%%\?*}"
|
|
200
|
-
export DATABASE_URL="${_pg}"
|
|
201
|
-
fi
|
|
202
|
-
|
|
203
|
-
# ------------环境变量----------------------
|
|
204
|
-
|
|
205
187
|
write_log "INFO" "==================== 启动 server 服务 ===================="
|
|
206
188
|
write_log "INFO" "正在执行:npm run server"
|
|
207
189
|
PORT="$SERVER_PORT" nohup npm run server > logs/app.log 2>&1 &
|
|
@@ -221,7 +203,7 @@ if detect_expo_fetch_failed 8; then
|
|
|
221
203
|
: > logs/expo.log
|
|
222
204
|
EXPO_PID=$(start_expo 1)
|
|
223
205
|
fi
|
|
224
|
-
# 输出以下环境变量,确保 Expo 项目能正确连接到
|
|
206
|
+
# 输出以下环境变量,确保 Expo 项目能正确连接到 Server 服务
|
|
225
207
|
write_log "INFO" "Expo 环境变量配置:"
|
|
226
208
|
write_log "INFO" "EXPO_PUBLIC_BACKEND_BASE_URL=${EXPO_PUBLIC_BACKEND_BASE_URL}"
|
|
227
209
|
write_log "INFO" "EXPO_PACKAGER_PROXY_URL=${EXPO_PACKAGER_PROXY_URL}"
|
|
@@ -4,19 +4,15 @@
|
|
|
4
4
|
*
|
|
5
5
|
* 基于固定的 API 接口实现,可复用到其他项目
|
|
6
6
|
* 其他项目使用时,只需修改 @api 的导入路径指向项目的 api 模块
|
|
7
|
+
*
|
|
8
|
+
* 注意:
|
|
9
|
+
* - 如果需要登录/鉴权场景,请扩展本文件,完善 login/logout、token 管理、用户信息获取与刷新等逻辑
|
|
10
|
+
* - 将示例中的占位实现替换为项目实际的接口调用与状态管理
|
|
7
11
|
*/
|
|
8
|
-
import React, {
|
|
9
|
-
createContext,
|
|
10
|
-
useContext,
|
|
11
|
-
useState,
|
|
12
|
-
useEffect,
|
|
13
|
-
ReactNode,
|
|
14
|
-
} from "react";
|
|
15
|
-
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
16
|
-
//import { UserOut, UsersService, AuthenticationService } from "@api";
|
|
12
|
+
import React, { createContext, useContext, ReactNode } from "react";
|
|
17
13
|
|
|
18
14
|
interface UserOut {
|
|
19
|
-
|
|
15
|
+
|
|
20
16
|
}
|
|
21
17
|
|
|
22
18
|
interface AuthContextType {
|
|
@@ -31,105 +27,16 @@ interface AuthContextType {
|
|
|
31
27
|
|
|
32
28
|
const AuthContext = createContext<AuthContextType | undefined>(undefined);
|
|
33
29
|
|
|
34
|
-
export const AuthProvider: React.FC<{ children: ReactNode }> = ({
|
|
35
|
-
children,
|
|
36
|
-
}) => {
|
|
37
|
-
const [user, setUser] = useState<UserOut | null>(null);
|
|
38
|
-
const [token, setToken] = useState<string | null>(null);
|
|
39
|
-
const [isLoading, setIsLoading] = useState(true);
|
|
40
|
-
|
|
41
|
-
useEffect(() => {
|
|
42
|
-
loadAuthData();
|
|
43
|
-
}, []);
|
|
44
|
-
|
|
45
|
-
const loadAuthData = async () => {
|
|
46
|
-
try {
|
|
47
|
-
const results = await AsyncStorage.multiGet(["access_token", "user_data"]);
|
|
48
|
-
const storedToken = results?.[0]?.[1] ?? null;
|
|
49
|
-
const storedUser = results?.[1]?.[1] ?? null;
|
|
50
|
-
|
|
51
|
-
if (!storedToken) {
|
|
52
|
-
setToken(null);
|
|
53
|
-
setUser(null);
|
|
54
|
-
await AsyncStorage.multiRemove(["access_token", "user_data"]);
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (storedToken && storedUser) {
|
|
59
|
-
setToken(storedToken);
|
|
60
|
-
setUser(JSON.parse(storedUser));
|
|
61
|
-
} else if (storedToken && !storedUser) {
|
|
62
|
-
// 若仅有 token,主动拉取当前用户信息
|
|
63
|
-
setToken(storedToken);
|
|
64
|
-
try {
|
|
65
|
-
// const me = await UsersService.getCurrentUserApiV1UsersMeGet();
|
|
66
|
-
//if (me?.success && me.data) {
|
|
67
|
-
// setUser(me.data);
|
|
68
|
-
// await AsyncStorage.setItem("user_data", JSON.stringify(me.data));
|
|
69
|
-
//}
|
|
70
|
-
} catch (e) {
|
|
71
|
-
// 拉取失败则保持未登录状态
|
|
72
|
-
console.error("Failed to fetch current user with stored token:", e);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
} catch (error) {
|
|
76
|
-
console.error("Failed to load auth data:", error);
|
|
77
|
-
} finally {
|
|
78
|
-
setIsLoading(false);
|
|
79
|
-
}
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
const login = async (newToken: string) => {
|
|
83
|
-
try {
|
|
84
|
-
setToken(newToken);
|
|
85
|
-
// 统一写入 access_token,供 OpenAPI 读取并自动携带
|
|
86
|
-
await AsyncStorage.setItem("access_token", newToken);
|
|
87
|
-
// 登录后拉取当前用户并缓存
|
|
88
|
-
try {
|
|
89
|
-
const me = await UsersService.getCurrentUserApiV1UsersMeGet();
|
|
90
|
-
if (me?.success && me.data) {
|
|
91
|
-
setUser(me.data);
|
|
92
|
-
await AsyncStorage.setItem("user_data", JSON.stringify(me.data));
|
|
93
|
-
}
|
|
94
|
-
} catch (e) {
|
|
95
|
-
console.error("Fetch current user after login failed:", e);
|
|
96
|
-
}
|
|
97
|
-
} catch (error) {
|
|
98
|
-
console.error("Login failed:", error);
|
|
99
|
-
throw error;
|
|
100
|
-
}
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
const logout = async () => {
|
|
104
|
-
try {
|
|
105
|
-
// await AuthenticationService.logoutApiV1AuthLogoutPost(true);
|
|
106
|
-
} catch(error) {
|
|
107
|
-
console.warn('Logout failed:', error);
|
|
108
|
-
}
|
|
109
|
-
// remove token
|
|
110
|
-
setToken(null);
|
|
111
|
-
setUser(null);
|
|
112
|
-
await AsyncStorage.multiRemove(["auth_token", "access_token", "user_data"]);
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
const updateUser = (userData: Partial<UserOut>) => {
|
|
116
|
-
if (user) {
|
|
117
|
-
const updatedUser = { ...user, ...userData };
|
|
118
|
-
setUser(updatedUser);
|
|
119
|
-
AsyncStorage.setItem("user_data", JSON.stringify(updatedUser));
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
|
|
30
|
+
export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
|
|
123
31
|
const value: AuthContextType = {
|
|
124
|
-
user,
|
|
125
|
-
token,
|
|
126
|
-
isAuthenticated:
|
|
127
|
-
isLoading,
|
|
128
|
-
login,
|
|
129
|
-
logout,
|
|
130
|
-
updateUser,
|
|
32
|
+
user: null,
|
|
33
|
+
token: null,
|
|
34
|
+
isAuthenticated: false,
|
|
35
|
+
isLoading: false,
|
|
36
|
+
login: async (token: string) => {},
|
|
37
|
+
logout: async () => {},
|
|
38
|
+
updateUser: () => {},
|
|
131
39
|
};
|
|
132
|
-
|
|
133
40
|
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
|
|
134
41
|
};
|
|
135
42
|
|
|
@@ -3,10 +3,7 @@ import {
|
|
|
3
3
|
View,
|
|
4
4
|
Text,
|
|
5
5
|
ScrollView,
|
|
6
|
-
TouchableOpacity,
|
|
7
6
|
RefreshControl,
|
|
8
|
-
Image,
|
|
9
|
-
ActivityIndicator,
|
|
10
7
|
} from 'react-native';
|
|
11
8
|
import { useRouter, useFocusEffect } from 'expo-router';
|
|
12
9
|
import { FontAwesome6 } from '@expo/vector-icons';
|
|
@@ -15,7 +12,7 @@ import { useTheme } from "@/hooks/useTheme";
|
|
|
15
12
|
|
|
16
13
|
import { Screen } from '@/components/Screen';
|
|
17
14
|
|
|
18
|
-
import styles from './styles';
|
|
15
|
+
import { styles } from './styles';
|
|
19
16
|
|
|
20
17
|
|
|
21
18
|
export default function HomeScreen() {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { StyleSheet, Platform } from 'react-native';
|
|
2
2
|
|
|
3
|
-
const styles = StyleSheet.create({
|
|
3
|
+
export const styles = StyleSheet.create({
|
|
4
4
|
loadingContainer: {
|
|
5
5
|
flex: 1,
|
|
6
6
|
justifyContent: 'center',
|
|
@@ -22,18 +22,6 @@ const styles = StyleSheet.create({
|
|
|
22
22
|
fontSize: 16,
|
|
23
23
|
color: '#64748B',
|
|
24
24
|
},
|
|
25
|
-
retryButton: {
|
|
26
|
-
marginTop: 20,
|
|
27
|
-
paddingHorizontal: 24,
|
|
28
|
-
paddingVertical: 12,
|
|
29
|
-
backgroundColor: '#2563EB',
|
|
30
|
-
borderRadius: 8,
|
|
31
|
-
},
|
|
32
|
-
retryButtonText: {
|
|
33
|
-
color: '#FFFFFF',
|
|
34
|
-
fontSize: 14,
|
|
35
|
-
fontWeight: '600',
|
|
36
|
-
},
|
|
37
25
|
header: {
|
|
38
26
|
flexDirection: 'row',
|
|
39
27
|
justifyContent: 'space-between',
|
|
@@ -44,11 +32,6 @@ const styles = StyleSheet.create({
|
|
|
44
32
|
// borderBottomWidth: 1,
|
|
45
33
|
borderBottomColor: '#E2E8F0',
|
|
46
34
|
},
|
|
47
|
-
headerLeft: {
|
|
48
|
-
flexDirection: 'row',
|
|
49
|
-
alignItems: 'center',
|
|
50
|
-
gap: 10,
|
|
51
|
-
},
|
|
52
35
|
logoContainer: {
|
|
53
36
|
width: 32,
|
|
54
37
|
height: 32,
|
|
@@ -74,259 +57,4 @@ const styles = StyleSheet.create({
|
|
|
74
57
|
color: '#1E293B',
|
|
75
58
|
letterSpacing: -0.5,
|
|
76
59
|
},
|
|
77
|
-
userMenuContainer: {
|
|
78
|
-
flexDirection: 'row',
|
|
79
|
-
alignItems: 'center',
|
|
80
|
-
gap: 10,
|
|
81
|
-
paddingLeft: 16,
|
|
82
|
-
borderLeftWidth: 1,
|
|
83
|
-
borderLeftColor: '#E2E8F0',
|
|
84
|
-
},
|
|
85
|
-
userInfo: {
|
|
86
|
-
alignItems: 'flex-end',
|
|
87
|
-
},
|
|
88
|
-
userName: {
|
|
89
|
-
fontSize: 14,
|
|
90
|
-
fontWeight: '500',
|
|
91
|
-
color: '#1E293B',
|
|
92
|
-
},
|
|
93
|
-
userRole: {
|
|
94
|
-
fontSize: 12,
|
|
95
|
-
color: '#64748B',
|
|
96
|
-
},
|
|
97
|
-
avatar: {
|
|
98
|
-
width: 36,
|
|
99
|
-
height: 36,
|
|
100
|
-
borderRadius: 18,
|
|
101
|
-
borderWidth: 2,
|
|
102
|
-
borderColor: '#FFFFFF',
|
|
103
|
-
...Platform.select({
|
|
104
|
-
ios: {
|
|
105
|
-
shadowColor: '#000',
|
|
106
|
-
shadowOffset: { width: 0, height: 1 },
|
|
107
|
-
shadowOpacity: 0.1,
|
|
108
|
-
shadowRadius: 2,
|
|
109
|
-
},
|
|
110
|
-
android: {
|
|
111
|
-
elevation: 2,
|
|
112
|
-
},
|
|
113
|
-
}),
|
|
114
|
-
},
|
|
115
|
-
avatarPlaceholder: {
|
|
116
|
-
width: 36,
|
|
117
|
-
height: 36,
|
|
118
|
-
borderRadius: 18,
|
|
119
|
-
justifyContent: 'center',
|
|
120
|
-
alignItems: 'center',
|
|
121
|
-
borderWidth: 2,
|
|
122
|
-
borderColor: '#FFFFFF',
|
|
123
|
-
backgroundColor: '#3B82F6',
|
|
124
|
-
...Platform.select({
|
|
125
|
-
ios: {
|
|
126
|
-
shadowColor: '#000',
|
|
127
|
-
shadowOffset: { width: 0, height: 1 },
|
|
128
|
-
shadowOpacity: 0.1,
|
|
129
|
-
shadowRadius: 2,
|
|
130
|
-
},
|
|
131
|
-
android: {
|
|
132
|
-
elevation: 2,
|
|
133
|
-
},
|
|
134
|
-
}),
|
|
135
|
-
},
|
|
136
|
-
avatarInitial: {
|
|
137
|
-
fontSize: 14,
|
|
138
|
-
fontWeight: '700',
|
|
139
|
-
color: '#FFFFFF',
|
|
140
|
-
},
|
|
141
|
-
content: {
|
|
142
|
-
paddingHorizontal: 16,
|
|
143
|
-
paddingTop: 24,
|
|
144
|
-
},
|
|
145
|
-
welcomeSection: {
|
|
146
|
-
marginBottom: 24,
|
|
147
|
-
},
|
|
148
|
-
welcomeTitle: {
|
|
149
|
-
fontSize: 22,
|
|
150
|
-
fontWeight: '700',
|
|
151
|
-
color: '#1E293B',
|
|
152
|
-
marginBottom: 4,
|
|
153
|
-
},
|
|
154
|
-
welcomeSubtitle: {
|
|
155
|
-
fontSize: 14,
|
|
156
|
-
color: '#64748B',
|
|
157
|
-
},
|
|
158
|
-
statsGrid: {
|
|
159
|
-
flexDirection: 'row',
|
|
160
|
-
gap: 12,
|
|
161
|
-
marginBottom: 24,
|
|
162
|
-
},
|
|
163
|
-
statCard: {
|
|
164
|
-
flex: 1,
|
|
165
|
-
backgroundColor: '#FFFFFF',
|
|
166
|
-
borderRadius: 12,
|
|
167
|
-
padding: 16,
|
|
168
|
-
...Platform.select({
|
|
169
|
-
ios: {
|
|
170
|
-
shadowColor: '#000',
|
|
171
|
-
shadowOffset: { width: 0, height: 1 },
|
|
172
|
-
shadowOpacity: 0.05,
|
|
173
|
-
shadowRadius: 3,
|
|
174
|
-
},
|
|
175
|
-
android: {
|
|
176
|
-
elevation: 2,
|
|
177
|
-
},
|
|
178
|
-
}),
|
|
179
|
-
},
|
|
180
|
-
statCardHeader: {
|
|
181
|
-
flexDirection: 'row',
|
|
182
|
-
justifyContent: 'space-between',
|
|
183
|
-
alignItems: 'flex-start',
|
|
184
|
-
marginBottom: 12,
|
|
185
|
-
},
|
|
186
|
-
statIconContainer: {
|
|
187
|
-
width: 40,
|
|
188
|
-
height: 40,
|
|
189
|
-
borderRadius: 10,
|
|
190
|
-
justifyContent: 'center',
|
|
191
|
-
alignItems: 'center',
|
|
192
|
-
},
|
|
193
|
-
statIconBlue: {
|
|
194
|
-
backgroundColor: '#EFF6FF',
|
|
195
|
-
},
|
|
196
|
-
statIconRed: {
|
|
197
|
-
backgroundColor: '#FEF2F2',
|
|
198
|
-
},
|
|
199
|
-
statIconGreen: {
|
|
200
|
-
backgroundColor: '#ECFDF5',
|
|
201
|
-
},
|
|
202
|
-
attentionBadge: {
|
|
203
|
-
backgroundColor: '#FEF2F2',
|
|
204
|
-
paddingHorizontal: 6,
|
|
205
|
-
paddingVertical: 2,
|
|
206
|
-
borderRadius: 10,
|
|
207
|
-
},
|
|
208
|
-
attentionBadgeText: {
|
|
209
|
-
fontSize: 10,
|
|
210
|
-
fontWeight: '500',
|
|
211
|
-
color: '#EF4444',
|
|
212
|
-
},
|
|
213
|
-
rateBadge: {
|
|
214
|
-
backgroundColor: '#ECFDF5',
|
|
215
|
-
paddingHorizontal: 6,
|
|
216
|
-
paddingVertical: 2,
|
|
217
|
-
borderRadius: 10,
|
|
218
|
-
},
|
|
219
|
-
rateBadgeText: {
|
|
220
|
-
fontSize: 10,
|
|
221
|
-
fontWeight: '500',
|
|
222
|
-
color: '#10B981',
|
|
223
|
-
},
|
|
224
|
-
statValue: {
|
|
225
|
-
fontSize: 28,
|
|
226
|
-
fontWeight: '700',
|
|
227
|
-
color: '#1E293B',
|
|
228
|
-
marginBottom: 2,
|
|
229
|
-
},
|
|
230
|
-
statLabel: {
|
|
231
|
-
fontSize: 13,
|
|
232
|
-
color: '#64748B',
|
|
233
|
-
},
|
|
234
|
-
shortcutsSection: {
|
|
235
|
-
gap: 12,
|
|
236
|
-
marginBottom: 24,
|
|
237
|
-
},
|
|
238
|
-
shortcutCard: {
|
|
239
|
-
flexDirection: 'row',
|
|
240
|
-
justifyContent: 'space-between',
|
|
241
|
-
alignItems: 'center',
|
|
242
|
-
backgroundColor: '#FFFFFF',
|
|
243
|
-
borderRadius: 12,
|
|
244
|
-
padding: 16,
|
|
245
|
-
...Platform.select({
|
|
246
|
-
ios: {
|
|
247
|
-
shadowColor: '#000',
|
|
248
|
-
shadowOffset: { width: 0, height: 1 },
|
|
249
|
-
shadowOpacity: 0.05,
|
|
250
|
-
shadowRadius: 3,
|
|
251
|
-
},
|
|
252
|
-
android: {
|
|
253
|
-
elevation: 2,
|
|
254
|
-
},
|
|
255
|
-
}),
|
|
256
|
-
},
|
|
257
|
-
shortcutContent: {
|
|
258
|
-
flex: 1,
|
|
259
|
-
marginRight: 16,
|
|
260
|
-
},
|
|
261
|
-
shortcutTitle: {
|
|
262
|
-
fontSize: 16,
|
|
263
|
-
fontWeight: '600',
|
|
264
|
-
color: '#1E293B',
|
|
265
|
-
marginBottom: 6,
|
|
266
|
-
},
|
|
267
|
-
shortcutDescription: {
|
|
268
|
-
fontSize: 13,
|
|
269
|
-
color: '#64748B',
|
|
270
|
-
marginBottom: 10,
|
|
271
|
-
lineHeight: 18,
|
|
272
|
-
},
|
|
273
|
-
shortcutAction: {
|
|
274
|
-
flexDirection: 'row',
|
|
275
|
-
alignItems: 'center',
|
|
276
|
-
gap: 6,
|
|
277
|
-
},
|
|
278
|
-
shortcutActionText: {
|
|
279
|
-
fontSize: 13,
|
|
280
|
-
fontWeight: '500',
|
|
281
|
-
color: '#2563EB',
|
|
282
|
-
},
|
|
283
|
-
shortcutIconContainer: {
|
|
284
|
-
width: 56,
|
|
285
|
-
height: 56,
|
|
286
|
-
borderRadius: 28,
|
|
287
|
-
justifyContent: 'center',
|
|
288
|
-
alignItems: 'center',
|
|
289
|
-
},
|
|
290
|
-
shortcutIconBlue: {
|
|
291
|
-
backgroundColor: '#EFF6FF',
|
|
292
|
-
},
|
|
293
|
-
shortcutIconGreen: {
|
|
294
|
-
backgroundColor: '#ECFDF5',
|
|
295
|
-
},
|
|
296
|
-
bannerContainer: {
|
|
297
|
-
height: 160,
|
|
298
|
-
borderRadius: 12,
|
|
299
|
-
overflow: 'hidden',
|
|
300
|
-
backgroundColor: '#1E3A8A',
|
|
301
|
-
},
|
|
302
|
-
bannerOverlay: {
|
|
303
|
-
flex: 1,
|
|
304
|
-
justifyContent: 'center',
|
|
305
|
-
paddingHorizontal: 20,
|
|
306
|
-
},
|
|
307
|
-
bannerTitle: {
|
|
308
|
-
fontSize: 18,
|
|
309
|
-
fontWeight: '700',
|
|
310
|
-
color: '#FFFFFF',
|
|
311
|
-
marginBottom: 6,
|
|
312
|
-
},
|
|
313
|
-
bannerSubtitle: {
|
|
314
|
-
fontSize: 13,
|
|
315
|
-
color: '#BFDBFE',
|
|
316
|
-
marginBottom: 16,
|
|
317
|
-
},
|
|
318
|
-
bannerButton: {
|
|
319
|
-
alignSelf: 'flex-start',
|
|
320
|
-
backgroundColor: '#FFFFFF',
|
|
321
|
-
paddingHorizontal: 20,
|
|
322
|
-
paddingVertical: 10,
|
|
323
|
-
borderRadius: 8,
|
|
324
|
-
},
|
|
325
|
-
bannerButtonText: {
|
|
326
|
-
fontSize: 13,
|
|
327
|
-
fontWeight: '500',
|
|
328
|
-
color: '#2563EB',
|
|
329
|
-
},
|
|
330
60
|
});
|
|
331
|
-
|
|
332
|
-
export default styles;
|