style: 更新UI样式和字体设置
This commit is contained in:
+443
-188
@@ -1,117 +1,168 @@
|
||||
<template>
|
||||
<div class="plink-page pt-4 flex justify-between" :style="boxStyle">
|
||||
<div class="left ml-4 ">
|
||||
<n-card class="card w-100 shadow">
|
||||
<template #header>
|
||||
<div class="flex items-center gap-4 text-primary text-xl font-bold">
|
||||
<icon-loading class="zhuan text-primary w-6 h-6" />
|
||||
申请友链
|
||||
</div>
|
||||
</template>
|
||||
<div>
|
||||
<n-form :model="plinkData" ref="formRef" :rules="rules" label-width="80" :inline="false"
|
||||
feedback-style="font-size: 12px">
|
||||
<n-form-item path="name">
|
||||
<template #label>
|
||||
<div class="flex items-center gap-1 text-sm text-gray-500">
|
||||
<user-icon></user-icon>
|
||||
昵称
|
||||
</div>
|
||||
</template>
|
||||
<n-input v-model:value="plinkData.name" placeholder="请输入你的昵称" />
|
||||
</n-form-item>
|
||||
<n-form-item path="title">
|
||||
<template #label>
|
||||
<div class="flex items-center gap-1 text-sm text-gray-500">
|
||||
<site-icon></site-icon>
|
||||
网站名称
|
||||
</div>
|
||||
</template>
|
||||
<n-input v-model:value="plinkData.title" placeholder="请输入你的网站名称" />
|
||||
</n-form-item>
|
||||
<n-form-item path="url">
|
||||
<template #label>
|
||||
<div class="flex items-center gap-1 text-sm text-gray-500">
|
||||
<url-icon></url-icon>
|
||||
站点地址
|
||||
</div>
|
||||
</template>
|
||||
<n-input v-model:value="plinkData.url" placeholder="请输入你的网站地址" />
|
||||
</n-form-item>
|
||||
<n-form-item path="avater">
|
||||
<template #label>
|
||||
<div class="flex items-center gap-1 text-sm text-gray-500">
|
||||
<ava-icon></ava-icon>
|
||||
头像链接
|
||||
</div>
|
||||
</template>
|
||||
<n-input v-model:value="plinkData.avater" placeholder="请输入你的头像链接" />
|
||||
</n-form-item>
|
||||
<n-form-item path="desc">
|
||||
<template #label>
|
||||
<div class="flex items-center gap-1 text-sm text-gray-500">
|
||||
<desc-icon></desc-icon>
|
||||
站点介绍
|
||||
</div>
|
||||
</template>
|
||||
<n-input type="textarea" :autosize="{ minRows: 2, maxRows: 3 }" maxlength="50"
|
||||
v-model:value="plinkData.desc" placeholder="请用一句话简短的描述你的站点" />
|
||||
</n-form-item>
|
||||
<n-form-item path="tagname">
|
||||
<template #label>
|
||||
<div class="flex items-center gap-1 text-sm text-gray-500">
|
||||
<tag-icon></tag-icon>
|
||||
标签
|
||||
</div>
|
||||
</template>
|
||||
<n-input type="textarea" :autosize="{ minRows: 2, maxRows: 3 }" maxlength="50"
|
||||
v-model:value="plinkData.tagname" placeholder="输入你的标签,用逗号隔开,注意每个标签最多3个字符,且只显示前3个标签哦~" />
|
||||
</n-form-item>
|
||||
<n-form-item>
|
||||
<n-button class="w-full" type="primary" @click="submitPut">申请友链</n-button>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</div>
|
||||
</n-card>
|
||||
<div class="mt-4 text-right text-primary text-sm font-italic">申请完不显示是因为需要审核奥~~</div>
|
||||
<div
|
||||
class="relative overflow-hidden bg-[radial-gradient(circle_at_12%_18%,rgba(215,177,123,0.24),transparent_24%),radial-gradient(circle_at_86%_12%,rgba(120,162,182,0.18),transparent_24%),radial-gradient(circle_at_50%_100%,rgba(176,198,172,0.14),transparent_28%),linear-gradient(180deg,#efe7da_0%,#e8f0ef_44%,#f3f1e8_100%)]"
|
||||
:style="boxStyle">
|
||||
<div
|
||||
class="pointer-events-none absolute left-[-5rem] top-6 h-80 w-80 rounded-full bg-[rgba(234,176,107,0.45)] opacity-48 blur-[88px]">
|
||||
</div>
|
||||
<div
|
||||
class="pointer-events-none absolute right-[-5rem] top-32 h-[22rem] w-[22rem] rounded-full bg-[rgba(118,176,214,0.32)] opacity-48 blur-[88px]">
|
||||
</div>
|
||||
<div
|
||||
class="pointer-events-none absolute inset-0 opacity-14 [background-image:linear-gradient(rgba(255,255,255,0.18)_1px,transparent_1px),linear-gradient(90deg,rgba(255,255,255,0.18)_1px,transparent_1px)] [background-size:36px_36px] [mask-image:linear-gradient(180deg,rgba(0,0,0,0.8),transparent_85%)]">
|
||||
</div>
|
||||
<n-scrollbar class="h-full">
|
||||
<div class="right h-full grid grid-cols-3 gap-5 flex-1 px-12">
|
||||
<div
|
||||
class="rounded-lg bg-white shadow flex flex-col items-center justify-center p-4 cursor-pointer transition-transform duration-300 box-border hover:-translate-y-1.5"
|
||||
v-for="p in pList" :key="p.pid" @click="gotoWebsite(p.url)">
|
||||
<div class="ava">
|
||||
<n-avatar round size="large" :src="p.avater"></n-avatar>
|
||||
</div>
|
||||
<em class="bg-[#fbf2e3] px-4 rounded-full text-sm text-primary mb-4">{{ p.name }}</em>
|
||||
<div class="font-bold text-xl text-gray-700 mb-1">
|
||||
{{ p.title }}
|
||||
</div>
|
||||
|
||||
<div class="flex gap-1 truncate mb-1 text-sm">
|
||||
<div v-for="i in getTags(p.tagname)" :key="i.tid"
|
||||
:style="{ backgroundColor: getDictValue(tagColorList, 'tag', i, 'color') }"
|
||||
class="flex items-center gap-1 cursor-pointer text-sm text-white rounded-full px-3">
|
||||
<icon-tag2 class="w-3 h-3 " />{{ i }}
|
||||
<div class="relative z-[1] mx-auto flex h-full w-[86%] gap-6 py-5">
|
||||
<aside class="hidden w-[25rem] shrink-0 xl:block">
|
||||
<div class="sticky top-4">
|
||||
<section
|
||||
class="relative rounded-[28px] border border-white/62 bg-[linear-gradient(145deg,rgba(255,251,246,0.68),rgba(237,246,244,0.56))] p-5 shadow-[0_20px_50px_rgba(110,124,112,0.11)] backdrop-blur-[20px] after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:bg-[linear-gradient(120deg,rgba(255,255,255,0.24),transparent_45%)] after:content-['']">
|
||||
<div class="relative z-[1]">
|
||||
<h1 class="mt-2 text-[1.65rem] leading-[1.2] text-[#2c3a4a]">留下你的站点名片</h1>
|
||||
<section
|
||||
class="mt-4 rounded-[24px] border border-white/72 bg-white/58 p-4 shadow-[0_14px_32px_rgba(112,128,118,0.1)]">
|
||||
<div class="mb-3 flex items-center justify-between gap-3 text-primary">
|
||||
<div class="flex items-center gap-2">
|
||||
<icon-loading class="zhuan h-4 w-4" />
|
||||
<span class="text-sm font-semibold">申请友链</span>
|
||||
</div>
|
||||
<span
|
||||
class="rounded-full bg-[rgba(250,239,220,0.92)] px-2.5 py-1 text-[11px] cursor-pointer text-primary"
|
||||
@click="fillForm">一键填入</span>
|
||||
</div>
|
||||
|
||||
<n-form ref="formRef" :model="plinkData" :rules="rules" class="compact-side-form" label-placement="top"
|
||||
require-mark-placement="right-hanging" size="small">
|
||||
<n-form-item v-for="field in formFields" :key="field.key" :path="field.key">
|
||||
<template #label>
|
||||
<div class="flex items-center gap-2 text-sm font-medium text-[#526376]">
|
||||
<component :is="field.icon" class="h-4 w-4" />
|
||||
{{ field.label }}
|
||||
</div>
|
||||
</template>
|
||||
<n-input :value="plinkData[field.key]" :type="field.inputType"
|
||||
:maxlength="field.maxlength" :placeholder="field.placeholder" :rows="field.rows"
|
||||
@update:value="updateField(field.key, $event)" />
|
||||
</n-form-item>
|
||||
|
||||
<div class="!mb-0 btn">
|
||||
<n-button
|
||||
class="!h-10 !w-full !rounded-full !border-none !bg-[linear-gradient(135deg,#ec66ab,#f48a6f)] !text-sm !font-semibold shadow-[0_14px_28px_rgba(236,102,171,0.24)]"
|
||||
type="primary" @click="submitPut">
|
||||
提交友链申请
|
||||
</n-button>
|
||||
</div>
|
||||
</n-form>
|
||||
</section>
|
||||
|
||||
<p class="mt-3 text-right text-[12px] leading-5 text-[#7a8797]">
|
||||
如果暂未显示,通常是因为还在审核中...
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="truncate w-full text-gray-400 text-sm text-center">
|
||||
{{ p.desc }}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</n-scrollbar>
|
||||
</aside>
|
||||
|
||||
<section
|
||||
class="min-w-0 flex-1 overflow-hidden rounded-[30px] border border-white/70 bg-transparent p-4 ring-1 ring-inset ring-[rgba(255,255,255,0.38)] shadow-[0_20px_46px_rgba(109,126,117,0.1)] sm:p-6">
|
||||
<n-scrollbar :style="contentStyle" trigger="none" class="pr-1">
|
||||
<div class="space-y-5 pr-1">
|
||||
|
||||
|
||||
<section class="rounded-[26px] bg-transparent p-5 sm:p-6">
|
||||
<div class="mb-5 flex items-center justify-between">
|
||||
<div>
|
||||
<div class="text-[0.82rem] font-semibold tracking-[0.16em] text-[#718195]">已通过友链</div>
|
||||
<h3 class="mt-2 text-[1.4rem] font-semibold text-[#2f4050]">一起逛逛这些站点</h3>
|
||||
</div>
|
||||
<div
|
||||
class="rounded-full border border-white/70 bg-white/42 px-4 py-2 text-sm text-[#526376] shadow-[0_8px_18px_rgba(112,128,118,0.08)]">
|
||||
共 {{ pList.length }} 个站点
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-5 md:grid-cols-2 2xl:grid-cols-3">
|
||||
<article v-for="p in pList" :key="p.pid"
|
||||
class="cursor-pointer rounded-[26px] border border-white/72 bg-[linear-gradient(145deg,rgba(255,251,246,0.78),rgba(237,246,244,0.62))] p-6 shadow-[0_16px_34px_rgba(116,132,124,0.12)] backdrop-blur-[18px] transition-[transform,box-shadow,border-color] duration-[320ms] [transition-timing-function:cubic-bezier(0.22,1,0.36,1)] hover:-translate-y-1 hover:border-white/90 hover:shadow-[0_22px_42px_rgba(102,123,112,0.16)]"
|
||||
@click="gotoWebsite(p.url)">
|
||||
<div class="flex items-center gap-8">
|
||||
<n-avatar round :size="56" :src="p.avater"
|
||||
class="shrink-0 ring-2 ring-white/80 shadow-[0_10px_22px_rgba(88,108,125,0.14)]" />
|
||||
<div class="min-w-0 flex-1">
|
||||
<div
|
||||
class="inline-flex items-center rounded-full bg-[rgba(250,239,220,0.92)] px-3 py-1 text-sm text-primary">
|
||||
{{ p.name }}
|
||||
</div>
|
||||
<h4 class="mt-3 truncate text-[1.3rem] font-semibold text-[#2f4050]">
|
||||
{{ p.title }}
|
||||
</h4>
|
||||
<p class="mt-2 line-clamp-2 min-h-10 text-sm text-[#6a7a88]">
|
||||
{{ p.desc }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-5 flex flex-wrap gap-3 justify-center">
|
||||
<div v-for="tag in getTags(p.tagname)" :key="tag" :style="{ backgroundColor: getTagColor(tag) }"
|
||||
class="inline-flex items-center gap-1 rounded-full px-3 py-1 text-sm text-white shadow-[0_8px_20px_rgba(88,108,125,0.16)]">
|
||||
<icon-tag2 class="h-4 w-4" />
|
||||
{{ tag }}
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div v-if="!pList.length" class="py-14 text-center text-[#7a8797]">
|
||||
暂无友链数据,等你来留下第一张站点名片。
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section
|
||||
class="rounded-[26px] border border-white/66 bg-transparent p-5 ring-1 ring-inset ring-[rgba(255,255,255,0.32)] shadow-[0_16px_34px_rgba(116,132,124,0.09)] xl:hidden">
|
||||
<div class="mb-4 flex items-center gap-3 text-primary">
|
||||
<icon-loading class="zhuan h-5 w-5" />
|
||||
<span class="text-base font-semibold">申请友链</span>
|
||||
</div>
|
||||
|
||||
<n-form ref="mobileFormRef" :model="plinkData" :rules="rules" label-placement="top"
|
||||
require-mark-placement="right-hanging">
|
||||
<n-form-item v-for="field in formFields" :key="field.key" :path="field.key">
|
||||
<template #label>
|
||||
<div class="flex items-center gap-2 text-sm font-medium text-[#526376]">
|
||||
<component :is="field.icon" class="h-4 w-4" />
|
||||
{{ field.label }}
|
||||
</div>
|
||||
</template>
|
||||
<n-input :value="plinkData[field.key]" :type="field.inputType" :rows="field.rows"
|
||||
:maxlength="field.maxlength" :placeholder="field.placeholder"
|
||||
@update:value="updateField(field.key, $event)" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item class="btn">
|
||||
<n-button
|
||||
class="!h-11 !w-full !rounded-full !border-none !bg-[linear-gradient(135deg,#ec66ab,#f48a6f)] !font-semibold shadow-[0_14px_28px_rgba(236,102,171,0.24)]"
|
||||
type="primary" @click="submitPut">
|
||||
提交友链申请
|
||||
</n-button>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</section>
|
||||
</div>
|
||||
</n-scrollbar>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import avaIcon from '@/icon/plink/ava.svg';
|
||||
import descIcon from '@/icon/plink/desc.svg';
|
||||
import siteIcon from '@/icon/plink/site.svg';
|
||||
import tagIcon from '@/icon/plink/tag.svg';
|
||||
import urlIcon from '@/icon/plink/uri.svg';
|
||||
import userIcon from '@/icon/plink/user.svg';
|
||||
import { getDictValue } from '@/util';
|
||||
import avaIcon from '@/icon/plink/ava.svg'
|
||||
import descIcon from '@/icon/plink/desc.svg'
|
||||
import siteIcon from '@/icon/plink/site.svg'
|
||||
import tagIcon from '@/icon/plink/tag.svg'
|
||||
import urlIcon from '@/icon/plink/uri.svg'
|
||||
import userIcon from '@/icon/plink/user.svg'
|
||||
import type { FormInst, FormRules } from 'naive-ui'
|
||||
import type { Component } from 'vue'
|
||||
|
||||
definePage({
|
||||
name: 'plink',
|
||||
@@ -119,109 +170,263 @@ definePage({
|
||||
title: '友链',
|
||||
}
|
||||
})
|
||||
// 友链页逻辑
|
||||
const boxStyle: any = ref({})
|
||||
const nav: any = $store.nav.useNavStore()
|
||||
const plinkData = reactive<any>({
|
||||
|
||||
interface PlinkFormData {
|
||||
name: string
|
||||
title: string
|
||||
avater: string
|
||||
url: string
|
||||
desc: string
|
||||
tagname: string
|
||||
}
|
||||
|
||||
interface PlinkItem {
|
||||
pid: string | number
|
||||
name: string
|
||||
title: string
|
||||
avater: string
|
||||
url: string
|
||||
desc: string
|
||||
tagname: string
|
||||
}
|
||||
|
||||
interface PlinkListResponse {
|
||||
data: PlinkItem[]
|
||||
}
|
||||
|
||||
interface TagColorItem {
|
||||
tag: string
|
||||
color: string
|
||||
}
|
||||
|
||||
interface UserCookieInfo {
|
||||
nickname?: string
|
||||
ava_url?: string
|
||||
}
|
||||
|
||||
type PlinkFieldKey = keyof PlinkFormData
|
||||
|
||||
interface PlinkFormField {
|
||||
key: PlinkFieldKey
|
||||
label: string
|
||||
placeholder: string
|
||||
icon: Component | string
|
||||
inputType?: 'text' | 'textarea'
|
||||
maxlength?: number
|
||||
rows?: number
|
||||
}
|
||||
|
||||
const SOFT_TAG_PALETTE = [
|
||||
'#d46a7c',
|
||||
'#c97956',
|
||||
'#b9894d',
|
||||
'#6f9d86',
|
||||
'#5d92a8',
|
||||
'#7d88b8',
|
||||
'#9a78b5',
|
||||
'#8f7d6b',
|
||||
'#c86b8f',
|
||||
'#cf7f6a',
|
||||
'#a98f55',
|
||||
'#7aa37b',
|
||||
'#5d9f95',
|
||||
'#6d8fc7',
|
||||
'#8a80c4',
|
||||
'#a16fa1',
|
||||
'#b67b67',
|
||||
'#927f72',
|
||||
'#6f8b5f',
|
||||
'#4f8aa8',
|
||||
'#7a96a1',
|
||||
'#b38754',
|
||||
'#a66767',
|
||||
'#7b6aa8',
|
||||
] as const
|
||||
|
||||
const TEXTAREA_AUTOSIZE = {
|
||||
minRows: 1,
|
||||
maxRows: 2,
|
||||
} as const
|
||||
|
||||
const formFields: PlinkFormField[] = [
|
||||
{
|
||||
key: 'name',
|
||||
label: '昵称',
|
||||
placeholder: '请输入你的昵称',
|
||||
icon: userIcon,
|
||||
inputType: 'text',
|
||||
},
|
||||
{
|
||||
key: 'title',
|
||||
label: '网站名称',
|
||||
placeholder: '请输入你的网站名称',
|
||||
icon: siteIcon,
|
||||
inputType: 'text',
|
||||
},
|
||||
{
|
||||
key: 'url',
|
||||
label: '站点地址',
|
||||
placeholder: '请输入你的网站地址',
|
||||
icon: urlIcon,
|
||||
inputType: 'text',
|
||||
},
|
||||
{
|
||||
key: 'avater',
|
||||
label: '头像链接',
|
||||
placeholder: '请输入你的头像链接',
|
||||
icon: avaIcon,
|
||||
inputType: 'text',
|
||||
},
|
||||
{
|
||||
key: 'desc',
|
||||
label: '站点介绍',
|
||||
placeholder: '请用一句话简短描述你的站点',
|
||||
icon: descIcon,
|
||||
inputType: 'textarea',
|
||||
maxlength: 50,
|
||||
rows:2
|
||||
},
|
||||
{
|
||||
key: 'tagname',
|
||||
label: '标签',
|
||||
placeholder: '用逗号隔开,每个标签最多 4 个字,只显示前 3 个',
|
||||
icon: tagIcon,
|
||||
inputType: 'textarea',
|
||||
maxlength: 50,
|
||||
rows:2
|
||||
},
|
||||
]
|
||||
|
||||
const boxStyle = ref<Record<string, string>>({})
|
||||
const contentStyle = ref<Record<string, string>>({})
|
||||
const screenWidth = ref(typeof window === 'undefined' ? 0 : window.innerWidth)
|
||||
const nav = $store.nav.useNavStore() as { navH: number }
|
||||
const formRef = ref<FormInst | null>(null)
|
||||
const mobileFormRef = ref<FormInst | null>(null)
|
||||
const pList = ref<PlinkItem[]>([])
|
||||
const tagColorList = ref<TagColorItem[]>([])
|
||||
|
||||
const plinkData = reactive<PlinkFormData>({
|
||||
name: '',
|
||||
title: '',
|
||||
avater: '',
|
||||
url: '',
|
||||
desc: '',
|
||||
tagname: '',
|
||||
});
|
||||
const rules: any = {
|
||||
name: [{ required: true, message: '昵称不能为空~~', trigger: ['blur'] }],
|
||||
title: [{ required: true, message: '网站名称不能为空~~', trigger: ['blur'] }],
|
||||
url: [{ required: true, message: '站点地址不能为空~~', trigger: ['blur'] }],
|
||||
avater: [{ required: true, message: '头像链接不能为空~~', trigger: ['blur'] }],
|
||||
desc: [{ required: true, message: '站点介绍不能为空~~', trigger: ['blur'] }],
|
||||
tagname: [{ required: true, message: '标签不能为空~~', trigger: ['blur'] }],
|
||||
}
|
||||
const pList = ref<any>([])
|
||||
const formRef = ref<any>(null)
|
||||
const tagColorList: any = ref([])
|
||||
async function getPlinkList() {
|
||||
const res = await $http.plink.getPlinkList()
|
||||
|
||||
const list: Array<string> = []
|
||||
// 对res.data.tags进行去重
|
||||
res.data.forEach((i: any) => {
|
||||
const t = getTags(i.tagname)
|
||||
t.forEach((ii: string) => {
|
||||
if (!list.includes(ii)) list.push(ii)
|
||||
})
|
||||
});
|
||||
})
|
||||
|
||||
tagColorList.value = list.map((i: string) => {
|
||||
return {
|
||||
tag: i,
|
||||
color: getRandomFromPalette()
|
||||
}
|
||||
})
|
||||
const rules: FormRules = {
|
||||
name: [{ required: true, message: '昵称不能为空', trigger: ['blur'] }],
|
||||
title: [{ required: true, message: '网站名称不能为空', trigger: ['blur'] }],
|
||||
url: [{ required: true, message: '站点地址不能为空', trigger: ['blur'] }],
|
||||
avater: [{ required: true, message: '头像链接不能为空', trigger: ['blur'] }],
|
||||
desc: [{ required: true, message: '站点介绍不能为空', trigger: ['blur'] }],
|
||||
tagname: [{ required: true, message: '标签不能为空', trigger: ['blur'] }],
|
||||
}
|
||||
|
||||
function updateLayout() {
|
||||
const viewportHeight = window.innerHeight - nav.navH - 1
|
||||
screenWidth.value = window.innerWidth
|
||||
boxStyle.value = { height: `${viewportHeight}px` }
|
||||
contentStyle.value = { height: `${Math.max(viewportHeight - 48, 280)}px` }
|
||||
}
|
||||
|
||||
function updateField(key: PlinkFieldKey, value: string) {
|
||||
plinkData[key] = value
|
||||
}
|
||||
|
||||
function normalizeTag(tag: string) {
|
||||
return tag.trim().slice(0, 4)
|
||||
}
|
||||
|
||||
function getTags(str: string) {
|
||||
const normalized = (str || '').replace(/,/g, ',')
|
||||
return normalized.split(',').slice(0, 3).map(normalizeTag).filter(Boolean)
|
||||
}
|
||||
|
||||
function buildTagColorMap(tags: string[]): TagColorItem[] {
|
||||
return tags.map((tag, index) => ({
|
||||
tag,
|
||||
color: SOFT_TAG_PALETTE[index % SOFT_TAG_PALETTE.length],
|
||||
}))
|
||||
}
|
||||
|
||||
function getTagColor(tag: string) {
|
||||
return tagColorList.value.find((item) => item.tag === tag)?.color || SOFT_TAG_PALETTE[0]
|
||||
}
|
||||
|
||||
async function getPlinkList() {
|
||||
const res = await $http.plink.getPlinkList() as PlinkListResponse
|
||||
const uniqueTags = Array.from(new Set(res.data.flatMap((item) => getTags(item.tagname))))
|
||||
tagColorList.value = buildTagColorMap(uniqueTags)
|
||||
pList.value = res.data
|
||||
}
|
||||
function getTags(str: any) {
|
||||
str = str.replaceAll(',', ',')
|
||||
let tags = str.split(',').slice(0, 3)
|
||||
tags.forEach((tag: any, idx: number) => {
|
||||
tags[idx] = tag.trim().slice(0, 4)
|
||||
});
|
||||
return tags
|
||||
}
|
||||
|
||||
function gotoWebsite(url: string) {
|
||||
if (!url) return
|
||||
window.open(url, '_blank')
|
||||
}
|
||||
|
||||
function submitPut() {
|
||||
formRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
$msg.error('请完善表单~~')
|
||||
} else {
|
||||
const res = await $http.plink.addPlink(plinkData)
|
||||
if (res?.code !== 200) {
|
||||
$msg.error(res.msg)
|
||||
return
|
||||
}
|
||||
$msg.success(res.msg)
|
||||
plinkData.name = ''
|
||||
plinkData.title = ''
|
||||
plinkData.avater = ''
|
||||
plinkData.url = ''
|
||||
plinkData.desc = ''
|
||||
plinkData.tagname = ''
|
||||
getPlinkList()
|
||||
}
|
||||
})
|
||||
function resetFormData() {
|
||||
plinkData.name = ''
|
||||
plinkData.title = ''
|
||||
plinkData.avater = ''
|
||||
plinkData.url = ''
|
||||
plinkData.desc = ''
|
||||
plinkData.tagname = ''
|
||||
}
|
||||
|
||||
// 生成一个随机的鲜艳颜色,和白色能对比
|
||||
|
||||
function getRandomFromPalette(): string {
|
||||
const hue = Math.floor(Math.random() * 360);
|
||||
return hslToHex(hue, 80, 50);
|
||||
}
|
||||
|
||||
function hslToHex(h: number, s: number, l: number): any {
|
||||
l /= 100;
|
||||
const a = s * Math.min(l, 1 - l) / 100;
|
||||
const f = (n: number) => {
|
||||
const k = (n + h / 30) % 12;
|
||||
const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
|
||||
return Math.round(255 * color).toString(16).padStart(2, '0');
|
||||
function fillForm() {
|
||||
const token = $cookies.get('token')
|
||||
if (!token) {
|
||||
$msg.warning('请先登录后再一键填入')
|
||||
return
|
||||
}
|
||||
return `#${f(0)}${f(8)}${f(4)}`;
|
||||
|
||||
const userinfo = ($cookies.get('userinfo') || {}) as UserCookieInfo
|
||||
plinkData.name = userinfo.nickname || ''
|
||||
plinkData.avater = userinfo.ava_url || ''
|
||||
}
|
||||
|
||||
function getActiveForm() {
|
||||
if (screenWidth.value >= 1280) return formRef.value || mobileFormRef.value
|
||||
return mobileFormRef.value || formRef.value
|
||||
}
|
||||
|
||||
async function submitPut() {
|
||||
const activeForm = getActiveForm()
|
||||
if (!activeForm) return
|
||||
|
||||
try {
|
||||
await activeForm.validate()
|
||||
} catch {
|
||||
$msg.error('请先完善表单内容')
|
||||
return
|
||||
}
|
||||
|
||||
const res = await $http.plink.addPlink(plinkData)
|
||||
if (res?.code !== 200) {
|
||||
$msg.error(res.msg)
|
||||
return
|
||||
}
|
||||
|
||||
$msg.success(res.msg)
|
||||
resetFormData()
|
||||
await getPlinkList()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
boxStyle.value = {
|
||||
height: window.innerHeight - nav.navH - 1 + 'px',
|
||||
}
|
||||
getPlinkList()
|
||||
updateLayout()
|
||||
void getPlinkList()
|
||||
window.addEventListener('resize', updateLayout)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('resize', updateLayout)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 无限旋转动画 */
|
||||
<style scoped lang="less">
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
@@ -236,8 +441,58 @@ onMounted(() => {
|
||||
animation: spin 1.5s linear infinite;
|
||||
}
|
||||
|
||||
:deep(.n-form-item) {
|
||||
grid-template-rows: unset !important;
|
||||
}
|
||||
|
||||
:deep(.btn.n-form-item) {
|
||||
.n-form-item-feedback-wrapper {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.compact-side-form .n-input) {
|
||||
--n-height: 38px !important;
|
||||
}
|
||||
|
||||
:deep(.n-form-item-feedback__line) {
|
||||
text-align: right;
|
||||
font-size: 12px !important;
|
||||
color: #8b96a3;
|
||||
}
|
||||
</style>
|
||||
|
||||
:deep(.n-input),
|
||||
:deep(.n-input .n-input-wrapper),
|
||||
:deep(.n-input .n-input__textarea) {
|
||||
background: rgba(255, 255, 255, 0.72) !important;
|
||||
border-radius: 18px !important;
|
||||
}
|
||||
|
||||
:deep(.n-input) {
|
||||
--n-border: 1px solid rgba(214, 224, 226, 0.92) !important;
|
||||
--n-border-hover: 1px solid rgba(190, 206, 214, 0.98) !important;
|
||||
--n-border-focus: 1px solid rgba(236, 102, 171, 0.52) !important;
|
||||
--n-box-shadow-focus: 0 0 0 4px rgba(236, 102, 171, 0.1) !important;
|
||||
}
|
||||
|
||||
:deep(.n-input__input-el),
|
||||
:deep(.n-input__textarea-el) {
|
||||
color: #314155 !important;
|
||||
}
|
||||
|
||||
:deep(.n-input__placeholder) {
|
||||
color: #95a3b2 !important;
|
||||
}
|
||||
|
||||
:deep(.n-input__placeholder) {
|
||||
font-size: 13px;
|
||||
|
||||
span {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.n-form-item-feedback__line) {
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user