planet
shenhan 2025-03-03 17:58:26 +08:00
parent e4b2ba69a9
commit f2d8f098e6
55 changed files with 3093 additions and 962 deletions

2
.env.dev 100644
View File

@ -0,0 +1,2 @@
NODE_ENV = 'development'
VITE_NUXT_ENV = 'http://1.13.246.108:8080/'

2
.env.pro 100644
View File

@ -0,0 +1,2 @@
NODE_ENV = 'production'
VITE_NUXT_ENV = 'http://1.13.246.108:8080/'

24
Dockerfile 100644
View File

@ -0,0 +1,24 @@
FROM node:20-slim --platform=linux/amd64 AS base
ENV TZ=Asia/Shanghai
WORKDIR /app
# Build
FROM base AS build
COPY . .
RUN npm config set registry https://registry.npmmirror.com
RUN npm install -g pnpm
RUN pnpm install --registry=https://registry.npmmirror.com
RUN pnpm run build
# Run
FROM base
ENV PORT=3000
ENV NODE_ENV=production
COPY --from=build /app/.output /app/.output
EXPOSE 3000
CMD [ "node", ".output/server/index.mjs" ]

5
app/components.d.ts vendored
View File

@ -8,18 +8,16 @@ export {}
declare module 'vue' {
export interface GlobalComponents {
NAvatar: typeof import('naive-ui')['NAvatar']
NBadge: typeof import('naive-ui')['NBadge']
NButton: typeof import('naive-ui')['NButton']
NCard: typeof import('naive-ui')['NCard']
NCarousel: typeof import('naive-ui')['NCarousel']
NCascader: typeof import('naive-ui')['NCascader']
NCheckbox: typeof import('naive-ui')['NCheckbox']
NCheckboxGroup: typeof import('naive-ui')['NCheckboxGroup']
NConfigProvider: typeof import('naive-ui')['NConfigProvider']
NDatePicker: typeof import('naive-ui')['NDatePicker']
NDropdown: typeof import('naive-ui')['NDropdown']
NEllipsis: typeof import('naive-ui')['NEllipsis']
NEmpty: typeof import('naive-ui')['NEmpty']
NFor: typeof import('naive-ui')['NFor']
NForm: typeof import('naive-ui')['NForm']
NFormItem: typeof import('naive-ui')['NFormItem']
NIcon: typeof import('naive-ui')['NIcon']
@ -30,7 +28,6 @@ declare module 'vue' {
NModal: typeof import('naive-ui')['NModal']
NQrCode: typeof import('naive-ui')['NQrCode']
NRadio: typeof import('naive-ui')['NRadio']
NRadioButton: typeof import('naive-ui')['NRadioButton']
NRadioGroup: typeof import('naive-ui')['NRadioGroup']
NSelect: typeof import('naive-ui')['NSelect']
NSpace: typeof import('naive-ui')['NSpace']

View File

@ -29,7 +29,7 @@ const commentParams = ref({
content: '',
parentId: '',
replyUserId: '',
userId: userStore.userInfo.userId,
userId: userStore?.userInfo?.userId,
workFlowId: props.detailsInfo.id,
})
function commentParamsInit() {
@ -44,9 +44,9 @@ const sortType = ref(1)
//
const urlList = ref({
workflow: '/WorkFlowComment/comment?',
pictrue: '/imageComment/comment?',
model: '/ModelComment/comment?',
workflow: '/WorkFlowComment/getComment?',
pictrue: '/imageComment/getComment?',
model: '/ModelComment/getComment?',
})
//
const likeList = ref({
@ -253,10 +253,10 @@ function changeType(type: string) {
</div>
</div>
<div class="header-wrap">
<div v-if="userStore.userInfo.avatar" class="left">
<div v-if="userStore?.userInfo?.avatar" class="left">
<img
alt="avatar"
:src="userStore.userInfo.avatar"
:src="userStore?.userInfo?.avatar"
>
</div>
<div class="input-wrap">
@ -304,7 +304,7 @@ function changeType(type: string) {
<span style="vertical-align: middle">{{ item.likeNum }}</span>
</div>
<span class="cursor-pointer m-r16" @click="handleMessage(item)"></span>
<span v-if="item.userId === userStore.userInfo.userId" class="cursor-pointer" @click="handleDel(item)"></span>
<span v-if="item.userId === userStore?.userInfo?.userId" class="cursor-pointer" @click="handleDel(item)"></span>
</div>
</div>
<!-- 父项评论回复操作 -->
@ -351,7 +351,7 @@ function changeType(type: string) {
<span style="vertical-align: middle">{{ ele.likeNum }}</span>
</div>
<span class="cursor-pointer m-r16" @click="handleMessage(ele)"></span>
<span v-if="item.userId === userStore.userInfo.userId" class="cursor-pointer" @click="handleDel(ele)"></span>
<span v-if="item.userId === userStore?.userInfo?.userId" class="cursor-pointer" @click="handleDel(ele)"></span>
</div>
</div>
<!-- 子项评论回复操作 -->

View File

@ -1,6 +1,6 @@
<script setup lang="ts">
import { ref } from 'vue'
import { uploadImagesInBatches } from '../utils/uploadImg.ts'
import { ref } from 'vue';
import { uploadImagesInBatches } from '../utils/uploadImg.ts';
const userStore = useUserStore()
const userInfo = userStore.userInfo

View File

@ -0,0 +1,14 @@
<template>
<div class="h-[300px] flex items-center">
<n-empty description="你什么也找不到">
<!-- <template #extra>
<n-button size="small"> 看看别的 </n-button>
</template> -->
暂无作品
</n-empty>
</div>
</template>
<script setup lang="ts"></script>
<style scoped></style>

View File

@ -45,7 +45,9 @@ function onSearch(value: any) {
console.log("搜索:", value);
//
}
function initSearch(){
console.log( 'initSearch');
}
//
const notificationOptions = [
{
@ -85,20 +87,20 @@ const publishOptions = [
const userOptions = ref([
{
label: "我的模型",
key: "model",
key: "0",
},
{
label: "我的作品",
key: "project",
key: "2",
},
{
label: "我的点赞",
key: "like",
},
{
label: "账号设置",
key: "userSettings",
},
// {
// label: "",
// key: "userSettings",
// },
{
label: "退出登录",
key: "logout",
@ -115,10 +117,17 @@ async function handleUserSelect(key: string) {
} catch (error) {
console.error("Logout failed:", error);
}
}else if(key === "like"){
router.push(`/personal-center?type=${key}`)
}else{
router.push(`/personal-center?status=${key}`)
}
}
//
async function handlePublishSelect(key: string) {
if (!userStore.isLoggedIn) {
modalStore.showLoginModal();
} else {
if (key === "picture") {
isShowPublishPicture.value = true;
if (PublishPictureRef.value) {
@ -134,6 +143,7 @@ async function handlePublishSelect(key: string) {
// },
// })
}
}
}
function closePublishImg() {
isShowPublishPicture.value = false;
@ -147,6 +157,7 @@ function handleLogin() {
}
const msgList = ref([]);
const isRead = ref('0')
async function getAllMessage() {
try {
const res = await request.get("/advice/getAllMsg");
@ -157,12 +168,12 @@ async function getAllMessage() {
console.log(err);
}
}
getAllMessage();
// getAllMessage();
//
function toDetail(){
const baseUrl = window.location.origin
window.open(`${baseUrl}/message`, '_blank', 'noopener,noreferrer')
function toDetail() {
const baseUrl = window.location.origin;
window.open(`${baseUrl}/message`, "_blank", "noopener,noreferrer");
}
onMounted(() => {});
@ -179,7 +190,12 @@ onMounted(() => {});
<div class="flex items-center gap-2">
<NuxtLink to="/" class="text-xl font-semibold tracking-tight no-underline">
<!-- <img src="/vite.png" alt="Logo" class="h-9 w-9" /> -->
魔创未来
<!-- 魔创未来 -->
<img
src="https://liblibai-web-static.liblib.cloud/liblibai_v4_online/static/_next/static/images/icon-logo.e3ce24f316fb81dbde1cafc3bf956080.svg"
alt=""
/>
<!-- <a class="Topbar_iconLogo__RhuYB" style="background-image: url(&quot;https://liblibai-web-static.liblib.cloud/liblibai_v4_online/static/_next/static/images/icon-logo.e3ce24f316fb81dbde1cafc3bf956080.svg&quot;);"></a> -->
</NuxtLink>
<!-- <span class="text-xl font-semibold tracking-tight">魔创未来</span> -->
</div>
@ -196,10 +212,13 @@ onMounted(() => {});
<!-- Right Actions -->
<NSpace align="center" :size="24">
<!-- PC Client -->
<NButton text class="header-btn-primary">
<div class="header-btn-primary">
<Monitor class="h-4 w-4 mr-1" />
<span>PC客户端</span>
</NButton>
</div>
<!-- <NButton text class="header-btn-primary">
</NButton> -->
<!-- Tutorials -->
<NButton text class="header-btn">
@ -207,12 +226,17 @@ onMounted(() => {});
<span>教程专区</span>
</NButton>
<!-- <div class="header-btn">
<GraduationCap class="h-4 w-4 mr-1" />
<span>教程专区</span>
</div> -->
<NDropdown
:options="publishOptions"
trigger="hover"
:on-select="handlePublishSelect"
>
<NButton text class="header-btn">
<NButton text class="header-btn" size="large">
<CirclePlus class="h-4 w-4 mr-1" />
<span>发布</span>
</NButton>
@ -235,6 +259,7 @@ onMounted(() => {});
</NButton>
</NBadge>
</NDropdown> -->
<client-only v-if="userStore.token">
<div
class="p-1 bg-[#f1f1f6] rounded-full flex items-center justify-center relative group"
>
@ -244,11 +269,11 @@ onMounted(() => {});
class="border-solid border border-[#f0f0f0] py-2 w-[300px] rounded-lg bg-white"
>
<div
class="border-b-solid border-b border-b-[#f0f0f0] p-2 text-sm font-bold"
class="border-b-solid border-b border-b-[#f0f0f0] p-4 text-sm font-bold"
>
通知
</div>
<div class="p-2 max-h-[300px] overflow-y-auto">
<div class="px-4 py-2 max-h-[300px] overflow-y-auto">
<div
v-for="(item, index) in msgList"
:key="index"
@ -276,15 +301,20 @@ onMounted(() => {});
更多通知可点击查看全部~
</div>
<div class="flex justify-center">
<div class="bg-[#4c79ee] w-[270px] h-10 flex items-center justify-center rounded-lg text-white cursor-pointer" @click="toDetail">
<div
class="bg-[#4c79ee] w-[270px] h-10 flex items-center justify-center rounded-lg text-white cursor-pointer"
@click="toDetail"
>
查看全部
</div>
</div>
</div>
</div>
</div>
</client-only>
<!-- User -->
<div class="min-w-10">
<div class="min-w-10 flex items-center">
<client-only>
<NDropdown
v-if="userStore.token"
@ -296,12 +326,12 @@ onMounted(() => {});
class="cursor-pointer w-10 h-10"
round
size="small"
:src="userStore.userInfo.avatar"
:src="userStore?.userInfo?.avatar"
/>
</NDropdown>
<div
v-if="!userStore.token"
class="flex text-white bg-[#197dff] rounded-[4px] px-4 py-2 text-xs cursor-pointer hover:bg-[#1a6eff]"
class="flex text-white bg-gradient-to-r from-[#197dff] to-[#2c4dff] rounded-[4px] px-4 py-2 text-xs cursor-pointer hover:bg-[#1a6eff]"
@click="handleLogin"
>
登录/注册
@ -328,9 +358,9 @@ onMounted(() => {});
<style scoped>
.header-btn-primary {
@apply border border-solid border-[#3162ff] px-1 py-1 text-[#3162ff] rounded-md hover:text-[#3162ff];
@apply border border-solid border-[#3162ff] px-1 py-1 text-[#3162ff] rounded-md hover:text-[#3162ff] flex items-center cursor-pointer;
}
.header-btn {
@apply bg-[#f1f1f7] font-bold px-2 py-2 rounded flex items-center hover:text-black hover:bg-[#f1f1f7];
@apply bg-[#f1f1f7] font-bold px-2 py-2 rounded flex items-center hover:text-black hover:bg-[#f1f1f7] focus:text-blue-600;
}
</style>

View File

@ -1,42 +1,80 @@
<!-- components/SearchInput.vue -->
<script setup>
import { CloseCircle } from '@vicons/ionicons5'
import {
Camera,
Search,
} from 'lucide-vue-next'
const props = defineProps({
modelValue: {
type: String,
default: '',
},
})
const emit = defineEmits(['update:modelValue', 'search'])
import { CloseCircle } from "@vicons/ionicons5";
import { Camera, Search } from "lucide-vue-next";
import { computed } from 'vue';
import { useRoute } from "vue-router";
const modalStore = useModalStore();
const route = useRoute();
// const currentPath = route.path;
const searchType = ref({
"/picture-square": "image",
"/work-square": "workFlow",
});
// const props = defineProps({
// modelValue: {
// type: String,
// default: "",
// },
// });
// const emit = defineEmits(["update:modelValue", "initSearch"]);
const keyword = ref("");
if (modalStore.searchQuery) {
keyword.value = modalStore.searchQuery;
}
function handleSearch() {
if (props.modelValue) {
emit('search', props.modelValue)
if (keyword.value) {
modalStore.updateSearchQuery(keyword.value);
if (route.path !== "/search") {
const baseUrl = window.location.origin;
const type = searchType.value[route.path]
debugger
window.open(
`${baseUrl}/search?keyword=${keyword.value}&type=${type}`,
"_blank",
"noopener,noreferrer"
);
// router.push({
// path: `/search`,
// query: {
// keyword: props.modelValue,
// type:searchType[currentPath]
// },
// });
} else {
// modalStore.updateSearchQuery(keyword.value);
// this.$store.dispatch('updateSearchQuery', props.modelValue)
}
}
}
function clearInput() {
emit('update:modelValue', '')
keyword.value = ''
modalStore.searchQuery = ''
// modalStore.updateSearchQuery('')
// emit("update:modelValue", "");
}
const searchQuery = computed(() => modalStore.searchQuery);
watch(searchQuery, (newValue) => {
keyword.value = newValue
});
</script>
<template>
<!-- // @input="$emit('update:modelValue', $event.target.value)" -->
<!-- :value="modalStore.searchQuery" -->
<div class="relative flex items-center bg-[#f1f2f7] rounded-md px-2 py-2">
<input
type="text"
:value="modelValue"
v-model="keyword"
placeholder="搜索模型/图片/创作者寻找灵感"
class="w-[280px] h-4 bg-[#f1f2f7] rounded-md border-0 outline-none text-gray-800 text-[12px] placeholder:text-gray-400"
@input="$emit('update:modelValue', $event.target.value)"
@keyup.enter="handleSearch"
>
/>
<div class="flex items-center w-5 mr-2">
<n-icon v-if="modelValue" size="20" class="cursor-pointer" @click="clearInput">
<n-icon v-if="keyword" size="20" color="#ccc" class="cursor-pointer" @click="clearInput">
<CloseCircle />
</n-icon>
</div>
@ -46,5 +84,4 @@ function clearInput() {
</div>
</template>
<style scoped>
</style>
<style scoped></style>

View File

@ -57,7 +57,7 @@ async function getQrCode() {
pollingTimer && clearTimeout(pollingTimer)
pollingTimer = setInterval(async () => {
try {
const res2 = await request.get(`/web/pay/queryTradeStatus?outTradeNo=${res.data.orderNo}`)
const res2 = await request.get(`/order/queryTradeStatus?outTradeNo=${res.data.orderNo}`)
if (res2.data === 2) { // 1 2 4
paymentStatus.value = 2
clearTimeout(pollingTimer)

View File

@ -1,7 +1,7 @@
<script setup lang="ts">
import type { FormInst, FormRules } from 'naive-ui'
import phoneImg from '@/assets/img/phone.png'
import wechatImg from '@/assets/img/wechat.png'
import type { FormInst, FormRules } from 'naive-ui'
import { createDiscreteApi } from 'naive-ui'
import { ref } from 'vue'
@ -99,7 +99,8 @@ async function handleValidateClick(e: MouseEvent) {
})
userStore.setUserInfo(res1.user)
onCloseLogin()
window.location.href = '/'
window.location.reload();
// window.location.href = '/'
}
else {
console.log(errors)

View File

@ -0,0 +1,42 @@
<template>
<div class="flex gap-2">
<div
class="flex flex-wrap"
:class="[
'overflow-hidden transition-all duration-200',
isExpanded ? 'max-h-[1000px]' : 'max-h-[2rem]',
]"
>
<slot></slot>
</div>
<button @click="isExpanded = !isExpanded" class="flex-shrink-0 w-6 h-6 mt-1">
<!-- <svg
xmlns="http://www.w3.org/2000/svg"
:class="[
'transform transition-transform duration-200',
isExpanded ? 'rotate-90' : '',
]"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
> -->
<ChevronsDown size="20" class="text-gray-600" :class="[
'transform transition-transform duration-200',
isExpanded ? 'rotate-180' : '',
]"
viewBox></ChevronsDown>
<!-- <polyline points="9 18 15 12 9 6" /> -->
<!-- </svg> -->
</button>
</div>
</template>
<script setup>
import {
ChevronsDown
} from "lucide-vue-next";
import { ref } from "vue";
const isExpanded = ref(false);
</script>

View File

@ -1,13 +1,13 @@
<template>
<div class="flex flex-wrap justify-center">
<div class="grid grid-cols-2 lg:grid-cols-4 xl:grid-cols-5 2xl:grid-cols-7 gap-4 p-4">
<div class="grid grid-cols-2 lg:grid-cols-4 xl:grid-cols-5 2xl:grid-cols-6 gap-4 p-4">
<div
v-for="item in dataList"
:key="item.id"
class="relative rounded-lg overflow-hidden"
>
<!-- 图片 -->
<div class="relative h-[300px] overflow-hidden rounded-lg" @click="toDetail(item)">
<div class="relative border border-solid border-[#e5e7eb] h-[300px] overflow-hidden rounded-lg" @click="toDetail(item)">
<img
:src="item.surfaceUrl"
class="w-full h-full object-cover rounded-lg cursor-pointer ransform transition-transform duration-300 hover:scale-110"
@ -42,14 +42,19 @@
<!-- 作者信息条 -->
<div class="mt-1 px-2 py-1">
<div>
<span class="text-[#19191c] text-[14px]">
{{ item.modelName }}
</span>
</div>
<div class="flex mt-2">
<img :src="item.avatar" class="w-5 h-5 rounded-full mr-2" alt="" />
<span class="text-sm text-gray-500 truncate">{{ item.nickName }}</span>
<div class="flex mt-1">
<img :src="item.avatar" class="w-4 h-4 rounded-full mr-2" alt="" />
<span class="text-xs text-gray-500 truncate">{{ item.nickName }}</span>
</div>
</div>
</div>
<div v-if="!loading && dataList.length === 0">
<Empty></Empty>
</div>
</div>
<div
ref="loadingTrigger"
@ -64,8 +69,7 @@
<script setup lang="ts">
import { Download, Play } from "lucide-vue-next";
import { nextTick, onMounted, onUnmounted, ref } from "vue";
import { useRouter } from 'vue-router';
const router = useRouter()
const emit = defineEmits(['modelTotal'])
const loading = ref(false);
const finished = ref(false);
@ -114,6 +118,7 @@ async function getDataList() {
}
//
listParams.value.pageNumber++;
emit('modelTotal', total.value)
}
} catch (err) {
dataList.value = [];
@ -128,7 +133,9 @@ getDataList();
//
function toDetail(item:any){
router.push(`/model-details/${item.id}`)
// router.push(`/model-details/${item.id}`)
const baseUrl = window.location.origin
window.open(`${baseUrl}/model-details/${item.id}`, '_blank', 'noopener,noreferrer')
}
onMounted(() => {

View File

@ -1,7 +1,7 @@
<script setup lang="ts">
import { RotateCcw, X } from 'lucide-vue-next'
import { useMessage } from 'naive-ui'
import { defineProps, onBeforeMount, onBeforeUnmount, ref } from 'vue'
import { RotateCcw, X } from 'lucide-vue-next';
import { useMessage } from 'naive-ui';
import { defineProps, onBeforeMount, onBeforeUnmount, ref } from 'vue';
const props = defineProps({
info: {
@ -89,7 +89,7 @@ async function getQrCode() {
pollingTimer && clearTimeout(pollingTimer)
pollingTimer = setInterval(async () => {
try {
const res2 = await request.get(`/web/pay/queryTradeStatus?outTradeNo=${res.data.orderNo}`)
const res2 = await request.get(`/order/queryTradeStatus?outTradeNo=${res.data.orderNo}`)
if (res2.data === 2) {
paymentStatus.value = 2
clearTimeout(pollingTimer)

View File

@ -5,6 +5,7 @@ Download,
EllipsisVertical,
Play
} from 'lucide-vue-next';
import { NConfigProvider, NMessageProvider } from "naive-ui";
import { nextTick, ref } from 'vue';
import { useRouter } from 'vue-router';
@ -206,7 +207,7 @@ function updateLike(type:number){
<div>
<div v-if="currentState === 'like' && currentType === '2'">
<div
class="h-80 rounded-2xl overflow-hidden cursor-pointer relative group"
class="h-80 rounded-2xl border border-solid border-[#e5e7eb] overflow-hidden cursor-pointer relative group"
@click="toDetails"
>
<img
@ -238,7 +239,7 @@ function updateLike(type:number){
</div>
<div v-else>
<div
class="h-80 rounded-2xl overflow-hidden cursor-pointer relative"
class="h-80 rounded-2xl overflow-hidden cursor-pointer relative border border-solid border-[#e5e7eb]"
@click="toDetails"
>
<img v-if="currentType === '0'" class="w-full h-full object-cover block" :src="item.surfaceUrl" alt="">
@ -334,7 +335,7 @@ function updateLike(type:number){
</div>
</div>
<div v-if="currentType !== '2'" class="mt-2 text-[12px] text-[#67787e]">
<div class="text-[#000] mb-1">
<div class="text-[#19191c] text-[14px]">
<span v-if="currentType === '0'">
{{ item.modelName }}
</span>
@ -344,13 +345,13 @@ function updateLike(type:number){
<!-- <span>{{ item.userName }}</span> -->
</div>
<div class="flex">
<div class="flex mt-1">
<img
class="block w-[20px] h-[20px] rounded-full mr-2"
class="block w-4 h-4 rounded-full mr-2"
:src="item.userAvatar"
alt=""
>
<span>{{ item.userName }} </span>
<span class="text-xs text-gray-500">{{ item.userName }} </span>
</div>
</div>
</div>

View File

@ -0,0 +1,204 @@
<script setup lang="ts">
import {
Download, Play
} from 'lucide-vue-next';
import { NConfigProvider, NMessageProvider } from "naive-ui";
import { ref } from 'vue';
import { useRouter } from 'vue-router';
const props = defineProps({
item: {
type: Object,
default: () => ({}),
},
currentType: {
type: String,
default: '',
},
})
// emit
const emit = defineEmits(['topedRefresh'])
const router = useRouter()
//
function toDetails() {
if (props.currentType === '0') {
router.push(`/model-details/${props.item.id}`)
}
else if (props.currentType === '1') {
// console.log('object', 111);
router.push(`/workflow-details/${props.item.id}`)
}else if(props.currentType === '2'){
// onEditPicture()
}
}
//
const publishPictureData = ref<any>({})
async function getPublishPicture() {
try {
const res = await request.get(`/image/detail?id=${props.item.id}`)
if (res.code === 200) {
publishPictureData.value = res.data
publishPictureData.value.imagePaths = res.data.imagePaths.split(',')
// publishPictureData.value.tags = res.data.tags.split(',')
}
}
catch (e) {
console.log(e)
}
}
function getFirstImagePath(imagePaths: string): string {
if (!imagePaths)
return ''
return imagePaths.split(',')[0] || ''
}
//
const isShowPublishPicture = ref<boolean>(false)
const PublishPictureRef = ref<Payment | null>(null)
function showPublishImg() {
isShowPublishPicture.value = true
if (PublishPictureRef.value) {
PublishPictureRef.value.isVisible = true
}
}
function closePublishImg() {
isShowPublishPicture.value = false
if (PublishPictureRef.value) {
PublishPictureRef.value.isVisible = false
}
}
</script>
<template>
<div>
<div>
<div
class="h-80 rounded-2xl overflow-hidden cursor-pointer relative"
@click="toDetails"
>
<img v-if="currentType === '0'" class="rounded-2xl w-full h-full object-cover block border border-solid border-[#e5e7eb]" :src="item.surfaceUrl" alt="">
<img v-if="currentType === '1'" class="rounded-2xl w-full h-full object-cover block border border-solid border-[#e5e7eb]" :src="item.coverPath" alt="">
<img v-if="currentType === '2'" class="rounded-2xl w-full h-full object-cover block border border-solid border-[#e5e7eb]" :src="getFirstImagePath(item.imagePaths)" alt="">
<div
v-if="item.isTop === 1"
class="text-[#58c08e] border-[#58c08e] border-solid border-[1px] bg-white rounded-lg px-1 w-10 text-[12px] ml-2 text-center absolute top-4 right-8"
>
置顶
</div>
<div
class="modelSelectByUserIdModel w-full h-full top-0 left-0 flex px-4 py-4 box-border"
>
<div
v-if="currentType === '0'"
class="text-white text-[12px] px-3 bg-[#000] bg-opacity-40 rounded-lg h-[20px] leading-relaxed"
>
<span>
{{ item.modelType }}
</span>
</div>
<div
v-if="currentType === '1'"
class="text-white text-[12px] px-3 bg-[#000] bg-opacity-40 rounded-lg h-[20px] leading-relaxed"
>
工作流
</div>
<div
v-if="currentType !== '2'"
class="absolute bottom-0 left-0 px-4 py-2 text-white box-border flex justify-between items-center"
>
<component :is="Play" class="h-[14px] w-[14px] text-white menu-icon m-1" />
<span v-if="currentType === '0'">
{{ item.reals || 0 }}
</span>
<span v-if="currentType === '1'">
{{ item.useNumber || 0 }}
</span>
<component
:is="Download"
class="h-[14px] w-[14px] text-white menu-icon m-1"
/>
<span v-if="currentType === '0'">
{{ item.numbers || 0 }}
</span>
<span v-if="currentType === '1'">
{{ item.downloadNumber || 0 }}
</span>
</div>
</div>
</div>
<div v-if="currentType !== '2'" class="mt-2 text-[12px] text-[#67787e]">
<div class="text-[#000] mb-1">
<span v-if="currentType === '0'">
{{ item.modelName }}
</span>
<span v-if="currentType === '1'">
{{ item.workflowName }}
</span>
<!-- <span>{{ item.userName }}</span> -->
</div>
<div class="flex">
<img
class="block w-[20px] h-[20px] rounded-full mr-2"
:src="item.userAvatar"
alt=""
>
<span>{{ item.userName }} </span>
</div>
</div>
</div>
<NConfigProvider>
<NMessageProvider>
<Publish-picture v-if="isShowPublishPicture" type="edit" ref="PublishPictureRef" :form-data="publishPictureData" @close-publish-img="closePublishImg" />
</NMessageProvider>
</NConfigProvider>
</div>
</template>
<style lang="scss">
.modelSelectByUserIdModel {
position: absolute;
&:hover {
.modelSelectByUserIdModel-mask {
display: block;
}
}
.modelSelectByUserIdModel-mask {
position: absolute;
width: 100%;
display: none;
.menu-content {
width: 20px;
height: 30px;
position: absolute;
right: 10px;
}
.menu-content:hover {
.menu-group {
display: block;
}
}
.menu-group {
position: absolute;
top: 10px;
right: 0;
.menu-item {
padding: 4px 0 4px 0;
margin: 4px;
border-radius: 2px;
&:hover {
background-color: #eeeded;
// border: solid;
}
}
}
}
}
</style>

View File

@ -1,13 +1,12 @@
<script setup lang="ts">
import { commonApi } from "@/api/common";
import { CopyOutline, Heart } from "@vicons/ionicons5";
import { CopyOutline, Heart, PersonAddOutline } from '@vicons/ionicons5';
import { Download, PartyPopper } from "lucide-vue-next";
import { NConfigProvider, NMessageProvider } from "naive-ui";
import { ref } from "vue";
const emit = defineEmits(["updateLike"]);
const userStore = useUserStore();
const userInfo = userStore.userInfo;
const message = useMessage();
const props = defineProps({
item: {
@ -16,11 +15,16 @@ const props = defineProps({
},
});
const dataInfo = ref({});
const isAttention = ref(false)
async function getDetail() {
if (props.item && props.item.id) {
const res = await request.get(`/image/detail?id=${props.item.id}`);
if (res.code === 200) {
dataInfo.value = res.data;
const res1 = await request.get(`/attention/selectAttention?userId=${res.data.userId}`)
if(res1.code === 200){
isAttention.value = res1.data
}
getDictType();
}
}
@ -78,6 +82,27 @@ async function onLike() {
console.log(err);
}
}
// /
async function onChangeAttention() {
try {
const res = await request.get(`/attention/addAttention?userId=${dataInfo.value.userId}`)
if (res.code === 200) {
isAttention.value = res.data
if (res.data) {
message.success('关注成功')
}
else {
message.success('取消关注成功')
}
}
}
catch (err) {
console.log(err)
}
}
defineExpose({
isVisible,
});
@ -95,7 +120,7 @@ defineExpose({
<div class="p-2 w-[700px]" style="box-sizing: border-box">
<div class="flex w-full">
<div class="flex-1 p-1">
<img class="w-full h-[300px]" :src="dataInfo.imagePaths" alt="" />
<img class="w-full h-[350px] rounded-lg" :src="item.imagePaths" alt="" />
<div class="flex mt-2">
<div
class="mr-2 w-40 px2 py-3 flex items-center justify-center text-[#8a4200] cursor-pointer rounded-lg bg-gradient-to-r from-[#ffe9c8] to-[#ffd264]"
@ -124,11 +149,26 @@ defineExpose({
</div>
<div class="flex-1 p-1">
<div class="flex items-center">
<img class="w-10 h-10 rounded-full mr-2" :src="dataInfo.userAvatar" alt="" />
<div>
<img
class="w-10 h-10 rounded-full mr-2"
:src="dataInfo.userAvatar"
alt=""
/>
<div>
{{ dataInfo.userName }}
</div>
</div>
<div class="flex-1 flex justify-end" v-if="userStore?.userInfo?.userId !== props.item.userId">
<div class="flex items-center font-bold px-1 justify-center w-24 h-10 rounded-full text-[#426af7] border-2 border-[#426af7] border-solid cursor-pointer" @click="onChangeAttention">
<n-icon v-if="!isAttention" size="20" class="mr-2">
<PersonAddOutline />
</n-icon>
{{ isAttention ? '已关注' : '关注' }}
</div>
</div>
</div>
<div class="text-[20px] mt-3">
{{ dataInfo.title }}

View File

@ -4,12 +4,13 @@
<div
v-for="item in dataList"
:key="item.id"
@click="onEditPicture(item)"
class="relative rounded-lg overflow-hidden"
>
<!-- 图片 -->
<div class="relative h-[300px] overflow-hidden rounded-lg group">
<div class="relative border border-solid border-[#e5e7eb] h-[300px] overflow-hidden rounded-lg group">
<img
:src="item.avatar"
:src="item.imagePaths"
class="w-full h-full object-cover rounded-lg cursor-pointer"
alt=""
/>
@ -73,6 +74,9 @@
</div>
</div> -->
</div>
<div v-if="!loading && dataList.length === 0">
<Empty></Empty>
</div>
</div>
<div
ref="loadingTrigger"
@ -81,11 +85,21 @@
<div v-if="loading">...</div>
<div v-if="finished && dataList.length >= 20"></div>
</div>
<NConfigProvider>
<NMessageProvider>
<div v-if="isShowEditorPicture">
<PictureDetail @close-editor-picture="closeEditorPicture" ref="editUserInfoRef" :item="currentPicture" @update-like="updateLike"/>
</div>
</NMessageProvider>
</NConfigProvider>
</div>
</template>
<script setup lang="ts">
import { Heart } from "@vicons/ionicons5";
import { NConfigProvider, NMessageProvider } from "naive-ui";
const emit = defineEmits(['imageTotal'])
import { nextTick, onMounted, onUnmounted, ref } from "vue";
const loading = ref(false);
@ -137,6 +151,7 @@ async function getDataList() {
}
//
listParams.value.pageNumber++;
emit('imageTotal', total.value)
}
} catch (err) {
dataList.value = [];
@ -202,6 +217,37 @@ async function onLike(item: any) {
console.log(err);
}
}
//
const currentPicture = ref({})
const isShowEditorPicture = ref(false)
interface EditUserInfoType {
isVisible: boolean
}
const editUserInfoRef = ref<EditUserInfoType | null>(null)
function onEditPicture(item:any) {
currentPicture.value = item
isShowEditorPicture.value = true
nextTick(()=>{
if(editUserInfoRef.value){
editUserInfoRef.value.isVisible = true
}
})
}
function closeEditorPicture(){
isShowEditorPicture.value = false
}
function updateLike(type:number){
// if (props.item.isLike === 1) {
// props.item.isLike = 0;
// props.item.likeNum -= 1;
// } else {
// props.item.isLike = 1;
// props.item.likeNum += 1;
// }
}
defineExpose({
initPageNUm,
});

View File

@ -37,9 +37,13 @@ async function handleFileChange(event: Event) {
const files = target.files
if (files && files.length > 0) {
try{
const res = await uploadImagesInBatches(files)
const urlList = res.map(item => item.url)
props.formData.imagePaths.push(...urlList)
}catch(err){
console.log(err);
}
}
target.value = ''
}

View File

@ -0,0 +1,111 @@
<template>
<n-modal
v-model:show="isVisibleReport"
:preset="null"
:mask-closable="false"
transform-origin="center"
class="custom-modal"
>
<div class="bg-white rounded-xl p-4">
<div class="flex items-center justify-between">
<div class="text-xl">举报</div>
<div>
<n-icon size="20" class="mr-2 cursor-pointer" @click="closeReport">
<Close />
</n-icon>
</div>
</div>
<div class="flex flex-col">
<n-radio
class="m-4 text-[#fff000]"
size="large"
v-for="(item, index) in reportList"
:key="index"
:checked="reportParams.reportId === item.dictValue"
value="Definitely Maybe"
name="basic-demo"
@change="handleChange(item)"
>
{{ item.dictLabel }}
</n-radio>
<n-input
v-if="reportParams.reportId !== undefined && reportParams.reportId === '5'"
v-model:value="reportParams.text"
placeholder="点击输入"
type="textarea"
:autosize="{
minRows: 5,
maxRows: 10,
}"
/>
<div
@click="onReport"
class="mt-4 w-[100%] h-10 flex rounded-lg text-white items-center justify-center cursor-pointer"
:class="[
reportParams.reportId !== undefined
? 'bg-[#4c79ee]'
: 'bg-[#cccccc]',
]"
>
确认
</div>
</div>
</div>
</n-modal>
</template>
<script setup lang="ts">
import { commonApi } from "@/api/common";
import { Close } from "@vicons/ionicons5";
//
const isVisibleReport = ref(true);
const reportParams = ref({
reportId: undefined,
text: "",
type:1
});
const reportList = ref([]);
async function getDictType() {
try {
const res = await commonApi.dictType({ type: "report_type" });
if (res.code === 200) {
reportList.value = res.data;
}
} catch (error) {
console.log(error);
}
}
getDictType();
function handleChange(item: any) {
reportParams.value.reportId = item.dictValue;
if (item.dictValue !== "5") {
reportParams.value.text = "";
}
console.log("object", reportParams.value);
}
function closeReport() {
isVisibleReport.value = false;
}
async function onReport(){
if( reportParams.value.reportId !== undefined){
reportParams.value.productId = detailsInfo.value.id
const res = await request.post('/report/addReport', reportParams.value)
}
}
</script>
<style scoped>
.container{
/* position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
opacity: 0.4;
background: #000; */
}
</style>

View File

@ -1,90 +1,85 @@
<script setup>
import { uploadImagesInBatches } from '@/utils/uploadImg.ts'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import { uploadImagesInBatches } from "@/utils/uploadImg.ts";
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
import { onBeforeUnmount, onMounted, shallowRef } from 'vue'
import '@wangeditor/editor/dist/css/style.css'
import "@wangeditor/editor/dist/css/style.css";
import { onBeforeUnmount, onMounted, shallowRef } from "vue";
const props = defineProps({
modelValue: {
type: Object,
required: true,
},
})
});
// css
const emit = defineEmits(['update:modelValue'])
const emit = defineEmits(["update:modelValue"]);
const mode = 'default'
const mode = "default";
// shallowRef
const editorRef = shallowRef()
const editorRef = shallowRef();
const localForm = computed({
get() {
return props.modelValue
return props.modelValue;
},
set(value) {
emit('update:modelValue', value)
emit("update:modelValue", value);
},
})
});
watch(
() => localForm.value,
(newVal) => {
emit('update:modelValue', newVal)
emit("update:modelValue", newVal);
},
{ immediate: true, deep: true },
)
{ immediate: true, deep: true }
);
// HTML
const valueHtml = ref('')
const valueHtml = ref("");
// ajax
onMounted(() => {
// setTimeout(() => {
// valueHtml.value = '<p> Ajax </p>'
// }, 1500)
})
});
const toolbarConfig = {
}
const toolbarConfig = {};
const editorConfig = {
placeholder: '请输入内容...',
placeholder: "请输入内容...",
MENU_CONF: {},
}
};
editorConfig.MENU_CONF.uploadImage = {
//
async customUpload(file, insertFn) {
const files = [file];
try {
const files = [file]
const res = await uploadImagesInBatches(files)
const res = await uploadImagesInBatches(files);
for (let i = 0; i < res.length; i++) {
insertFn(res[i].url)
insertFn(res[i].url);
}
}
catch (error) {
console.log('error', error)
} catch (error) {
console.log("error", error);
}
},
}
};
//
onBeforeUnmount(() => {
const editor = editorRef.value
if (editor == null)
return
editor.destroy()
})
const editor = editorRef.value;
if (editor == null) return;
editor.destroy();
});
function handleCreated(editor) {
editorRef.value = editor // editor
editorRef.value = editor; // editor
}
function handleChange(editor) {
const dom = editor.getHtml()
emit('update:modelValue', dom)
const dom = editor.getHtml();
emit("update:modelValue", dom);
}
</script>
@ -100,7 +95,7 @@ function handleChange(editor) {
<Editor
v-model="localForm"
class="editor"
style="max-height: 500px; min-height: 100px; overflow-y: auto;"
style="max-height: 500px; min-height: 100px; overflow-y: auto"
:default-config="editorConfig"
:mode="mode"
@on-created="handleCreated"
@ -110,8 +105,8 @@ function handleChange(editor) {
</div>
</template>
<style scoped lang='scss'>
.editor .w-e-text {
<style scoped lang="scss">
.editor .w-e-text {
line-height: 1.2; /* 行高为字体大小的 2 倍 */
}
</style>

View File

@ -3,8 +3,8 @@
// import { getUUid, uuidLogin } from '@api/login'
// import { useStore } from '@store/index'
// import { IosRefresh } from '@vicons/ionicons5';
import { RotateCcw } from 'lucide-vue-next'
import { onBeforeUnmount, onMounted, ref } from 'vue'
import { RotateCcw } from 'lucide-vue-next';
import { onBeforeUnmount, onMounted, ref } from 'vue';
//
const emit = defineEmits<{
(event: 'login-success', data: any): void
@ -31,9 +31,9 @@ async function onGetUUid() {
// /wx/uuid/get
const res = await request.get('/wx/uuid/get')
if (res.code === 200) {
const appid = 'wx82d4c3c96f0ffa5b'
const appid = 'wx7d0003f44e27fbfd'
const { uuid } = res
const redirect_uri = `http://rtec8z.natappfree.cc/wx/uuid/bind/openid?uuid=${uuid}`
const redirect_uri = `http://a7u3z9.natappfree.cc/wx/uuid/bind/openid?uuid=${uuid}`
const codeUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${encodeURIComponent(
redirect_uri,
)}&response_type=code&scope=snsapi_userinfo&state=123456#wechat_redirect`
@ -55,7 +55,9 @@ async function onGetUUid() {
token: res.token,
})
userStore.setUserInfo(res1.user)
window.location.href = '/'
// window.location.href = '/'
//
window.location.reload();
}
}).catch(() => {
clearTimeout(pollingTimer)
@ -85,16 +87,17 @@ onBeforeUnmount(() => {
<template>
<div class="w-[280px] px-5 text-center relative">
<div v-if="bindTimeout" class="absolute left-[41px] h-full w-[230px] top-0 z-[9999] flex items-center justify-center flex-col cursor-pointer text-white bg-black/40" @click="onGetUUid">
<div v-if="qrUrl" class="relative w-full">
<div v-if="bindTimeout" class="absolute py-3 left-0 w-full h-full top-0 z-[9999] flex items-center justify-center flex-col cursor-pointer text-white bg-black/40" @click="onGetUUid">
刷新二维码
<RotateCcw />
</div>
<div v-if="qrUrl" class="relative w-full">
<!-- <component
is="RotateCcw"
class="h-[18px] w-[18px] color-white"
/> -->
<n-qr-code style="padding: 0;" class="p-0" :value="qrUrl" :size="qrSize" />
<n-qr-code style="padding: 0;" class="p-0 w-full h-full" :value="qrUrl" :size="qrSize" />
</div>
<div v-else class="p-5 text-gray-400">
加载中...

View File

@ -7,7 +7,7 @@
class="relative rounded-lg overflow-hidden"
>
<!-- 图片 -->
<div class="relative h-[300px] overflow-hidden rounded-lg" @click="toDetail(item)">
<div class="relative border border-solid border-[#e5e7eb] h-[300px] overflow-hidden rounded-lg" @click="toDetail(item)">
<img
:src="item.coverPath"
class="w-full h-full object-cover rounded-lg cursor-pointer ransform transition-transform duration-300 hover:scale-110"
@ -42,14 +42,19 @@
<!-- 作者信息条 -->
<div class="mt-1 px-2 py-1">
<div>
{{ item.workflowNam }}
<span class="text-[#19191c] text-[14px]">
{{ item.workflowName }}
</span>
</div>
<div class="flex mt-2">
<img :src="item.avatar" class="w-5 h-5 rounded-full mr-2" alt="" />
<span class="text-sm text-gray-500 truncate">{{ item.nickName }}</span>
<div class="flex mt-1">
<img :src="item.avatar" class="w-4 h-4 rounded-full mr-2" alt="" />
<span class="text-xs text-gray-500 truncate">{{ item.nickName }}</span>
</div>
</div>
</div>
<div v-if="!loading && dataList.length === 0">
<Empty></Empty>
</div>
</div>
<div
ref="loadingTrigger"
@ -65,6 +70,9 @@
import { Download, Play } from "lucide-vue-next";
import { nextTick, onMounted, onUnmounted, ref } from "vue";
import { useRouter } from 'vue-router';
const emit = defineEmits(['workFlowTotal'])
const modalStore = useModalStore()
const router = useRouter()
const loading = ref(false);
const finished = ref(false);
@ -82,6 +90,7 @@ const listParams = ref({
...props.params,
pageNumber: 1,
pageSize: 20,
name:modalStore.searchQuery
});
function initPageNUm() {
listParams.value.pageNumber = 1;
@ -113,6 +122,7 @@ async function getDataList() {
}
//
listParams.value.pageNumber++;
emit('workFlowTotal', total.value)
}
} catch (err) {
dataList.value = [];
@ -126,8 +136,9 @@ getDataList();
//
function toDetail(item:any){
router.push(`/workflow-details/${item.id}`)
// router.push(`/workflow-details/${item.id}`)
const baseUrl = window.location.origin
window.open(`${baseUrl}/workflow-details/${item.id}`, '_blank', 'noopener,noreferrer')
}
onMounted(() => {
@ -166,18 +177,6 @@ async function topedRefresh() {
initPageNUm();
}
const workFlowCategoryList = ref([]);
async function getDictType() {
try {
const res = await commonApi.dictType({ type: "work_flow_type_child" });
if (res.code === 200) {
workFlowCategoryList.value = res.data;
}
} catch (error) {
console.log(error);
}
}
getDictType();
defineExpose({
initPageNUm,

View File

@ -0,0 +1,13 @@
<template>
<div class="">
</div>
</template>
<script setup lang="ts">
</script>
<style scoped lang="scss">
.
</style>

View File

@ -28,14 +28,14 @@ const props = defineProps({
},
});
async function toDetail(item){
try{
const res = await request.get(`/advice/read?adviceId=${item.id}`)
debugger
async function toDetail(item:any){
// try{
// const res = await request.get(`/advice/read?adviceId=${item.id}`)
// debugger
}catch(err){
console.log(err);
}
// }catch(err){
// console.log(err);
// }
}
</script>

View File

@ -3,6 +3,7 @@
<div
v-for="(item, index) in dataList"
:key="index"
@click="toDetail(item)"
class="bg-white h-20 rounded-lg p-3 mb-2 flex items-center justify-center cursor-pointer relative"
>
<div class="flex-1">
@ -10,7 +11,7 @@
<div class="text-[12px] text-gray-400 mt-1">{{ item.createTime }}</div>
</div>
<div class="w-10 h-10">
<img class="w-full h-full rounded-lg" :src="item.userAvatar" />
<img class="w-full h-full rounded-lg" :src="item.productImag" />
</div>
<div
v-if="item.isRead === 0"
@ -19,16 +20,70 @@
</div>
<n-empty v-if="dataList.length === 0" size="large" description="暂无数据!">
</n-empty>
<NConfigProvider>
<NMessageProvider>
<div v-if="isShowEditorPicture">
<PictureDetail @close-editor-picture="closeEditorPicture" ref="editUserInfoRef" :item="pictureDetail" @update-like="updateLike"/>
</div>
<Publish-picture v-if="isShowPublishPicture" type="edit" ref="PublishPictureRef" :form-data="publishPictureData" @close-publish-img="closePublishImg" />
</NMessageProvider>
</NConfigProvider>
</div>
</template>
<script setup lang="ts">
import { NConfigProvider, NMessageProvider } from "naive-ui";
import { useRouter } from 'vue-router';
const props = defineProps({
dataList: {
type: Object,
default: () => [],
},
});
const router = useRouter()
async function toDetail(item:any){
try{
const res = await request.get(`/advice/read?adviceId=${item.id}`)
if(res.code === 200){
// 0 1 2
if(item.productType === 0){
router.push(`/model-details/${item.productId}`)
}else if(item.productType === 1){
router.push(`/workflow-details/${item.productId}`)
}else{
onEditPicture(item)
}
}
}catch(err){
console.log(err);
}
}
//
const pictureDetail = ref({})
const isShowEditorPicture = ref(false)
interface EditUserInfoType {
isVisible: boolean
}
const editUserInfoRef = ref<EditUserInfoType | null>(null)
async function onEditPicture(item) {
const res = await request.get(`/image/detail?id=${item.productId}`)
if(res.code === 200){
pictureDetail.value = res.data
}
isShowEditorPicture.value = true
nextTick(()=>{
if(editUserInfoRef.value){
editUserInfoRef.value.isVisible = true
}
})
}
function closeEditorPicture(){
isShowEditorPicture.value = false
}
</script>
<style scoped>

View File

@ -10,7 +10,7 @@
<div class="text-[12px] text-gray-400 mt-1">{{ item.createTime }}</div>
</div>
<div class="w-10 h-10 ">
<img class="w-full h-full rounded-lg" :src="item.userAvatar" />
<img class="w-full h-full rounded-lg" :src="item.productImag" />
</div>
<div
v-if="item.isRead === 0"
@ -19,10 +19,19 @@
</div>
<n-empty v-if="dataList.length === 0" size="large" description="暂无数据!">
</n-empty>
<NConfigProvider>
<NMessageProvider>
<div v-if="isShowEditorPicture">
<PictureDetail @close-editor-picture="closeEditorPicture" ref="editUserInfoRef" :item="pictureDetail" @update-like="updateLike"/>
</div>
<Publish-picture v-if="isShowPublishPicture" type="edit" ref="PublishPictureRef" :form-data="publishPictureData" @close-publish-img="closePublishImg" />
</NMessageProvider>
</NConfigProvider>
</div>
</template>
<script setup lang="ts">
import { NConfigProvider, NMessageProvider } from "naive-ui";
import { useRouter } from 'vue-router';
const props = defineProps({
@ -33,24 +42,48 @@ const props = defineProps({
});
const router = useRouter()
async function toDetail(item){
async function toDetail(item:any){
try{
debugger
const res = await request.get(`/advice/read?adviceId=${item.id}`)
if(res.code === 200){
// 0 1 2
if(item.productType === 0){
router.push(`/model-details/${item.id}`)
router.push(`/model-details/${item.productId}`)
}else if(item.productType === 1){
router.push(`/workflow-details/${item.id}`)
router.push(`/workflow-details/${item.productId}`)
}else{
// onEditPicture()
onEditPicture(item)
}
}
}catch(err){
console.log(err);
}
}
//
const pictureDetail = ref({})
const isShowEditorPicture = ref(false)
interface EditUserInfoType {
isVisible: boolean
}
const editUserInfoRef = ref<EditUserInfoType | null>(null)
async function onEditPicture(item) {
const res = await request.get(`/image/detail?id=${item.productId}`)
if(res.code === 200){
pictureDetail.value = res.data
}
isShowEditorPicture.value = true
nextTick(()=>{
if(editUserInfoRef.value){
editUserInfoRef.value.isVisible = true
}
})
}
function closeEditorPicture(){
isShowEditorPicture.value = false
}
</script>
<style scoped>

View File

@ -64,6 +64,7 @@ async function getDictType() {
categoryList.value = res1.data
//
categoryList.value.forEach((item: any) => {
item.dictValue += 99999
// children
item.children = []
//
@ -127,9 +128,9 @@ function handleCategoryUpdateValue(value) {
// localForm.value.modelProduct.category = value.includes('-') ? value : `${value}-0`
// }
}
function changeModelType(item){
debugger
}
// function changeModelType(item){
// debugger
// }
</script>
<template>
@ -146,10 +147,10 @@ function changeModelType(item){
<n-input v-model:value="localForm.modelProduct.modelName" placeholder="输入模型名" />
</n-form-item>
<n-form-item label="模型类型" path="modelProduct.modelType">
<!-- @update:value="changeModelType" -->
<n-select
v-model:value="localForm.modelProduct.modelType"
label-field="dictLabel"
@update:value="changeModelType"
value-field="dictValue"
placeholder="请选择模型类型"
:options="model_category"

View File

@ -36,7 +36,7 @@ const modelVersionItem = {
allowUsage: 1, //
isExclusiveModel: 1, //
hideImageGenInfo:0, //
id:null
};
const isPublicList = [
{
@ -144,9 +144,13 @@ async function handleFileChange(event: Event) {
const files = target.files;
if (files && files.length > 0) {
try{
const res = await uploadImagesInBatches(files);
localForm.value.modelVersionList[uploadFileIndex.value].filePath = res[0].url;
localForm.value.modelVersionList[uploadFileIndex.value].fileName = res[0].fileName;
}catch(err){
console.log(err);
}
}
target.value = "";
}
@ -262,7 +266,7 @@ function onDelete(index: number) {
<n-input v-model:value="item.triggerWords" placeholder="例如: 1boy" />
</n-form-item>
<div v-if="localForm.modelProduct.modelType === '0'">
<!-- <div v-if="localForm.modelProduct.modelType === '0'">
<n-form-item label="采样方法" path="modelVersionType">
<n-select
v-model:value="item.modelVersionType"
@ -275,7 +279,7 @@ function onDelete(index: number) {
<div>
<n-select v-model:value="item.modelVersionType" multiple :options="baseModelTypeList" />
</div>
</div>
</div> -->
<div class="">权限设置</div>
<div class="mt-1 mb-2 text-gray-400 text-[12px]">可见范围</div>

View File

@ -102,9 +102,13 @@ async function handleFileChange(event: Event) {
const sum = localForm.value.modelVersionList[uploadFileIndex.value].sampleImagePaths.length + files.length
if (sum >= 20)
return message.error('最多20张')
try{
const res = await uploadImagesInBatches(files)
const urlList = res.map(item => item.url)
localForm.value.modelVersionList[uploadFileIndex.value].sampleImagePaths.push(...urlList)
}catch(err){
console.log(err);
}
}
target.value = ''
}

View File

@ -1,5 +1,7 @@
<script setup lang="ts">
import { uploadFileBatches } from '@/utils/uploadImg.ts';
// import { uploadFileBatches } from '@/utils/uploadImg.ts';
import { uploadImagesInBatches } from '@/utils/uploadImg.ts';
import { cloneDeep } from 'lodash-es';
import { Asterisk, Trash } from 'lucide-vue-next';
import type { FormInst } from 'naive-ui';
@ -46,6 +48,7 @@ const modelVersionItem = {
fileName: '', //
delFlag: '0',
imagePaths: [],
id:null
}
const rules = {
versionName: {
@ -110,9 +113,16 @@ async function handleFileChange(event: Event) {
const files = target.files
if (files && files.length > 0) {
const res = await uploadFileBatches(files)
try{
const res = await uploadImagesInBatches(files)
localForm.value.workFlowVersionList[uploadFileIndex.value].filePath = res[0].url
localForm.value.workFlowVersionList[uploadFileIndex.value].fileName = res[0].fileName
}catch(err){
console.log(err);
}
// if(res[0].success){
// }
}
target.value = ''
}

View File

@ -1,121 +1,127 @@
<script setup lang="ts">
import { cloneDeep } from 'lodash-es';
import { Asterisk } from 'lucide-vue-next';
import { useRoute, useRouter } from 'vue-router';
import { cloneDeep } from "lodash-es";
import { Asterisk } from "lucide-vue-next";
import { useRoute, useRouter } from "vue-router";
const props = defineProps({
modelValue: {
type: Object,
required: true,
},
})
const emit = defineEmits(['update:modelValue', 'preStep'])
const router = useRouter()
});
const emit = defineEmits(["update:modelValue", "preStep"]);
const router = useRouter();
const route = useRoute()
const route = useRoute();
const { type } = route.query
const { type } = route.query;
const message = useMessage()
const message = useMessage();
const localForm = computed({
get() {
return props.modelValue
return props.modelValue;
},
set(value) {
emit('update:modelValue', value)
emit("update:modelValue", value);
},
})
});
function preStep() {
emit('preStep')
emit("preStep");
}
const showSuccessModal = ref(false)
const showSuccessModal = ref(false);
async function handlePublish() {
for (let i = 0; i < localForm.value.workFlowVersionList.length; i++) {
if (localForm.value.workFlowVersionList[i].delFlag === '0' && localForm.value.workFlowVersionList[i].imagePaths.length === 0) {
return message.error('请上传图片')
if (
localForm.value.workFlowVersionList[i].delFlag === "0" &&
localForm.value.workFlowVersionList[i].imagePaths.length === 0
) {
return message.error("请上传图片");
}
}
try {
const param = cloneDeep(localForm.value)
const param = cloneDeep(localForm.value);
if (param.workFlow.typeList.length !== 0) {
param.workFlow.type = param.workFlow.typeList.join(',')
}
else {
param.workFlow.type = ''
param.workFlow.type = param.workFlow.typeList.join(",");
} else {
param.workFlow.type = "";
}
for (let i = 0; i < param.workFlowVersionList.length; i++) {
if (param.workFlowVersionList[i].imagePaths.length !== 0) {
param.workFlowVersionList[i].imagePaths = param.workFlowVersionList[i].imagePaths.join(',')
}
else {
param.workFlowVersionList[i].imagePaths = ''
param.workFlowVersionList[i].imagePaths = param.workFlowVersionList[
i
].imagePaths.join(",");
} else {
param.workFlowVersionList[i].imagePaths = "";
}
}
if(param.modelProduct.workFlow === 0){
param.modelProduct.originalAuthorName = ''
if (param.workFlow.original === 0) {
param.workFlow.originalAuthorName = "";
}
// await request.post('/WorkFlow/addWorkFlow', param)
if (type === 'add') {
if (type === "add") {
try {
const res = await request.post('/WorkFlow/addWorkFlow', param)
const res = await request.post("/WorkFlow/addWorkFlow", param);
if (res.code === 200) {
showSuccessModal.value = true
showSuccessModal.value = true;
}
} catch (error) {
console.log(error);
}
catch (error) {
console.log(error)
}
}
else {
} else {
try {
const res = await request.post('/WorkFlow/updateWorkFlow', param)
const res = await request.post("/WorkFlow/updateWorkFlow", param);
if (res.code === 200) {
showSuccessModal.value = true
showSuccessModal.value = true;
}
} catch (error) {
console.log(error);
}
}
catch (error) {
console.log(error)
}
}
}
catch (error) {
console.log(error)
} catch (error) {
console.log(error);
}
}
watch(
() => localForm.value,
(newVal) => {
emit('update:modelValue', newVal)
emit("update:modelValue", newVal);
},
{ immediate: true, deep: true },
)
const fileInput = ref<HTMLInputElement | null>(null)
const uploadFileIndex = ref(0)
{ immediate: true, deep: true }
);
const fileInput = ref<HTMLInputElement | null>(null);
const uploadFileIndex = ref(0);
function triggerFileInput(index: number) {
(fileInput.value as HTMLInputElement)?.click()
uploadFileIndex.value = index
(fileInput.value as HTMLInputElement)?.click();
uploadFileIndex.value = index;
}
async function handleFileChange(event: Event) {
const target = event.target as HTMLInputElement
const files = target.files
const target = event.target as HTMLInputElement;
const files = target.files;
if (files && files.length > 0) {
const sum = localForm.value.workFlowVersionList[uploadFileIndex.value].imagePaths.length + files.length
if (sum >= 20)
return message.error('最多20张')
const res = await uploadImagesInBatches(files)
const urlList = res.map(item => item.url)
localForm.value.workFlowVersionList[uploadFileIndex.value].imagePaths.push(...urlList)
const sum =
localForm.value.workFlowVersionList[uploadFileIndex.value].imagePaths.length +
files.length;
if (sum >= 20) return message.error("最多20张");
try {
const res = await uploadImagesInBatches(files);
const urlList = res.map((item) => item.url);
localForm.value.workFlowVersionList[uploadFileIndex.value].imagePaths.push(
...urlList
);
} catch (err) {
console.log(err);
}
target.value = ''
}
target.value = "";
}
function onPositiveClick() {
showSuccessModal.value = false
router.push('/personal-center')
showSuccessModal.value = false;
router.push("/personal-center");
}
</script>
@ -131,7 +137,8 @@ function onPositiveClick() {
<div>
<n-checkbox
v-model:checked="item.hideGenInfo"
:checked-value="1" :unchecked-value="0"
:checked-value="1"
:unchecked-value="0"
/>
隐藏图片生成信息
</div>
@ -141,18 +148,19 @@ function onPositiveClick() {
添加版本示例图片
<Asterisk :size="10" color="#ff0000" class="mt-1" />
</div>
<div class="text-[12px] text-gray-400">
最多20张图片图片不超过30M
</div>
<div class="text-[12px] text-gray-400">最多20张图片图片不超过30M</div>
</div>
<div>
<div class="flex flex-col justify-center items-center w-30 h-40 border border-dashed mt-2 rounded-lg bg-white">
<div class="w-24 bg-gradient-to-r from-[#2D28FF] to-[#1A7DFF] h-8 text-white rounded-sm bg-[#3162ff] cursor-pointer flex justify-center items-center" @click="triggerFileInput(index)">
<div
class="flex flex-col justify-center items-center w-30 h-40 border border-dashed mt-2 rounded-lg bg-white"
>
<div
class="w-24 bg-gradient-to-r from-[#2D28FF] to-[#1A7DFF] h-8 text-white rounded-sm bg-[#3162ff] cursor-pointer flex justify-center items-center"
@click="triggerFileInput(index)"
>
上传文件
</div>
<div class="my-3">
点击上传文件
</div>
<div class="my-3">点击上传文件</div>
<div class="text-[#999999] text-xs">
请勿上传裸露暴力血腥或其他包含非法信息图片
</div>
@ -160,17 +168,27 @@ function onPositiveClick() {
</div>
<div class="grid grid-cols-3 gap-2.5 mt-4 w-full">
<div v-for="(subItem, subIndex) in item.imagePaths" :key="subIndex">
<img class="w-full h-[200px] object-cover rounded-lg" :src="subItem" alt="">
<img
class="w-full h-[200px] object-cover rounded-lg"
:src="subItem"
alt=""
/>
</div>
</div>
</div>
</template>
</div>
<div class="flex items-center justify-center mt-5">
<div class="flex justify-center items-center mt-5 w-[20%] mx-2 h-10 rounded-lg bg-[#f1f2f7] cursor-pointer" @click="preStep">
<div
class="flex justify-center items-center mt-5 w-[20%] mx-2 h-10 rounded-lg bg-[#f1f2f7] cursor-pointer"
@click="preStep"
>
上一步
</div>
<div class="flex justify-center items-center mt-5 text-white mx-2 w-[20%] h-10 rounded-lg bg-[#3162ff] cursor-pointer" @click="handlePublish">
<div
class="flex justify-center items-center mt-5 text-white mx-2 w-[20%] h-10 rounded-lg bg-[#3162ff] cursor-pointer"
@click="handlePublish"
>
发布
</div>
</div>
@ -182,7 +200,7 @@ function onPositiveClick() {
accept="image/*"
multiple
@change="handleFileChange"
>
/>
<!-- 成功之后的弹框 -->
<n-modal
@ -196,6 +214,4 @@ function onPositiveClick() {
/>
</template>
<style scoped>
</style>
<style scoped></style>

View File

@ -2,7 +2,7 @@
export const appName = '魔创未来'
export const appDescription = '魔创未来'
export const authRoutes = ['/personal-center', '/publish-model', '/publish-workflow']
export const verifyBlankRoute = ['/member-center', 'int-detail']
export const verifyBlankRoute = ['/member-center', '/int-detail', '/personal-publish']
export const isOriginalList = [{
label: '原创',
value: 0,
@ -18,5 +18,8 @@ export const isPublicList = [{
value: 2,
}]
export const headerRole = { // 包括就隐藏
inputSearch: ['/model-square','/picture-square', '/work-square'],
inputSearch: ['/model-square']
}
// export const searchType = { // 包括就隐藏
// 'picture-square':'image',
// }

View File

@ -2,54 +2,111 @@
import {
Binary,
Code2,
Crown,
Image,
Crown, Earth, Image,
LayoutGrid,
Lightbulb,
Maximize,
User,
Maximize, Network, User,
Workflow
} from 'lucide-vue-next';
const menuStore = useMenuStore()
} from "lucide-vue-next";
import { useRouter } from "vue-router";
const userStore = useUserStore();
const modalStore = useModalStore();
const menuStore = useMenuStore();
const router = useRouter();
//
const iconMap: any = {
'/model-square': LayoutGrid,
'/picture-square':Lightbulb,
'/work-square':Workflow,
'/web-ui': Image,
'/comfy-ui': Workflow,
'/training-lora': Binary,
'/high-availability': Maximize,
'/api-platform': Code2,
'/creator-center': Code2,
'/personal-center': User,
'/member-center': Crown,
}
const route = useRoute()
"/model-square": LayoutGrid,
"/picture-square": Lightbulb,
"/work-square": Workflow,
"/web-ui": Image,
"/comfy-ui": Workflow,
"/training-lora": Binary,
"/high-availability": Maximize,
"/api-platform": Code2,
"/creator-center": Code2,
"/personal-center": User,
"/member-center": Crown,
};
const route = useRoute();
//
watch(
() => route.path,
(path) => {
menuStore.setActiveMenu(path)
menuStore.setActiveMenu(path);
},
{ immediate: true }, //
)
{ immediate: true } //
);
const menuItems1 = ref({
title: "探索",
list: [
{
icon: LayoutGrid,
text: "模型广场",
route: "/model-square",
},
{
icon: Lightbulb,
text: "作品灵感",
route: "/picture-square",
},
{
icon: Workflow,
text: "工作流",
route: "/work-square",
},
],
});
const menuItems2 = ref({
title: "创作",
list: [
{
icon: Network,
text: "在线工作流",
route: "",
desc:'Comfy UI'
},
{
icon: Earth,
text: "魔创星球",
route: "",
},
],
});
const menuItems3 = ref({
title: "其他",
list: [
{
icon: User,
text: "个人中心",
route: "/personal-center",
},
{
icon: Crown,
text: "会员中心",
route: "/member-center",
},
],
});
//
menuStore.menuItems = menuStore.menuItems.map(item => ({
menuStore.menuItems = menuStore.menuItems.map((item:any) => ({
...item,
LucideIcon: iconMap[item.path], // Lucide
}))
}));
function handleSide(event: Event, path: string) {
if (path === '/member-center') {
event.preventDefault() //
event.stopPropagation() //
const baseUrl = window.location.origin
window.open(`${baseUrl}/member-center`, '_blank', 'noopener,noreferrer')
if (path === "/member-center") {
if (!userStore.isLoggedIn) {
modalStore.showLoginModal();
} else {
event.preventDefault(); //
event.stopPropagation(); //
const baseUrl = window.location.origin;
window.open(`${baseUrl}/member-center`, "_blank", "noopener,noreferrer");
}
//
// nextTick(() => {
// debugger
@ -57,9 +114,8 @@ function handleSide(event: Event, path: string) {
// navigateTo(route.path, { replace: true })
// }
// })
}
else {
menuStore.setActiveMenu(path)
} else {
menuStore.setActiveMenu(path);
}
}
</script>
@ -72,9 +128,116 @@ function handleSide(event: Event, path: string) {
<!-- Main Content -->
<div class="flex flex-1 overflow-hidden">
<!-- Sidebar -->
<nav class="w-[200px] border-r border-gray-100 bg-gray-50/50 py-2 dark:border-dark-700 dark:bg-dark-800/50">
<nav
class="w-[220px] border-r border-gray-100 bg-gray-50/50 dark:border-dark-700 dark:bg-dark-800/50"
>
<div class="space-y-1 px-2">
<div class="text-[#000] p-4">
<div class="px-3 pt-4">
<span class="text-gray-400 text-xs">
{{ menuItems1.title }}
</span>
</div>
<div class="py-4 space-y-2 border-b border-b-solid border-b-gray-200">
<NuxtLink
v-for="item in menuItems1.list"
:key="item.route"
class="py-3 px-2 w-full block hover:bg-gray-100 rounded-lg"
:to="item.route"
:class="[
menuStore.activeMenu === item.route
? 'bg-blue-500/8 bg-gray-100 dark:bg-blue-500/10 dark:text-blue-400'
: 'dark:text-gray-300 dark:hover:bg-dark-700/50',
]"
@click="(event: Event) => handleSide(event, item.route)"
>
<div class="flex items-center">
<component
:is="item.icon"
class="h-[18px] w-[18px] mr-2"
:class="
menuStore.activeMenu === item.route
? 'text-blue-600 dark:text-blue-400'
: 'dark:text-gray-400'
"
/>
<span class="text-sm">
{{ item.text }}
</span>
</div>
</NuxtLink>
</div>
</div>
<div class="text-[#000] px-4">
<div class="px-3 py-4">
<span class="text-gray-400 text-xs">
{{ menuItems2.title }}
</span>
</div>
<div>
<NuxtLink
v-for="item in menuItems2.list"
:key="item.route"
:to="item.route"
target="_blank"
@click="(event: Event) => handleSide(event, item.route)"
>
<div class="cursor-pointer mb-3 flex flex-col justify-center py-3 px-2 w-full block hover:bg-gray-100 border-[#ccc] rounded-lg border-dashed border">
<div class="flex items-center">
<component
:is="item.icon"
class="h-[18px] w-[18px] mr-[10px]"
/>
<div class="text-sm">
{{ item.text }}
</div>
</div>
<div v-if="item.desc" class="text-xs text-gray-500 mt-1 ml-[28px]">
{{ item.desc }}
</div>
</div>
</NuxtLink>
</div>
</div>
<div class="text-[#000] px-4">
<div class="px-3 pt-4">
<span class="text-gray-400 text-xs">
{{ menuItems3.title }}
</span>
</div>
<div class="py-4 space-y-2">
<NuxtLink
v-for="item in menuItems3.list"
:key="item.route"
class="py-3 px-2 w-full block hover:bg-gray-100 rounded-lg"
:to="item.route"
:class="[
menuStore.activeMenu === item.route
? 'bg-blue-500/8 bg-gray-100 dark:bg-blue-500/10 dark:text-blue-400'
: 'dark:text-gray-300 dark:hover:bg-dark-700/50',
]"
@click="(event: Event) => handleSide(event, item.route)"
>
<div class="flex items-center">
<component
:is="item.icon"
class="h-[18px] w-[18px] mr-2"
:class="
menuStore.activeMenu === item.route
? 'text-blue-600 dark:text-blue-400'
: 'dark:text-gray-400'
"
/>
<span class="text-sm">
{{ item.text }}
</span>
</div>
</NuxtLink>
</div>
</div>
<!-- <NuxtLink
v-for="item in menuStore.menuItems"
:key="item.path"
:to="item.path"
@ -86,7 +249,6 @@ function handleSide(event: Event, path: string) {
]"
@click="(event: Event) => handleSide(event, item.path)"
>
<!-- 只显示 Lucide 图标 -->
<component
:is="item.LucideIcon"
class="h-[14px] w-[14px]"
@ -96,7 +258,7 @@ function handleSide(event: Event, path: string) {
/>
<span>{{ item.label }}</span>
</NuxtLink>
</NuxtLink> -->
</div>
</nav>
@ -117,12 +279,15 @@ function handleSide(event: Event, path: string) {
}
::selection {
/* cursor: pointer; */
background: var(--primary);
color: white;
/* border: dashed; */
}
/* 自定义滚动条 */
::-webkit-scrollbar {
justify-content: center;
width: 6px;
height: 6px;
}

View File

@ -14,6 +14,9 @@ import { authRoutes, verifyBlankRoute } from '@/constants/index'
export default defineNuxtRouteMiddleware((to, from) => {
const userStore = useUserStore()
const modalStore = useModalStore()
if(to.path !== '/search'){
modalStore.searchQuery = ''
}
const menuStore = useMenuStore()
if (verifyBlankRoute.includes(to.path) && !verifyBlankRoute.includes(from.path)) {
return abortNavigation()

View File

@ -0,0 +1,13 @@
<script setup lang="ts">
definePageMeta({
layout: "default",
});
</script>
<template>
<div>
1111
</div>
</template>
<style scoped>
</style>

View File

@ -1,6 +1,6 @@
<script setup lang="ts">
import { CheckmarkCircleSharp, Close } from '@vicons/ionicons5'
import { NConfigProvider, NMessageProvider } from 'naive-ui'
import { CheckmarkCircleSharp, Close } from '@vicons/ionicons5';
import { NConfigProvider, NMessageProvider } from 'naive-ui';
definePageMeta({
layout: 'header',
@ -123,6 +123,11 @@ function toIntDetail() {
const baseUrl = window.location.origin
window.open(`${baseUrl}/int-detail`, '_blank', 'noopener,noreferrer')
}
function toOrderManage(){
const baseUrl = window.location.origin
window.open(`${baseUrl}/order-management`, '_blank', 'noopener,noreferrer')
}
</script>
<template>
@ -133,7 +138,7 @@ function toIntDetail() {
<div class="w-60 bg-[#2b2421] rounded-lg p-6 my-3">
<!-- 右上角订阅管理 -->
<div class="text-right">
<button class="text-[#8b8685] text-sm bg-inherit border-none cursor-pointer">
<button class="text-[#8b8685] text-sm bg-inherit border-none cursor-pointer" @click="toOrderManage">
订阅管理 >
</button>
</div>

View File

@ -3,7 +3,7 @@ import AttentionMsg from "@/components/message/AttentionMsg.vue";
import LikeMsg from "@/components/message/LikeMsg.vue";
import OfficialMsg from "@/components/message/OfficialMsg.vue";
import ReplyMsg from "@/components/message/ReplyMsg.vue";
import { Check, Heart, MessageSquareMore, UserPlus, Volume2 } from "lucide-vue-next";
import { Check, ChevronDown, Heart, MessageSquareMore, UserPlus, Volume2 } from "lucide-vue-next";
const currentMsgType = ref("reply");
const MsgTypeList = ref([

View File

@ -1,179 +1,237 @@
<script setup lang="ts">
import { Heart, PersonAddOutline } from '@vicons/ionicons5'
import { commonApi } from "@/api/common";
import { Close, DiamondSharp, PersonAddOutline } from "@vicons/ionicons5";
import {
CircleUser,
Download,
EllipsisVertical, Play,
EllipsisVertical, Heart, Play,
SquarePlus
} from 'lucide-vue-next'
import { NConfigProvider, NMessageProvider } from 'naive-ui'
import { ref } from 'vue'
import { useRouter } from 'vue-router'
} from "lucide-vue-next";
import { NConfigProvider, NMessageProvider } from "naive-ui";
import { ref } from "vue";
import { useRouter } from "vue-router";
const userStore = useUserStore();
const message = useMessage();
const message = useMessage()
const router = useRouter()
const router = useRouter();
// tabs
definePageMeta({
layout: 'default',
})
layout: "default",
});
// const userStore = useUserStore()
const route = useRoute()
const { id } = route.params as { id: string }
const activeTab = ref(null)
const commentHeight = ref(800)
const detailsInfo = ref({})
const currentUserInfo = ref<any>({})
const route = useRoute();
const { id } = route.params as { id: string };
const activeTab = ref(null);
const commentHeight = ref(800);
const detailsInfo = ref({});
const currentUserInfo = ref<any>({});
const isVisibleReport = ref(false);
//
const versionByWorkInfo = ref([])
const versionByWorkInfo = ref([]);
async function getInfo() {
try {
const res = await request.get(`/model/selectModelById?id=${id}`)
const res = await request.get(`/model/selectModelById?id=${id}`);
if (res.code === 200) {
detailsInfo.value = res.data
detailsInfo.value = res.data;
detailsInfo.value.styleList = JSON.parse(res.data.styleList);
debugger
// detailsInfo.value.styleList =JSON.parse(res.data.styleList)
// // 1
try {
const res1 = await request.get(`/ModelVersion/finbyid?id=${res.data.id}`)//
const res1 = await request.get(`/ModelVersion/finbyid?id=${res.data.id}`); //
if (res1.code === 200 && res1.data.length > 0) {
versionByWorkInfo.value = res1.data
versionByWorkInfo.value = res1.data;
versionByWorkInfo.value.forEach((item) => {
item.sampleImagePaths = item.sampleImagePaths.split(',')
})
item.sampleImagePaths = item.sampleImagePaths.split(",");
});
nextTick(() => {
activeTab.value = versionByWorkInfo.value[0].id
})
activeTab.value = versionByWorkInfo.value[0].id;
});
// const commentRes = await request.get(`/WorkFlowComment/comment/${res.data.id}`)
}
}
catch (error) {
console.log(error)
} catch (error) {
console.log(error);
}
// //
try {
const res = await request.get(`/system/user/selectUserById?id=${detailsInfo.value.userId}`)
const res = await request.get(
`/system/user/selectUserById?id=${detailsInfo.value.userId}`
);
if (res.code === 200) {
currentUserInfo.value = res.data
currentUserInfo.value = res.data;
}
} catch (error) {
console.log(error);
}
catch (error) {
console.log(error)
getAttention();
}
getAttention()
}
}
catch (error) {
console.log(error)
} catch (error) {
console.log(error);
}
}
getInfo()
getInfo();
// //
interface SelectUserInfo {
attention: number
bean: number
imageLikeNum:number
modelDownLoadNum:number
modelLikeNum:number
modelRunNum:number
attention: number;
bean: number;
imageLikeNum: number;
modelDownLoadNum: number;
modelLikeNum: number;
modelRunNum: number;
}
const selectUserInfo = ref<SelectUserInfo>({
attention: 0,
bean: 0,
imageLikeNum:0,
modelDownLoadNum:0,
modelLikeNum:0,
modelRunNum:0,
})
imageLikeNum: 0,
modelDownLoadNum: 0,
modelLikeNum: 0,
modelRunNum: 0,
});
//
async function getAttention() {
try {
const res = await request.get(`/attention/selectUserInfo?userId=${detailsInfo.value.userId}`)
const res = await request.get(
`/attention/selectUserInfo?userId=${detailsInfo.value.userId}`
);
if (res.code === 200) {
selectUserInfo.value = res.data
selectUserInfo.value = res.data;
}
}
catch (err) {
console.log(err)
} catch (err) {
console.log(err);
}
}
// //
const isDelete = ref(false)
const isDelete = ref(false);
async function handleSelect(event: Event, type: string) {
event.stopPropagation() //
if (type === 'report') {
await request.get(`/WorkFlow/report?id=${id}`) //
}
else if (type === 'edit') {
event.stopPropagation(); //
if (type === "report") {
isVisibleReport.value = true;
// await request.get(`/WorkFlow/report?id=${id}`) //
} else if (type === "edit") {
router.push({
path: `/publish-model`,
query: {
type: 'edit',
type: "edit",
id: detailsInfo.value.id,
},
})
}
else {
isDelete.value = true
});
} else {
isDelete.value = true;
}
}
//
async function onDelete() {
try {
const res = await request.get(`/model/delete?id=${detailsInfo.value.id}`)
const res = await request.get(`/model/delete?id=${detailsInfo.value.id}`);
if (res.code === 200) {
message.success('删除成功')
isDelete.value = false
router.push('/personal-center')
message.success("删除成功");
isDelete.value = false;
router.push("/personal-center");
}
}
catch (err) {
console.log(err)
} catch (err) {
console.log(err);
}
}
// /
async function onChangeAttention() {
try {
const res = await request.get(`/attention/addAttention?userId=${detailsInfo.value.userId}`)
const res = await request.get(
`/attention/addAttention?userId=${detailsInfo.value.userId}`
);
if (res.code === 200) {
if (res.data) {
detailsInfo.value.isAttention = 1
message.success('关注成功')
}
else {
detailsInfo.value.isAttention = 0
message.success('取消关注成功')
detailsInfo.value.isAttention = 1;
message.success("关注成功");
} else {
detailsInfo.value.isAttention = 0;
message.success("取消关注成功");
}
}
}
catch (err) {
console.log(err)
} catch (err) {
console.log(err);
}
}
//
async function onLike() {
try {
const res = await request.get(`/ModelComment/modelLike?modelId=${detailsInfo.value.id}`)
const res = await request.get(
`/ModelComment/modelLike?modelId=${detailsInfo.value.id}`
);
if (res.code === 200) {
detailsInfo.value.isLike === 0 ? detailsInfo.value.isLike = 1 : detailsInfo.value.isLike = 0
detailsInfo.value.isLike === 0
? (detailsInfo.value.isLike = 1)
: (detailsInfo.value.isLike = 0);
if (detailsInfo.value.isLike === 0) {
message.success('取消点赞成功')
}
else {
message.success('点赞成功')
message.success("取消点赞成功");
} else {
message.success("点赞成功");
}
}
} catch (err) {
console.log(err);
}
catch (err) {
console.log(err)
}
//
const reportParams = ref({
reportId: undefined,
text: "",
type:1
});
const reportList = ref([]);
async function getDictType() {
try {
const res = await commonApi.dictType({ type: "report_type" });
if (res.code === 200) {
reportList.value = res.data;
}
} catch (error) {
console.log(error);
}
}
getDictType();
function handleChange(item: any) {
reportParams.value.reportId = item.dictValue;
if (item.dictValue !== "5") {
reportParams.value.text = "";
}
console.log("object", reportParams.value);
}
function closeReport() {
isVisibleReport.value = false;
}
async function onReport(){
if( reportParams.value.reportId !== undefined){
reportParams.value.productId = detailsInfo.value.id
try{
const res = await request.post('/report/addReport', reportParams.value)
if(res.code === 200){
message.success("举报成功");
closeReport()
}
}catch(err){
console.log(err);
}
}
}
function toPersonalCenter(){
const baseUrl = window.location.origin
if(userStore?.userInfo?.userId === detailsInfo.value.userId){
window.open(`${baseUrl}/personal-center`, '_blank', 'noopener,noreferrer')
}else{
debugger
window.open(`${baseUrl}/personal-publish?userId=${detailsInfo.value.userId}`, '_blank', 'noopener,noreferrer')
}
}
</script>
@ -212,8 +270,12 @@ async function onLike() {
<n-tooltip trigger="hover">
<template #trigger>
<div class="flex items-center bg-[#f4f5f9] px-2 rounded-full">
<img src="@/assets/img/heart.png" class="w-[14px] h-[14px] mr-1" alt="">
<span>{{ detailsInfo.likeNum || 0}} </span>
<!-- <img src="@/assets/img/heart.png" class="w-[14px] h-[14px] mr-1" alt="" /> -->
<component
:is="Heart"
class="h-[12px] w-[12px] mr-1 text-[#000]"
/>
<span>{{ detailsInfo.likeNum || 0 }} </span>
</div>
</template>
点赞数
@ -245,9 +307,9 @@ async function onLike() {
v-for="(subItem, subIndex) in item.sampleImagePaths"
:key="subIndex"
:src="subItem"
class="w-full h-[300px]"
class="w-full h-[350px] rounded-lg"
alt=""
>
/>
</div>
<div v-if="detailsInfo.original === 1" class="font-bold text-[20px] my-6">
@ -264,7 +326,12 @@ async function onLike() {
<div style="padding: 20px">
<NConfigProvider>
<NMessageProvider>
<BaseComment v-if="detailsInfo.id" type="model" :height="commentHeight" :details-info="detailsInfo" />
<BaseComment
v-if="detailsInfo.id"
type="model"
:height="commentHeight"
:details-info="detailsInfo"
/>
</NMessageProvider>
</NConfigProvider>
</div>
@ -284,7 +351,11 @@ async function onLike() {
</div>
<div class="flex items-center relative">
<n-icon size="20" :color="detailsInfo.isLike === 0 ? '#ccc' : '#ff0000'" @click="onLike">
<n-icon
size="20"
:color="detailsInfo.isLike === 0 ? '#ccc' : '#ff0000'"
@click="onLike"
>
<Heart class="cursor-pointer" />
</n-icon>
<div class="group relative">
@ -295,18 +366,26 @@ async function onLike() {
<div
class="absolute right-0 top-[10px] hidden group-hover:block text-[#000000] text-[12px] bg-white rounded-lg text-center px-2 py-2 w-20 mt-2 shadow-lg z-10"
>
<div class="menu-item hover:bg-gray-100 py-2 cursor-pointer rounded-lg" @click="(event) => handleSelect(event, 'report')">
<div
class="menu-item hover:bg-gray-100 py-2 cursor-pointer rounded-lg"
@click="(event) => handleSelect(event, 'report')"
>
举报
</div>
<template v-if="userStore?.userInfo?.userId === detailsInfo.userId">
<div
class="menu-item hover:bg-gray-100 py-2 cursor-pointer rounded-lg"
@click="(event) => handleSelect(event, 'edit')"
>
编辑
</div>
<div class="menu-item hover:bg-gray-100 py-2 cursor-pointer rounded-lg" @click="(event) => handleSelect(event, 'delete')">
<div
class="menu-item hover:bg-gray-100 py-2 cursor-pointer rounded-lg"
@click="(event) => handleSelect(event, 'delete')"
>
删除
</div>
</template>
</div>
</div>
</div>
@ -314,10 +393,11 @@ async function onLike() {
<div
class="flex items-center mt-10 p-2 bg-[#f3f5f9] w-full rounded-md h-[80px] box-border"
>
<div class="w-[70px] h-[70px] rounded-full overflow-hidden mr-4">
<div class="w-[60px] h-[60px] rounded-full overflow-hidden mr-4">
<client-only>
<NAvatar
class="w-full h-full mr-2 block"
@click="toPersonalCenter"
class="w-full h-full mr-2 block cursor-pointer"
round
size="small"
:src="currentUserInfo.avatar"
@ -333,16 +413,25 @@ async function onLike() {
</div>
</client-only>
<!-- 0代表原创 1代表转载 -->
<div v-if="detailsInfo.original === 0" class="text-[14px]">
<div v-if="detailsInfo.original === 1" class="original">
<n-icon size="14" class="mr-2">
<DiamondSharp />
</n-icon>
原创作者
</div>
</div>
<div class="flex-1 flex justify-end">
<div class="flex items-center font-bold px-1 justify-center w-24 h-10 rounded-full text-[#426af7] border-2 border-[#426af7] border-solid cursor-pointer" @click="onChangeAttention">
<n-icon v-if="detailsInfo.isAttention === 0" size="20" class="mr-2">
<div
class="flex-1 flex justify-end"
v-if="userStore?.userInfo?.userId !== detailsInfo.userId"
>
<div
class="flex items-center font-bold px-1 justify-center w-20 h-8 rounded-full text-[#426af7] border border-[#426af7] border-solid cursor-pointer"
@click="onChangeAttention"
>
<n-icon v-if="detailsInfo.isAttention === 0" size="16" class="mr-2">
<PersonAddOutline />
</n-icon>
{{ detailsInfo.isAttention === 1 ? '已关注' : '关注' }}
{{ detailsInfo.isAttention === 1 ? "已关注" : "关注" }}
</div>
</div>
</div>
@ -362,7 +451,7 @@ async function onLike() {
:is="Play"
class="h-[12px] w-[12px] text-black menu-icon m-1 text-[#969798]"
/>
<span class="mr-2"> {{ selectUserInfo.modelRunNum }} </span>
<span class="mr-2"> {{ selectUserInfo.productNum }} </span>
<component
:is="Download"
class="h-[12px] w-[12px] text-black menu-icon m-1 text-[#969798]"
@ -382,7 +471,9 @@ async function onLike() {
<span class="mr-1"> 立即生图</span>
</div>
<div class="flex gap-y-2">
<div class="flex flex-1 items-center justify-center bg-[#eceef4] h-[50px] mt-4 mr-1 rounded-md">
<div
class="flex flex-1 items-center justify-center bg-[#eceef4] h-[50px] mt-4 mr-1 rounded-md"
>
<component
:is="SquarePlus"
class="h-[20px] w-[20px] text-black menu-icon m-1 text-[#969798]"
@ -401,7 +492,6 @@ async function onLike() {
</div>
</div>
<!-- <div style="background: linear-gradient(135deg,#3cc9ff, #8fa6ff, 41%, #d8b4ff 74%,#326bff)" class="flex items-center justify-center mt-4 w-full h-14 text-black bg-[#fff] w-full rounded-md h-[80px] cursor-pointer hover:bg-[#f1f2f7]">
<component :is="Download" class="h-[20px] w-[20px] text-black menu-icon m-1 text-[#969798]" />
<span class="mr-1">
@ -419,10 +509,66 @@ async function onLike() {
@negative-click="onDelete"
@positive-click="onDelete"
/>
<n-modal
v-model:show="isVisibleReport"
:preset="null"
:mask-closable="false"
transform-origin="center"
class="custom-modal"
>
<div class="bg-white rounded-xl p-4">
<div class="flex items-center justify-between">
<div class="text-xl">举报</div>
<div>
<n-icon size="20" class="mr-2 cursor-pointer" @click="closeReport">
<Close />
</n-icon>
</div>
</div>
<div class="flex flex-col">
<n-radio
class="m-4 text-[#fff000]"
size="large"
v-for="(item, index) in reportList"
:key="index"
:checked="reportParams.reportId === item.dictValue"
value="Definitely Maybe"
name="basic-demo"
@change="handleChange(item)"
>
{{ item.dictLabel }}
</n-radio>
<n-input
v-if="reportParams.reportId !== undefined && reportParams.reportId === '5'"
v-model:value="reportParams.text"
placeholder="点击输入"
type="textarea"
:autosize="{
minRows: 5,
maxRows: 10,
}"
/>
<div
@click="onReport"
class="mt-4 w-[100%] h-10 flex rounded-lg text-white items-center justify-center cursor-pointer"
:class="[
reportParams.reportId !== undefined
? 'bg-[#4c79ee]'
: 'bg-[#cccccc]',
]"
>
确认
</div>
</div>
</div>
</n-modal>
<div />
<!-- <Report></Report> -->
</div>
</div>
</div>
<!-- <Report></Report> -->
</div>
</template>
@ -453,10 +599,21 @@ async function onLike() {
height: 4px;
background: linear-gradient(90deg, #173eff 0%, #1b7dff 100%);
border-radius: 2px;
transition:
left 0.2s var(--n-bezier),
max-width 0.2s var(--n-bezier),
opacity 0.3s var(--n-bezier),
background-color 0.3s var(--n-bezier);
transition: left 0.2s var(--n-bezier), max-width 0.2s var(--n-bezier),
opacity 0.3s var(--n-bezier), background-color 0.3s var(--n-bezier);
}
.original{
margin: 2px 0;
padding: 2px 0;
display: flex;
align-items: center;
justify-content: center;
width: 90px;
font-size: 12px;
color: #aa8645;
font-weight: 400;
background: linear-gradient(94.11deg, #efd6a9 10.52%, #f0dcbc 107.96%);
border-radius: 4px;
transform: skew(-10deg);
}
</style>

View File

@ -1,7 +1,9 @@
<script setup lang="ts">
import { commonApi } from "@/api/common";
import { ArrowBack, ArrowForward } from '@vicons/ionicons5';
import { ref } from "vue";
const modalStore = useModalStore()
definePageMeta({
layout: "default",
@ -50,23 +52,25 @@ function changeCategory(item:any){
onSearch()
}
// function onHot(name:string){
// params.value.name = name
// onSearch()
// }
function onInputSearch(){
modalStore.updateSearchQuery(params.value.name)
const baseUrl = window.location.origin
window.open(`${baseUrl}/search?keyword=${params.value.name}&type=model`, "_blank", "noopener,noreferrer");
}
</script>
<template>
<div class="p-6">
<div class="header flex h-[150px] border-b border-b-[#ebebeb]">
<div class="flex-1 py-2">
<div class="max-w-4xl mx-auto">
<div class="header flex h-[130px] border-b border-b-[#ebebeb]">
<div class="py-2" style="flex: 3;">
<div class="w-full">
<div class="relative flex items-center w-full">
<!-- 搜索输入框 -->
<input
type="text"
class="w-full py-3 px-6 text-lg text-gray-600 placeholder-gray-400 bg-white border-2 border-blue-500 rounded-full focus:outline-none focus:border-blue-600"
class="w-full py-3 px-6 text-lg text-gray-600 placeholder-gray-400 bg-white border-2 border-blue-500 rounded-lg focus:outline-none focus:border-blue-600"
placeholder="搜索模型/图片/创作者寻找灵感"
@keyup.enter="onSearch"
@keyup.enter="onInputSearch"
v-model="params.name"
/>
@ -96,8 +100,8 @@ function changeCategory(item:any){
<!-- 搜索按钮 -->
<button
class="absolute right-0 px-8 py-3 mr-2 text-white bg-blue-500 rounded-full hover:bg-blue-600 focus:outline-none"
@click="onSearch"
class="absolute right-0 px-8 py-3 mr-2 text-white bg-blue-500 rounded-lg hover:bg-blue-600 focus:outline-none"
@click="onInputSearch"
>
搜索
</button>
@ -109,12 +113,7 @@ function changeCategory(item:any){
</div>
</div> -->
</div>
<div class="w-[500px] ml-4">
<!-- <img
class="h-[130px] w-full rounded-lg"
src="https://img.zcool.cn/tubelocation/e41767ac6706cd0109100099e04b.jpg?imageMogr2/format/webp"
alt=""
/> -->
<div style="flex: 2;" class="ml-4">
<n-carousel show-arrow autoplay>
<img
class="carousel-img"
@ -155,18 +154,18 @@ function changeCategory(item:any){
</n-carousel>
</div>
</div>
<div class="flex flex-wrap">
<div class="flex flex-wrap">
<div class="flex flex-wrap mt-4">
<MenuFold v-if="modelCategoryList.length > 0">
<div
v-for="(item, index) in modelCategoryList"
:key="index"
:style="{color: item.dictValue === params.type ? '#000' : '#6f6f6f'}"
@click="changeCategory(item)"
class="pt-4 mr-4 cursor-pointer"
class="py-1 mr-4 cursor-pointer"
>
{{ item.dictLabel }}
</div>
</div>
</MenuFold>
</div>
<div class="flex flex-wrap">
<ModelList ref="listRef" :params="params"></ModelList>
@ -182,7 +181,7 @@ function changeCategory(item:any){
}
.carousel-img {
width: 100%;
height: 120px;
height: 100px;
border-radius: 6px;
object-fit: cover;
}

View File

@ -0,0 +1,140 @@
<script setup lang="ts">
import { nextTick, onMounted, ref } from 'vue';
definePageMeta({
layout: 'header',
})
const activeTab = ref('')
// const route = useRoute();
// const { id } = route.params as { id: string };
interface PointsResult {
points: number
memberConsumeList: any[]
}
const pointsResult = ref<PointsResult>()
async function getPoints() {
try {
const res = await request.get('/member/getPoints')
if (res.code === 200) {
pointsResult.value = res.data as PointsResult
nextTick(() => {
activeTab.value = 'manage'
})
}
}
catch (err) {
console.log(err)
}
}
getPoints()
const myMemberList = ref([
{
title:'基础版VIP会员',
type:'单月套餐',
time:'2021-02-10至2024-19-23',
payType:'支付宝'
},
{
title:'基础版VIP会员',
type:'单月套餐',
time:'2021-02-10至2024-19-23',
payType:'支付宝'
},
])
onMounted(() => {
// nextTick(() => {
// activeTab.value = 'beatles'
// })
})
</script>
<template>
<div class="flex justify-center bg-[#f2f5f8] items-center h-[calc(100vh-48px)]">
<div class="w-[1200px] bg-white rounded-lg shadow-lg p-10 h-[calc(100%-40px)]">
<h1 class="text-2xl font-bold mb-4">
订单管理
</h1>
<n-tabs v-model:value="activeTab" type="line" animated>
<n-tab-pane name="manage" tab="订单管理">
<div class="h-[500px] overflow-y-auto">
<div class="p-2 text-base">我的会员</div>
<div v-for="(item, index) in myMemberList" :key="index" class="p-2 bg-[#f9fbfc] rounded-lg text-gray-500 mb-2">
<div class="p-2 text-[#ff9e0b]">
{{ item.title }}
</div>
<div class="flex justify-between p-2">
<div>订单类型</div>
<div>{{ item.type }}</div>
</div>
<div class="flex justify-between p-2">
<div>生效时间</div>
<div>{{item.time}}</div>
</div>
<div class="flex justify-between p-2">
<div>支付方式</div>
<div>{{item.payType}}</div>
</div>
</div>
</div>
</n-tab-pane>
<n-tab-pane name="record" tab="购买记录">
<div class="h-[500px] overflow-y-auto">
<div class="mc-table flex w-full">
<div class="w-[200px]">
交易时间
</div>
<div class="w-[200px]">
商品名称
</div>
<div class="flex-1">
订单编号
</div>
<div class="w-[130px]">
交易金额
</div>
<div class="w-[130px]">
交易状态
</div>
<div class="w-[130px]">
操作
</div>
</div>
<div v-for="item in pointsResult.memberConsumeList" :key="item" class="mc-table flex w-full">
<div class="w-[200px]">
2021.02.12 12:21
</div>
<div class="w-[200px]">
基础班VIP1个月
</div>
<div class="flex-1">
OHF_202454221134433222
</div>
<div class="w-[130px]">
¥ 45.0
</div>
<div class="w-[130px]">
成功
</div>
<div class="w-[130px]">
<div class="border border-solid border-[#ccc] rounded-lg w-20 h-8 flex justify-center items-center cursor-pointer">开票</div>
</div>
</div>
</div>
</n-tab-pane>
</n-tabs>
</div>
</div>
</template>
<style lang="scss" scoped>
.mc-table {
display: flex;
padding: 10px 4px;
border-bottom: 1px solid #eee;
align-items: center;
// justify-content: space-between;
}
</style>

View File

@ -1,356 +1,457 @@
<script setup lang="ts">
import { commonApi } from '@/api/common'
import EditUserInfo from '@/components/EditUserInfo.vue'
import { useUserStore } from '@/stores/user'
import { formatDate } from '@/utils/index.ts'
import { NConfigProvider, NMessageProvider } from 'naive-ui'
import { nextTick, onMounted, onUnmounted, ref } from 'vue'
import { Close } from "@vicons/ionicons5";
const message = useMessage()
const loading = ref(false)
const finished = ref(false)
const total = ref(0) //
const loadingTrigger = ref(null)
import { commonApi } from "@/api/common";
import EditUserInfo from "@/components/EditUserInfo.vue";
import { useUserStore } from "@/stores/user";
import { formatDate } from "@/utils/index.ts";
import { NConfigProvider, NMessageProvider } from "naive-ui";
import { nextTick, onMounted, onUnmounted, ref } from "vue";
const route = useRoute();
const { type, status } = route.query as { type: string; status: string };
const observer = ref<IntersectionObserver | null>(null)
const loading = ref(false);
const finished = ref(false);
const total = ref(0); //
const loadingTrigger = ref(null);
const observer = ref<IntersectionObserver | null>(null);
definePageMeta({
layout: 'default',
})
layout: "default",
});
interface UserInfo {
nickName?: string // 使 ? nickName
avatar?: string
name?: string
brief?: string
nickName?: string; // 使 ? nickName
avatar?: string;
name?: string;
brief?: string;
}
const userStore = useUserStore()
const userInfo: UserInfo = userStore.userInfo
const userStore = useUserStore();
const userInfo: UserInfo = userStore.userInfo;
//
const currentState = ref('mallProduct')
const currentState = ref("mallProduct");
//
const currentType = ref('0')
const currentType = ref("0");
const orderOptions = ref([
{
dictLabel: '最新',
dictValue: 'create_time',
dictLabel: "最新",
dictValue: "create_time",
},
{
dictLabel: '最热',
dictValue: 'like_num',
dictLabel: "最热",
dictValue: "like_num",
},
])
]);
const stateList = ref([
{ id: 'mallProduct', title: '发布' },
{ id: 'like', title: '点赞' },
])
{ id: "mallProduct", title: "发布" },
{ id: "like", title: "点赞" },
]);
const typeList = ref([
{ id: '0', title: '模型' },
{ id: '1', title: '工作流' },
{ id: '2', title: '图片' },
])
{ id: "0", title: "模型" },
{ id: "1", title: "工作流" },
{ id: "2", title: "图片" },
]);
// form
const publishParams = ref({
pageNum: 1,
pageSize: 12,
status: '0',
orderByColumn: 'create_time',
status: "0",
orderByColumn: "create_time",
date: null,
endTime: '',
startTime: '',
})
endTime: "",
startTime: "",
});
function initPublishParams() {
publishParams.value = {
pageNum: 1,
pageSize: 12,
status: '0',
orderByColumn: 'create_time',
status: "0",
orderByColumn: "create_time",
date: null,
endTime: '',
startTime: '',
}
endTime: "",
startTime: "",
};
}
// form
const likesParams = ref({
pageNum: 1,
pageSize: 12,
orderByColumn: 'create_time',
})
orderByColumn: "create_time",
});
function initLikesParams() {
likesParams.value = {
pageNum: 1,
pageSize: 12,
orderByColumn: 'create_time',
}
orderByColumn: "create_time",
};
}
const urlList = ref({
mallProduct: {
0: '/model/selectByUserIdModel',
1: '/model/selectByUserIdWorkFlow',
2: '/model/selectByUserIdImage',
0: "/model/selectByUserIdModel",
1: "/model/selectByUserIdWorkFlow",
2: "/model/selectByUserIdImage",
},
like: {
0: '/model/likeModel',
1: '/model/likeWorkFlow',
2: '/model/likeImage',
0: "/model/likeModel",
1: "/model/likeWorkFlow",
2: "/model/likeImage",
},
})
});
//
const statusOptions = ref([])
const statusOptions = ref([]);
async function getDictType() {
try {
const res = await commonApi.dictType({
type: 'mall_product_status',
})
type: "mall_product_status",
});
if (res.code === 200 && res.data.length > 0) {
statusOptions.value = res.data
publishParams.value.status = res.data[0].dictValue
statusOptions.value = res.data;
publishParams.value.status = res.data[0].dictValue;
}
}
catch (error) {
console.log(error)
} catch (error) {
console.log(error);
}
}
getDictType()
getDictType();
//
interface EditUserInfoType {
isVisible: boolean
isVisible: boolean;
}
const editUserInfoRef = ref<EditUserInfoType | null>(null)
const editUserInfoRef = ref<EditUserInfoType | null>(null);
function onEditInfo() {
if (editUserInfoRef.value) {
editUserInfoRef.value.isVisible = true
editUserInfoRef.value.isVisible = true;
}
}
//
interface AuthComponentType {
isVisible: boolean
isVisible: boolean;
}
const authenticationRef = ref<AuthComponentType | null>(null)
const authenticationRef = ref<AuthComponentType | null>(null);
function onAuth() {
if (authenticationRef.value) {
authenticationRef.value.isVisible = true
authenticationRef.value.isVisible = true;
}
}
function initChangeParams() {
if (currentState.value === 'mallProduct') {
initPublishParams()
if (currentState.value === "mallProduct") {
initPublishParams();
} else {
initLikesParams();
}
else {
initLikesParams()
}
finished.value = false //
getList()
finished.value = false; //
getList();
}
// /
function changeTabs(id: string) {
currentState.value = id
currentType.value = '0'
initChangeParams()
currentState.value = id;
currentType.value = "0";
initChangeParams();
}
// //
function changeType(id: string) {
currentType.value = id
initChangeParams()
if(id === '2'){
statusOptions.value.forEach(item => {
if(item.dictValue === '2'){
item.disabled = true
}
});
}else{
statusOptions.value.forEach(item => {
if(item.dictValue === '2'){
item.disabled = false
}
});
}
currentType.value = id;
initChangeParams();
}
function initPageNUm() {
if (currentState.value === 'mallProduct') {
publishParams.value.pageNum = 1
if (currentState.value === "mallProduct") {
publishParams.value.pageNum = 1;
} else {
likesParams.value.pageNum = 1;
}
else {
likesParams.value.pageNum = 1
}
finished.value = false //
getList()
finished.value = false; //
getList();
}
// select//
function changeStatus(value: string) {
publishParams.value.status = value
initPageNUm()
publishParams.value.status = value;
initPageNUm();
}
// /
function changeOrder(value: string) {
publishParams.value.orderByColumn = value
initPageNUm()
publishParams.value.orderByColumn = value;
initPageNUm();
}
// /
function changeLikeOrder(value: string) {
likesParams.value.orderByColumn = value
initPageNUm()
likesParams.value.orderByColumn = value;
initPageNUm();
}
//
async function changeDate(value: string[]) {
publishParams.value.startTime = `${await formatDate(value[0] as string)} 00:00:00`
publishParams.value.endTime = `${await formatDate(value[1] as string)} 23:59:59`
initPageNUm()
publishParams.value.startTime = `${await formatDate(value[0] as string)} 00:00:00`;
publishParams.value.endTime = `${await formatDate(value[1] as string)} 23:59:59`;
initPageNUm();
}
// //
interface SelectUserInfo {
likeCount: number
bean: number
download: number
attention: number
likeCount: number;
bean: number;
download: number;
attention: number;
}
const selectUserInfo = ref<SelectUserInfo>({
likeCount: 0,
bean: 0,
download: 0,
attention: 0,
})
});
async function getAttention() {
try {
const res = await request.get('/attention/selectUserInfo')
const res = await request.get("/attention/selectUserInfo");
if (res.code === 200) {
selectUserInfo.value = res.data
selectUserInfo.value = res.data;
}
}
catch (err) {
console.log(err)
} catch (err) {
console.log(err);
}
}
getAttention()
getAttention();
// Banner
const bannerStyle = {
backgroundImage:
'url(\'https://liblibai-web-static.liblib.cloud/liblibai_v4_online/static/_next/static/images/defaultBgImg.381282c0f2b01780c83d8fe6dc0aa90a.png\')',
}
"url('https://liblibai-web-static.liblib.cloud/liblibai_v4_online/static/_next/static/images/defaultBgImg.381282c0f2b01780c83d8fe6dc0aa90a.png')",
};
//
interface ApiResponse<T> {
code: number
rows: T[]
message: string
code: number;
rows: T[];
message: string;
}
//
interface UserData {
id: number
name: string
email: string
status: number
id: number;
name: string;
email: string;
status: number;
}
//
const dataList = ref([])
const dataList = ref([]);
async function getList() {
if (loading.value || finished.value)
return
if (loading.value || finished.value) return;
loading.value = true
let params = {}
if (currentState.value === 'mallProduct') {
params = publishParams.value
loading.value = true;
let params = {};
if (currentState.value === "mallProduct") {
params = publishParams.value;
} else {
params = likesParams.value;
}
else {
params = likesParams.value
}
const url = urlList.value[currentState.value][currentType.value]
const url = urlList.value[currentState.value][currentType.value];
try {
const res = await request.post<ApiResponse<UserData>>(url, params)
const res = await request.post<ApiResponse<UserData>>(url, params);
if (res.code === 200) {
//
if (params.pageNum === 1) {
dataList.value = res.rows
}
else {
dataList.value = [...dataList.value, ...res.rows]
dataList.value = res.rows;
} else {
dataList.value = [...dataList.value, ...res.rows];
}
total.value = res.total //
total.value = res.total; //
//
if (dataList.value.length >= total.value) {
finished.value = true
finished.value = true;
}
//
if (currentState.value === 'mallProduct') {
publishParams.value.pageNum++
}
else {
likesParams.value.pageNum++
if (currentState.value === "mallProduct") {
publishParams.value.pageNum++;
} else {
likesParams.value.pageNum++;
}
}
}
catch (err) {
dataList.value = []
finished.value = true
console.log(err)
}
finally {
loading.value = false
} catch (err) {
dataList.value = [];
finished.value = true;
console.log(err);
} finally {
loading.value = false;
}
}
getList()
onMounted(() => {
window.addEventListener('scroll', topedRefresh)
observer.value = new IntersectionObserver(([entry]) => {
window.addEventListener("scroll", topedRefresh);
observer.value = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting && !loading.value && !finished.value) {
getList()
getList();
}
}, {
},
{
threshold: 0.1,
})
}
);
if (loadingTrigger.value) {
observer.value.observe(loadingTrigger.value)
observer.value.observe(loadingTrigger.value);
}
})
if (type && type === "like") {
currentState.value = type;
}
if (status === "0" || status === "1" || status === "2") {
currentType.value = status;
}
getList();
});
onUnmounted(() => {
window.removeEventListener('scroll', topedRefresh)
window.removeEventListener("scroll", topedRefresh);
if (observer.value) {
observer.value.disconnect()
observer.value.disconnect();
}
})
});
async function topedRefresh() {
if (import.meta.client) {
await nextTick()
await nextTick();
window.scrollTo({
top: 0,
behavior: 'smooth',
})
behavior: "smooth",
});
}
initPageNUm()
initPageNUm();
}
// /
const currentAttentionType = ref<string>('attention')
const attentionIsVisible = ref<boolean>(false)
// function onShowAttentionModel(type: string) {
// attentionIsVisible.value = true
// }
function onCloseAttentionModel() {
attentionIsVisible.value = false
function onClearDate() {
(publishParams.value.startTime = ""), (publishParams.value.endTime = ""), initPageNUm();
}
function onClearDate(){
publishParams.value.startTime = '',
publishParams.value.endTime = '',
initPageNUm()
//
const isShowFan = ref(false)
const attentionFinished = ref(false)
const attentionList = ref([]);
const attentionListParams = ref({
pageNumber: 1,
pageSize: 15,
});
async function getAttentionList() {
try{
if(attentionFinished.value) return
const res = await request.post(`/attention/selectToAttention`, {
...attentionListParams.value,
});
if (res.code === 200) {
if (attentionListParams.value.pageNumber === 1) {
attentionList.value = res.data.list;
} else {
attentionList.value = [...attentionList.value, ...res.data.list];
}
total.value = res.data.total; //
//
if ( attentionList.value.length >= total.value) {
attentionFinished.value = true;
}
attentionListParams.value.pageNumber++
}
} catch (err) {
attentionList.value = [];
attentionFinished.value = true;
console.log(err);
}
}
getAttentionList();
//
const likeFinished = ref(false)
const likeList = ref([]);
const likeListParams = ref({
pageNumber: 1,
pageSize: 15,
});
async function getLikeList() {
try{
if(likeFinished.value) return
const res = await request.post(`/attention/selectAttentionList`, {
...likeListParams.value,
});
if (res.code === 200) {
if (likeListParams.value.pageNumber === 1) {
likeList.value = res.data.list;
} else {
likeList.value = [...likeList.value, ...res.data.list];
}
total.value = res.data.total; //
//
if ( likeList.value.length >= total.value) {
likeFinished.value = true;
}
likeListParams.value.pageNumber++
}
} catch (err) {
likeList.value = [];
likeFinished.value = true;
console.log(err);
}
}
getLikeList();
function closefanList() {
isShowFan.value = false
}
// /
async function onAttention(item:any){
try {
const res = await request.get(`/attention/addAttention?userId=${item.userId}`);
if (res.code === 200) {
if(res.data){
message.success('关注成功')
}else{
message.success('取消关注成功')
}
item.attention = !item.attention
}
} catch (err) {
console.log(err);
}
}
</script>
<template>
<div class="mx-auto container">
<div class="mx-auto">
<!-- Banner Section -->
<div class="banner-content h-32 bg-blue bg-cover bg-center" :style="bannerStyle" />
@ -358,15 +459,16 @@ function onClearDate(){
<div class="info-content mt-[-50px] p-5">
<div class="edit-info-content flex items-center">
<!-- Avatar -->
<div class="mc-head mr-5 h-20 w-20 rounded-full bg-white shadow-lg flex items-center justify-center">
<div
class="mc-head mr-5 h-20 w-20 rounded-full bg-white shadow-lg flex items-center justify-center"
>
<div class="mc-head-inner h-18 w-18 m-1 rounded-full bg-blue-200">
<client-only>
<img
class="head-img m-1 h-16 w-16 rounded-full bg-white"
:src="userStore.userInfo.avatar"
:src="userStore?.userInfo?.avatar"
alt="User Avatar"
>
/>
</client-only>
<!-- {{ userStore.userInfo.avatar }} -->
</div>
@ -397,7 +499,7 @@ function onClearDate(){
<!-- User Details -->
<div class="user-info mt-4">
<div v-if="userStore.userInfo" class="nickname text-2xl font-bold">
<div v-if="userStore.userInfo" class="nickname text-xl font-bold">
{{ userStore.userInfo.nickName }}
<!-- {{ userInfo.nickName }} -->
</div>
@ -405,13 +507,21 @@ function onClearDate(){
{{ userStore.userInfo.brief }}
</div>
<div class="production-state mt-4 flex text-sm text-gray-700">
<div class="production-state-item mr-5 cursor-pointer" @click="onShowAttentionModel('bean')">
<div
class="production-state-item mr-5 cursor-pointer"
@click="isShowFan = true"
>
<span class="production-state-number font-bold">{{
selectUserInfo.bean ? selectUserInfo.bean : 0
}}</span>
粉丝
</div>
<div class="production-state-item mr-5 cursor-pointer" @click="onShowAttentionModel('attention')">
<div
class="production-state-item mr-5 cursor-pointer"
@click="isShowFan = true"
>
<span class="production-state-number font-bold">{{
selectUserInfo.attention ? selectUserInfo.attention : 0
}}</span>
@ -472,7 +582,7 @@ function onClearDate(){
label-field="dictLabel"
value-field="dictValue"
placeholder="请选择"
style="width: 180px;"
style="width: 180px"
class="mr-2"
@update:value="changeStatus"
/>
@ -492,7 +602,7 @@ function onClearDate(){
<n-date-picker
v-model:value="publishParams.date"
type="daterange"
style="width: 230px;"
style="width: 230px"
format="yyyy-MM-dd"
value-format="yyyy.MM.dd"
range-separator="至"
@ -525,8 +635,8 @@ function onClearDate(){
</NMessageProvider>
</NConfigProvider>
<!-- Dialog Components -->
<div class="login-content my-4 grid grid-cols-4 gap-4 px-5">
<!-- grid grid-cols-2 lg:grid-cols-4 xl:grid-cols-5 2xl:grid-cols-6 gap-4 p-4 -->
<div class="login-content my-4 grid xl:grid-cols-4 2xl:grid-cols-5 gap-4 px-5">
<PersonalCenterCard
v-for="(item, index) in dataList"
:key="index"
@ -537,31 +647,86 @@ function onClearDate(){
/>
</div>
<div ref="loadingTrigger" class="h-10">
<div v-if="loading" class="text-center text-gray-500">
加载中...
<div v-if="loading" class="text-center text-gray-500">...</div>
<div v-if="finished" class="text-center text-gray-500"></div>
</div>
<div v-if="finished" class="text-center text-gray-500">
没有更多数据了
</div>
</div>
<NModal
v-model:show="attentionIsVisible"
:on-after-leave="onCloseAttentionModel"
preset="card"
style="width: 400px"
:mask-closable="false"
<div class="fan-centent" v-if="isShowFan">
<div
class="w-[550px] h-[calc(100vh-100px)] max-h-[700px] m-auto py-0 px-8 pb-[43px] bg-[#fff] rounded-lg relative"
>
<div>
<div class="">
<div>粉丝</div>
<div>关注</div>
<n-icon size="20" class="mr-2 cursor-pointer absolute top-4 right-2" @click="closefanList">
<Close />
</n-icon>
<n-tabs
v-model:value="activeTab"
default-value="like"
justify-content="space-evenly"
type="line"
>
<n-tab-pane name="like" :tab="`粉丝${selectUserInfo.bean || 0}`">
<n-infinite-scroll style="height: calc(100vh - 200px);padding:0 10px" :distance="10" @load="getAttentionList">
<!-- <div class="overflow-y-auto h-[calc(100vh-200px)] px-2"> -->
<div
v-for="(item, index) in attentionList"
:key="index"
class="flex justify-between items-center p-2"
>
<div class="flex items-center">
<img :src="item.avatar || ''" alt="" class="w-14 h-14 rounded-full mr-2" />
{{ item.nickName }}
</div>
<div class="bg-[#f4f5f9] px-4 py-2 rounded-full cursor-pointer" @click="onAttention(item)">
{{ item.attention ? '已关注' : '未关注' }}
</div>
</div>
<div v-if="attentionList.length === 0" class="w-full text-center text-gray-500 font-bold mt-2">
暂无数据
</div>
<!-- </div> -->
</n-infinite-scroll>
</n-tab-pane>
<n-tab-pane name="attention" :tab="`关注${selectUserInfo.attention || 0}`">
<!-- <div class="overflow-y-auto h-[calc(100vh-200px)] px-2"> -->
<n-infinite-scroll style="height: calc(100vh - 200px); padding:0 10px" :distance="10" @load="getLikeList">
<div
v-for="(item, index) in likeList"
:key="index"
class="flex justify-between items-center p-2"
>
<div class="flex items-center">
<img :src="item.avatar || ''" alt="" class="w-14 h-14 rounded-full mr-2" />
{{ item.nickName }}
</div>
<div class="bg-[#f4f5f9] px-4 py-2 rounded-full cursor-pointer" @click="onAttention(item)">
{{ item.attention ? '已关注' : '未关注' }}
</div>
</div>
<div v-if="attentionList.length === 0" class="w-full text-center text-gray-500 font-bold mt-2">
暂无数据
</div>
<!-- </div> -->
</n-infinite-scroll>
</n-tab-pane>
</n-tabs>
</div>
</div>
</NModal>
</div>
</template>
<style scoped>
.fan-centent {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background: rgba(0, 0, 0, 0.4);
}
.edit-info {
box-shadow: 0 2px 10px 0 rgba(0, 0, 0, 0.2);
}

View File

@ -0,0 +1,449 @@
<template>
<div class="mx-auto container">
<div
class="banner-content h-32 bg-blue bg-cover bg-center rounded-sm"
:style="bannerStyle"
/>
<div class="info-content mt-[-50px] p-5">
<div class="edit-info-content flex items-center">
<div
class="mc-head mr-5 h-20 w-20 rounded-full bg-white shadow-lg flex items-center justify-center"
>
<div class="mc-head-inner h-18 w-18 m-1 rounded-full bg-blue-200">
<client-only>
<img
class="head-img m-1 h-16 w-16 rounded-full bg-white"
:src="currentUserInfo.avatar"
alt="User Avatar"
/>
</client-only>
<!-- {{ userStore.userInfo.avatar }} -->
</div>
</div>
<div
class="mr-2 cursor-pointer rounded-full bg-gradient-to-r from-[#1f66df] to-[#3faeff] px-4 py-1 text-white"
@click="onAttention"
v-if="isAttention !== null"
>
{{ isAttention ? '已关注' : '关注' }}
</div>
</div>
<div class="user-info mt-4">
<div v-if="currentUserInfo" class="nickname text-xl font-bold">
{{ currentUserInfo.nickName }}
<!-- {{ userInfo.nickName }} -->
</div>
<div v-if="currentUserInfo" class="info-desc mt-1 text-sm text-gray-700">
{{ currentUserInfo.brief }}
</div>
<div class="production-state mt-4 flex text-sm text-gray-700">
<div
class="production-state-item mr-5 cursor-pointer"
@click="isShowFan = true"
>
<span class="production-state-number font-bold" >{{
selectUserInfo.bean ? selectUserInfo.bean : 0
}}</span>
粉丝
</div>
<div
class="production-state-item mr-5 cursor-pointer"
@click="isShowFan = true"
>
<span class="production-state-number font-bold">{{
selectUserInfo.attention ? selectUserInfo.attention : 0
}}</span>
关注
</div>
<div class="production-state-item mr-5">
<span class="production-state-number font-bold">{{
selectUserInfo.download ? selectUserInfo.download : 0
}}</span>
作品被使用次数
</div>
<div class="production-state-item">
<span class="production-state-number font-bold">{{
selectUserInfo.likeCount ? selectUserInfo.likeCount : 0
}}</span>
作品被点赞次数
</div>
</div>
</div>
<div class="select-content mt-4 flex items-center justify-between">
<div class="flex items-center rounded-full bg-gray-100">
<div
v-for="(item, index) in typeList"
:key="index"
class="m-1 mr-2 cursor-pointer rounded-full px-4 py-1 text-sm"
:class="{
'bg-white': item.id === currentType,
}"
@click="changeType(item.id)"
>
{{ item.title }}
</div>
</div>
<div class="flex items-center">
<NSelect
v-model:value="publishParams.orderByColumn"
:options="orderOptions"
label-field="dictLabel"
value-field="dictValue"
placeholder="请选择"
class="w-32"
@update:value="changeLikeOrder"
/>
</div>
</div>
</div>
<div class="login-content my-4 grid grid-cols-4 gap-4 px-5">
<PersonalCenterPublishCard
v-for="(item, index) in dataList"
:key="index"
:item="item"
:current-type="currentType"
@toped-refresh="topedRefresh"
/>
</div>
<div ref="loadingTrigger" class="h-10">
<div v-if="loading" class="text-center text-gray-500">...</div>
<div v-if="finished" class="text-center text-gray-500"></div>
</div>
<div class="fan-centent" v-if="isShowFan">
<div
class="w-[550px] h-[calc(100vh-100px)] max-h-[700px] m-auto py-0 px-8 pb-[43px] bg-[#fff] rounded-lg relative"
>
<n-icon size="20" class="mr-2 cursor-pointer absolute top-4 right-2" @click="closefanList">
<Close />
</n-icon>
<n-tabs
v-model:value="activeTab"
default-value="like"
justify-content="space-evenly"
type="line"
>
<n-tab-pane name="like" :tab="`粉丝${selectUserInfo.bean || 0}`">
<n-infinite-scroll style="height: calc(100vh - 200px)" :distance="10" @load="getAttentionList">
<div class="overflow-y-auto h-[calc(100vh-200px)] px-2">
<div
v-for="(item, index) in attentionList"
:key="index"
class="flex justify-between items-center py-2"
>
<div class="flex items-center">
<img :src="item.avatar || ''" alt="" class="w-14 h-14 rounded-full mr-2" />
{{ item.nickName }}
</div>
<div class="bg-[#f4f5f9] px-4 py-2 rounded-full cursor-pointer" @click="onAttention(item)">
{{ item.attention ? '已关注' : '未关注' }}
</div>
</div>
<div v-if="attentionList.length === 0" class="w-full text-center text-gray-500 font-bold mt-2">
暂无数据
</div>
</div>
</n-infinite-scroll>
</n-tab-pane>
<n-tab-pane name="attention" :tab="`关注${selectUserInfo.attention || 0}`">
<div class="overflow-y-auto h-[calc(100vh-200px)] px-2">
<div
v-for="(item, index) in likeList"
:key="index"
class="flex justify-between items-center py-2"
>
<div class="flex items-center">
<img :src="item.avatar || ''" alt="" class="w-14 h-14 rounded-full mr-2" />
{{ item.nickName }}
</div>
<div class="bg-[#f4f5f9] px-4 py-2 rounded-full cursor-pointer" @click="onAttention(item)">
{{ item.attention ? '已关注' : '未关注' }}
</div>
</div>
<div v-if="attentionList.length === 0" class="w-full text-center text-gray-500 font-bold mt-2">
暂无数据
</div>
</div>
</n-tab-pane>
</n-tabs>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { Close } from "@vicons/ionicons5";
import { nextTick, onMounted, onUnmounted, ref } from "vue";
import { useRoute } from "vue-router";
const observer = ref<IntersectionObserver | null>(null);
const message = useMessage()
const route = useRoute();
const { userId } = route.query;
const loading = ref(false);
const finished = ref(false);
const total = ref(0); //
const loadingTrigger = ref(null);
const urlList = ref({
"0": "/model/selectByUserIdModel",
"1": "/model/selectByUserIdWorkFlow",
"2": "/model/selectByUserIdImage",
});
const currentType = ref("0");
const typeList = ref([
{ id: "0", title: "模型" },
{ id: "1", title: "工作流" },
{ id: "2", title: "图片" },
]);
const orderOptions = ref([
{
dictLabel: "最新",
dictValue: "create_time",
},
{
dictLabel: "最热",
dictValue: "like_num",
},
]);
const isShowFan = ref(false);
const activeTab = ref("like");
function closefanList() {
isShowFan.value = false
}
const bannerStyle = {
backgroundImage:
"url('https://liblibai-web-static.liblib.cloud/liblibai_v4_online/static/_next/static/images/defaultBgImg.381282c0f2b01780c83d8fe6dc0aa90a.png')",
};
const publishParams = ref({
pageNum: 1,
pageSize: 12,
orderByColumn: "create_time",
userId: userId,
});
const currentUserInfo = ref({});
async function getCurrentUserInfo() {
const res = await request.get(`/system/user/selectUserById?id=${userId}`);
if (res.code === 200) {
currentUserInfo.value = res.data;
}
}
getCurrentUserInfo();
//
const attentionList = ref([]);
const attentionListParams = ref({
pageNumber: 1,
pageSize: 20,
type: userId,
});
async function getAttentionList() {
const res = await request.post(`/attention/selectToAttention`, {
...attentionListParams.value,
});
if (res.code === 200) {
attentionList.value = res.data.list;
}
}
getAttentionList();
//
const likeList = ref([]);
const likeListParams = ref({
pageNumber: 1,
pageSize: 20,
type: userId,
});
async function getLikeList() {
const res = await request.post(`/attention/selectAttentionList`, {
...likeListParams.value,
});
if (res.code === 200) {
likeList.value = res.data.list;
}
}
getLikeList();
//
const isAttention = ref(false)
async function getIsAttention(){
const res = await request.get(`/attention/selectAttention?userId=${userId}`)
if(res.code === 200){
isAttention.value = res.data
}
}
getIsAttention()
// /
async function onAttention(item:any){
let paramsUserId
if(item.userId){
paramsUserId = item.userId
}else{
paramsUserId = userId
}
try {
const res = await request.get(`/attention/addAttention?userId=${paramsUserId}`);
if (res.code === 200) {
if(res.data){
message.success('关注成功')
}else{
message.success('取消关注成功')
}
if(item.userId){
item.attention = !item.attention
}else{
isAttention.value = !isAttention.value
}
}
} catch (err) {
console.log(err);
}
}
// //
interface SelectUserInfo {
likeCount: number;
bean: number;
download: number;
attention: number;
}
const selectUserInfo = ref<SelectUserInfo>({
likeCount: 0,
bean: 0,
download: 0,
attention: 0,
});
async function getAttention() {
try {
const res = await request.get(`/attention/selectUserInfo?userId=${userId}`);
if (res.code === 200) {
selectUserInfo.value = res.data;
}
} catch (err) {
console.log(err);
}
}
getAttention();
// //
function changeType(id: string) {
currentType.value = id;
initPageNUm();
}
// /
function changeLikeOrder(value: string) {
publishParams.value.orderByColumn = value;
initPageNUm();
}
function initPageNUm() {
publishParams.value.pageNum = 1;
finished.value = false; //
getList();
}
//
const dataList = ref([]);
async function getList() {
if (loading.value || finished.value) return;
loading.value = true;
const url = urlList.value[currentType.value];
try {
const res = await request.post(url, publishParams.value);
if (res.code === 200) {
//
if (publishParams.value.pageNum === 1) {
dataList.value = res.rows;
} else {
dataList.value = [...dataList.value, ...res.rows];
}
total.value = res.total; //
//
if (dataList.value.length >= total.value) {
finished.value = true;
}
publishParams.value.pageNum++;
}
} catch (err) {
dataList.value = [];
finished.value = true;
console.log(err);
} finally {
loading.value = false;
}
}
getList();
async function topedRefresh() {
if (import.meta.client) {
await nextTick();
window.scrollTo({
top: 0,
behavior: "smooth",
});
}
initPageNUm();
}
onMounted(() => {
window.addEventListener("scroll", topedRefresh);
observer.value = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting && !loading.value && !finished.value) {
getList();
}
},
{
threshold: 0.1,
}
);
if (loadingTrigger.value) {
observer.value.observe(loadingTrigger.value);
}
});
onUnmounted(() => {
window.removeEventListener("scroll", topedRefresh);
if (observer.value) {
observer.value.disconnect();
}
});
</script>
<style scoped lang="scss">
.fan-centent {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background: rgba(0, 0, 0, 0.4);
}
.n-tabs.n-tabs--flex .n-tabs-nav .n-tabs-wrapper .n-tabs-tab {
margin-right: 0;
font-size: 20px;
}
</style>

View File

@ -90,10 +90,11 @@ function changeCategory(item: any) {
</div>
<div class="flex items-center mt-4">
<div class="text-[20px] mr-4">作品灵感</div>
<HeaderSearchInput v-model="params.name" @search="onSearch" />
<!-- <HeaderSearchInput v-model="params.name" @search="onSearch" /> -->
</div>
<div class="flex flex-wrap mt-2">
<div class="flex flex-wrap">
<MenuFold v-if="modelCategoryList.length > 0">
<div
v-for="(item, index) in modelCategoryList"
:key="index"
@ -106,6 +107,7 @@ function changeCategory(item: any) {
>
{{ item.dictLabel }}
</div>
</MenuFold>
</div>
</div>
<div class="flex flex-wrap">

View File

@ -59,12 +59,12 @@ async function initFormData() {
try {
const res = await request.get(`/model/finbyid?id=${id}`);
formData.value = res.data;
if(res.data.modelProduct.modelType && res.data.modelProduct.modelType != 0){
formData.value.modelProduct.modelType = res.data.modelProduct.modelType.toString();
}
if(res.data.modelProduct.activityId && res.data.modelProduct.activityId != 0){
if(res.data.modelProduct.activityId != null){
formData.value.modelProduct.activityId = Number(res.data.modelProduct.activityId);
}
if(formData.value.modelProduct.tags){
formData.value.modelProduct.tagsList = JSON.parse(formData.value.modelProduct.tags);
}else{
@ -76,20 +76,6 @@ async function initFormData() {
formData.value.modelVersionList[i].modelVersionType = formData.value.modelVersionList[i].modelVersionType.toString()
}
}
// if (formData.value.workFlow.type) {
// formData.value.workFlow.typeList = formData.value.workFlow.type.split(',')
// }
// else {
// formData.value.workFlow.typeList = []
// }
// if (formData.value.workFlow.activityParticipation) {
// formData.value.workFlow.activityParticipation = Number(formData.value.workFlow.activityParticipation)
// }
// for (let i = 0; i < formData.value.workFlowVersionList.length; i++) {
// if (formData.value.workFlowVersionList[i].imagePaths) {
// formData.value.workFlowVersionList[i].imagePaths = formData.value.workFlowVersionList[i].imagePaths.split(',')
// }
// }
} catch (error) {
console.log(error);
}

View File

@ -0,0 +1,169 @@
<template>
<div class="p-4">
<div class="flex bg-[#f2f1f7] rounded-lg w-[300px]">
<div
v-for="(item, index) in typeList"
:key="index"
class="px-2 py-3 flex-1 flex items-center justify-center cursor-pointer rounded-lg"
:style="{
background: item.type === currentType ? '#3162ff1a' : '#f1f2f7',
color: item.type === currentType ? '#3162ff' : '#666',
}"
@click="changeType(item.type)"
>
{{ item.text }}
{{ item.total > 999 ? "999+" : item.total }}
</div>
</div>
<div>
<!-- <PictureList ref="listRef" :params="imageParams" /> -->
<ModelList
@modelTotal="modelTotal"
v-show="currentType === 'model'"
ref="modelRef"
:params="modelParams"
></ModelList>
<PictureList
@imageTotal="imageTotal"
v-show="currentType === 'image'" ref="imageRef" :params="imageParams" />
<WorkFlowList
@workFlowTotal="workFlowTotal"
v-show="currentType === 'workFlow'"
ref="workFlowRef"
:params="workFlowParams"
/>
</div>
</div>
</template>
<script setup lang="ts">
const modalStore = useModalStore();
// definePageMeta({
// middleware:[
// function (to:any){
// if(to.path !== '/search'){
// modalStore.searchQuery = ''
// }
// }
// ]
// })
import { computed, ref, watch } from "vue";
const route = useRoute();
const { type, keyword } = route.query as {type: string, keyword:string };
const currentType = ref("model");
const modelParams = ref({
name:modalStore.searchQuery
});
const workFlowParams = ref({
name:modalStore.searchQuery
});
const imageParams = ref({
name:modalStore.searchQuery
});
if(type != 'undefined'){
currentType.value = type
}
// debugger
// if(keyword){
// modelParams.value.name = keyword;
// imageParams.value.name = keyword;
// workFlowParams.value.name = keyword;
// }
const typeList = ref([
{
type: "model",
total: 0,
text: "模型",
},
{
type: "workFlow",
total: 0,
text: "工作流",
},
{
type: "image",
total: 0,
text: "作品",
},
]);
//
const modelRef = ref(null);
function onSearchModel() {
if (modelRef.value) {
modelRef.value?.initPageNUm();
}
}
onSearchModel();
//
const workFlowRef = ref(null);
function onSearchWorkFlow() {
if (workFlowRef.value) {
workFlowRef.value?.initPageNUm();
}
}
onSearchWorkFlow();
//
const imageRef = ref(null);
function onSearchImage() {
if (imageRef.value) {
imageRef.value?.initPageNUm();
}
}
onSearchImage()
function handleSearch(newValue: string = "") {
// if (newValue) {
modelParams.value.name = newValue;
imageParams.value.name = newValue;
workFlowParams.value.name = newValue;
// }
onSearchModel();
onSearchImage();
onSearchWorkFlow();
// if (currentType.value === "model") {
// } else if (currentType.value === "image") {
// } else {
// }
}
//
function changeType(type: string) {
currentType.value = type;
handleSearch();
}
//
function modelTotal(total:number){
typeList.value[0].total = total
}
function workFlowTotal(total:number){
typeList.value[1].total = total
}
function imageTotal(total:number){
typeList.value[2].total = total
}
const searchQuery = computed(() => modalStore.searchQuery);
watch(searchQuery, (newValue:string) => {
handleSearch(newValue);
});
</script>
<style scoped>
.test {
justify-content: center;
cursor: pointer;
}
</style>

View File

@ -89,10 +89,11 @@ function changeCategory(item: any) {
</div>
<div class="flex items-center mt-4">
<div class="text-[20px] mr-4">工作流</div>
<HeaderSearchInput v-model="params.name" @search="onSearch" />
<!-- <HeaderSearchInput v-model="params.name" @search="onSearch" /> -->
</div>
<div class="flex flex-wrap mt-2">
<div class="flex flex-wrap">
<MenuFold v-if="workFlowCategoryList.length > 0">
<div
v-for="(item, index) in workFlowCategoryList"
:key="index"
@ -105,6 +106,7 @@ function changeCategory(item: any) {
>
{{ item.dictLabel }}
</div>
</MenuFold>
</div>
</div>
<div class="flex flex-wrap">

View File

@ -1,15 +1,16 @@
<script setup lang="ts">
import { Heart, PersonAddOutline } from '@vicons/ionicons5'
import { commonApi } from "@/api/common";
import { Close, DiamondSharp, PersonAddOutline } from '@vicons/ionicons5';
import {
CircleUser,
Download,
EllipsisVertical, Play
} from 'lucide-vue-next'
import { NConfigProvider, NMessageProvider } from 'naive-ui'
import { nextTick, ref } from 'vue'
import { useRouter } from 'vue-router'
EllipsisVertical, Heart, Play
} from 'lucide-vue-next';
// import { NConfigProvider, NMessageProvider } from 'naive-ui';
import { nextTick, ref } from 'vue';
import { useRouter } from 'vue-router';
const userStore = useUserStore();
const message = useMessage()
const router = useRouter()
@ -24,6 +25,7 @@ const activeTab = ref(null)
const commentHeight = ref(800)
const detailsInfo = ref({})
const currentUserInfo = ref<any>({})
const isVisibleReport = ref(false);
//
const versionByWorkInfo = ref([])
@ -103,7 +105,8 @@ const isDelete = ref(false)
async function handleSelect(event: Event, type: string) {
event.stopPropagation() //
if (type === 'report') {
await request.get(`/WorkFlow/report?id=${id}`) //
// await request.get(`/WorkFlow/report?id=${id}`) //
isVisibleReport.value = true;
}
else if (type === 'edit') {
router.push({
@ -172,6 +175,61 @@ async function onLike() {
console.log(err)
}
}
//
const reportParams = ref({
reportId: undefined,
text: "",
type:3
});
const reportList = ref([]);
async function getDictType() {
try {
const res = await commonApi.dictType({ type: "report_type" });
if (res.code === 200) {
reportList.value = res.data;
}
} catch (error) {
console.log(error);
}
}
getDictType();
function handleChange(item: any) {
reportParams.value.reportId = item.dictValue;
if (item.dictValue !== "5") {
reportParams.value.text = "";
}
console.log("object", reportParams.value);
}
function closeReport() {
isVisibleReport.value = false;
}
async function onReport(){
if( reportParams.value.reportId !== undefined){
reportParams.value.productId = detailsInfo.value.id
try{
const res = await request.post('/report/addReport', reportParams.value)
if(res.code === 200){
message.success("举报成功");
closeReport()
}
}catch(err){
console.log(err);
}
}
}
function toPersonalCenter(){
const baseUrl = window.location.origin
if(userStore?.userInfo?.userId === detailsInfo.value.userId){
window.open(`${baseUrl}/personal-center`, '_blank', 'noopener,noreferrer')
}else{
window.open(`${baseUrl}/personal-publish?userId=${detailsInfo.value.userId}`, '_blank', 'noopener,noreferrer')
}
}
</script>
<template>
@ -208,8 +266,12 @@ async function onLike() {
<n-tooltip trigger="hover">
<template #trigger>
<div class="flex items-center bg-[#f4f5f9] px-2 rounded-full">
<img src="@/assets/img/heart.png" class="w-[14px] h-[14px] mr-1" alt="">
<span> <!-- {{ item.numbers }} -->{{ detailsInfo.likeCount }} </span>
<!-- <img src="@/assets/img/heart.png" class="w-[14px] h-[14px] mr-1" alt=""> -->
<component
:is="Heart"
class="h-[12px] w-[12px] mr-1 text-[#000]"
/>
<span>{{ detailsInfo.likeCount }} </span>
</div>
</template>
点赞数
@ -257,13 +319,17 @@ async function onLike() {
</n-tabs>
</div>
<div class="mt-4">
<client-only>
<div style="padding: 20px">
<NConfigProvider>
<BaseComment v-if="detailsInfo.id" type="workflow" :height="commentHeight" :details-info="detailsInfo" />
<!-- <NConfigProvider>
<NMessageProvider>
<BaseComment v-if="detailsInfo.id" type="workflow" :height="commentHeight" :details-info="detailsInfo" />
</NMessageProvider>
</NConfigProvider>
</NConfigProvider> -->
</div>
</client-only>
</div>
</div>
<div class="w-1/3 mt-3">
@ -299,6 +365,7 @@ async function onLike() {
<div class="menu-item hover:bg-gray-100 py-2 cursor-pointer rounded-lg" @click="(event) => handleSelect(event, 'report')">
举报
</div>
<template v-if="userStore?.userInfo?.userId === detailsInfo.userId">
<div
class="menu-item hover:bg-gray-100 py-2 cursor-pointer rounded-lg"
@click="(event) => handleSelect(event, 'edit')"
@ -308,6 +375,7 @@ async function onLike() {
<div class="menu-item hover:bg-gray-100 py-2 cursor-pointer rounded-lg" @click="(event) => handleSelect(event, 'delete')">
删除
</div>
</template>
</div>
</div>
</div>
@ -315,7 +383,7 @@ async function onLike() {
<div
class="flex items-center mt-10 p-2 bg-[#f3f5f9] w-full rounded-md h-[80px] box-border"
>
<div class="w-[70px] h-[70px] rounded-full overflow-hidden mr-4">
<div class="w-[60px] h-[60px] rounded-full overflow-hidden mr-4">
<!-- <img
src="@/assets/img/default-avatar.png"
class="w-full h-full mr-2 block"
@ -323,7 +391,8 @@ async function onLike() {
> -->
<client-only>
<NAvatar
class="w-full h-full mr-2 block"
@click="toPersonalCenter"
class="w-full h-full mr-2 block cursor-pointer"
round
size="small"
:src="currentUserInfo.avatar"
@ -339,18 +408,23 @@ async function onLike() {
</div>
</client-only>
<!-- 0代表原创 1代表转载 -->
<div v-if="detailsInfo.original === 0" class="text-[14px]">
<div v-if="detailsInfo.original === 0" class="original">
<n-icon size="14" class="mr-2">
<DiamondSharp />
</n-icon>
原创作者
</div>
</div>
<div class="flex-1 flex justify-end">
<div class="flex items-center font-bold px-1 justify-center w-24 h-10 rounded-full text-[#426af7] border-2 border-[#426af7] border-solid cursor-pointer" @click="onChangeAttention">
<n-icon v-if="detailsInfo.isAttention === 0" size="20" class="mr-2">
<client-only>
<div class="flex-1 flex justify-end" v-if="userStore?.userInfo?.userId !== detailsInfo.userId">
<div class="flex items-center font-bold px-1 justify-center w-20 h-8 rounded-full text-[#426af7] border border-[#426af7] border-solid cursor-pointer" @click="onChangeAttention">
<n-icon v-if="detailsInfo.isAttention === 0" size="16" class="mr-2">
<PersonAddOutline />
</n-icon>
{{ detailsInfo.isAttention === 1 ? '已关注' : '关注' }}
</div>
</div>
</client-only>
</div>
<div class="flex items-center text-[#969798]">
@ -368,7 +442,7 @@ async function onLike() {
:is="Play"
class="h-[12px] w-[12px] text-black menu-icon m-1 text-[#969798]"
/>
<span class="mr-2"> {{ selectUserInfo.modelRunNum }} </span>
<span class="mr-2"> {{ selectUserInfo.productNum }} </span>
<component
:is="Download"
class="h-[12px] w-[12px] text-black menu-icon m-1 text-[#969798]"
@ -379,7 +453,7 @@ async function onLike() {
</div>
<!-- 不支持的bg #b1b2b2 -->
<div
class="flex items-center justify-center mt-4 w-full h-14 text-white bg-[#3c7af6] w-full rounded-md h-[80px] cursor-pointer"
class="flex items-center justify-center mt-4 w-full h-14 text-white bg-[#3c7af6] w-full rounded-md h-[50px] cursor-pointer"
>
<component
:is="Play"
@ -389,7 +463,7 @@ async function onLike() {
</div>
<div
class="flex items-center justify-center mt-4 w-full h-14 text-black bg-[#eceef4] w-full rounded-md h-[80px] cursor-pointer hover:bg-[#f1f2f7]"
class="flex items-center justify-center mt-4 w-full h-14 text-black bg-[#eceef4] w-full rounded-md h-[50px] cursor-pointer hover:bg-[#f1f2f7]"
>
<component
:is="Download"
@ -415,6 +489,60 @@ async function onLike() {
@negative-click="onDelete"
@positive-click="onDelete"
/>
<n-modal
v-model:show="isVisibleReport"
:preset="null"
:mask-closable="false"
transform-origin="center"
class="custom-modal"
>
<div class="bg-white rounded-xl p-4">
<div class="flex items-center justify-between">
<div class="text-xl">举报</div>
<div>
<n-icon size="20" class="mr-2 cursor-pointer" @click="closeReport">
<Close />
</n-icon>
</div>
</div>
<div class="flex flex-col">
<n-radio
class="m-4 text-[#fff000]"
size="large"
v-for="(item, index) in reportList"
:key="index"
:checked="reportParams.reportId === item.dictValue"
value="Definitely Maybe"
name="basic-demo"
@change="handleChange(item)"
>
{{ item.dictLabel }}
</n-radio>
<n-input
v-if="reportParams.reportId !== undefined && reportParams.reportId === '5'"
v-model:value="reportParams.text"
placeholder="点击输入"
type="textarea"
:autosize="{
minRows: 5,
maxRows: 10,
}"
/>
<div
@click="onReport"
class="mt-4 w-[100%] h-10 flex rounded-lg text-white items-center justify-center cursor-pointer"
:class="[
reportParams.reportId !== undefined
? 'bg-[#4c79ee]'
: 'bg-[#cccccc]',
]"
>
确认
</div>
</div>
</div>
</n-modal>
<div />
</div>
</div>
@ -455,4 +583,17 @@ async function onLike() {
opacity 0.3s var(--n-bezier),
background-color 0.3s var(--n-bezier);
}
.original{
display: flex;
align-items: center;
justify-content: center;
margin: 2px 0;
padding: 2px 0;
width: 90px;
color: #aa8645;
font-weight: 400;
background: linear-gradient(94.11deg, #efd6a9 10.52%, #f0dcbc 107.96%);
border-radius: 4px;
transform: skew(-10deg);
}
</style>

View File

@ -5,6 +5,11 @@ import { ref } from 'vue'
export const useModalStore = defineStore('modal', () => {
const loginModalRef = ref<any>(null)
const isModalVisible = ref(false)
const searchQuery = ref('')
function updateSearchQuery(keywork:string){
searchQuery.value = keywork
}
function setLoginModal(modalRef: any) {
loginModalRef.value = modalRef
@ -33,5 +38,27 @@ export const useModalStore = defineStore('modal', () => {
setLoginModal,
showLoginModal,
hideLoginModal,
searchQuery,
updateSearchQuery
}
},{
persist: {
key: 'mc-modal',
// paths: ['isLoggedIn', 'mymcname', 'token', 'userInfo'], // 只持久化 token
storage: import.meta.client ? localStorage : undefined,
},
// persist: {
// storage: {
// getItem(key) {
// return window.localStorage.getItem(key)
// },
// setItem(key, value) {
// window.localStorage.setItem(key, value)
// },
// },
// serializer: {
// deserialize: parse,
// serialize: stringify,
// },
// },
})

View File

@ -3,10 +3,6 @@ import defaultAvatar from '@/assets/img/default-avatar.png'
import { defineStore } from 'pinia'
import { ref } from 'vue'
import {
parse,
stringify,
} from 'zipson'
export interface UserInfoType {
nickName: string

View File

@ -1,7 +1,8 @@
// utils/request.ts
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
import axios from 'axios'
import { createDiscreteApi } from 'naive-ui'
import { useModalStore } from '@/stores/modal.ts';
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
import axios from 'axios';
import { createDiscreteApi } from 'naive-ui';
const { message, loadingBar } = createDiscreteApi(['message', 'loadingBar'])
@ -25,8 +26,10 @@ class RequestHttp {
// 请求拦截器
this.instance.interceptors.request.use(
(config) => {
(config:any) => {
const userStore = useUserStore()
const isToken = (config.headers || {}).isToken === false
if (userStore.token && !isToken) {
config.headers.Authorization = `Bearer ${userStore.token}` // 让每个请求携带自定义token 请根据实际情况自行修改
@ -37,7 +40,7 @@ class RequestHttp {
}
return config
},
(error) => {
(error:any) => {
return Promise.reject(error)
},
)
@ -56,27 +59,28 @@ class RequestHttp {
this.handleError(data.code)
// token过期以后需要重新登录
if (data.code === 401) {
debugger
// message.error(data.message || '登录已过期,请重新登录')
// const modalStore = useModalStore()
const modalStore = useModalStore();
modalStore.showLoginModal();
const userStore = useUserStore()
// useUser.logout()
// modalStore.showLoginModal()
try {
// eslint-disable-next-line ts/no-use-before-define
await request.post('/logout')
userStore.logout()
navigateTo('/model-square')
// navigateTo('/model-square')
}
catch (error) {
console.log(error)
}
}
// message.error(data.message || '请求失败')
return Promise.reject(data)
}
return data
},
(error) => {
(error:any) => {
// 关闭 loading
loadingBar.error()
@ -166,7 +170,7 @@ class RequestHttp {
}
const request = new RequestHttp({
baseURL: process.env.NUXT_API_BASE_URL || '/api',
baseURL: import.meta.env.VITE_NUXT_ENV || '/api',
timeout: 15000,
headers: {
'Content-Type': 'application/json',

View File

@ -10,7 +10,6 @@ import type { ApiResponse } from '~/types/api'
export async function uploadImagesInBatches(files: File[], batchSize = 3) {
const uploadResults = []
for (let i = 0; i < files.length; i++) {
const file = files[i]
@ -31,8 +30,7 @@ export async function uploadImagesInBatches(files: File[], batchSize = 3) {
}
}
catch (error) {
console.error(`图片上传失败: ${file.name}`, error)
uploadResults.push({ success: false, error })
throw new Error(`上传第 ${i + 1} 张图片失败!`);
}
}
return uploadResults

View File

@ -5,7 +5,6 @@ import { NaiveUiResolver } from 'unplugin-vue-components/resolvers'
import Components from 'unplugin-vue-components/vite'
import { pwa } from './app/config/pwa'
import { appDescription } from './app/constants/index'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
@ -58,7 +57,7 @@ export default defineNuxtConfig({
},
build: {
transpile: process.env.NODE_ENV === 'production'
transpile: import.meta.env.NODE_ENV === 'production'
? ['naive-ui', 'vueuc', '@css-render/vue3-ssr', '@juggle/resize-observer']
: ['@juggle/resize-observer'],
},
@ -84,8 +83,8 @@ export default defineNuxtConfig({
devProxy: {
'/api': {
// target: 'http://1.13.246.108:8080', // 线上
// target: 'http://192.168.2.10:8080', // 代
target: 'http://192.168.1.69:8080', // 嗨
target: 'http://192.168.2.10:8080', // 代
// target: 'http://192.168.1.69:8080', // 嗨
// target: 'https://2d1a399f.r27.cpolar.top', // 嗨
changeOrigin: true,
prependPath: true,
@ -125,7 +124,7 @@ export default defineNuxtConfig({
css: {
preprocessorOptions: {
scss: {
additionalData: '@use "@assets/scss/_variables.scss";', // 使用 @import 而不是 @use
// additionalData: '@use "@assets/scss/_variables.scss";', // 使用 @import 而不是 @use
},
},
},
@ -150,7 +149,7 @@ export default defineNuxtConfig({
pwa,
tailwindcss: {
cssPath: 'assets/scss/_tailwind.scss',
// cssPath: 'assets/scss/_tailwind.scss',
configPath: 'tailwind.config.js',
exposeConfig: false,
viewer: true,

View File

@ -1,16 +1,19 @@
{
"name": "mcwl",
"version": "1.0.0",
"type": "module",
"private": true,
"packageManager": "pnpm@9.15.1",
"scripts": {
"build": "nuxi build",
"build": "nuxi build --dotenv .env.pro",
"dev:pwa": "VITE_PLUGIN_PWA=true nuxi dev",
"dev": "nuxi dev",
"dev": "nuxi dev --port 3002",
"generate": "nuxi generate",
"prepare": "nuxi prepare",
"start": "node .output/server/index.mjs",
"start:generate": "npx serve .output/public",
"lint": "eslint .",
"preview": "nuxt preview",
"typecheck": "vue-tsc --noEmit"
},
"dependencies": {
@ -29,6 +32,7 @@
"devDependencies": {
"@antfu/eslint-config": "^3.12.1",
"@css-render/vue3-ssr": "^0.15.14",
"@esbuild/linux-x64": "0.24.2",
"@iconify-json/carbon": "^1.2.5",
"@iconify-json/twemoji": "^1.2.2",
"@nuxt/devtools": "^1.7.0",
@ -37,6 +41,7 @@
"@nuxtjs/tailwindcss": "^6.13.1",
"@pinia-plugin-persistedstate/nuxt": "^1.2.1",
"@pinia/nuxt": "^0.9.0",
"@rollup/rollup-linux-x64-gnu": "^4.34.8",
"@types/node": "^22.10.6",
"@vite-pwa/nuxt": "^0.10.6",
"@vueuse/nuxt": "^12.2.0",
@ -49,6 +54,7 @@
"nuxtjs-naive-ui": "^1.0.2",
"pinia": "^2.3.0",
"postcss": "^8.5.1",
"rollup": "^4.34.8",
"sass": "^1.83.4",
"sass-loader": "^16.0.4",
"tailwindcss": "^3.4.17",

View File

@ -36,7 +36,7 @@ dependencies:
version: 2.41.0
pinia-plugin-persistedstate:
specifier: ^4.2.0
version: 4.2.0(@pinia/nuxt@0.9.0)(pinia@2.3.1)
version: 4.2.0(@pinia/nuxt@0.9.0)(pinia@2.3.1)(rollup@4.34.8)
wangeditor:
specifier: ^4.7.15
version: 4.7.15
@ -51,6 +51,9 @@ devDependencies:
'@css-render/vue3-ssr':
specifier: ^0.15.14
version: 0.15.14
'@esbuild/linux-x64':
specifier: 0.24.2
version: 0.24.2
'@iconify-json/carbon':
specifier: ^1.2.5
version: 1.2.5
@ -59,31 +62,34 @@ devDependencies:
version: 1.2.2
'@nuxt/devtools':
specifier: ^1.7.0
version: 1.7.0(vue@3.5.13)
version: 1.7.0(rollup@4.34.8)(vue@3.5.13)
'@nuxt/eslint':
specifier: ^0.7.4
version: 0.7.6(eslint-plugin-format@0.1.3)(eslint@9.19.0)(typescript@5.7.3)
version: 0.7.6(eslint-plugin-format@0.1.3)(eslint@9.19.0)(rollup@4.34.8)(typescript@5.7.3)
'@nuxtjs/color-mode':
specifier: ^3.5.2
version: 3.5.2
version: 3.5.2(rollup@4.34.8)
'@nuxtjs/tailwindcss':
specifier: ^6.13.1
version: 6.13.1
version: 6.13.1(rollup@4.34.8)
'@pinia-plugin-persistedstate/nuxt':
specifier: ^1.2.1
version: 1.2.1(@pinia/nuxt@0.9.0)(pinia@2.3.1)
version: 1.2.1(@pinia/nuxt@0.9.0)(pinia@2.3.1)(rollup@4.34.8)
'@pinia/nuxt':
specifier: ^0.9.0
version: 0.9.0(pinia@2.3.1)
version: 0.9.0(pinia@2.3.1)(rollup@4.34.8)
'@rollup/rollup-linux-x64-gnu':
specifier: ^4.34.8
version: 4.34.8
'@types/node':
specifier: ^22.10.6
version: 22.13.0
'@vite-pwa/nuxt':
specifier: ^0.10.6
version: 0.10.6
version: 0.10.6(rollup@4.34.8)
'@vueuse/nuxt':
specifier: ^12.2.0
version: 12.5.0(nuxt@3.15.4)(typescript@5.7.3)
version: 12.5.0(nuxt@3.15.4)(rollup@4.34.8)(typescript@5.7.3)
autoprefixer:
specifier: ^10.4.20
version: 10.4.20(postcss@8.5.1)
@ -98,16 +104,19 @@ devDependencies:
version: 0.1.3(eslint@9.19.0)
nuxt:
specifier: ^3.15.0
version: 3.15.4(@types/node@22.13.0)(eslint@9.19.0)(sass@1.83.4)(typescript@5.7.3)(vue-tsc@2.2.0)
version: 3.15.4(@types/node@22.13.0)(eslint@9.19.0)(rollup@4.34.8)(sass@1.83.4)(typescript@5.7.3)(vue-tsc@2.2.0)
nuxtjs-naive-ui:
specifier: ^1.0.2
version: 1.0.2
version: 1.0.2(rollup@4.34.8)
pinia:
specifier: ^2.3.0
version: 2.3.1(typescript@5.7.3)
postcss:
specifier: ^8.5.1
version: 8.5.1
rollup:
specifier: ^4.34.8
version: 4.34.8
sass:
specifier: ^1.83.4
version: 1.83.4
@ -122,10 +131,10 @@ devDependencies:
version: 5.7.3
unplugin-auto-import:
specifier: ^19.0.0
version: 19.0.0
version: 19.0.0(rollup@4.34.8)
unplugin-vue-components:
specifier: ^28.0.0
version: 28.0.0
version: 28.0.0(rollup@4.34.8)
vue-tsc:
specifier: ^2.2.0
version: 2.2.0(typescript@5.7.3)
@ -1612,7 +1621,6 @@ packages:
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/netbsd-arm64@0.24.2:
resolution: {integrity: sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==}
@ -2061,12 +2069,12 @@ packages:
resolution: {integrity: sha512-GBzP8zOc7CGWyFQS6dv1lQz8VVpz5C2yRszbXufwG/9zhStTIH50EtD87NmWbTMwXDvZLNg8GIpb1UFdH93JCA==}
dev: true
/@nuxt/devtools-kit@1.7.0(magicast@0.3.5):
/@nuxt/devtools-kit@1.7.0(magicast@0.3.5)(rollup@4.34.8):
resolution: {integrity: sha512-+NgZ2uP5BuneqvQbe7EdOEaFEDy8762c99pLABtn7/Ur0ExEsQJMP7pYjjoTfKubhBqecr5Vo9yHkPBj1eHulQ==}
peerDependencies:
vite: ^6.0.6
dependencies:
'@nuxt/kit': 3.15.4(magicast@0.3.5)
'@nuxt/kit': 3.15.4(magicast@0.3.5)(rollup@4.34.8)
'@nuxt/schema': 3.15.4
execa: 7.2.0
transitivePeerDependencies:
@ -2091,16 +2099,16 @@ packages:
semver: 7.7.0
dev: true
/@nuxt/devtools@1.7.0(vue@3.5.13):
/@nuxt/devtools@1.7.0(rollup@4.34.8)(vue@3.5.13):
resolution: {integrity: sha512-uvnjt5Zowkz7tZmnks2cGreg1XZIiSyVzQ2MYiRXACodlXcwJ0dpUS3WTxu8BR562K+772oRdvKie9AQlyZUgg==}
hasBin: true
peerDependencies:
vite: ^6.0.6
dependencies:
'@antfu/utils': 0.7.10
'@nuxt/devtools-kit': 1.7.0(magicast@0.3.5)
'@nuxt/devtools-kit': 1.7.0(magicast@0.3.5)(rollup@4.34.8)
'@nuxt/devtools-wizard': 1.7.0
'@nuxt/kit': 3.15.4(magicast@0.3.5)
'@nuxt/kit': 3.15.4(magicast@0.3.5)(rollup@4.34.8)
'@vue/devtools-core': 7.6.8(vue@3.5.13)
'@vue/devtools-kit': 7.6.8
birpc: 0.2.19
@ -2129,8 +2137,8 @@ packages:
simple-git: 3.27.0
sirv: 3.0.0
tinyglobby: 0.2.10
unimport: 3.14.6(rollup@4.34.0)
vite-plugin-inspect: 0.10.6(@nuxt/kit@3.15.4)
unimport: 3.14.6(rollup@4.34.8)
vite-plugin-inspect: 0.10.6(@nuxt/kit@3.15.4)(rollup@4.34.8)
vite-plugin-vue-inspector: 5.3.1
which: 3.0.1
ws: 8.18.0
@ -2192,7 +2200,7 @@ packages:
- typescript
dev: true
/@nuxt/eslint@0.7.6(eslint-plugin-format@0.1.3)(eslint@9.19.0)(typescript@5.7.3):
/@nuxt/eslint@0.7.6(eslint-plugin-format@0.1.3)(eslint@9.19.0)(rollup@4.34.8)(typescript@5.7.3):
resolution: {integrity: sha512-q0tKt+2LHczd0xdlfQoB11i6rgdLHHG/OZk7f/DCQdsr5IxAobGZhPAdhRn9FPxo1IecRh732BYA+usr4MPd7g==}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
@ -2205,10 +2213,10 @@ packages:
optional: true
dependencies:
'@eslint/config-inspector': 1.0.0(eslint@9.19.0)
'@nuxt/devtools-kit': 1.7.0(magicast@0.3.5)
'@nuxt/devtools-kit': 1.7.0(magicast@0.3.5)(rollup@4.34.8)
'@nuxt/eslint-config': 0.7.6(eslint-plugin-format@0.1.3)(eslint@9.19.0)(typescript@5.7.3)
'@nuxt/eslint-plugin': 0.7.6(eslint@9.19.0)(typescript@5.7.3)
'@nuxt/kit': 3.15.4(magicast@0.3.5)
'@nuxt/kit': 3.15.4(magicast@0.3.5)(rollup@4.34.8)
chokidar: 4.0.3
eslint: 9.19.0
eslint-flat-config-utils: 2.0.0
@ -2217,7 +2225,7 @@ packages:
get-port-please: 3.1.2
mlly: 1.7.4
pathe: 2.0.2
unimport: 4.0.0
unimport: 4.0.0(rollup@4.34.8)
transitivePeerDependencies:
- '@vue/compiler-sfc'
- bufferutil
@ -2230,7 +2238,7 @@ packages:
- vite
dev: true
/@nuxt/kit@3.15.4(magicast@0.3.5):
/@nuxt/kit@3.15.4(magicast@0.3.5)(rollup@4.34.8):
resolution: {integrity: sha512-dr7I7eZOoRLl4uxdxeL2dQsH0OrbEiVPIyBHnBpA4co24CBnoJoF+JINuP9l3PAM3IhUzc5JIVq3/YY3lEc3Hw==}
engines: {node: '>=18.12.0'}
dependencies:
@ -2252,7 +2260,7 @@ packages:
std-env: 3.8.0
ufo: 1.5.4
unctx: 2.4.1
unimport: 4.0.0
unimport: 4.0.0(rollup@4.34.8)
untyped: 1.5.2
transitivePeerDependencies:
- magicast
@ -2269,12 +2277,12 @@ packages:
std-env: 3.8.0
dev: true
/@nuxt/telemetry@2.6.4:
/@nuxt/telemetry@2.6.4(rollup@4.34.8):
resolution: {integrity: sha512-2Lgdn07Suraly5dSfVQ4ttBQBMtmjvCTGKGUHpc1UyH87HT9xCm3KLFO0UcVQ8+LNYCgoOaK7lq9qDJOfBfZ5A==}
engines: {node: '>=18.20.5'}
hasBin: true
dependencies:
'@nuxt/kit': 3.15.4(magicast@0.3.5)
'@nuxt/kit': 3.15.4(magicast@0.3.5)(rollup@4.34.8)
citty: 0.1.6
consola: 3.4.0
destr: 2.0.3
@ -2293,14 +2301,14 @@ packages:
- supports-color
dev: true
/@nuxt/vite-builder@3.15.4(@types/node@22.13.0)(eslint@9.19.0)(sass@1.83.4)(typescript@5.7.3)(vue-tsc@2.2.0)(vue@3.5.13):
/@nuxt/vite-builder@3.15.4(@types/node@22.13.0)(eslint@9.19.0)(rollup@4.34.8)(sass@1.83.4)(typescript@5.7.3)(vue-tsc@2.2.0)(vue@3.5.13):
resolution: {integrity: sha512-yBK6tWT973+ExKC3ciTWymZpjJ+enToOtYz574kXCyGO0PbSnuXdoJKTvrwXw1lK97PajCKxExlmwI/3oLOmMQ==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0.0}
peerDependencies:
vue: ^3.3.4
dependencies:
'@nuxt/kit': 3.15.4(magicast@0.3.5)
'@rollup/plugin-replace': 6.0.2(rollup@4.34.0)
'@nuxt/kit': 3.15.4(magicast@0.3.5)(rollup@4.34.8)
'@rollup/plugin-replace': 6.0.2(rollup@4.34.8)
'@vitejs/plugin-vue': 5.2.1(vite@6.0.11)(vue@3.5.13)
'@vitejs/plugin-vue-jsx': 4.1.1(vite@6.0.11)(vue@3.5.13)
autoprefixer: 10.4.20(postcss@8.5.1)
@ -2321,7 +2329,7 @@ packages:
perfect-debounce: 1.0.0
pkg-types: 1.3.1
postcss: 8.5.1
rollup-plugin-visualizer: 5.14.0(rollup@4.34.0)
rollup-plugin-visualizer: 5.14.0(rollup@4.34.8)
std-env: 3.8.0
ufo: 1.5.4
unenv: 1.10.0
@ -2357,10 +2365,10 @@ packages:
- yaml
dev: true
/@nuxtjs/color-mode@3.5.2:
/@nuxtjs/color-mode@3.5.2(rollup@4.34.8):
resolution: {integrity: sha512-cC6RfgZh3guHBMLLjrBB2Uti5eUoGM9KyauOaYS9ETmxNWBMTvpgjvSiSJp1OFljIXPIqVTJ3xtJpSNZiO3ZaA==}
dependencies:
'@nuxt/kit': 3.15.4(magicast@0.3.5)
'@nuxt/kit': 3.15.4(magicast@0.3.5)(rollup@4.34.8)
pathe: 1.1.2
pkg-types: 1.3.1
semver: 7.7.0
@ -2370,10 +2378,10 @@ packages:
- supports-color
dev: true
/@nuxtjs/tailwindcss@6.13.1:
/@nuxtjs/tailwindcss@6.13.1(rollup@4.34.8):
resolution: {integrity: sha512-atL2SaPsxLfMTlXUQvr1UpDYdz6ocNOhH35H+t7M++g4r79QiQScJ7XuyyMR9AyBN19lkPA3nw7NXxazXmYxlA==}
dependencies:
'@nuxt/kit': 3.15.4(magicast@0.3.5)
'@nuxt/kit': 3.15.4(magicast@0.3.5)(rollup@4.34.8)
autoprefixer: 10.4.20(postcss@8.5.1)
c12: 2.0.1(magicast@0.3.5)
consola: 3.4.0
@ -2553,16 +2561,16 @@ packages:
'@parcel/watcher-win32-x64': 2.5.1
dev: true
/@pinia-plugin-persistedstate/nuxt@1.2.1(@pinia/nuxt@0.9.0)(pinia@2.3.1):
/@pinia-plugin-persistedstate/nuxt@1.2.1(@pinia/nuxt@0.9.0)(pinia@2.3.1)(rollup@4.34.8):
resolution: {integrity: sha512-q8s+4aQW/AjBMyeqLL48/qzBR5lcgnvvf1525ovNuKf6Wl9CsoLjPKh/5X8vNoKGwSow4gP7lVmdYPQRypgjgg==}
deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
peerDependencies:
'@pinia/nuxt': ^0.5.0
dependencies:
'@nuxt/kit': 3.15.4(magicast@0.3.5)
'@pinia/nuxt': 0.9.0(pinia@2.3.1)
'@nuxt/kit': 3.15.4(magicast@0.3.5)(rollup@4.34.8)
'@pinia/nuxt': 0.9.0(pinia@2.3.1)(rollup@4.34.8)
defu: 6.1.4
pinia-plugin-persistedstate: 4.2.0(@pinia/nuxt@0.9.0)(pinia@2.3.1)
pinia-plugin-persistedstate: 4.2.0(@pinia/nuxt@0.9.0)(pinia@2.3.1)(rollup@4.34.8)
transitivePeerDependencies:
- magicast
- pinia
@ -2570,12 +2578,12 @@ packages:
- supports-color
dev: true
/@pinia/nuxt@0.9.0(pinia@2.3.1):
/@pinia/nuxt@0.9.0(pinia@2.3.1)(rollup@4.34.8):
resolution: {integrity: sha512-2yeRo7LeyCF68AbNeL3xu2h6uw0617RkcsYxmA8DJM0R0PMdz5wQHnc44KeENQxR/Mrq8T910XVT6buosqsjBQ==}
peerDependencies:
pinia: ^2.3.0
dependencies:
'@nuxt/kit': 3.15.4(magicast@0.3.5)
'@nuxt/kit': 3.15.4(magicast@0.3.5)(rollup@4.34.8)
pinia: 2.3.1(typescript@5.7.3)
transitivePeerDependencies:
- magicast
@ -2628,7 +2636,7 @@ packages:
- supports-color
dev: true
/@rollup/plugin-alias@5.1.1(rollup@4.34.0):
/@rollup/plugin-alias@5.1.1(rollup@4.34.8):
resolution: {integrity: sha512-PR9zDb+rOzkRb2VD+EuKB7UC41vU5DIwZ5qqCpk0KJudcWAyi8rvYOhS7+L5aZCspw1stTViLgN5v6FF1p5cgQ==}
engines: {node: '>=14.0.0'}
peerDependencies:
@ -2637,7 +2645,7 @@ packages:
rollup:
optional: true
dependencies:
rollup: 4.34.0
rollup: 4.34.8
dev: true
/@rollup/plugin-babel@5.3.1(@babel/core@7.26.7)(rollup@2.79.2):
@ -2659,7 +2667,7 @@ packages:
- supports-color
dev: true
/@rollup/plugin-commonjs@28.0.2(rollup@4.34.0):
/@rollup/plugin-commonjs@28.0.2(rollup@4.34.8):
resolution: {integrity: sha512-BEFI2EDqzl+vA1rl97IDRZ61AIwGH093d9nz8+dThxJNH8oSoB7MjWvPCX3dkaK1/RCJ/1v/R1XB15FuSs0fQw==}
engines: {node: '>=16.0.0 || 14 >= 14.17'}
peerDependencies:
@ -2668,17 +2676,17 @@ packages:
rollup:
optional: true
dependencies:
'@rollup/pluginutils': 5.1.4(rollup@4.34.0)
'@rollup/pluginutils': 5.1.4(rollup@4.34.8)
commondir: 1.0.1
estree-walker: 2.0.2
fdir: 6.4.3(picomatch@4.0.2)
is-reference: 1.2.1
magic-string: 0.30.17
picomatch: 4.0.2
rollup: 4.34.0
rollup: 4.34.8
dev: true
/@rollup/plugin-inject@5.0.5(rollup@4.34.0):
/@rollup/plugin-inject@5.0.5(rollup@4.34.8):
resolution: {integrity: sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==}
engines: {node: '>=14.0.0'}
peerDependencies:
@ -2687,13 +2695,13 @@ packages:
rollup:
optional: true
dependencies:
'@rollup/pluginutils': 5.1.4(rollup@4.34.0)
'@rollup/pluginutils': 5.1.4(rollup@4.34.8)
estree-walker: 2.0.2
magic-string: 0.30.17
rollup: 4.34.0
rollup: 4.34.8
dev: true
/@rollup/plugin-json@6.1.0(rollup@4.34.0):
/@rollup/plugin-json@6.1.0(rollup@4.34.8):
resolution: {integrity: sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==}
engines: {node: '>=14.0.0'}
peerDependencies:
@ -2702,8 +2710,8 @@ packages:
rollup:
optional: true
dependencies:
'@rollup/pluginutils': 5.1.4(rollup@4.34.0)
rollup: 4.34.0
'@rollup/pluginutils': 5.1.4(rollup@4.34.8)
rollup: 4.34.8
dev: true
/@rollup/plugin-node-resolve@15.3.1(rollup@2.79.2):
@ -2723,7 +2731,7 @@ packages:
rollup: 2.79.2
dev: true
/@rollup/plugin-node-resolve@15.3.1(rollup@4.34.0):
/@rollup/plugin-node-resolve@15.3.1(rollup@4.34.8):
resolution: {integrity: sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==}
engines: {node: '>=14.0.0'}
peerDependencies:
@ -2732,12 +2740,12 @@ packages:
rollup:
optional: true
dependencies:
'@rollup/pluginutils': 5.1.4(rollup@4.34.0)
'@rollup/pluginutils': 5.1.4(rollup@4.34.8)
'@types/resolve': 1.20.2
deepmerge: 4.3.1
is-module: 1.0.0
resolve: 1.22.10
rollup: 4.34.0
rollup: 4.34.8
dev: true
/@rollup/plugin-replace@2.4.2(rollup@2.79.2):
@ -2750,7 +2758,7 @@ packages:
rollup: 2.79.2
dev: true
/@rollup/plugin-replace@6.0.2(rollup@4.34.0):
/@rollup/plugin-replace@6.0.2(rollup@4.34.8):
resolution: {integrity: sha512-7QaYCf8bqF04dOy7w/eHmJeNExxTYwvKAmlSAH/EaWWUzbT0h5sbF6bktFoX/0F/0qwng5/dWFMyf3gzaM8DsQ==}
engines: {node: '>=14.0.0'}
peerDependencies:
@ -2759,9 +2767,9 @@ packages:
rollup:
optional: true
dependencies:
'@rollup/pluginutils': 5.1.4(rollup@4.34.0)
'@rollup/pluginutils': 5.1.4(rollup@4.34.8)
magic-string: 0.30.17
rollup: 4.34.0
rollup: 4.34.8
dev: true
/@rollup/plugin-terser@0.4.4(rollup@2.79.2):
@ -2779,7 +2787,7 @@ packages:
terser: 5.37.0
dev: true
/@rollup/plugin-terser@0.4.4(rollup@4.34.0):
/@rollup/plugin-terser@0.4.4(rollup@4.34.8):
resolution: {integrity: sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==}
engines: {node: '>=14.0.0'}
peerDependencies:
@ -2788,7 +2796,7 @@ packages:
rollup:
optional: true
dependencies:
rollup: 4.34.0
rollup: 4.34.8
serialize-javascript: 6.0.2
smob: 1.5.0
terser: 5.37.0
@ -2821,7 +2829,7 @@ packages:
rollup: 2.79.2
dev: true
/@rollup/pluginutils@5.1.4(rollup@4.34.0):
/@rollup/pluginutils@5.1.4(rollup@4.34.8):
resolution: {integrity: sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==}
engines: {node: '>=14.0.0'}
peerDependencies:
@ -2833,146 +2841,145 @@ packages:
'@types/estree': 1.0.6
estree-walker: 2.0.2
picomatch: 4.0.2
rollup: 4.34.0
rollup: 4.34.8
/@rollup/rollup-android-arm-eabi@4.34.0:
resolution: {integrity: sha512-Eeao7ewDq79jVEsrtWIj5RNqB8p2knlm9fhR6uJ2gqP7UfbLrTrxevudVrEPDM7Wkpn/HpRC2QfazH7MXLz3vQ==}
/@rollup/rollup-android-arm-eabi@4.34.8:
resolution: {integrity: sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw==}
cpu: [arm]
os: [android]
requiresBuild: true
optional: true
/@rollup/rollup-android-arm64@4.34.0:
resolution: {integrity: sha512-yVh0Kf1f0Fq4tWNf6mWcbQBCLDpDrDEl88lzPgKhrgTcDrTtlmun92ywEF9dCjmYO3EFiSuJeeo9cYRxl2FswA==}
/@rollup/rollup-android-arm64@4.34.8:
resolution: {integrity: sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q==}
cpu: [arm64]
os: [android]
requiresBuild: true
optional: true
/@rollup/rollup-darwin-arm64@4.34.0:
resolution: {integrity: sha512-gCs0ErAZ9s0Osejpc3qahTsqIPUDjSKIyxK/0BGKvL+Tn0n3Kwvj8BrCv7Y5sR1Ypz1K2qz9Ny0VvkVyoXBVUQ==}
/@rollup/rollup-darwin-arm64@4.34.8:
resolution: {integrity: sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q==}
cpu: [arm64]
os: [darwin]
requiresBuild: true
optional: true
/@rollup/rollup-darwin-x64@4.34.0:
resolution: {integrity: sha512-aIB5Anc8hngk15t3GUkiO4pv42ykXHfmpXGS+CzM9CTyiWyT8HIS5ygRAy7KcFb/wiw4Br+vh1byqcHRTfq2tQ==}
/@rollup/rollup-darwin-x64@4.34.8:
resolution: {integrity: sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw==}
cpu: [x64]
os: [darwin]
requiresBuild: true
optional: true
/@rollup/rollup-freebsd-arm64@4.34.0:
resolution: {integrity: sha512-kpdsUdMlVJMRMaOf/tIvxk8TQdzHhY47imwmASOuMajg/GXpw8GKNd8LNwIHE5Yd1onehNpcUB9jHY6wgw9nHQ==}
/@rollup/rollup-freebsd-arm64@4.34.8:
resolution: {integrity: sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA==}
cpu: [arm64]
os: [freebsd]
requiresBuild: true
optional: true
/@rollup/rollup-freebsd-x64@4.34.0:
resolution: {integrity: sha512-D0RDyHygOBCQiqookcPevrvgEarN0CttBecG4chOeIYCNtlKHmf5oi5kAVpXV7qs0Xh/WO2RnxeicZPtT50V0g==}
/@rollup/rollup-freebsd-x64@4.34.8:
resolution: {integrity: sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q==}
cpu: [x64]
os: [freebsd]
requiresBuild: true
optional: true
/@rollup/rollup-linux-arm-gnueabihf@4.34.0:
resolution: {integrity: sha512-mCIw8j5LPDXmCOW8mfMZwT6F/Kza03EnSr4wGYEswrEfjTfVsFOxvgYfuRMxTuUF/XmRb9WSMD5GhCWDe2iNrg==}
/@rollup/rollup-linux-arm-gnueabihf@4.34.8:
resolution: {integrity: sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g==}
cpu: [arm]
os: [linux]
libc: [glibc]
requiresBuild: true
optional: true
/@rollup/rollup-linux-arm-musleabihf@4.34.0:
resolution: {integrity: sha512-AwwldAu4aCJPob7zmjuDUMvvuatgs8B/QiVB0KwkUarAcPB3W+ToOT+18TQwY4z09Al7G0BvCcmLRop5zBLTag==}
/@rollup/rollup-linux-arm-musleabihf@4.34.8:
resolution: {integrity: sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA==}
cpu: [arm]
os: [linux]
libc: [musl]
requiresBuild: true
optional: true
/@rollup/rollup-linux-arm64-gnu@4.34.0:
resolution: {integrity: sha512-e7kDUGVP+xw05pV65ZKb0zulRploU3gTu6qH1qL58PrULDGxULIS0OSDQJLH7WiFnpd3ZKUU4VM3u/Z7Zw+e7Q==}
/@rollup/rollup-linux-arm64-gnu@4.34.8:
resolution: {integrity: sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A==}
cpu: [arm64]
os: [linux]
libc: [glibc]
requiresBuild: true
optional: true
/@rollup/rollup-linux-arm64-musl@4.34.0:
resolution: {integrity: sha512-SXYJw3zpwHgaBqTXeAZ31qfW/v50wq4HhNVvKFhRr5MnptRX2Af4KebLWR1wpxGJtLgfS2hEPuALRIY3LPAAcA==}
/@rollup/rollup-linux-arm64-musl@4.34.8:
resolution: {integrity: sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q==}
cpu: [arm64]
os: [linux]
libc: [musl]
requiresBuild: true
optional: true
/@rollup/rollup-linux-loongarch64-gnu@4.34.0:
resolution: {integrity: sha512-e5XiCinINCI4RdyU3sFyBH4zzz7LiQRvHqDtRe9Dt8o/8hTBaYpdPimayF00eY2qy5j4PaaWK0azRgUench6WQ==}
/@rollup/rollup-linux-loongarch64-gnu@4.34.8:
resolution: {integrity: sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ==}
cpu: [loong64]
os: [linux]
libc: [glibc]
requiresBuild: true
optional: true
/@rollup/rollup-linux-powerpc64le-gnu@4.34.0:
resolution: {integrity: sha512-3SWN3e0bAsm9ToprLFBSro8nJe6YN+5xmB11N4FfNf92wvLye/+Rh5JGQtKOpwLKt6e61R1RBc9g+luLJsc23A==}
/@rollup/rollup-linux-powerpc64le-gnu@4.34.8:
resolution: {integrity: sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw==}
cpu: [ppc64]
os: [linux]
libc: [glibc]
requiresBuild: true
optional: true
/@rollup/rollup-linux-riscv64-gnu@4.34.0:
resolution: {integrity: sha512-B1Oqt3GLh7qmhvfnc2WQla4NuHlcxAD5LyueUi5WtMc76ZWY+6qDtQYqnxARx9r+7mDGfamD+8kTJO0pKUJeJA==}
/@rollup/rollup-linux-riscv64-gnu@4.34.8:
resolution: {integrity: sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw==}
cpu: [riscv64]
os: [linux]
libc: [glibc]
requiresBuild: true
optional: true
/@rollup/rollup-linux-s390x-gnu@4.34.0:
resolution: {integrity: sha512-UfUCo0h/uj48Jq2lnhX0AOhZPSTAq3Eostas+XZ+GGk22pI+Op1Y6cxQ1JkUuKYu2iU+mXj1QjPrZm9nNWV9rg==}
/@rollup/rollup-linux-s390x-gnu@4.34.8:
resolution: {integrity: sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA==}
cpu: [s390x]
os: [linux]
libc: [glibc]
requiresBuild: true
optional: true
/@rollup/rollup-linux-x64-gnu@4.34.0:
resolution: {integrity: sha512-chZLTUIPbgcpm+Z7ALmomXW8Zh+wE2icrG+K6nt/HenPLmtwCajhQC5flNSk1Xy5EDMt/QAOz2MhzfOfJOLSiA==}
/@rollup/rollup-linux-x64-gnu@4.34.8:
resolution: {integrity: sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA==}
cpu: [x64]
os: [linux]
libc: [glibc]
requiresBuild: true
optional: true
/@rollup/rollup-linux-x64-musl@4.34.0:
resolution: {integrity: sha512-jo0UolK70O28BifvEsFD/8r25shFezl0aUk2t0VJzREWHkq19e+pcLu4kX5HiVXNz5qqkD+aAq04Ct8rkxgbyQ==}
/@rollup/rollup-linux-x64-musl@4.34.8:
resolution: {integrity: sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ==}
cpu: [x64]
os: [linux]
libc: [musl]
requiresBuild: true
optional: true
/@rollup/rollup-win32-arm64-msvc@4.34.0:
resolution: {integrity: sha512-Vmg0NhAap2S54JojJchiu5An54qa6t/oKT7LmDaWggpIcaiL8WcWHEN6OQrfTdL6mQ2GFyH7j2T5/3YPEDOOGA==}
/@rollup/rollup-win32-arm64-msvc@4.34.8:
resolution: {integrity: sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ==}
cpu: [arm64]
os: [win32]
requiresBuild: true
optional: true
/@rollup/rollup-win32-ia32-msvc@4.34.0:
resolution: {integrity: sha512-CV2aqhDDOsABKHKhNcs1SZFryffQf8vK2XrxP6lxC99ELZAdvsDgPklIBfd65R8R+qvOm1SmLaZ/Fdq961+m7A==}
/@rollup/rollup-win32-ia32-msvc@4.34.8:
resolution: {integrity: sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w==}
cpu: [ia32]
os: [win32]
requiresBuild: true
optional: true
/@rollup/rollup-win32-x64-msvc@4.34.0:
resolution: {integrity: sha512-g2ASy1QwHP88y5KWvblUolJz9rN+i4ZOsYzkEwcNfaNooxNUXG+ON6F5xFo0NIItpHqxcdAyls05VXpBnludGw==}
/@rollup/rollup-win32-x64-msvc@4.34.8:
resolution: {integrity: sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g==}
cpu: [x64]
os: [win32]
requiresBuild: true
@ -3323,13 +3330,13 @@ packages:
nanoid: 3.3.8
dev: false
/@vercel/nft@0.27.10(rollup@4.34.0):
/@vercel/nft@0.27.10(rollup@4.34.8):
resolution: {integrity: sha512-zbaF9Wp/NsZtKLE4uVmL3FyfFwlpDyuymQM1kPbeT0mVOHKDQQNjnnfslB3REg3oZprmNFJuh3pkHBk2qAaizg==}
engines: {node: '>=16'}
hasBin: true
dependencies:
'@mapbox/node-pre-gyp': 2.0.0
'@rollup/pluginutils': 5.1.4(rollup@4.34.0)
'@rollup/pluginutils': 5.1.4(rollup@4.34.8)
acorn: 8.14.0
acorn-import-attributes: 1.9.5(acorn@8.14.0)
async-sema: 3.1.1
@ -3350,7 +3357,7 @@ packages:
resolution: {integrity: sha512-zvZKBPjEXKN7AXNo2Na2uy+nvuv6SP4KAMQxpKL2vfHMj0fSvuw7JZcOPCjQC3e7ayssKnaoFVAhbYcW6v41qQ==}
dev: false
/@vite-pwa/nuxt@0.10.6:
/@vite-pwa/nuxt@0.10.6(rollup@4.34.8):
resolution: {integrity: sha512-yQTrMNLz2KuroEaqstHYvylT258BgYryON1tC2MQGCG8VVyWXfmYZPeffid/zCE8pkKMQpp6e9owKUyVLgT5xg==}
peerDependencies:
'@vite-pwa/assets-generator': ^0.2.6
@ -3358,7 +3365,7 @@ packages:
'@vite-pwa/assets-generator':
optional: true
dependencies:
'@nuxt/kit': 3.15.4(magicast@0.3.5)
'@nuxt/kit': 3.15.4(magicast@0.3.5)(rollup@4.34.8)
pathe: 1.1.2
ufo: 1.5.4
vite-plugin-pwa: 0.21.1
@ -3644,16 +3651,16 @@ packages:
resolution: {integrity: sha512-Ui7Lo2a7AxrMAXRF+fAp9QsXuwTeeZ8fIB9wsLHqzq9MQk+2gMYE2IGJW48VMJ8ecvCB3z3GsGLKLbSasQ5Qlg==}
dev: true
/@vueuse/nuxt@12.5.0(nuxt@3.15.4)(typescript@5.7.3):
/@vueuse/nuxt@12.5.0(nuxt@3.15.4)(rollup@4.34.8)(typescript@5.7.3):
resolution: {integrity: sha512-daqSOlXv5ilAiT5GlRBtfqdkYjeMO9P6n50OpbEVm9hXmfXmZoXK3YMND8l5n5KcscD4pnD66IrYPqqOW5eH1Q==}
peerDependencies:
nuxt: ^3.0.0
dependencies:
'@nuxt/kit': 3.15.4(magicast@0.3.5)
'@nuxt/kit': 3.15.4(magicast@0.3.5)(rollup@4.34.8)
'@vueuse/core': 12.5.0(typescript@5.7.3)
'@vueuse/metadata': 12.5.0
local-pkg: 1.0.0
nuxt: 3.15.4(@types/node@22.13.0)(eslint@9.19.0)(sass@1.83.4)(typescript@5.7.3)(vue-tsc@2.2.0)
nuxt: 3.15.4(@types/node@22.13.0)(eslint@9.19.0)(rollup@4.34.8)(sass@1.83.4)(typescript@5.7.3)(vue-tsc@2.2.0)
vue: 3.5.13(typescript@5.7.3)
transitivePeerDependencies:
- magicast
@ -6488,10 +6495,10 @@ packages:
resolve-from: 4.0.0
dev: true
/impound@0.2.0:
/impound@0.2.0(rollup@4.34.8):
resolution: {integrity: sha512-gXgeSyp9Hf7qG2/PLKmywHXyQf2xFrw+mJGpoj9DsAB9L7/MIKn+DeEx98UryWXdmbv8wUUPdcQof6qXnZoCGg==}
dependencies:
'@rollup/pluginutils': 5.1.4(rollup@4.34.0)
'@rollup/pluginutils': 5.1.4(rollup@4.34.8)
mlly: 1.7.4
pathe: 1.1.2
unenv: 1.10.0
@ -7958,16 +7965,16 @@ packages:
dependencies:
'@cloudflare/kv-asset-handler': 0.3.4
'@netlify/functions': 2.8.2
'@rollup/plugin-alias': 5.1.1(rollup@4.34.0)
'@rollup/plugin-commonjs': 28.0.2(rollup@4.34.0)
'@rollup/plugin-inject': 5.0.5(rollup@4.34.0)
'@rollup/plugin-json': 6.1.0(rollup@4.34.0)
'@rollup/plugin-node-resolve': 15.3.1(rollup@4.34.0)
'@rollup/plugin-replace': 6.0.2(rollup@4.34.0)
'@rollup/plugin-terser': 0.4.4(rollup@4.34.0)
'@rollup/pluginutils': 5.1.4(rollup@4.34.0)
'@rollup/plugin-alias': 5.1.1(rollup@4.34.8)
'@rollup/plugin-commonjs': 28.0.2(rollup@4.34.8)
'@rollup/plugin-inject': 5.0.5(rollup@4.34.8)
'@rollup/plugin-json': 6.1.0(rollup@4.34.8)
'@rollup/plugin-node-resolve': 15.3.1(rollup@4.34.8)
'@rollup/plugin-replace': 6.0.2(rollup@4.34.8)
'@rollup/plugin-terser': 0.4.4(rollup@4.34.8)
'@rollup/pluginutils': 5.1.4(rollup@4.34.8)
'@types/http-proxy': 1.17.15
'@vercel/nft': 0.27.10(rollup@4.34.0)
'@vercel/nft': 0.27.10(rollup@4.34.8)
archiver: 7.0.1
c12: 2.0.1(magicast@0.3.5)
chokidar: 3.6.0
@ -8009,8 +8016,8 @@ packages:
pkg-types: 1.3.1
pretty-bytes: 6.1.1
radix3: 1.1.2
rollup: 4.34.0
rollup-plugin-visualizer: 5.14.0(rollup@4.34.0)
rollup: 4.34.8
rollup-plugin-visualizer: 5.14.0(rollup@4.34.8)
scule: 1.3.0
semver: 7.7.0
serve-placeholder: 2.0.2
@ -8020,7 +8027,7 @@ packages:
uncrypto: 0.1.3
unctx: 2.4.1
unenv: 1.10.0
unimport: 3.14.6(rollup@4.34.0)
unimport: 3.14.6(rollup@4.34.8)
unstorage: 1.14.4(db0@0.2.3)(ioredis@5.4.2)
untyped: 1.5.2
unwasm: 0.3.9
@ -8133,7 +8140,7 @@ packages:
boolbase: 1.0.0
dev: true
/nuxt@3.15.4(@types/node@22.13.0)(eslint@9.19.0)(sass@1.83.4)(typescript@5.7.3)(vue-tsc@2.2.0):
/nuxt@3.15.4(@types/node@22.13.0)(eslint@9.19.0)(rollup@4.34.8)(sass@1.83.4)(typescript@5.7.3)(vue-tsc@2.2.0):
resolution: {integrity: sha512-hSbZO4mR0uAMJtZPNTnCfiAtgleoOu28gvJcBNU7KQHgWnNXPjlWgwMczko2O4Tmnv9zIe/CQged+2HsPwl2ZA==}
engines: {node: ^18.20.5 || ^20.9.0 || >=22.0.0}
hasBin: true
@ -8148,11 +8155,11 @@ packages:
dependencies:
'@nuxt/cli': 3.21.1
'@nuxt/devalue': 2.0.2
'@nuxt/devtools': 1.7.0(vue@3.5.13)
'@nuxt/kit': 3.15.4(magicast@0.3.5)
'@nuxt/devtools': 1.7.0(rollup@4.34.8)(vue@3.5.13)
'@nuxt/kit': 3.15.4(magicast@0.3.5)(rollup@4.34.8)
'@nuxt/schema': 3.15.4
'@nuxt/telemetry': 2.6.4
'@nuxt/vite-builder': 3.15.4(@types/node@22.13.0)(eslint@9.19.0)(sass@1.83.4)(typescript@5.7.3)(vue-tsc@2.2.0)(vue@3.5.13)
'@nuxt/telemetry': 2.6.4(rollup@4.34.8)
'@nuxt/vite-builder': 3.15.4(@types/node@22.13.0)(eslint@9.19.0)(rollup@4.34.8)(sass@1.83.4)(typescript@5.7.3)(vue-tsc@2.2.0)(vue@3.5.13)
'@types/node': 22.13.0
'@unhead/dom': 1.11.18
'@unhead/shared': 1.11.18
@ -8176,7 +8183,7 @@ packages:
h3: 1.14.0
hookable: 5.5.3
ignore: 7.0.3
impound: 0.2.0
impound: 0.2.0(rollup@4.34.8)
jiti: 2.4.2
klona: 2.0.6
knitwork: 1.2.0
@ -8202,9 +8209,9 @@ packages:
unctx: 2.4.1
unenv: 1.10.0
unhead: 1.11.18
unimport: 4.0.0
unimport: 4.0.0(rollup@4.34.8)
unplugin: 2.1.2
unplugin-vue-router: 0.11.2(vue-router@4.5.0)(vue@3.5.13)
unplugin-vue-router: 0.11.2(rollup@4.34.8)(vue-router@4.5.0)(vue@3.5.13)
unstorage: 1.14.4(db0@0.2.3)(ioredis@5.4.2)
untyped: 1.5.2
vue: 3.5.13(typescript@5.7.3)
@ -8265,11 +8272,11 @@ packages:
- yaml
dev: true
/nuxtjs-naive-ui@1.0.2:
/nuxtjs-naive-ui@1.0.2(rollup@4.34.8):
resolution: {integrity: sha512-qJ5ZKTEQieNaSNJFHdRCCz9SOLRB7Rg0vwzFJe64WYKt+SzDM2sQ7ZXj2raJzyIPBtKInQv6yDo2vvSBsLiUHA==}
dependencies:
'@css-render/vue3-ssr': 0.15.14
'@nuxt/kit': 3.15.4(magicast@0.3.5)
'@nuxt/kit': 3.15.4(magicast@0.3.5)(rollup@4.34.8)
transitivePeerDependencies:
- magicast
- rollup
@ -8631,7 +8638,7 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/pinia-plugin-persistedstate@4.2.0(@pinia/nuxt@0.9.0)(pinia@2.3.1):
/pinia-plugin-persistedstate@4.2.0(@pinia/nuxt@0.9.0)(pinia@2.3.1)(rollup@4.34.8):
resolution: {integrity: sha512-3buhA7ac+ssbOIx3VRCC8oHkoFwhDM9oHRCjo7nj+O8WUqnW+jRqh7eYT5eS/DNa3H28zp3dYf/nd/Vc8zj8eQ==}
peerDependencies:
'@pinia/nuxt': '>=0.9.0'
@ -8642,8 +8649,8 @@ packages:
pinia:
optional: true
dependencies:
'@nuxt/kit': 3.15.4(magicast@0.3.5)
'@pinia/nuxt': 0.9.0(pinia@2.3.1)
'@nuxt/kit': 3.15.4(magicast@0.3.5)(rollup@4.34.8)
'@pinia/nuxt': 0.9.0(pinia@2.3.1)(rollup@4.34.8)
deep-pick-omit: 1.2.1
defu: 6.1.4
destr: 2.0.3
@ -9406,7 +9413,7 @@ packages:
glob: 10.4.5
dev: true
/rollup-plugin-visualizer@5.14.0(rollup@4.34.0):
/rollup-plugin-visualizer@5.14.0(rollup@4.34.8):
resolution: {integrity: sha512-VlDXneTDaKsHIw8yzJAFWtrzguoJ/LnQ+lMpoVfYJ3jJF4Ihe5oYLAqLklIK/35lgUY+1yEzCkHyZ1j4A5w5fA==}
engines: {node: '>=18'}
hasBin: true
@ -9421,7 +9428,7 @@ packages:
dependencies:
open: 8.4.2
picomatch: 4.0.2
rollup: 4.34.0
rollup: 4.34.8
source-map: 0.7.4
yargs: 17.7.2
dev: true
@ -9434,32 +9441,32 @@ packages:
fsevents: 2.3.3
dev: true
/rollup@4.34.0:
resolution: {integrity: sha512-+4C/cgJ9w6sudisA0nZz0+O7lTP9a3CzNLsoDwaRumM8QHwghUsu6tqHXiTmNUp/rqNiM14++7dkzHDyCRs0Jg==}
/rollup@4.34.8:
resolution: {integrity: sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
dependencies:
'@types/estree': 1.0.6
optionalDependencies:
'@rollup/rollup-android-arm-eabi': 4.34.0
'@rollup/rollup-android-arm64': 4.34.0
'@rollup/rollup-darwin-arm64': 4.34.0
'@rollup/rollup-darwin-x64': 4.34.0
'@rollup/rollup-freebsd-arm64': 4.34.0
'@rollup/rollup-freebsd-x64': 4.34.0
'@rollup/rollup-linux-arm-gnueabihf': 4.34.0
'@rollup/rollup-linux-arm-musleabihf': 4.34.0
'@rollup/rollup-linux-arm64-gnu': 4.34.0
'@rollup/rollup-linux-arm64-musl': 4.34.0
'@rollup/rollup-linux-loongarch64-gnu': 4.34.0
'@rollup/rollup-linux-powerpc64le-gnu': 4.34.0
'@rollup/rollup-linux-riscv64-gnu': 4.34.0
'@rollup/rollup-linux-s390x-gnu': 4.34.0
'@rollup/rollup-linux-x64-gnu': 4.34.0
'@rollup/rollup-linux-x64-musl': 4.34.0
'@rollup/rollup-win32-arm64-msvc': 4.34.0
'@rollup/rollup-win32-ia32-msvc': 4.34.0
'@rollup/rollup-win32-x64-msvc': 4.34.0
'@rollup/rollup-android-arm-eabi': 4.34.8
'@rollup/rollup-android-arm64': 4.34.8
'@rollup/rollup-darwin-arm64': 4.34.8
'@rollup/rollup-darwin-x64': 4.34.8
'@rollup/rollup-freebsd-arm64': 4.34.8
'@rollup/rollup-freebsd-x64': 4.34.8
'@rollup/rollup-linux-arm-gnueabihf': 4.34.8
'@rollup/rollup-linux-arm-musleabihf': 4.34.8
'@rollup/rollup-linux-arm64-gnu': 4.34.8
'@rollup/rollup-linux-arm64-musl': 4.34.8
'@rollup/rollup-linux-loongarch64-gnu': 4.34.8
'@rollup/rollup-linux-powerpc64le-gnu': 4.34.8
'@rollup/rollup-linux-riscv64-gnu': 4.34.8
'@rollup/rollup-linux-s390x-gnu': 4.34.8
'@rollup/rollup-linux-x64-gnu': 4.34.8
'@rollup/rollup-linux-x64-musl': 4.34.8
'@rollup/rollup-win32-arm64-msvc': 4.34.8
'@rollup/rollup-win32-ia32-msvc': 4.34.8
'@rollup/rollup-win32-x64-msvc': 4.34.8
fsevents: 2.3.3
/run-applescript@7.0.0:
@ -10498,10 +10505,10 @@ packages:
resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==}
engines: {node: '>=18'}
/unimport@3.14.6(rollup@4.34.0):
/unimport@3.14.6(rollup@4.34.8):
resolution: {integrity: sha512-CYvbDaTT04Rh8bmD8jz3WPmHYZRG/NnvYVzwD6V1YAlvvKROlAeNDUBhkBGzNav2RKaeuXvlWYaa1V4Lfi/O0g==}
dependencies:
'@rollup/pluginutils': 5.1.4(rollup@4.34.0)
'@rollup/pluginutils': 5.1.4(rollup@4.34.8)
acorn: 8.14.0
escape-string-regexp: 5.0.0
estree-walker: 3.0.3
@ -10519,11 +10526,11 @@ packages:
- rollup
dev: true
/unimport@4.0.0:
/unimport@4.0.0(rollup@4.34.8):
resolution: {integrity: sha512-FH+yZ36YaVlh0ZjHesP20Q4uL+wL0EqTNxDZcUupsIn6WRYXZAbIYEMDLTaLBpkNVzFpqZXS+am51/HR3ANUNw==}
engines: {node: '>=18.12.0'}
dependencies:
'@rollup/pluginutils': 5.1.4(rollup@4.34.0)
'@rollup/pluginutils': 5.1.4(rollup@4.34.8)
acorn: 8.14.0
escape-string-regexp: 5.0.0
estree-walker: 3.0.3
@ -10579,7 +10586,7 @@ packages:
engines: {node: '>= 10.0.0'}
dev: true
/unplugin-auto-import@19.0.0:
/unplugin-auto-import@19.0.0(rollup@4.34.8):
resolution: {integrity: sha512-TREXtXqCM6YLy3rE2tjvKZEaCiPlP2e5bmnRKaS8AM2MlNgjV7UP4RPieWIfs4Isv0GoeHmov956PIIvJYdqpQ==}
engines: {node: '>=14'}
peerDependencies:
@ -10592,17 +10599,17 @@ packages:
optional: true
dependencies:
'@antfu/utils': 0.7.10
'@rollup/pluginutils': 5.1.4(rollup@4.34.0)
'@rollup/pluginutils': 5.1.4(rollup@4.34.8)
local-pkg: 0.5.1
magic-string: 0.30.17
picomatch: 4.0.2
unimport: 3.14.6(rollup@4.34.0)
unimport: 3.14.6(rollup@4.34.8)
unplugin: 2.1.2
transitivePeerDependencies:
- rollup
dev: true
/unplugin-vue-components@28.0.0:
/unplugin-vue-components@28.0.0(rollup@4.34.8):
resolution: {integrity: sha512-vYe0wSyqTVhyNFIad1iiGyQGhG++tDOMgohqenMDOAooMJP9vvzCdXTqCVx20A0rCQXFNjgoRbSeDAioLPH36Q==}
engines: {node: '>=14'}
peerDependencies:
@ -10616,7 +10623,7 @@ packages:
optional: true
dependencies:
'@antfu/utils': 0.7.10
'@rollup/pluginutils': 5.1.4(rollup@4.34.0)
'@rollup/pluginutils': 5.1.4(rollup@4.34.8)
chokidar: 3.6.0
debug: 4.4.0(supports-color@9.4.0)
fast-glob: 3.3.3
@ -10630,7 +10637,7 @@ packages:
- supports-color
dev: true
/unplugin-vue-router@0.11.2(vue-router@4.5.0)(vue@3.5.13):
/unplugin-vue-router@0.11.2(rollup@4.34.8)(vue-router@4.5.0)(vue@3.5.13):
resolution: {integrity: sha512-X8BbQ3BNnMqaCYeMj80jtz5jC4AB0jcpdmECIYey9qKm6jy/upaPZ/WzfuT+iTGRiQAY4WemHueXxuzH127oOg==}
peerDependencies:
vue-router: ^4.4.0
@ -10639,7 +10646,7 @@ packages:
optional: true
dependencies:
'@babel/types': 7.26.7
'@rollup/pluginutils': 5.1.4(rollup@4.34.0)
'@rollup/pluginutils': 5.1.4(rollup@4.34.8)
'@vue-macros/common': 1.16.1(vue@3.5.13)
ast-walker-scope: 0.6.2
chokidar: 3.6.0
@ -10912,7 +10919,7 @@ packages:
vue-tsc: 2.2.0(typescript@5.7.3)
dev: true
/vite-plugin-inspect@0.10.6(@nuxt/kit@3.15.4):
/vite-plugin-inspect@0.10.6(@nuxt/kit@3.15.4)(rollup@4.34.8):
resolution: {integrity: sha512-R3pwljjBbjFM2sZvy6Zvynnm51oaEwLYyYPk9Wp2lF97w/YMBq+KtTJXpCA17IO2pImX0bWA6WB05kuqRnkuyQ==}
engines: {node: '>=14'}
peerDependencies:
@ -10923,8 +10930,8 @@ packages:
optional: true
dependencies:
'@antfu/utils': 0.7.10
'@nuxt/kit': 3.15.4(magicast@0.3.5)
'@rollup/pluginutils': 5.1.4(rollup@4.34.0)
'@nuxt/kit': 3.15.4(magicast@0.3.5)(rollup@4.34.8)
'@rollup/pluginutils': 5.1.4(rollup@4.34.8)
debug: 4.4.0(supports-color@9.4.0)
error-stack-parser-es: 0.1.5
fs-extra: 11.3.0
@ -11019,7 +11026,7 @@ packages:
esbuild: 0.24.2
jiti: 2.4.2
postcss: 8.5.1
rollup: 4.34.0
rollup: 4.34.8
sass: 1.83.4
optionalDependencies:
fsevents: 2.3.3