Merge remote-tracking branch 'origin/main' into upload

This commit is contained in:
Junhui Chen 2025-07-17 20:21:30 +08:00
commit 0c96cc15d1
15 changed files with 175 additions and 6 deletions

1
.env Normal file
View File

@ -0,0 +1 @@
API_ENDPOINT=http://192.168.31.115:18080/api

1
.env.production Normal file
View File

@ -0,0 +1 @@
API_ENDPOINT=https://api.memorywake.com/api

View File

@ -0,0 +1,36 @@
name: Prod Deploy
run-name: ${{ gitea.actor }} is testing out Gitea Actions 🚀
on:
push:
tags:
- 'releases/*'
jobs:
Explore-Gitea-Actions:
runs-on: self_hosted
steps:
- run: echo "🎉 The job was automatically triggered by a ${{ gitea.event_name }} event."
- run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by Gitea!"
- run: echo "🔎 The name of your branch is ${{ gitea.ref }} and your repository is ${{ gitea.repository }}."
- name: Check out repository code
uses: https://git.fairclip.cn/mirrors/actions-checkout@v4
- run: echo "💡 The ${{ gitea.repository }} repository has been cloned to the runner."
- run: echo "🖥️ The workflow is now ready to test your code on the runner."
- name: List files in the repository
run: |
ls ${{ gitea.workspace }}
- name: Build Docker Image
run: |
echo "Building the Docker image..."
tag_name=${{ gitea.ref_name }}
tag_name=$(echo "${{ gitea.ref_name }}" | tr '/' '-')
docker build -t hub.fairclip.cn/memowake/memowake-front:${tag_name} -f dockerfiles/prod.Dockerfile .
docker push hub.fairclip.cn/memowake/memowake-front:${tag_name}
echo "Docker image built successfully!"
- name: Deploy
run: |
echo "Deploying the project..."
tag_name=${{ gitea.ref_name }}
tag_name=$(echo "${{ gitea.ref_name }}" | tr '/' '-')
bash ./scripts/prod_deploy.sh ${tag_name}
echo "Deploy successful!"

7
app.config.js Normal file
View File

@ -0,0 +1,7 @@
// app.config.js
export default ({ config }) => ({
...config,
extra: {
API_ENDPOINT: process.env.API_ENDPOINT || "http://192.168.31.115:18080/api"
}
});

63
app/(tabs)/download.tsx Normal file
View File

@ -0,0 +1,63 @@
import AndroidLogo from '@/assets/icons/svg/android.svg';
import AppleLogo from '@/assets/icons/svg/apple.svg';
import MemoIP from '@/assets/icons/svg/memo-ip.svg';
import { LinearGradient } from 'expo-linear-gradient';
import { useTranslation } from 'react-i18next';
import { Linking, Text, TouchableOpacity, View } from 'react-native';
const IOS_APP_STORE_URL = 'https://apps.apple.com/cn/app/id6748205761';
const ANDROID_APK_URL = 'https://cdn.memorywake.com/apks/application-f086a38c-dac1-43f1-9d24-e4378c2ce121.apk';
export default function DownloadScreen() {
const handleIOSDownload = () => {
Linking.openURL(IOS_APP_STORE_URL);
};
const handleAndroidDownload = () => {
Linking.openURL(ANDROID_APK_URL);
};
const { t } = useTranslation();
return (
<LinearGradient
colors={['#FFB645', '#E2793F']}
className="flex-1 items-center justify-center p-6"
>
<View className="absolute top-0 left-0 w-full h-full">
<MemoIP width="100%" height="100%" style={{ opacity: 0.1 }} />
</View>
<View className="items-center mb-12">
<Text className="text-white text-5xl font-extrabold tracking-tight">
MemoWake
</Text>
<Text className="text-white/90 text-lg mt-4 text-center max-w-xs">
{t('desc', { ns: 'download' })}
</Text>
</View>
<View className="w-full max-w-xs">
<TouchableOpacity
className="bg-white/90 rounded-xl px-6 py-4 flex-row items-center justify-center shadow-lg mb-5"
onPress={handleIOSDownload}
activeOpacity={0.8}
>
<AppleLogo width={24} height={24} fill="black" />
<Text className="text-black font-bold text-lg ml-3">
{t('ios', { ns: 'download' })}
</Text>
</TouchableOpacity>
<TouchableOpacity
className="bg-black/80 rounded-xl px-6 py-4 flex-row items-center justify-center shadow-lg"
onPress={handleAndroidDownload}
activeOpacity={0.8}
>
<AndroidLogo width={24} height={24} fill="#3DDC84" />
<Text className="text-white font-bold text-lg ml-3">
{t('android', { ns: 'download' })}
</Text>
</TouchableOpacity>
</View>
</LinearGradient>
);
}

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-android2" viewBox="0 0 16 16"> <path d="M11.358 1.342a.5.5 0 0 1 .478.67l-.632 1.9a.5.5 0 0 1-.952.142l.63-1.9a.5.5 0 0 1 .476-.312m-6.716 0a.5.5 0 0 1 .478.312l.63 1.9a.5.5 0 0 1-.952-.142l-.63-1.9a.5.5 0 0 1 .476-.67M7.48 10.152a.5.5 0 0 1 .96 0l.175.525a.5.5 0 0 1-.96.002zm-2.225 1.015a.5.5 0 1 1 .866-.5l.176.524a.5.5 0 1 1-.866.5l-.176-.524zm4.45 0a.5.5 0 1 1 .866.5l-.176-.524a.5.5 0 1 1-.866-.5l.176.524z"/> <path d="M14 4.478a1.5 1.5 0 0 0-1.5-1.5h-9A1.5 1.5 0 0 0 2 4.478V13.5a1.5 1.5 0 0 0 1.5 1.5h9a1.5 1.5 0 0 0 1.5-1.5zM3.5 13V6h9v7z"/> </svg>

