mirror of
https://github.com/ialley-workshop-open/uni-halo.git
synced 2026-09-12 16:40:40 +08:00
chore: 废弃第三方友链提交功能,重构友链相关配置与分类逻辑
1. 移除linksSubmitPlugin相关配置与提交接口代码 2. 重构友链配置数据结构,拆分linkInfo为miniInfo/siteInfo/authorInfo 3. 优化分类页审核模式渲染逻辑,补充postCount默认值处理 4. 更新所有关联页面与组件的数据源读取逻辑
This commit is contained in:
@@ -14,14 +14,41 @@ export interface IImagesConfig {
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
/** 插件配置(toolsPlugin/linksSubmitPlugin 等带 Authorization) */
|
||||
/** 插件配置(toolsPlugin/linksPlugin 等带 Authorization) */
|
||||
export interface IPluginConfig {
|
||||
votePlugin?: Record<string, unknown>
|
||||
toolsPlugin?: { Authorization?: string } & Record<string, unknown>
|
||||
linksPlugin?: Record<string, unknown>
|
||||
linksSubmitPlugin?: { Authorization?: string } & Record<string, unknown>
|
||||
/** 链接配置(插件端 spec.linkInfo 直接下发到本键,字段名无映射:displayName/miniProgramCode/link/description/applyRemark/authorName/avatar/website) */
|
||||
linkInfo?: Record<string, unknown>
|
||||
/**
|
||||
* 链接配置(插件端 spec.linkInfo 直接下发到本键,结构 = {miniInfo, siteInfo, authorInfo},字段名无映射;
|
||||
* linksSubmitPlugin 旧键已弃用不再下发)
|
||||
*/
|
||||
linkInfo?: {
|
||||
/** 小程序信息(「申请信息」弹窗展示) */
|
||||
miniInfo?: {
|
||||
displayName?: string
|
||||
miniProgramCode?: string
|
||||
link?: string
|
||||
description?: string
|
||||
applyRemark?: string
|
||||
}
|
||||
/** 站点信息(对齐 Halo 官方友链提交 API:displayName/url/logo/description/email/backlink/feedUrls) */
|
||||
siteInfo?: {
|
||||
displayName?: string
|
||||
url?: string
|
||||
logo?: string
|
||||
description?: string
|
||||
email?: string
|
||||
backlink?: string
|
||||
feedUrls?: string[]
|
||||
}
|
||||
/** 作者信息(小程序端作者区) */
|
||||
authorInfo?: {
|
||||
authorName?: string
|
||||
avatar?: string
|
||||
website?: string
|
||||
}
|
||||
}
|
||||
doubanPlugin?: { position?: string } & Record<string, unknown>
|
||||
[key: string]: unknown
|
||||
}
|
||||
@@ -78,7 +105,7 @@ export interface IPageConfig {
|
||||
visible?: boolean
|
||||
}>
|
||||
/** 首页精选分类引用(插件端「通用配置 → 页面设置 → 首页」配置,固定最多 3 个,
|
||||
* 快照含名称/封面/排序权重,数组顺序 = 展示顺序;配置模式下直接映射渲染不发请求,
|
||||
* 快照含名称/封面/排序权重/文章数,数组顺序 = 展示顺序;配置模式下直接映射渲染不发请求,
|
||||
* 未配置/为空时回退默认取数) */
|
||||
categories?: Array<{
|
||||
name: string
|
||||
@@ -86,6 +113,8 @@ export interface IPageConfig {
|
||||
cover?: string
|
||||
/** 分类排序权重(Halo Category.spec.priority,越大越靠前) */
|
||||
priority?: number
|
||||
/** 分类文章数(Halo Category.status.postCount 冗余快照,缺失默认 0) */
|
||||
postCount?: number
|
||||
}>
|
||||
}
|
||||
categoryConfig?: { type?: string }
|
||||
@@ -123,6 +152,16 @@ export interface IAuditDataResult {
|
||||
description?: string
|
||||
[key: string]: unknown
|
||||
}
|
||||
/** 分类完整快照(插件端公开接口附带:剔除失效、按配置顺序;app 端审核模式分类页免请求映射 ICategory) */
|
||||
categoryDetails?: Array<{
|
||||
name: string
|
||||
title?: string
|
||||
cover?: string
|
||||
/** 排序权重(Halo Category.spec.priority) */
|
||||
priority?: number
|
||||
/** 文章数(Halo Category.status.postCount,缺失默认 0) */
|
||||
postCount?: number
|
||||
}>
|
||||
}
|
||||
|
||||
/** 应用基础配置(对应旧 DefaultAppConfigs) */
|
||||
|
||||
@@ -377,19 +377,6 @@ export function createVerificationCode() {
|
||||
|
||||
/* ==================== 友链提交(linkssubmit.muyin.site) ==================== */
|
||||
|
||||
/**
|
||||
* 提交友链
|
||||
*/
|
||||
export function submitLink(form: ISubmitLinkForm) {
|
||||
return http.Post<IResponse<{ msg?: string, message?: string }>>('/apis/linkssubmit.muyin.site/v1alpha1/submit', form, {
|
||||
headers: {
|
||||
'Authorization': getLinksSubmitAuthorization(),
|
||||
'Wechat-Session-Id': getOpenid(),
|
||||
},
|
||||
meta: { requestFrom: RequestFrom.Halo },
|
||||
})
|
||||
}
|
||||
|
||||
/* ==================== 投票(api.vote.kunkunyu.com) ==================== */
|
||||
|
||||
/**
|
||||
@@ -510,13 +497,6 @@ function getToolsAuthorization(): string {
|
||||
return getAppConfigFromStore().pluginConfig?.toolsPlugin?.Authorization || ''
|
||||
}
|
||||
|
||||
/**
|
||||
* 友链提交插件授权头(源自应用配置 pluginConfig.linksSubmitPlugin.Authorization)
|
||||
*/
|
||||
function getLinksSubmitAuthorization(): string {
|
||||
return getAppConfigFromStore().pluginConfig?.linksSubmitPlugin?.Authorization || ''
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取应用配置(store 未就绪时兜底为空)
|
||||
* 注:待 src/store/appConfig.ts 建立后改为 useAppConfigStore 读取
|
||||
|
||||
@@ -34,7 +34,8 @@
|
||||
slug: '',
|
||||
cover: checkThumbnailUrl(c.cover),
|
||||
priority: c.priority,
|
||||
}
|
||||
},
|
||||
postCount: c.postCount ?? 0,
|
||||
} as ICategory))
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -24,20 +24,21 @@ const emit = defineEmits<{
|
||||
const isShow = ref(false)
|
||||
const appConfigStore = useAppConfigStore()
|
||||
|
||||
/** 小程序申请信息(字段与 uh-links-mini-apply 表单一致,从插件端 linkInfo 配置直接读取,字段名无映射) */
|
||||
/** 小程序申请信息(字段与 uh-links-mini-apply 表单一致;小程序信息读 linkInfo.miniInfo、作者信息读 linkInfo.authorInfo,字段名无映射) */
|
||||
const miniInfo = computed(() => {
|
||||
const cfg = (appConfigStore.configs.pluginConfig?.linkInfo || {}) as Record<string, unknown>
|
||||
const str = (key: string, fallback = '') => String(cfg[key] || fallback || '')
|
||||
const miniCfg = (appConfigStore.configs.pluginConfig?.linkInfo?.miniInfo || {}) as Record<string, unknown>
|
||||
const authorCfg = (appConfigStore.configs.pluginConfig?.linkInfo?.authorInfo || {}) as Record<string, unknown>
|
||||
const str = (cfg: Record<string, unknown>, key: string, fallback = '') => String(cfg[key] || fallback || '')
|
||||
return {
|
||||
displayName: str('displayName'),
|
||||
miniProgramCode: str('miniProgramCode'),
|
||||
link: str('link'),
|
||||
authorName: str('authorName'),
|
||||
avatar: str('avatar'),
|
||||
website: str('website'),
|
||||
description: str('description'),
|
||||
applyRemark: str('applyRemark'),
|
||||
email: str('email'),
|
||||
displayName: str(miniCfg, 'displayName'),
|
||||
miniProgramCode: str(miniCfg, 'miniProgramCode'),
|
||||
link: str(miniCfg, 'link'),
|
||||
authorName: str(authorCfg, 'authorName'),
|
||||
avatar: str(authorCfg, 'avatar'),
|
||||
website: str(authorCfg, 'website'),
|
||||
description: str(miniCfg, 'description'),
|
||||
applyRemark: str(miniCfg, 'applyRemark'),
|
||||
email: str(miniCfg, 'email'),
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
* 提交后等待站长审核,通过后展示在「站点」列表中
|
||||
*/
|
||||
import { ref, watch } from 'vue'
|
||||
import { submitLink } from '@/api/uni-halo'
|
||||
import type { ISubmitLinkForm } from '@/api/types/uni-halo'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
show?: boolean
|
||||
@@ -88,34 +86,9 @@ async function handleSubmit() {
|
||||
if (!validateForm())
|
||||
return
|
||||
|
||||
submitting.value = true
|
||||
uni.showLoading({ title: '正在提交...' })
|
||||
try {
|
||||
const payload: ISubmitLinkForm = {
|
||||
name: form.value.name.trim(),
|
||||
url: form.value.url.trim(),
|
||||
logo: form.value.logo.trim() || undefined,
|
||||
linkPageUrl: form.value.linkPageUrl.trim() || undefined,
|
||||
email: form.value.email.trim() || undefined,
|
||||
rssUrl: form.value.rssUrl.trim() || undefined,
|
||||
description: form.value.description.trim() || undefined,
|
||||
}
|
||||
const res = await submitLink(payload)
|
||||
const msg = res.data?.msg || res.data?.message || res.message || '提交成功'
|
||||
uni.showToast({ icon: 'none', title: msg })
|
||||
if (res.code === 200 || res.code === undefined) {
|
||||
handleClose(true)
|
||||
handleResetForm()
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.error('友链申请提交失败', err)
|
||||
uni.showToast({ icon: 'none', title: '提交失败,请稍后重试!' })
|
||||
}
|
||||
finally {
|
||||
submitting.value = false
|
||||
uni.hideLoading()
|
||||
}
|
||||
// linksSubmitPlugin 已弃用(2026-09-08),第三方友链自助提交暂未开放;
|
||||
// 后续可对接 Halo 官方 plugin-links link-applications 接口
|
||||
uni.showToast({ icon: 'none', title: '友链申请功能暂未开放,请联系站长' })
|
||||
}
|
||||
|
||||
function handleOnChange(isOpen: boolean) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
/**
|
||||
* 站点友链信息弹窗(源自旧页面 pages-blog/submit-link 的博客详情弹窗,重设计为底部玻璃弹窗)
|
||||
* 展示本站友链交换信息(博客名片 + 复制交换信息 + 站点缩略图)
|
||||
* 数据源为 linksSubmitPlugin 配置(即本站申请提交的信息)
|
||||
* 数据源为插件端 linkInfo.siteInfo 配置(字段对齐 Halo 官方友链提交 API:displayName/url/logo/description/email/backlink/feedUrls)
|
||||
*/
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { useAppConfigStore } from '@/store/appConfig'
|
||||
@@ -21,19 +21,22 @@ const emit = defineEmits<{
|
||||
const isShow = ref(false)
|
||||
const appConfigStore = useAppConfigStore()
|
||||
|
||||
const blogDetail = computed(() => (appConfigStore.configs.pluginConfig?.linksSubmitPlugin as {
|
||||
blogName?: string
|
||||
blogUrl?: string
|
||||
blogLogo?: string
|
||||
blogDesc?: string
|
||||
const blogDetail = computed(() => (appConfigStore.configs.pluginConfig?.linkInfo?.siteInfo as {
|
||||
displayName?: string
|
||||
url?: string
|
||||
logo?: string
|
||||
description?: string
|
||||
email?: string
|
||||
backlink?: string
|
||||
feedUrls?: string[]
|
||||
} | undefined) || {})
|
||||
|
||||
/** 友链交换信息文案(复制用) */
|
||||
const calcBlogContent = computed(() => `
|
||||
博客名称:${blogDetail.value.blogName || ''}
|
||||
博客地址:${blogDetail.value.blogUrl || ''}
|
||||
博客logo:${checkAvatarUrl(blogDetail.value.blogLogo)}
|
||||
博客简介:${blogDetail.value.blogDesc || ''}
|
||||
博客名称:${blogDetail.value.displayName || ''}
|
||||
博客地址:${blogDetail.value.url || ''}
|
||||
博客logo:${checkAvatarUrl(blogDetail.value.logo)}
|
||||
博客简介:${blogDetail.value.description || ''}
|
||||
`)
|
||||
|
||||
function calcSiteThumbnail(val?: string): string {
|
||||
@@ -88,14 +91,14 @@ watch(() => props.show, (val) => {
|
||||
<view class="flex items-center">
|
||||
<image
|
||||
class="uh-global-card-glass h-20 w-20 shrink-0 rounded-2xl"
|
||||
:src="checkAvatarUrl(blogDetail.blogLogo)" mode="aspectFill"
|
||||
:src="checkAvatarUrl(blogDetail.logo)" mode="aspectFill"
|
||||
/>
|
||||
<view class="ml-4 flex flex-1 flex-col justify-center gap-y-1">
|
||||
<text class="text-md text-gray-900 font-bold">
|
||||
{{ blogDetail.blogName || '未命名博客' }}
|
||||
{{ blogDetail.displayName || '未命名博客' }}
|
||||
</text>
|
||||
<text class="text-xs text-gray-500">
|
||||
{{ blogDetail.blogDesc || '这个博主很懒,没写简介~' }}
|
||||
{{ blogDetail.description || '这个博主很懒,没写简介~' }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
@@ -107,8 +110,8 @@ watch(() => props.show, (val) => {
|
||||
|
||||
<!-- 站点缩略图 -->
|
||||
<image
|
||||
v-if="blogDetail.blogUrl" class="mt-4 h-[320rpx] w-full rounded-xl"
|
||||
:src="calcSiteThumbnail(blogDetail.blogUrl)" mode="aspectFill"
|
||||
v-if="blogDetail.url" class="mt-4 h-[320rpx] w-full rounded-xl"
|
||||
:src="calcSiteThumbnail(blogDetail.url)" mode="aspectFill"
|
||||
/>
|
||||
|
||||
<view class="my-6">
|
||||
|
||||
@@ -10,8 +10,6 @@ export const DefaultAppConfigs: IAppConfig = {
|
||||
votePlugin: {},
|
||||
toolsPlugin: {},
|
||||
linksPlugin: {},
|
||||
// 保留:友链提交授权头(pluginConfig.linksSubmitPlugin.Authorization)与站点信息展示仍读取
|
||||
linksSubmitPlugin: {},
|
||||
doubanPlugin: {
|
||||
position: 'bottom',
|
||||
},
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
*/
|
||||
import { computed, ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { submitLink } from '@/api/uni-halo'
|
||||
import { useAppConfigStore } from '@/store/appConfig'
|
||||
import { checkAvatarUrl } from '@/utils/url'
|
||||
|
||||
@@ -18,11 +17,14 @@ definePage({
|
||||
const appConfigStore = useAppConfigStore()
|
||||
const haloPluginConfigs = computed(() => appConfigStore.configs.pluginConfig)
|
||||
|
||||
const blogDetail = computed(() => (haloPluginConfigs.value?.linksSubmitPlugin as {
|
||||
blogName?: string
|
||||
blogUrl?: string
|
||||
blogLogo?: string
|
||||
blogDesc?: string
|
||||
const blogDetail = computed(() => (haloPluginConfigs.value?.linkInfo?.siteInfo as {
|
||||
displayName?: string
|
||||
url?: string
|
||||
logo?: string
|
||||
description?: string
|
||||
email?: string
|
||||
backlink?: string
|
||||
feedUrls?: string[]
|
||||
} | undefined) || {})
|
||||
|
||||
const blogDetailPoupShow = ref(false)
|
||||
@@ -38,10 +40,10 @@ const form = ref({
|
||||
})
|
||||
|
||||
const calcBlogContent = computed(() => `
|
||||
博客名称:${blogDetail.value.blogName}
|
||||
博客地址:${blogDetail.value.blogUrl}
|
||||
博客logo:${checkAvatarUrl(blogDetail.value.blogLogo)}
|
||||
博客简介:${blogDetail.value.blogDesc}
|
||||
博客名称:${blogDetail.value.displayName}
|
||||
博客地址:${blogDetail.value.url}
|
||||
博客logo:${checkAvatarUrl(blogDetail.value.logo)}
|
||||
博客简介:${blogDetail.value.description}
|
||||
`)
|
||||
|
||||
function calcSiteThumbnail(val?: string): string {
|
||||
@@ -77,34 +79,9 @@ async function handleHandle() {
|
||||
return
|
||||
}
|
||||
|
||||
uni.showLoading({ title: '正在提交...' })
|
||||
try {
|
||||
const res = await submitLink({
|
||||
name: form.value.name,
|
||||
url: form.value.url,
|
||||
logo: form.value.logo,
|
||||
description: form.value.description,
|
||||
email: form.value.email,
|
||||
linkPageUrl: form.value.linkPageUrl,
|
||||
rssUrl: form.value.rssUrl,
|
||||
})
|
||||
uni.hideLoading()
|
||||
const code = res.code
|
||||
const msg = res.data?.msg || res.data?.message || res.message || '提交成功'
|
||||
uni.showToast({ icon: 'none', title: msg })
|
||||
if (code === 200 || code === undefined) {
|
||||
setTimeout(() => {
|
||||
uni.navigateTo({
|
||||
url: '/pages-blog/friend-links/friend-links',
|
||||
})
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err)
|
||||
uni.hideLoading()
|
||||
uni.showToast({ icon: 'none', title: '提交失败,请重试!' })
|
||||
}
|
||||
// linksSubmitPlugin 已弃用(2026-09-08),第三方友链自助提交暂未开放;
|
||||
// 后续可对接 Halo 官方 plugin-links link-applications 接口
|
||||
uni.showToast({ icon: 'none', title: '友链申请功能暂未开放,请联系站长' })
|
||||
}
|
||||
|
||||
function handleCopyLink() {
|
||||
@@ -129,13 +106,13 @@ onLoad(() => {
|
||||
<view class="app-page box-border min-h-screen w-screen bg-[#fafafd] p-8">
|
||||
<!-- 博客详情卡片 -->
|
||||
<view class="blog-coupon mb-6 flex items-center rounded-xl p-6" style="background: linear-gradient(135deg, #2196f3, #64b5f6);" @click="blogDetailPoupShow = true">
|
||||
<image class="coupon-img h-[80rpx] w-[80rpx] shrink-0 rounded-xl" :src="checkAvatarUrl(blogDetail.blogLogo)" mode="aspectFill" />
|
||||
<image class="coupon-img h-[80rpx] w-[80rpx] shrink-0 rounded-xl" :src="checkAvatarUrl(blogDetail.logo)" mode="aspectFill" />
|
||||
<view class="coupon-info ml-5 flex-1">
|
||||
<view class="coupon-title text-[30rpx] text-white font-bold">
|
||||
{{ blogDetail.blogName }}
|
||||
{{ blogDetail.displayName }}
|
||||
</view>
|
||||
<view class="coupon-desc mt-1 text-[24rpx] text-white/80">
|
||||
{{ blogDetail.blogDesc }}
|
||||
{{ blogDetail.description }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="coupon-btn border-2 border-white/60 rounded-3xl px-5 py-1 text-[24rpx] text-white">
|
||||
@@ -198,20 +175,20 @@ onLoad(() => {
|
||||
<wd-popup v-model="blogDetailPoupShow" position="center" custom-style="width:640rpx;border-radius:12rpx;">
|
||||
<view class="poup p-9">
|
||||
<view class="info flex">
|
||||
<image class="poup-logo h-[140rpx] w-[140rpx] rounded-3xl" :src="checkAvatarUrl(blogDetail.blogLogo)" mode="aspectFill" />
|
||||
<image class="poup-logo h-[140rpx] w-[140rpx] rounded-3xl" :src="checkAvatarUrl(blogDetail.logo)" mode="aspectFill" />
|
||||
<view class="info-detail ml-6 flex flex-1 flex-col justify-center">
|
||||
<view class="poup-name text-[34rpx] font-bold">
|
||||
{{ blogDetail.blogName }}
|
||||
{{ blogDetail.displayName }}
|
||||
</view>
|
||||
<view class="poup-tag mt-2.5 text-[24rpx] text-[#999]">
|
||||
{{ blogDetail.blogDesc }}
|
||||
{{ blogDetail.description }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="poup-desc mt-6 whitespace-pre-wrap text-[28rpx] text-[#555] leading-[1.8]">
|
||||
<text>{{ calcBlogContent }}</text>
|
||||
</view>
|
||||
<image v-if="blogDetail.blogUrl" class="poup-img mt-6 h-[320rpx] w-[568rpx] rounded-xl" :src="calcSiteThumbnail(blogDetail.blogUrl)" mode="aspectFill" />
|
||||
<image v-if="blogDetail.url" class="poup-img mt-6 h-[320rpx] w-[568rpx] rounded-xl" :src="calcSiteThumbnail(blogDetail.url)" mode="aspectFill" />
|
||||
<view class="poup-link my-6 flex justify-center gap-6">
|
||||
<wd-button size="small" plain type="primary" @click="handleCopyLink">
|
||||
复制友链交换信息
|
||||
|
||||
@@ -54,21 +54,20 @@
|
||||
updateLoadingStatus(DataLoadingStatusEnum.Loading)
|
||||
// 增加延迟,提升用户体验
|
||||
await sleep(800)
|
||||
// 审核模式
|
||||
// 审核模式:直接使用审核配置分类快照(categoryDetails)映射 ICategory,免请求
|
||||
if (calcAuditModeEnabled.value) {
|
||||
const auditCategoryNames = appConfigStore.auditData.spec?.categories || []
|
||||
const auditCategoryDetails = appConfigStore.auditData.categoryDetails || []
|
||||
try {
|
||||
const res = await getCategoryList({ page: 1, size: 99999 })
|
||||
const filtered = res.data.items
|
||||
.filter(item => auditCategoryNames.includes(item.metadata.name))
|
||||
.map(item => ({
|
||||
...item,
|
||||
postCount: item.postCount ?? 0,
|
||||
spec: { ...item.spec, cover: checkThumbnailUrl(item.spec.cover, true) },
|
||||
}))
|
||||
const orderMap = new Map(auditCategoryNames.map((name, index) => [name, index]))
|
||||
filtered.sort((a, b) => (orderMap.get(a.metadata.name) ?? 999) - (orderMap.get(b.metadata.name) ?? 999))
|
||||
dataList.value = filtered
|
||||
dataList.value = auditCategoryDetails.map(item => ({
|
||||
metadata: { name: item.name },
|
||||
spec: {
|
||||
displayName: item.title || item.name,
|
||||
slug: '',
|
||||
cover: checkThumbnailUrl(item.cover, true),
|
||||
priority: item.priority,
|
||||
},
|
||||
postCount: item.postCount ?? 0,
|
||||
} as ICategory))
|
||||
updateLoadingStatus(dataList.value.length === 0 ? DataLoadingStatusEnum.Empty : DataLoadingStatusEnum.Success)
|
||||
loadMoreText.value = t('common.noMore')
|
||||
uni.hideLoading()
|
||||
|
||||
Reference in New Issue
Block a user