Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 

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