After

Width:  |  Height:  |  Size: 653 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-apple" viewBox="0 0 16 16"> <path d="M11.182.008C11.148-.03 9.923.023 8.857 1.18c-1.066 1.156-.902 2.482-.878 2.516s1.52.087 2.475-1.258.762-2.391.728-2.43m3.314 11.733c-.048-.096-2.325-1.234-2.113-3.422s1.675-2.789 1.698-2.854-.597-.79-1.254-1.157a3.7 3.7 0 0 0-1.563-.434c-.108-.003-.483-.095-1.254.116-.508.139-1.653.589-1.968.607-.316.018-1.256-.522-2.267-.665-.647-.125-1.333.131-1.824.328-.49.196-1.422.754-2.074 2.237-.652 1.482-.311 3.83-.067 4.56s.625 1.924 1.273 2.796c.576.984 1.34 1.667 1.659 1.899s1.219.386 1.843.067c.502-.308 1.408-.485 1.766-.472.357.013 1.061.154 1.782.539.571.197 1.111.115 1.652-.105.541-.221 1.324-1.059 2.238-2.758q.52-1.185.473-1.282"/> <path d="M11.182.008C11.148-.03 9.923.023 8.857 1.18c-1.066 1.156-.902 2.482-.878 2.516s1.52.087 2.475-1.258.762-2.391.728-2.43m3.314 11.733c-.048-.096-2.325-1.234-2.113-3.422s1.675-2.789 1.698-2.854-.597-.79-1.254-1.157a3.7 3.7 0 0 0-1.563-.434c-.108-.003-.483-.095-1.254.116-.508.139-1.653.589-1.968.607-.316.018-1.256-.522-2.267-.665-.647-.125-1.333.131-1.824.328-.49.196-1.422.754-2.074 2.237-.652 1.482-.311 3.83-.067 4.56s.625 1.924 1.273 2.796c.576.984 1.34 1.667 1.659 1.899s1.219.386 1.843.067c.502-.308 1.408-.485 1.766-.472.357.013 1.061.154 1.782.539.571.197 1.111.115 1.652-.105.541-.221 1.324-1.059 2.238-2.758q.52-1.185.473-1.282"/> </svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,18 @@
# 第一阶段:构建 Expo Web 静态文件
FROM docker.fairclip.cn/node:22 AS builder
WORKDIR /app
COPY package.json .
# 设置npm源
RUN npm config set registry http://192.168.31.115:8081/repository/npm/
RUN npm install -g expo-cli && npm install
COPY . .
RUN cp .env.production .env
ENV API_ENDPOINT=https://api.memorywake.com/api
RUN npx expo export -p web
# 第二阶段:使用 nginx 作为 Web 服务器
FROM docker.fairclip.cn/nginx:1.29-alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

View File

