From af708b904357fa775ce4029f1d282a608b557d4a Mon Sep 17 00:00:00 2001 From: littletry Date: Mon, 21 Apr 2025 00:09:42 +0800 Subject: [PATCH] refactor code --- .eslintrc.json | 7 +- .gitignore | 6 ++ package.json | 8 +- .../{8_search_log.sql => 7_search_log.sql} | 0 sql/tables/7_works_translate_task.sql | 25 ------ ...sitive_words.sql => 8_sensitive_words.sql} | 0 .../[locale]/api/cron/workTranslate/route.ts | 78 ------------------- src/app/[locale]/api/generate/handle/route.ts | 60 +++++++------- src/app/[locale]/layout.tsx | 58 +++++++------- src/app/[locale]/my/page.tsx | 8 +- src/app/[locale]/page.tsx | 10 +-- src/app/[locale]/pricing/page.tsx | 6 +- src/app/[locale]/privacy-policy/page.tsx | 8 +- src/app/[locale]/search/page.tsx | 14 ++-- src/app/[locale]/sticker/[uid]/page.tsx | 12 +-- src/app/[locale]/stickers/[page]/page.tsx | 14 ++-- src/app/[locale]/stickers/page.tsx | 12 +-- src/app/[locale]/terms-of-service/page.tsx | 8 +- src/components/HeadInfo.tsx | 18 ++--- src/components/Header.tsx | 70 ++++++++--------- src/config.ts | 34 -------- src/i18n.ts | 10 --- src/i18n/config.ts | 22 ++++++ src/{configs => i18n}/languageText.ts | 0 src/i18n/navigation.ts | 4 + src/i18n/request.ts | 17 ++++ src/i18n/routing.ts | 13 ++++ src/middleware.ts | 21 ++--- src/navigation.ts | 9 --- vercel.json | 8 -- 30 files changed, 231 insertions(+), 329 deletions(-) rename sql/tables/{8_search_log.sql => 7_search_log.sql} (100%) delete mode 100644 sql/tables/7_works_translate_task.sql rename sql/tables/{9_sensitive_words.sql => 8_sensitive_words.sql} (100%) delete mode 100644 src/app/[locale]/api/cron/workTranslate/route.ts delete mode 100644 src/config.ts delete mode 100755 src/i18n.ts create mode 100644 src/i18n/config.ts rename src/{configs => i18n}/languageText.ts (100%) create mode 100644 src/i18n/navigation.ts create mode 100644 src/i18n/request.ts create mode 100644 src/i18n/routing.ts delete mode 100644 src/navigation.ts delete mode 100644 vercel.json diff --git a/.eslintrc.json b/.eslintrc.json index bffb357..03925c7 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,3 +1,8 @@ { - "extends": "next/core-web-vitals" + "extends": "next/core-web-vitals", + "rules": { + "@next/next/no-img-element": "off", + "react-hooks/exhaustive-deps": "off", + "@next/next/no-html-link-for-pages": "off" + } } diff --git a/.gitignore b/.gitignore index fd3dbb5..185fc45 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,9 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts + +.idea +.vscode +yarn.lock +pnpm-lock.yaml +package-lock.json diff --git a/package.json b/package.json index 768bfc4..5d2d4dc 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "dependencies": { "@headlessui/react": "^1.7.18", "@heroicons/react": "^2.1.1", - "@next/third-parties": "^14.1.3", + "@next/third-parties": "^14.2.25", "@stripe/stripe-js": "^3.0.7", "@tailwindcss/typography": "^0.5.10", "ahooks": "^3.7.10", @@ -18,9 +18,9 @@ "clsx": "^2.1.0", "date-fns": "^3.3.1", "google-auth-library": "^9.6.3", - "next": "14.1.3", + "next": "14.2.25", "next-auth": "^4.24.6", - "next-intl": "^3.9.2", + "next-intl": "^3.26.0", "pg": "^8.11.3", "react": "^18", "react-dom": "^18", @@ -36,7 +36,7 @@ "@types/react-dom": "^18", "autoprefixer": "^10.0.1", "eslint": "^8", - "eslint-config-next": "14.1.3", + "eslint-config-next": "14.2.25", "postcss": "^8", "tailwindcss": "^3.3.0", "typescript": "^5" diff --git a/sql/tables/8_search_log.sql b/sql/tables/7_search_log.sql similarity index 100% rename from sql/tables/8_search_log.sql rename to sql/tables/7_search_log.sql diff --git a/sql/tables/7_works_translate_task.sql b/sql/tables/7_works_translate_task.sql deleted file mode 100644 index d601d43..0000000 --- a/sql/tables/7_works_translate_task.sql +++ /dev/null @@ -1,25 +0,0 @@ --- auto-generated definition -create table works_translate_task -( - id bigint generated by default as identity - primary key, - created_at timestamp with time zone default now() not null, - updated_at timestamp with time zone default now() not null, - uid varchar, - origin_language varchar, - status varchar -); - -comment on table works_translate_task is 'works_translate_task'; - -comment on column works_translate_task.id is '自增id'; - -comment on column works_translate_task.created_at is '创建时间'; - -comment on column works_translate_task.updated_at is '更新时间'; - -comment on column works_translate_task.uid is 'uid'; - -comment on column works_translate_task.origin_language is 'origin_language'; - -comment on column works_translate_task.status is 'status: 0未翻译,1已翻译'; diff --git a/sql/tables/9_sensitive_words.sql b/sql/tables/8_sensitive_words.sql similarity index 100% rename from sql/tables/9_sensitive_words.sql rename to sql/tables/8_sensitive_words.sql diff --git a/src/app/[locale]/api/cron/workTranslate/route.ts b/src/app/[locale]/api/cron/workTranslate/route.ts deleted file mode 100644 index 9763cc9..0000000 --- a/src/app/[locale]/api/cron/workTranslate/route.ts +++ /dev/null @@ -1,78 +0,0 @@ -import {getDb} from "~/libs/db"; -import {locales} from "~/config"; -import {translateContent} from "~/servers/translate"; - -export const maxDuration = 300; - -export async function GET() { - const db = getDb(); - const timeFlag = 'workTranslate' + '-=->' + new Date().getTime(); - console.time(timeFlag); - const results = await db.query('select * from works_translate_task where status=$1 order by created_at asc limit 3', [0]); - const rows = results.rows; - if (rows.length <= 0) { - console.log('没有任务需要处理'); - console.timeEnd(timeFlag); - return Response.json({message: '没有任务需要处理'}); - } - for (let i = 0; i < rows.length; i++) { - const oneTask = rows[i]; - // 翻译为除了原始语言的其他语言,如果原始语言不在支持列表,就翻译为支持的十种语言 - const origin_language = oneTask.origin_language; - const uid = oneTask.uid; - - const needLanguage = getNeedTranslateLanguage(origin_language); - - if (needLanguage.length <= 0) { - // 更新状态为已翻译完成 - await db.query('update works_translate_task set status=$1 where uid=$2', [1, uid]); - console.log('没有需要翻译的语言-=->', uid); - console.timeEnd(timeFlag); - return Response.json({message: '没有需要翻译的语言'}); - } - - // 查出原始数据 - const resultsOrigin = await db.query('select * from works where uid=$1 and is_origin=$2 and is_delete=$3', [uid, true, false]); - const rowsOrigin = resultsOrigin.rows; - if (rowsOrigin.length <= 0) { - console.log('没有原始数据-=->', uid); - console.timeEnd(timeFlag); - // 更新状态为已翻译完成 - await db.query('update works_translate_task set status=$1 where uid=$2', [1, uid]); - return Response.json({message: '没有原始数据'}); - } - const originData = rowsOrigin[0]; - if (originData.output_url == '') { - // 如果原始数据的url还没生成,就不翻译了 - console.log('原始数据的url还没生成-=->', uid); - console.timeEnd(timeFlag); - return Response.json({message: '原始数据的url还没生成'}); - } - const timeFlagCurrent = '翻译' + '-=->' + uid; - console.time(timeFlagCurrent); - for (let i = 0; i < needLanguage.length; i++) { - const toLanguage = needLanguage[i]; - const translateText = await translateContent(originData.input_text, toLanguage); - const sqlStr = 'insert into works(uid, input_text, output_url, is_public, status, user_id, revised_text, is_origin, origin_language, current_language) values ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10)'; - const data = [uid, translateText, originData.output_url, originData.is_public, originData.status, originData.user_id, originData.revised_text, false, originData.origin_language, toLanguage]; - await db.query(sqlStr, data); - } - console.timeEnd(timeFlagCurrent); - console.log('翻译完-=->', uid); - // 更新状态为已翻译完成 - await db.query('update works_translate_task set status=$1 where uid=$2', [1, uid]); - } - console.timeEnd(timeFlag); - return Response.json({message: '本次翻译任务翻译完'}); -} - -function getNeedTranslateLanguage(origin_language: string) { - const needTranslateLanguage = []; - // 判断出需要翻译的语言,并调用翻译 - for (let i = 0; i < locales.length; i++) { - if (origin_language != locales[i]) { - needTranslateLanguage.push(locales[i]); - } - } - return needTranslateLanguage; -} diff --git a/src/app/[locale]/api/generate/handle/route.ts b/src/app/[locale]/api/generate/handle/route.ts index 27cbd60..644f398 100644 --- a/src/app/[locale]/api/generate/handle/route.ts +++ b/src/app/[locale]/api/generate/handle/route.ts @@ -1,13 +1,12 @@ -import {getUserById} from "~/servers/user"; -import {checkUserTimes, countDownUserTimes} from "~/servers/manageUserTimes"; -import {v4 as uuidv4} from 'uuid'; -import {getReplicateClient} from "~/libs/replicateClient"; -import {getInput} from "~/libs/replicate"; -import {getDb} from "~/libs/db"; -import {getLanguage} from "~/servers/language"; -import {checkSubscribe} from "~/servers/subscribe"; -import {checkSensitiveInputText} from "~/servers/checkInput"; - +import { getUserById } from "~/servers/user"; +import { checkUserTimes, countDownUserTimes } from "~/servers/manageUserTimes"; +import { v4 as uuidv4 } from "uuid"; +import { getReplicateClient } from "~/libs/replicateClient"; +import { getInput } from "~/libs/replicate"; +import { getDb } from "~/libs/db"; +import { getLanguage } from "~/servers/language"; +import { checkSubscribe } from "~/servers/subscribe"; +import { checkSensitiveInputText } from "~/servers/checkInput"; export async function POST(req: Request, res: Response) { let json = await req.json(); @@ -15,14 +14,14 @@ export async function POST(req: Request, res: Response) { let user_id = json.user_id; let is_public = json.is_public; - if (!user_id && process.env.NEXT_PUBLIC_CHECK_GOOGLE_LOGIN != '0') { - return Response.json({msg: "Login to continue.", status: 601}); + if (!user_id && process.env.NEXT_PUBLIC_CHECK_GOOGLE_LOGIN != "0") { + return Response.json({ msg: "Login to continue.", status: 601 }); } // 检查用户在数据库是否存在,不存在则返回需登录 const resultsUser = await getUserById(user_id); - if (resultsUser.email == '' && process.env.NEXT_PUBLIC_CHECK_GOOGLE_LOGIN != '0') { - return Response.json({msg: "Login to continue.", status: 601}); + if (resultsUser.email == "" && process.env.NEXT_PUBLIC_CHECK_GOOGLE_LOGIN != "0") { + return Response.json({ msg: "Login to continue.", status: 601 }); } const checkSubscribeStatus = await checkSubscribe(user_id); @@ -30,14 +29,14 @@ export async function POST(req: Request, res: Response) { if (!is_public) { // 判断用户是否订阅状态,否则返回错误 if (!checkSubscribeStatus) { - return Response.json({msg: "Pricing to continue.", status: 602}); + return Response.json({ msg: "Pricing to continue.", status: 602 }); } } if (!checkSubscribeStatus) { const check = await checkUserTimes(user_id); - if (!check && process.env.NEXT_PUBLIC_CHECK_AVAILABLE_TIME != '0') { - return Response.json({msg: "Pricing to continue.", status: 602}); + if (!check && process.env.NEXT_PUBLIC_CHECK_AVAILABLE_TIME != "0") { + return Response.json({ msg: "Pricing to continue.", status: 602 }); } } @@ -46,7 +45,7 @@ export async function POST(req: Request, res: Response) { // 敏感词没通过,校验是否订阅 if (!checkSubscribeStatus) { // 未订阅则返回付费再继续 - return Response.json({msg: "Pricing to continue.", status: 602}); + return Response.json({ msg: "Pricing to continue.", status: 602 }); } else { // 订阅强制设置其为用户私有,不公开 is_public = false; @@ -63,23 +62,30 @@ export async function POST(req: Request, res: Response) { input: input, webhook: `${process.env.REPLICATE_WEBHOOK}/api/generate/callByReplicate?uid=${uid}`, webhook_events_filter: ["completed"], - }) + }); const db = getDb(); // 创建新的数据 - await db.query('insert into works(uid, input_text, output_url, is_public, status, user_id, revised_text, is_origin, origin_language, current_language) values ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10)', - [uid, textStr, '', is_public, 0, user_id, input.prompt, true, origin_language, origin_language]); - // 创建一条翻译任务 - await db.query('insert into works_translate_task(uid,origin_language,status) values($1,$2,$3)', [uid, origin_language, 0]); - + await db.query("insert into works(uid, input_text, output_url, is_public, status, user_id, revised_text, is_origin, origin_language, current_language) values ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10)", [ + uid, + textStr, + "", + is_public, + 0, + user_id, + input.prompt, + true, + origin_language, + origin_language, + ]); // 需要登录,且需要支付时,才操作该项 - if (process.env.NEXT_PUBLIC_CHECK_GOOGLE_LOGIN != '0' && process.env.NEXT_PUBLIC_CHECK_AVAILABLE_TIME != '0' && !checkSubscribeStatus) { + if (process.env.NEXT_PUBLIC_CHECK_GOOGLE_LOGIN != "0" && process.env.NEXT_PUBLIC_CHECK_AVAILABLE_TIME != "0" && !checkSubscribeStatus) { // 减少用户次数 await countDownUserTimes(user_id); } const resultInfo = { - uid: uid - } + uid: uid, + }; return Response.json(resultInfo); } diff --git a/src/app/[locale]/layout.tsx b/src/app/[locale]/layout.tsx index 230db3e..6b6654a 100644 --- a/src/app/[locale]/layout.tsx +++ b/src/app/[locale]/layout.tsx @@ -1,14 +1,14 @@ import clsx from 'clsx'; -import {Inter} from 'next/font/google'; -import {notFound} from 'next/navigation'; -import {unstable_setRequestLocale} from 'next-intl/server'; -import {ReactNode} from 'react'; -import {locales} from '~/config'; -import {CommonProvider} from '~/context/common-context'; -import {NextAuthProvider} from '~/context/next-auth-context'; -import {getAuthText, getCommonText, getMenuText, getPricingText} from "~/configs/languageText"; +import { Inter } from 'next/font/google'; +import { notFound } from 'next/navigation'; +import { setRequestLocale } from 'next-intl/server'; +import { ReactNode } from 'react'; +import { locales } from '~/i18n/config'; +import { CommonProvider } from '~/context/common-context'; +import { NextAuthProvider } from '~/context/next-auth-context'; +import { getAuthText, getCommonText, getMenuText, getPricingText } from "~/i18n/languageText"; -const inter = Inter({subsets: ['latin']}); +const inter = Inter({ subsets: ['latin'] }); type Props = { children: ReactNode; @@ -16,19 +16,19 @@ type Props = { }; export function generateStaticParams() { - return locales.map((locale) => ({locale})); + return locales.map((locale) => ({ locale })); } export default async function LocaleLayout({ - children, - params: {locale} - }: Props) { + children, + params: { locale } +}: Props) { // Validate that the incoming `locale` parameter is valid if (!locales.includes(locale as any)) notFound(); // Enable static rendering - unstable_setRequestLocale(locale); + setRequestLocale(locale); const commonText = await getCommonText(); const authText = await getAuthText(); @@ -37,21 +37,21 @@ export default async function LocaleLayout({ return ( - - - - - - - {children} - - - + + + + + + + {children} + + + ); } diff --git a/src/app/[locale]/my/page.tsx b/src/app/[locale]/my/page.tsx index 33eb58b..fe60753 100644 --- a/src/app/[locale]/my/page.tsx +++ b/src/app/[locale]/my/page.tsx @@ -1,13 +1,13 @@ import PageComponent from "./PageComponent"; -import {unstable_setRequestLocale} from 'next-intl/server'; +import { setRequestLocale } from 'next-intl/server'; import { getWorksText -} from "~/configs/languageText"; +} from "~/i18n/languageText"; -export default async function IndexPage({params: {locale = ''}}) { +export default async function IndexPage({ params: { locale = '' } }) { // Enable static rendering - unstable_setRequestLocale(locale); + setRequestLocale(locale); const worksText = await getWorksText(); diff --git a/src/app/[locale]/page.tsx b/src/app/[locale]/page.tsx index 2de2f4d..7bfb84d 100644 --- a/src/app/[locale]/page.tsx +++ b/src/app/[locale]/page.tsx @@ -1,16 +1,16 @@ import PageComponent from "./PageComponent"; -import {unstable_setRequestLocale} from 'next-intl/server'; +import { setRequestLocale } from 'next-intl/server'; import { getIndexPageText, getQuestionText -} from "~/configs/languageText"; -import {getLatestPublicResultList} from "~/servers/works"; +} from "~/i18n/languageText"; +import { getLatestPublicResultList } from "~/servers/works"; export const revalidate = 120; -export default async function IndexPage({params: {locale = ''}, searchParams: searchParams}) { +export default async function IndexPage({ params: { locale = '' }, searchParams: searchParams }) { // Enable static rendering - unstable_setRequestLocale(locale); + setRequestLocale(locale); const indexText = await getIndexPageText(); const questionText = await getQuestionText(); diff --git a/src/app/[locale]/pricing/page.tsx b/src/app/[locale]/pricing/page.tsx index 1225b48..baf6c9e 100644 --- a/src/app/[locale]/pricing/page.tsx +++ b/src/app/[locale]/pricing/page.tsx @@ -1,9 +1,9 @@ import PageComponent from "./PageComponent"; -import {unstable_setRequestLocale} from 'next-intl/server'; +import { setRequestLocale } from 'next-intl/server'; -export default async function IndexPage({params: {locale = ''}}) { +export default async function IndexPage({ params: { locale = '' } }) { // Enable static rendering - unstable_setRequestLocale(locale); + setRequestLocale(locale); return ( { + locale, + page, + title, + description, +}) => { return ( <> {title} - + { languages.map((item) => { const currentPage = page; @@ -29,7 +29,7 @@ const HeadInfo = ({ href = `${process.env.NEXT_PUBLIC_SITE_URL}/`; } } - return + return }) } { @@ -49,7 +49,7 @@ const HeadInfo = ({ } } if (locale == item.lang) { - return + return } }) } diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 913d64b..a2336dc 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -1,25 +1,25 @@ 'use client' -import {useState} from 'react' -import {Dialog} from '@headlessui/react' -import {Bars3Icon, XMarkIcon} from '@heroicons/react/24/outline' -import {GlobeAltIcon} from '@heroicons/react/24/outline' -import {Fragment} from 'react' -import {Menu, Transition} from '@headlessui/react' -import {ChevronDownIcon} from '@heroicons/react/20/solid' +import { useState } from 'react' +import { Dialog } from '@headlessui/react' +import { Bars3Icon, XMarkIcon } from '@heroicons/react/24/outline' +import { GlobeAltIcon } from '@heroicons/react/24/outline' +import { Fragment } from 'react' +import { Menu, Transition } from '@headlessui/react' +import { ChevronDownIcon } from '@heroicons/react/20/solid' import Link from "next/link"; -import {languages} from "~/config"; -import {useCommonContext} from '~/context/common-context' +import { languages } from "~/i18n/config"; +import { useCommonContext } from '~/context/common-context' import LoadingModal from "./LoadingModal"; import GeneratingModal from "~/components/GeneratingModal"; import LoginButton from './LoginButton'; import LoginModal from './LoginModal'; import LogoutModal from "./LogoutModal"; -import {getLinkHref} from "~/configs/buildLink"; +import { getLinkHref } from "~/configs/buildLink"; export default function Header({ - locale, - page - }) { + locale, + page +}) { const [mobileMenuOpen, setMobileMenuOpen] = useState(false) const { setShowLoadingModal, @@ -47,8 +47,8 @@ export default function Header({ return (
- - + + setMobileMenuOpen(true)} > Open main menu -