You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

706 lines
33 KiB

  1. <template>
  2. <div class="overflow-hidden">
  3. <!-- ==================== 1. Hero ==================== -->
  4. <section class="relative border-b border-[var(--c-e8eef7)] bg-gradient-to-br from-[var(--c-ffffff)] via-[var(--c-eef6ff)] to-[var(--c-f3fbf9)]">
  5. <div class="pointer-events-none absolute -right-32 -top-40 size-[420px] rounded-full bg-[var(--c-0b8cff)]/10 blur-3xl" />
  6. <div class="pointer-events-none absolute -bottom-40 -left-24 size-[360px] rounded-full bg-[var(--c-20d3a2)]/10 blur-3xl" />
  7. <div class="relative mx-auto max-w-7xl px-4 py-16 sm:px-6 lg:px-8 lg:py-24">
  8. <div class="grid items-center gap-12 lg:grid-cols-2 lg:gap-16">
  9. <!-- 左:文案 -->
  10. <div>
  11. <span class="inline-flex items-center gap-1.5 rounded-full bg-[var(--c-ffffff)] px-3.5 py-1.5 text-xs font-extrabold text-[var(--c-0b8cff)] shadow-[0_4px_14px_var(--sh-11-140-255-120)]">
  12. <UIcon name="i-lucide-sparkles" class="size-3.5" />
  13. 一站式 AI 创作平台
  14. </span>
  15. <h1 class="mt-5 text-4xl font-extrabold leading-[1.15] tracking-tight text-[var(--c-172033)] sm:text-5xl lg:text-[56px]">
  16. 解放你的<br>
  17. <span class="bg-gradient-to-r from-[var(--c-0b8cff)] via-[var(--c-3aa9ff)] to-[var(--c-20d3a2)] bg-clip-text text-transparent">生产力</span>
  18. </h1>
  19. <p class="mt-5 max-w-xl text-base leading-relaxed text-[var(--c-66758a)] sm:text-lg">
  20. AI 取名、动漫头像、证件照、AI 绘画……把重复又费时的创作交给 AI,
  21. 几秒钟拿到可直接用的结果。按点数计费,多端通用。
  22. </p>
  23. <div class="mt-8 flex flex-col gap-3 sm:flex-row sm:items-center">
  24. <NuxtLink
  25. to="/writing/naming/"
  26. class="inline-flex h-13 items-center justify-center gap-2 rounded-full bg-gradient-to-r from-[var(--c-0b8cff)] to-[var(--c-3aa9ff)] px-8 text-base font-bold text-white shadow-[0_14px_30px_var(--sh-11-140-255-280)] transition-all hover:-translate-y-0.5 hover:shadow-[0_18px_36px_var(--sh-11-140-255-360)]"
  27. >
  28. <UIcon name="i-lucide-zap" class="size-5" />
  29. 免费开始创作
  30. </NuxtLink>
  31. <a
  32. href="#tools"
  33. class="inline-flex h-13 items-center justify-center gap-2 rounded-full bg-[var(--c-ffffff)] px-8 text-base font-bold text-[var(--c-172033)] shadow-[0_8px_20px_var(--sh-23-32-51-60)] transition-colors hover:bg-[var(--c-f7faff)]"
  34. >
  35. 查看全部工具
  36. <UIcon name="i-lucide-arrow-down" class="size-4" />
  37. </a>
  38. </div>
  39. </div>
  40. <!-- 右:动漫头像示例(原图 / 生成图 对照) -->
  41. <div class="relative mx-auto w-full max-w-lg lg:max-w-none">
  42. <div class="grid grid-cols-2 gap-4 sm:gap-5">
  43. <!-- 原图 -->
  44. <figure class="group relative overflow-hidden rounded-3xl bg-[var(--c-e7eef8)] shadow-[0_18px_44px_var(--sh-23-58-110-120)]">
  45. <img
  46. :src="demo.original"
  47. alt="上传的原始照片示例"
  48. class="aspect-[3/4] w-full object-cover"
  49. loading="eager"
  50. >
  51. <figcaption class="absolute left-3 top-3 rounded-full bg-[var(--c-0f172a)]/55 px-2.5 py-1 text-[11px] font-bold text-white backdrop-blur">
  52. 原图
  53. </figcaption>
  54. </figure>
  55. <!-- 生成图 -->
  56. <figure class="group relative overflow-hidden rounded-3xl bg-[var(--c-e7eef8)] shadow-[0_24px_54px_var(--sh-11-140-255-220)] ring-2 ring-[var(--c-0b8cff)] sm:translate-y-6">
  57. <img
  58. :src="demo.anime"
  59. alt="AI 生成的动漫头像示例"
  60. class="aspect-[3/4] w-full object-cover"
  61. loading="eager"
  62. >
  63. <figcaption class="absolute left-3 top-3 rounded-full bg-[var(--c-0b8cff)] px-2.5 py-1 text-[11px] font-bold text-white">
  64. AI 动漫头像
  65. </figcaption>
  66. </figure>
  67. </div>
  68. <!-- 浮标 -->
  69. <div class="absolute -top-4 right-2 flex items-center gap-1.5 rounded-full bg-[var(--c-ffffff)] px-3.5 py-2 shadow-[0_10px_24px_var(--sh-23-58-110-160)]">
  70. <UIcon name="i-lucide-sparkles" class="size-4 text-[var(--c-ff8a00)]" />
  71. <span class="text-xs font-extrabold text-[var(--c-172033)]">10 秒出图</span>
  72. </div>
  73. </div>
  74. </div>
  75. </div>
  76. </section>
  77. <!-- ==================== 2. 工具(Services) ==================== -->
  78. <section id="tools" class="mx-auto max-w-7xl scroll-mt-20 px-4 py-16 sm:px-6 lg:px-8 lg:py-24">
  79. <div class="mx-auto max-w-2xl text-center">
  80. <span class="inline-flex items-center gap-1.5 rounded-full bg-[var(--c-eef7ff)] px-3 py-1 text-xs font-extrabold text-[var(--c-0b8cff)]">
  81. <UIcon name="i-lucide-layout-grid" class="size-3.5" />
  82. AI 工具箱
  83. </span>
  84. <h2 class="mt-4 text-3xl font-extrabold text-[var(--c-172033)] sm:text-4xl">开箱即用的 AI 能力</h2>
  85. <p class="mt-4 text-base leading-relaxed text-[var(--c-66758a)]">
  86. 不用学提示词、不用配环境,选好参数点一下就出结果。
  87. </p>
  88. </div>
  89. <div class="mt-12 grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
  90. <template v-for="tool in tools" :key="tool.title">
  91. <!-- 已上线:可点击卡片 -->
  92. <NuxtLink
  93. v-if="!tool.soon"
  94. :to="tool.to"
  95. class="group relative flex cursor-pointer flex-col overflow-hidden rounded-3xl border border-[var(--c-eef2f7)] bg-[var(--c-ffffff)] p-6 transition-all duration-300 hover:-translate-y-1 hover:border-[var(--c-0b8cff)]/30 hover:shadow-[0_20px_44px_var(--sh-23-58-110-120)]"
  96. >
  97. <span
  98. v-if="tool.hot"
  99. class="absolute right-5 top-5 rounded-full bg-[var(--c-fff4ec)] px-2.5 py-1 text-[10px] font-extrabold text-[var(--c-ff681f)]"
  100. >热门</span>
  101. <div
  102. class="flex size-14 items-center justify-center rounded-2xl transition-transform duration-300 group-hover:scale-105"
  103. :class="tool.iconBg"
  104. >
  105. <UIcon :name="tool.icon" class="size-7" :class="tool.iconColor" />
  106. </div>
  107. <h3 class="mt-5 text-lg font-extrabold text-[var(--c-172033)]">{{ tool.title }}</h3>
  108. <p class="mt-2 flex-1 text-sm leading-relaxed text-[var(--c-66758a)]">{{ tool.desc }}</p>
  109. <div class="mt-5 flex items-center justify-between border-t border-[var(--c-f1f5fa)] pt-4">
  110. <span class="text-sm font-extrabold text-[var(--c-0b8cff)]">{{ toolPrice(tool) }}</span>
  111. <span class="inline-flex items-center gap-1 text-sm font-bold text-[var(--c-172033)] transition-colors group-hover:text-[var(--c-0b8cff)]">
  112. 立即使用
  113. <UIcon name="i-lucide-arrow-right" class="size-4 transition-transform group-hover:translate-x-0.5" />
  114. </span>
  115. </div>
  116. </NuxtLink>
  117. <!-- 未上线:静态卡片 -->
  118. <div
  119. v-else
  120. class="relative flex cursor-default flex-col overflow-hidden rounded-3xl border border-[var(--c-eef2f7)] bg-[var(--c-ffffff)] p-6 opacity-70"
  121. >
  122. <span class="absolute right-5 top-5 rounded-full bg-[var(--c-f1f5fa)] px-2.5 py-1 text-[10px] font-bold text-[var(--c-8a97a8)]">
  123. 即将上线
  124. </span>
  125. <div class="flex size-14 items-center justify-center rounded-2xl" :class="tool.iconBg">
  126. <UIcon :name="tool.icon" class="size-7" :class="tool.iconColor" />
  127. </div>
  128. <h3 class="mt-5 text-lg font-extrabold text-[var(--c-172033)]">{{ tool.title }}</h3>
  129. <p class="mt-2 flex-1 text-sm leading-relaxed text-[var(--c-66758a)]">{{ tool.desc }}</p>
  130. <div class="mt-5 flex items-center justify-between border-t border-[var(--c-f1f5fa)] pt-4">
  131. <span class="text-sm font-extrabold text-[var(--c-0b8cff)]">{{ tool.price }}</span>
  132. <span class="text-sm text-[var(--c-a0aabb)]">敬请期待</span>
  133. </div>
  134. </div>
  135. </template>
  136. </div>
  137. </section>
  138. <!-- ==================== 4. 点数套餐(Pricing) ==================== -->
  139. <section id="pricing" class="mx-auto max-w-7xl scroll-mt-20 px-4 py-16 sm:px-6 lg:px-8 lg:py-24">
  140. <div class="mx-auto max-w-2xl text-center">
  141. <span class="inline-flex items-center gap-1.5 rounded-full bg-[var(--c-fff4ec)] px-3 py-1 text-xs font-extrabold text-[var(--c-ff681f)]">
  142. <UIcon name="i-lucide-coins" class="size-3.5" />
  143. 点数套餐
  144. </span>
  145. <h2 class="mt-4 text-3xl font-extrabold text-[var(--c-172033)] sm:text-4xl">按需付费,没有订阅</h2>
  146. <p class="mt-4 text-base text-[var(--c-66758a)]">点数长期有效,小程序、H5、PC 端共享同一份余额。</p>
  147. </div>
  148. <!-- 加载中骨架 -->
  149. <div v-if="pkgLoading" class="mx-auto mt-12 grid max-w-4xl gap-6 sm:grid-cols-3">
  150. <div v-for="i in 3" :key="i" class="h-[380px] animate-pulse rounded-3xl bg-[var(--c-eef2f7)]" />
  151. </div>
  152. <div v-else-if="packages.length" class="mx-auto mt-12 grid max-w-5xl items-start gap-6 sm:grid-cols-3">
  153. <div
  154. v-for="(pkg, idx) in packages"
  155. :key="pkg.id"
  156. class="relative rounded-3xl border-2 bg-[var(--c-ffffff)] p-7 transition-all duration-300"
  157. :class="isFeatured(pkg, idx)
  158. ? 'border-[var(--c-0b8cff)] shadow-[0_24px_50px_var(--sh-11-140-255-180)] sm:-mt-4 sm:pb-10'
  159. : 'border-[var(--c-eef2f7)] hover:border-[var(--c-0b8cff)]/30 hover:shadow-[0_16px_36px_var(--sh-23-58-110-100)]'"
  160. >
  161. <span
  162. v-if="isFeatured(pkg, idx)"
  163. class="absolute -top-3.5 left-1/2 -translate-x-1/2 whitespace-nowrap rounded-full bg-gradient-to-r from-[var(--c-0b8cff)] to-[var(--c-3aa9ff)] px-4 py-1.5 text-[11px] font-extrabold text-white shadow-[0_8px_18px_var(--sh-11-140-255-300)]"
  164. >
  165. {{ pkg.badge || '最受欢迎' }}
  166. </span>
  167. <div class="flex size-12 items-center justify-center rounded-2xl bg-[var(--c-eef7ff)]">
  168. <UIcon :name="pkgIcon(idx)" class="size-6 text-[var(--c-0b8cff)]" />
  169. </div>
  170. <h3 class="mt-4 text-lg font-extrabold text-[var(--c-172033)]">{{ pkg.title }}</h3>
  171. <p class="mt-1 text-xs text-[var(--c-8a97a8)]">{{ pkgSubtitle(pkg) }}</p>
  172. <div class="mt-5 flex items-end gap-1">
  173. <span class="text-4xl font-extrabold text-[var(--c-172033)]">¥{{ pkg.price_yuan }}</span>
  174. </div>
  175. <div v-if="pkg.old_price_yuan || pkgBonusPercent(pkg)" class="mt-1 flex min-h-5 items-center gap-2 text-xs">
  176. <span v-if="pkg.old_price_yuan" class="text-[var(--c-a0aabb)] line-through">¥{{ pkg.old_price_yuan }}</span>
  177. <span
  178. v-if="pkgBonusPercent(pkg)"
  179. class="rounded-full bg-[var(--c-edfdf4)] px-2 py-0.5 font-extrabold text-[var(--c-159a54)]"
  180. >
  181. 多送{{ pkgBonusPercent(pkg) }}%
  182. </span>
  183. </div>
  184. <ul class="mt-6 space-y-2.5">
  185. <li v-for="f in pkgFeatures(pkg)" :key="f" class="flex items-start gap-2 text-sm text-[var(--c-4b5b70)]">
  186. <UIcon name="i-lucide-check" class="mt-0.5 size-4 shrink-0 text-[var(--c-17a65a)]" />
  187. <span>{{ f }}</span>
  188. </li>
  189. </ul>
  190. <NuxtLink
  191. to="/recharge"
  192. class="mt-7 flex h-11 items-center justify-center rounded-full text-sm font-bold transition-all"
  193. :class="isFeatured(pkg, idx)
  194. ? 'bg-gradient-to-r from-[var(--c-0b8cff)] to-[var(--c-3aa9ff)] text-white shadow-[0_10px_22px_var(--sh-11-140-255-250)] hover:opacity-90'
  195. : 'bg-[var(--c-eef7ff)] text-[var(--c-0b8cff)] hover:bg-[var(--c-e0f0ff)]'"
  196. >
  197. 立即充值
  198. </NuxtLink>
  199. </div>
  200. </div>
  201. <p class="mt-8 text-center text-xs text-[var(--c-a0aabb)]">* 点数购买后长期有效,不支持退款</p>
  202. </section>
  203. <!-- ==================== 4.5 热门资讯(移植原 PC 首页) ==================== -->
  204. <section v-if="news.length" class="border-y border-[var(--c-e8eef7)] bg-[var(--c-ffffff)] py-16 lg:py-24">
  205. <div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
  206. <div class="flex flex-wrap items-end justify-between gap-4">
  207. <div>
  208. <span class="inline-flex items-center gap-1.5 rounded-full bg-[var(--c-eef7ff)] px-3 py-1 text-xs font-extrabold text-[var(--c-0b8cff)]">
  209. <UIcon name="i-lucide-newspaper" class="size-3.5" />
  210. AI 资讯
  211. </span>
  212. <h2 class="mt-4 text-3xl font-extrabold text-[var(--c-172033)] sm:text-4xl">热门资讯</h2>
  213. <p class="mt-3 text-base text-[var(--c-66758a)]">AI 前沿动态、使用教程与常见问题解答</p>
  214. </div>
  215. <NuxtLink
  216. to="/info"
  217. class="inline-flex items-center gap-1.5 text-sm font-bold text-[var(--c-0b8cff)] hover:underline"
  218. >
  219. 查看全部资讯
  220. <UIcon name="i-lucide-arrow-right" class="size-4" />
  221. </NuxtLink>
  222. </div>
  223. <!-- 栏目快捷入口 -->
  224. <div class="mt-6 flex flex-wrap gap-2">
  225. <NuxtLink
  226. v-for="col in COLUMNS"
  227. :key="col.colId"
  228. :to="col.path"
  229. class="inline-flex items-center gap-1.5 rounded-full bg-[var(--c-f7f9fd)] px-4 py-2 text-sm font-bold text-[var(--c-5b6b80)] transition-colors hover:bg-[var(--c-eef7ff)] hover:text-[var(--c-0b8cff)]"
  230. >
  231. <UIcon :name="col.icon" class="size-4" />
  232. {{ col.name }}
  233. </NuxtLink>
  234. </div>
  235. <!-- 头条大卡 + 列表 -->
  236. <div class="mt-8 grid gap-6 lg:grid-cols-12 lg:gap-8">
  237. <!-- 头条:图片铺满 + 底部渐变压字 -->
  238. <article v-if="topNews" class="lg:col-span-5">
  239. <NuxtLink
  240. :to="topNews.url"
  241. class="group relative block h-full min-h-[320px] overflow-hidden rounded-3xl bg-[var(--c-0f172a)] shadow-[0_14px_36px_var(--sh-23-58-110-140)]"
  242. >
  243. <img
  244. v-if="topNews.cover"
  245. :src="topNews.cover"
  246. :alt="topNews.title"
  247. class="absolute inset-0 size-full object-cover transition-transform duration-700 group-hover:scale-105"
  248. loading="lazy"
  249. >
  250. <div class="absolute inset-0 bg-gradient-to-t from-[var(--c-0b1324)]/92 via-[var(--c-0b1324)]/45 to-transparent" />
  251. <div class="absolute left-5 top-5">
  252. <span class="rounded-full bg-[var(--c-ffffff)]/95 px-2.5 py-1 text-[11px] font-extrabold text-[var(--c-0b8cff)]">
  253. {{ colName(topNews.col_id) }}
  254. </span>
  255. </div>
  256. <div class="relative flex h-full min-h-[320px] flex-col justify-end p-5 sm:p-6">
  257. <h3 class="line-clamp-2 text-xl font-extrabold leading-snug text-white sm:text-2xl">
  258. {{ topNews.title }}
  259. </h3>
  260. <p v-if="topNews.info" class="mt-2.5 line-clamp-2 text-sm leading-relaxed text-white/75">
  261. {{ topNews.info }}
  262. </p>
  263. <div class="mt-4 flex items-center gap-4 text-xs text-white/60">
  264. <span>{{ topNews.time }}</span>
  265. <span class="inline-flex items-center gap-1">
  266. <UIcon name="i-lucide-eye" class="size-3.5" />
  267. {{ formatViews(topNews.view_num) }}
  268. </span>
  269. <span class="ml-auto inline-flex items-center gap-1 font-bold text-white/85 transition-transform group-hover:translate-x-0.5">
  270. 阅读全文
  271. <UIcon name="i-lucide-arrow-right" class="size-3.5" />
  272. </span>
  273. </div>
  274. </div>
  275. </NuxtLink>
  276. </article>
  277. <!-- 列表:统一缩略图 + 序号,桌面两列 -->
  278. <div class="lg:col-span-7">
  279. <div class="grid gap-3 sm:grid-cols-2 lg:grid-cols-1 xl:grid-cols-2">
  280. <article v-for="(item, idx) in restNews" :key="item.id">
  281. <NuxtLink
  282. :to="item.url"
  283. class="group flex h-full gap-3.5 rounded-2xl border border-[var(--c-eef2f7)] bg-[var(--c-ffffff)] p-3 transition-all hover:-translate-y-0.5 hover:border-[var(--c-0b8cff)]/30 hover:shadow-[0_12px_28px_var(--sh-23-58-110-100)]"
  284. >
  285. <!-- 缩略图(无封面时用序号占位,保证排版整齐) -->
  286. <div class="relative size-[74px] shrink-0 overflow-hidden rounded-xl bg-gradient-to-br from-[var(--c-eef6ff)] to-[var(--c-f3fbf9)]">
  287. <img
  288. v-if="item.cover"
  289. :src="item.cover"
  290. :alt="item.title"
  291. class="size-full object-cover transition-transform duration-500 group-hover:scale-110"
  292. loading="lazy"
  293. >
  294. <span
  295. v-else
  296. class="flex size-full items-center justify-center text-lg font-extrabold text-[var(--c-0b8cff)]/45"
  297. >{{ idx + 2 }}</span>
  298. </div>
  299. <div class="flex min-w-0 flex-1 flex-col">
  300. <h3 class="line-clamp-2 text-sm font-bold leading-snug text-[var(--c-172033)] transition-colors group-hover:text-[var(--c-0b8cff)]">
  301. {{ item.title }}
  302. </h3>
  303. <div class="mt-auto flex items-center gap-2.5 pt-2 text-[11px] text-[var(--c-a0aabb)]">
  304. <span class="rounded bg-[var(--c-f7f9fd)] px-1.5 py-0.5 font-bold text-[var(--c-7b8797)]">
  305. {{ colName(item.col_id) }}
  306. </span>
  307. <span>{{ item.time }}</span>
  308. <span class="inline-flex items-center gap-0.5">
  309. <UIcon name="i-lucide-eye" class="size-3" />
  310. {{ formatViews(item.view_num) }}
  311. </span>
  312. </div>
  313. </div>
  314. </NuxtLink>
  315. </article>
  316. </div>
  317. </div>
  318. </div>
  319. </div>
  320. </section>
  321. <!-- ==================== 5. AI 绘画作品(数据源:/art/getlist) ==================== -->
  322. <section class="border-y border-[var(--c-e8eef7)] bg-[var(--c-ffffff)] py-16 lg:py-24">
  323. <div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
  324. <div class="flex flex-wrap items-end justify-between gap-5">
  325. <div>
  326. <span class="inline-flex items-center gap-1.5 rounded-full bg-[var(--c-f3f0ff)] px-3 py-1 text-xs font-extrabold text-[var(--c-7a5af8)]">
  327. <UIcon name="i-lucide-images" class="size-3.5" />
  328. 作品广场
  329. </span>
  330. <h2 class="mt-4 text-3xl font-extrabold text-[var(--c-172033)] sm:text-4xl">看看大家用 AI 画出了什么</h2>
  331. <p class="mt-3 text-base text-[var(--c-66758a)]">来自 AI 在线用户的公开作品,鼠标悬停可查看生成提示词</p>
  332. </div>
  333. <NuxtLink
  334. to="/pic/"
  335. class="inline-flex h-11 items-center gap-1.5 rounded-full bg-[var(--c-f7f9fd)] px-6 text-sm font-bold text-[var(--c-5b6b80)] transition-colors hover:bg-[var(--c-eef7ff)] hover:text-[var(--c-0b8cff)]"
  336. >
  337. 浏览全部作品
  338. <UIcon name="i-lucide-arrow-right" class="size-4" />
  339. </NuxtLink>
  340. </div>
  341. <!--
  342. 12 张作品的马赛克排布(各断点都能整行铺满,不留空格):
  343. 桌面 5 列:首图占 2×2 + 右侧 6 小图(2 行 × 3 个) + 第 3 行 5 小图
  344. 平板 3 列:首图占 2×2 + 右侧 2 小图 + 后续 3 行 × 3 个
  345. 移动 2 列:全部等大,6 行
  346. -->
  347. <div v-if="artworks.length" class="mt-10 grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-5 lg:gap-4">
  348. <NuxtLink
  349. v-for="(item, idx) in artworks"
  350. :key="`${item.chat_open_id}_${item.img_index}`"
  351. :to="`/pic/${item.chat_open_id}_${item.img_index || 0}.html`"
  352. class="group relative aspect-square overflow-hidden rounded-2xl bg-[var(--c-eef3f8)] ring-1 ring-[var(--c-eef2f7)] transition-all hover:ring-2 hover:ring-[var(--c-0b8cff)]/50 hover:shadow-[0_14px_32px_var(--sh-23-58-110-140)]"
  353. :class="idx === 0 ? 'sm:col-span-2 sm:row-span-2' : ''"
  354. >
  355. <img
  356. :src="item.img"
  357. :alt="item.prompts || 'AI 绘画作品'"
  358. class="size-full object-cover transition-transform duration-700 group-hover:scale-105"
  359. loading="lazy"
  360. >
  361. <!-- 常驻的类型角标 -->
  362. <span class="absolute left-3 top-3 rounded-full bg-[var(--c-ffffff)]/90 px-2 py-0.5 text-[10px] font-bold text-[var(--c-4b5b70)] backdrop-blur">
  363. {{ artTypeName(item.ai_type) }}
  364. </span>
  365. <!-- hover 提示词浮层 -->
  366. <div class="absolute inset-0 flex flex-col justify-end bg-gradient-to-t from-black/80 via-black/20 to-transparent opacity-0 transition-opacity duration-300 group-hover:opacity-100">
  367. <div class="p-3 lg:p-4">
  368. <p
  369. v-if="item.prompts"
  370. class="line-clamp-3 text-xs leading-relaxed text-white/95"
  371. :class="idx === 0 && 'lg:text-sm'"
  372. >
  373. {{ item.prompts }}
  374. </p>
  375. <p v-else class="text-xs text-white/80">AI 生成作品</p>
  376. <div class="mt-2 flex items-center gap-3 text-[10px] text-white/70">
  377. <span v-if="item.resolution">{{ item.resolution }}</span>
  378. <span class="inline-flex items-center gap-1">
  379. <UIcon name="i-lucide-heart" class="size-3" />
  380. {{ item.like_num || 0 }}
  381. </span>
  382. <span class="ml-auto inline-flex items-center gap-1 font-bold text-white">
  383. 查看
  384. <UIcon name="i-lucide-arrow-up-right" class="size-3" />
  385. </span>
  386. </div>
  387. </div>
  388. </div>
  389. </NuxtLink>
  390. </div>
  391. <!-- 无数据兜底 -->
  392. <div v-else class="mt-10 rounded-3xl bg-[var(--c-f7f9fd)] py-16 text-center">
  393. <UIcon name="i-lucide-image-off" class="mx-auto mb-4 size-12 text-[var(--c-a0aabb)]" />
  394. <div class="text-base font-extrabold text-[var(--c-172033)]">还没有公开作品</div>
  395. <div class="mt-2 text-sm text-[var(--c-8a95a6)]">成为第一个分享 AI 作品的人</div>
  396. </div>
  397. </div>
  398. </section>
  399. <!-- ==================== 6. 结尾 CTA ==================== -->
  400. <section class="relative overflow-hidden bg-[var(--c-f3f7fb)] py-16 lg:py-24">
  401. <div class="pointer-events-none absolute -right-20 top-0 size-72 rounded-full bg-[var(--c-0b8cff)]/10 blur-3xl" />
  402. <div class="relative mx-auto max-w-3xl px-4 text-center sm:px-6">
  403. <h2 class="text-3xl font-extrabold text-[var(--c-172033)] sm:text-4xl">现在就开始,几秒钟拿到结果</h2>
  404. <p class="mt-4 text-base text-[var(--c-66758a)]">注册即可体验,按点数付费,不用订阅、不绑定套餐。</p>
  405. <div class="mt-8 flex flex-col items-center justify-center gap-3 sm:flex-row">
  406. <NuxtLink
  407. to="/writing/naming/"
  408. class="inline-flex h-13 w-full items-center justify-center gap-2 rounded-full bg-gradient-to-r from-[var(--c-0b8cff)] to-[var(--c-3aa9ff)] px-8 text-base font-bold text-white shadow-[0_14px_30px_var(--sh-11-140-255-280)] transition-all hover:-translate-y-0.5 sm:w-auto"
  409. >
  410. <UIcon name="i-lucide-zap" class="size-5" />
  411. 开始创作
  412. </NuxtLink>
  413. <NuxtLink
  414. to="/recharge"
  415. class="inline-flex h-13 w-full items-center justify-center rounded-full bg-[var(--c-ffffff)] px-8 text-base font-bold text-[var(--c-0b8cff)] shadow-[0_8px_20px_var(--sh-23-32-51-60)] transition-colors hover:bg-[var(--c-f7faff)] sm:w-auto"
  416. >
  417. 查看套餐
  418. </NuxtLink>
  419. </div>
  420. <div class="mt-10 flex flex-wrap items-center justify-center gap-x-8 gap-y-3 text-sm text-[var(--c-66758a)]">
  421. <span v-for="p in promises" :key="p" class="inline-flex items-center gap-1.5">
  422. <UIcon name="i-lucide-circle-check" class="size-4 text-[var(--c-17a65a)]" />
  423. {{ p }}
  424. </span>
  425. </div>
  426. </div>
  427. </section>
  428. </div>
  429. </template>
  430. <script setup>
  431. useSeoMeta({
  432. title: 'AI在线网站-你的AI伙伴让创作更简单',
  433. description: 'AI在线是一个 AI 工具的集合地,可以找到各种各样的 AI 工具,满足你的不同需求。无论你是想翻译一段文字,还是想生成一篇文章,或者是想制作一张图片,AI在线都能为你提供帮助, AI 工具大全宝库!',
  434. keywords: 'AI,AI在线,AI伙伴,免费AI网站',
  435. })
  436. useHead({
  437. link: [{ rel: 'canonical', href: 'https://tool.aionline.cc/' }],
  438. })
  439. import { COLUMNS, articleUrl, colName, formatTime } from '~/composables/useArticle'
  440. const { post } = useApi()
  441. const { isLogin } = useUser()
  442. // ==================== 首屏动漫头像示例(后台可配,带兜底) ====================
  443. const demo = ref({
  444. original: 'https://cdn.aionline.cc/ai/anime/original_1.png',
  445. anime: 'https://cdn.aionline.cc/ai/anime/anime_1.png',
  446. })
  447. async function loadDemo() {
  448. try {
  449. const res = await post('/common/getconfig', { keys: 'anime_demo_v2,anime_demo' })
  450. const rows = res.list || []
  451. const v2 = rows.find(i => i.key === 'anime_demo_v2')
  452. if (v2?.value) {
  453. const data = typeof v2.value === 'string' ? JSON.parse(v2.value) : v2.value
  454. const first = Array.isArray(data) ? data[0] : data
  455. if (first?.original && first?.anime) {
  456. demo.value = { original: first.original, anime: first.anime }
  457. return
  458. }
  459. }
  460. const old = rows.find(i => i.key === 'anime_demo')
  461. if (old?.value) {
  462. const pics = String(old.value).split(',').map(s => s.trim()).filter(Boolean)
  463. if (pics.length >= 2) demo.value = { original: pics[0], anime: pics[1] }
  464. }
  465. } catch {
  466. // 保留兜底图
  467. }
  468. }
  469. // ==================== 静态内容 ====================
  470. const tools = [
  471. {
  472. title: 'AI 取名',
  473. desc: '结合姓氏、性别、出生信息,从诗经楚辞典故中生成有出处的好名字,含寓意与音律解析。',
  474. to: '/writing/naming/',
  475. icon: 'i-lucide-signature',
  476. iconBg: 'bg-[var(--c-eef7ff)]',
  477. iconColor: 'text-[var(--c-0b8cff)]',
  478. appKey: 'ai-name',
  479. price: '点数计费',
  480. hot: true,
  481. },
  482. {
  483. title: '动漫头像',
  484. desc: '上传一张自拍,一键生成专属动漫风格头像,多种画风可选,支持原图对比。',
  485. to: '/draw/anime/',
  486. icon: 'i-lucide-user-round',
  487. iconBg: 'bg-[var(--c-f3f0ff)]',
  488. iconColor: 'text-[var(--c-7a5af8)]',
  489. appKey: 'anime-avatar',
  490. billingParams: { model: 'tencent_anime' },
  491. price: '点数计费',
  492. hot: true,
  493. },
  494. {
  495. title: '证件照',
  496. desc: '一键生成标准证件照,自动换底色、智能裁剪,满足各类办证尺寸要求。',
  497. to: '/id-photo',
  498. icon: 'i-lucide-id-card',
  499. iconBg: 'bg-[var(--c-edfdf4)]',
  500. iconColor: 'text-[var(--c-17a65a)]',
  501. appKey: 'id-photo',
  502. price: '按张计费',
  503. soon: false,
  504. },
  505. {
  506. title: '形象照 / 写真',
  507. desc: '上传一张人像,生成商务形象照、日常职业照,或古风、港风等艺术写真,一次最多 4 张。',
  508. to: '/portrait-photo',
  509. icon: 'i-lucide-camera',
  510. iconBg: 'bg-[var(--c-fff4ec)]',
  511. iconColor: 'text-[var(--c-ff681f)]',
  512. appKey: 'portrait-photo',
  513. billingParams: { model: 'standard', count: 1 },
  514. price: '按张计费',
  515. soon: false,
  516. },
  517. {
  518. title: '老照片修复',
  519. desc: '黑白、泛黄、有划痕的老照片,一键修复破损并自然上色,支持前后对比。',
  520. to: '/old-photo',
  521. icon: 'i-lucide-wand-sparkles',
  522. iconBg: 'bg-[var(--c-fff4ec)]',
  523. iconColor: 'text-[var(--c-e85f1c)]',
  524. appKey: 'old-photo',
  525. billingParams: { mode: 'colorize' },
  526. price: '按张计费',
  527. soon: false,
  528. },
  529. {
  530. title: '更多能力',
  531. desc: '文本转语音、AI 装修设计等更多 AI 能力持续上线,敬请期待。',
  532. to: '#',
  533. icon: 'i-lucide-layout-grid',
  534. iconBg: 'bg-[var(--c-f1f5fa)]',
  535. iconColor: 'text-[var(--c-8a97a8)]',
  536. price: '持续更新',
  537. soon: true,
  538. },
  539. ]
  540. const { data: toolBillingData } = await useAsyncData('home-tool-billing', async () => {
  541. const billableTools = tools.filter(tool => tool.appKey)
  542. const entries = await Promise.all(billableTools.map(async (tool) => {
  543. try {
  544. const res = await post('/billing/config', {
  545. app_key: tool.appKey,
  546. ...(tool.billingParams || {}),
  547. })
  548. const rawPoints = res?.data?.quote?.points ?? res?.data?.points
  549. const points = Number(rawPoints)
  550. return [tool.appKey, Number.isFinite(points) ? points : null]
  551. } catch {
  552. return [tool.appKey, null]
  553. }
  554. }))
  555. return Object.fromEntries(entries)
  556. })
  557. function toolPrice(tool) {
  558. const points = toolBillingData.value?.[tool.appKey]
  559. return points === 0 ? '免费使用' : tool.price
  560. }
  561. const promises = ['点数长期有效', '多端共享余额', '结果可下载复制', '生成失败不扣点']
  562. // ==================== 点数套餐(真实数据) ====================
  563. const packages = ref([])
  564. const pkgLoading = ref(true)
  565. async function loadPackages() {
  566. try {
  567. const res = await post('/point/packagelist')
  568. packages.value = (res.list || []).slice(0, 3)
  569. } catch {
  570. packages.value = []
  571. } finally {
  572. pkgLoading.value = false
  573. }
  574. }
  575. // 中间一档或带「推荐」角标的高亮
  576. function isFeatured(pkg, idx) {
  577. const hasRecommend = packages.value.some(p => p.badge === '推荐')
  578. return hasRecommend ? pkg.badge === '推荐' : idx === 1
  579. }
  580. function pkgIcon(idx) {
  581. return ['i-lucide-sprout', 'i-lucide-rocket', 'i-lucide-crown'][idx] || 'i-lucide-coins'
  582. }
  583. function pkgSubtitle(pkg) {
  584. const p = Number(pkg.points || 0)
  585. if (p <= 200) return '轻量体验,先试试手感'
  586. if (p <= 1500) return '日常创作,性价比最高'
  587. return '高频创作,一次买够'
  588. }
  589. function pkgBonusPercent(pkg) {
  590. const provided = Number(pkg.bonus_percent || 0)
  591. if (Number.isFinite(provided) && provided > 0) return Math.round(provided)
  592. const price = Number(pkg.price || 0) || Number(pkg.price_yuan || 0) * 100
  593. const oldPrice = Number(pkg.old_price || 0) || Number(pkg.old_price_yuan || 0) * 100
  594. if (!Number.isFinite(price) || !Number.isFinite(oldPrice) || price <= 0 || oldPrice <= price) return 0
  595. return Math.max(0, Math.round((oldPrice / price - 1) * 100))
  596. }
  597. function pkgFeatures(pkg) {
  598. return [
  599. `获得 ${pkg.points} 点数`,
  600. '点数长期有效,不过期',
  601. '小程序 / H5 / PC 通用',
  602. '可用于全部 AI 工具',
  603. ]
  604. }
  605. // ==================== 热门资讯(移植原 PC 首页,SSR 渲染利于 SEO) ====================
  606. const { data: newsData } = await useAsyncData('home-news', () =>
  607. post('/article/getlist', { page_no: 1, page_size: 7, is_recommend: 1 })
  608. .catch(() => ({ list: [] })))
  609. const news = computed(() =>
  610. (newsData.value?.list || []).map(i => ({ ...i, url: articleUrl(i), time: formatTime(i.publish_time, 'YYYY-MM-DD') })))
  611. const topNews = computed(() => news.value[0] || null)
  612. const restNews = computed(() => news.value.slice(1, 7))
  613. /** 阅读量简写:1280 → 1.3k */
  614. function formatViews(n) {
  615. const v = Number(n || 0)
  616. return v >= 1000 ? `${(v / 1000).toFixed(1)}k` : String(v)
  617. }
  618. // ==================== AI 绘画作品(数据源同原 PC 首页:/art/getlist) ====================
  619. // ai_type:2 MJ绘画 3/7/8 AI画头像 4 变年龄 5 变性别 6 AI绘画
  620. const ART_TYPE_MAP = {
  621. 2: 'MJ 绘画', 3: 'AI 头像', 4: 'AI 变年龄',
  622. 5: 'AI 变性别', 6: 'AI 绘画', 7: 'AI 头像', 8: 'AI 头像',
  623. }
  624. function artTypeName(type) {
  625. return ART_TYPE_MAP[Number(type)] || 'AI 作品'
  626. }
  627. const { data: artData } = await useAsyncData('home-art', () =>
  628. post('/art/getlist', { page_no: 1, page_size: 30 }).catch(() => ({ list: [] })))
  629. // 展示 12 张:首图占 2×2,其余 1×1,桌面 5 列共 3 行正好铺满
  630. const artworks = computed(() => (artData.value?.list || []).filter(i => i.img).slice(0, 12))
  631. onMounted(() => {
  632. loadDemo()
  633. loadPackages()
  634. })
  635. watch(isLogin, () => loadPackages())
  636. </script>
  637. <style scoped>
  638. /* Tailwind 没有 h-13,这里补一个统一的按钮高度 */
  639. .h-13 {
  640. height: 3.25rem;
  641. }
  642. </style>