@ -17,7 +17,7 @@ i18n
resources: translations,
// 支持命名空间
ns: ['common', 'example'],
ns: ['common', 'example', 'download'],
defaultNS: 'common',
// 设置默认语言为中文

View File

@ -0,0 +1,6 @@
{
"title": "Download Our App",
"desc": "Get the full experience by downloading our app on your favorite platform.",
"ios": "Download for iOS",
"android": "Download for Android"
}

View File

@ -0,0 +1,6 @@
{
"title": "下载我们的应用",
"desc": "在您喜欢的平台上下载我们的应用,以获得完整的体验。",
"ios": "下载 iOS 版",
"android": "下载 Android 版"
}

View File

@ -3,6 +3,7 @@
import enAdmin from './locales/en/admin.json';
import enAsk from './locales/en/ask.json';
import enCommon from './locales/en/common.json';
import enDownload from './locales/en/download.json';
import enExample from './locales/en/example.json';
import enFairclip from './locales/en/fairclip.json';
import enLanding from './locales/en/landing.json';
@ -12,6 +13,7 @@ import enUpload from './locales/en/upload.json';
import zhAdmin from './locales/zh/admin.json';
import zhAsk from './locales/zh/ask.json';
import zhCommon from './locales/zh/common.json';
import zhDownload from './locales/zh/download.json';
import zhExample from './locales/zh/example.json';
import zhFairclip from './locales/zh/fairclip.json';
import zhLanding from './locales/zh/landing.json';
@ -22,25 +24,27 @@ import zhUpload from './locales/zh/upload.json';
const translations = {
en: {
admin: enAdmin,
ask: enAsk,
common: enCommon,
download: enDownload,
example: enExample,
fairclip: enFairclip,
landing: enLanding,
login: enLogin,
personal: enPersonal,
upload: enUpload,
ask: enAsk
upload: enUpload
},
zh: {
admin: zhAdmin,
ask: zhAsk,
common: zhCommon,
download: zhDownload,
example: zhExample,
fairclip: zhFairclip,
landing: zhLanding,
login: zhLogin,
personal: zhPersonal,
upload: zhUpload,
ask: zhAsk
upload: zhUpload
},
};

View File

@ -1,4 +1,5 @@
import { setCredentials } from '@/features/auth/authSlice';
import Constants from 'expo-constants';
import * as SecureStore from 'expo-secure-store';
import { Platform } from 'react-native';
import Toast from 'react-native-toast-message';
@ -23,7 +24,8 @@ export interface PagedResult<T> {
}
// 获取.env文件中的变量
export const API_ENDPOINT = "http://192.168.31.115:18080/api"
export const API_ENDPOINT = Constants.expoConfig?.extra?.API_ENDPOINT || "http://192.168.31.115:18080/api";
// 更新 access_token 的逻辑 - 用于React组件中
export const useAuthToken = async<T>(message: string | null) => {

11
package-lock.json generated
View File

@ -8889,6 +8889,17 @@
"react": "*"
}
},
"node_modules/expo-linear-gradient": {
"version": "14.1.5",
"resolved": "http://192.168.31.115:8081/repository/npm/expo-linear-gradient/-/expo-linear-gradient-14.1.5.tgz",
"integrity": "sha512-BSN3MkSGLZoHMduEnAgfhoj3xqcDWaoICgIr4cIYEx1GcHfKMhzA/O4mpZJ/WC27BP1rnAqoKfbclk1eA70ndQ==",
"license": "MIT",
"peerDependencies": {
"expo": "*",
"react": "*",
"react-native": "*"
}
},
"node_modules/expo-linking": {
"version": "7.1.7",
"resolved": "https://registry.npmjs.org/expo-linking/-/expo-linking-7.1.7.tgz",

12
scripts/prod_deploy.sh Normal file
View File

@ -0,0 +1,12 @@
#!/bin/bash
set -x
TAG=${1:-latest}
CONTROLPANEL_HOST="101.132.185.243"
CONTROLPANEL_USER="ecs-user"
CONTROLPANEL_SSH_KEY="~/.ssh/id_ed25519"
# SSH到CONTROLPANEL_HOST执行以下命令
# helm install memowake-front . -n memowake
ssh ${CONTROLPANEL_USER}@${CONTROLPANEL_HOST} "cd /home/ecs-user/infra-deploy/memowake-front && helm upgrade memowake-front . -n memowake --set image.tag=${TAG}"