活动功能

planet
shenhan 2025-03-10 17:33:34 +08:00
parent 1717d5abba
commit c738606731
48 changed files with 1968 additions and 699 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

3
app/components.d.ts vendored
View File

@ -24,7 +24,7 @@ declare module 'vue' {
NInfiniteScroll: typeof import('naive-ui')['NInfiniteScroll']
NInput: typeof import('naive-ui')['NInput']
NInputGroup: typeof import('naive-ui')['NInputGroup']
NMessageProvider: typeof import('naive-ui')['NMessageProvider']
NInputNumber: typeof import('naive-ui')['NInputNumber']
NModal: typeof import('naive-ui')['NModal']
NPopconfirm: typeof import('naive-ui')['NPopconfirm']
NQrCode: typeof import('naive-ui')['NQrCode']
@ -32,6 +32,7 @@ declare module 'vue' {
NRadioGroup: typeof import('naive-ui')['NRadioGroup']
NSelect: typeof import('naive-ui')['NSelect']
NSpace: typeof import('naive-ui')['NSpace']
NSpin: typeof import('naive-ui')['NSpin']
NTabPane: typeof import('naive-ui')['NTabPane']
NTabs: typeof import('naive-ui')['NTabs']
NTooltip: typeof import('naive-ui')['NTooltip']

View File

@ -17,7 +17,7 @@ const ruleForm = ref({})
const rules = ref({
nickName: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
{ min: 2, max: 10, message: '长度在 2 到 10 个字符', trigger: 'blur' },
{ min: 2, max: 15, message: '长度在 2 到 15 个字符', trigger: 'blur' },
],
})
//
@ -79,7 +79,8 @@ watch(
ruleForm.value.avatar = newUserInfo.avatar
ruleForm.value.brief = newUserInfo.brief
ruleForm.value.userId = newUserInfo.userId
// ruleForm.value.invitationName = newUserInfo.invitationName
ruleForm.value.invitationName = newUserInfo.invitationName
ruleForm.value.invitationCode = newUserInfo.invitationCode
}
},
{ immediate: true, deep: true }, // ruleForm
@ -128,13 +129,14 @@ onMounted(() => {
<n-form-item path="nickName" label="用户名">
<n-input v-model:value="ruleForm.nickName" placeholder="请输入用户名" @keydown.enter.prevent />
</n-form-item>
<div v-if="userInfo.invitationName" class="mb-3">
已经填写: {{ userInfo.invitationName }} 的邀请码
<div v-if="userStore.userInfo.invitationName" class="mb-3">
已经填写: {{ userStore.userInfo.invitationName }} 的邀请码
</div>
<!-- <n-form-item v-if="userInfo.invitationName" path="invitationCode">
</n-form-item> -->
<n-form-item v-else path="invitationCode" label="邀请码">
<n-input v-model:value="ruleForm.invitationName" placeholder="请输入邀请码" @keydown.enter.prevent />
<n-input v-model:value="ruleForm.invitationCode" placeholder="请输入邀请码" @keydown.enter.prevent />
</n-form-item>
<n-form-item label="简介" path="textareaValue">

View File

@ -0,0 +1,239 @@
<script setup lang="ts">
import { RotateCcw, X } from 'lucide-vue-next';
import type { FormInst } from 'naive-ui';
import { defineProps, onBeforeMount, onBeforeUnmount, ref } from 'vue';
const props = defineProps({
isMember: {
type: Object,
default: () => {},
},
})
const emit = defineEmits(['closePayment', 'paymentSuccess'])
const message = useMessage()
let pollingTimer: ReturnType<typeof setInterval> | undefined
const formRef = ref<FormInst | null>(null)
// const isShowPayment = ref(false)
const userStore = useUserStore()
interface UserInfoType {
nickName: string
avatar: string
brief: string
userId: number | string
}
const userInfo = {
nickName: userStore.userInfo?.nickName ?? '',
avatar: userStore.userInfo?.avatar ?? '',
brief: userStore.userInfo?.brief ?? '',
userId: userStore.userInfo?.userId ?? '',
} as UserInfoType
function onCloseModel() {
emit('closePayment')
}
function onPaymentSuccess() {
emit('paymentSuccess')
}
const qrUrl = ref('')
//
const paymentStatus = ref(1)
const amount = ref(10)
const paymentParams = ref({
amount: 10,
type: 'wallet',
})
async function getQrCode() {
try {
paymentParams.value.amount = amount.value
const res = await request.post(`/ali/pay/doPay`, paymentParams.value)
if (res.code === 200) {
paymentStatus.value = 1
qrUrl.value = res.data.url
pollingTimer && clearTimeout(pollingTimer)
pollingTimer = setInterval(async () => {
try {
const res2 = await request.get(`/order/queryTradeStatus?outTradeNo=${res.data.orderNo}`)
if (res2.data === 2) { // 1 2 4
paymentStatus.value = 2
clearTimeout(pollingTimer)
onPaymentSuccess()
emit('closePayment')
message.success('支付成功!')
}
else if (res2.data === 4) {
paymentStatus.value = 4
clearTimeout(pollingTimer)
}
}
catch (err) {
console.log('object', err)
}
}, 2000)
}
}
catch (err) {
console.log(err)
}
}
//
const isVisible = ref(true)
//
// const points = ref(0)
// async function getPoints() {
// try {
// const res = await request.get('/member/getPoints')
// if (res.code === 200) {
// points.value = res.data.points
// }
// }
// catch (err) {
// console.log(err)
// }
// }
// getPoints()
//
// const isMember = ref(false)
// async function getIsMember() {
// try {
// const res = await request.get('/member/isMember')
// if (res.code === 200) {
// isMember.value = res.data
// }
// }
// catch (err) {
// console.log(err)
// }
// }
// getIsMember()
onBeforeMount (() => {
getQrCode()
})
defineExpose({
isVisible,
})
onBeforeUnmount(() => {
clearInterval(pollingTimer)
})
</script>
<template>
<n-modal
v-model:show="isVisible"
:preset="null"
:mask-closable="false"
transform-origin="center"
class="custom-modal"
>
<div class="bg-white rounded-xl w-200">
<div
class="p-4 flex justify-between rounded-t-xl bg-gradient-to-r from-[#fcf2da] to-[#f9db9f]"
>
<div class="flex items-center">
<div>
<img :src="userInfo.avatar" class="w-14 h-14 rounded-full mr-4">
</div>
<div class="flex flex-col">
<div class="text-[#814600] text-xl">
{{ userInfo.nickName }}
</div>
<div class="text-[#6a6a6a] text-xs mt-1">
{{ props.isMember.result === '1' ? `会员到期时间: ${props.isMember.endDate}` : '您还不是魔创未来的会员' }}
</div>
</div>
</div>
<div @click="onCloseModel">
<component :is="X" class="h-[18px] w-[18px] text-[#61666d] cursor-pointer" />
</div>
</div>
<!-- <div class="p-4">
余额{{ points }}积分
</div> -->
<div class="mb-4 mt-6 flex">
<n-form
ref="formRef"
:label-width="80"
:model="paymentParams"
size="large"
label-placement="left"
style="width: 240px"
>
<n-form-item label="输入积分" path="modelProduct.modelName">
<n-input v-model:value="amount" type="number" placeholder="输入积分" />
</n-form-item>
</n-form>
<!-- <div>
确定
</div> -->
<n-button type="primary" class="mt-1 ml-2" @click="getQrCode">
确定
</n-button>
</div>
<!-- <div v-for="(item, index) in activityList" :key="index">
{{ item.activityName }}
</div> -->
<div class="mt-1 text-[#9d8c75] text-[12px] w-[500px] px-3">
1000个算力约可生图1000张或训练5次按照生图默认参数或训练基础参数预估即训练图片张数20张*单张训练次数15*训练轮数10
您充值的算力永久有效
算力充值不退不换
</div>
<div class="flex justify-center items-center my-4">
<div class="w-30 h-30 flex justify-center items-center relative">
<n-qr-code :value="qrUrl" :size="90" style="padding: 0;" />
<div v-if="paymentStatus === 4" class="absolute top-0 left-0 w-full h-full flex cursor-pointer flex-col justify-center items-center bg-opacity-50 bg-black text-white" @click="getQrCode">
请点击刷新<RotateCcw />
</div>
</div>
<div class="flex justify-center ml-2 flex-col pb-[14px]">
<div class="flex items-baseline">
<div class="text-[#222] font-medium mr-1">
支付
</div>
<div class="text-[#814600] mr-1">
<span class="text-[16px] mr-1">¥</span>
<span class="text-[40px]">{{ paymentParams.amount }}</span>
</div>
<!-- <div class="px-2 bg-gradient-to-r from-[#ffa700] to-[#ff006b] text-[#814600] text-white rounded-[4px] ml-1 text-[12px">
已减¥11
</div> -->
</div>
<div class="flex items-center mb-1">
<img src="@/assets/img/alipay.png" class="mr-1"> 请扫码完成支付
</div>
<div class="text-[12px]">
<span class="text-[#999]">
开通即代表同意
</span>
<span class="text-[#814600]">
魔创未来会员协议
</span>
</div>
</div>
</div>
</div>
</n-modal>
</template>
<style lang="scss" scoped>
.member-item {
display: flex;
justify-content: center;
align-items: center;
width: 16.66%;
height: 40px;
border: 1px solid #f0f0f0;
font-size: 12px;
font-weight: 400;
margin-right: -1px;
margin-bottom: -1px;
}
</style>

View File

@ -190,11 +190,11 @@ 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
魔创未来
<!-- <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> -->

View File

@ -1,6 +1,7 @@
<script setup lang="ts">
import { RotateCcw, X } from 'lucide-vue-next'
import { defineProps, onBeforeMount, onBeforeUnmount, ref } from 'vue'
import { RotateCcw, X } from 'lucide-vue-next';
import type { FormInst } from 'naive-ui';
import { defineProps, onBeforeMount, onBeforeUnmount, ref } from 'vue';
const props = defineProps({
isMember: {
@ -85,19 +86,19 @@ async function getQrCode() {
const isVisible = ref(true)
//
const points = ref(0)
async function getPoints() {
try {
const res = await request.get('/member/getPoints')
if (res.code === 200) {
points.value = res.data.points
}
}
catch (err) {
console.log(err)
}
}
getPoints()
// const points = ref(0)
// async function getPoints() {
// try {
// const res = await request.get('/member/getPoints')
// if (res.code === 200) {
// points.value = res.data.points
// }
// }
// catch (err) {
// console.log(err)
// }
// }
// getPoints()
//
// const isMember = ref(false)
@ -154,10 +155,10 @@ onBeforeUnmount(() => {
<component :is="X" class="h-[18px] w-[18px] text-[#61666d] cursor-pointer" />
</div>
</div>
<div class="p-4">
<!-- <div class="p-4">
余额{{ points }}积分
</div>
<div class="mt-4 px-6 flex">
</div> -->
<div class="mb-4 mt-6 flex">
<n-form
ref="formRef"
:label-width="80"

View File

@ -1,5 +1,5 @@
<template>
<div class="flex flex-wrap justify-center">
<div class="w-full">
<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"
@ -42,7 +42,7 @@
<!-- 作者信息条 -->
<div class="mt-1 px-2 py-1">
<div>
<span class="text-[#19191c] text-[14px]">
<span class="text-[#19191c] text-[14px] max-w-xs truncate ">
{{ item.modelName }}
</span>
</div>
@ -52,13 +52,13 @@
</div>
</div>
</div>
<div v-if="!loading && dataList.length === 0">
<Empty></Empty>
</div>
</div>
<div class="w-full flex justify-center" v-if="!loading && dataList.length === 0">
<Empty></Empty>
</div>
<div
ref="loadingTrigger"
class="h-20 w-[1000px] text-center text-gray-500 flex justify-center items-center"
class="h-20 w-full text-center text-gray-500 flex justify-center items-center"
>
<div v-if="loading">...</div>
<div v-if="finished && dataList.length >= 20"></div>

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: {
@ -12,139 +12,144 @@ const props = defineProps({
type: Object,
default: () => {},
},
})
});
const emit = defineEmits(['closePayment', 'paymentSuccess'])
const emit = defineEmits(["closePayment", "paymentSuccess"]);
const message = useMessage()
const message = useMessage();
let pollingTimer: ReturnType<typeof setInterval> | undefined
let pollingTimer: ReturnType<typeof setInterval> | undefined;
const currentNeedPayment = ref<number>(0)
const currentNeedPayment = ref<number>(0);
// const isShowPayment = ref(false)
const userStore = useUserStore()
const userStore = useUserStore();
interface UserInfoType {
nickName: string
avatar: string
brief: string
userId: number | string
nickName: string;
avatar: string;
brief: string;
userId: number | string;
}
const userInfo = {
nickName: userStore.userInfo?.nickName ?? '',
avatar: userStore.userInfo?.avatar ?? '',
brief: userStore.userInfo?.brief ?? '',
userId: userStore.userInfo?.userId ?? '',
} as UserInfoType
nickName: userStore.userInfo?.nickName ?? "",
avatar: userStore.userInfo?.avatar ?? "",
brief: userStore.userInfo?.brief ?? "",
userId: userStore.userInfo?.userId ?? "",
} as UserInfoType;
function onCloseModel() {
emit('closePayment')
emit("closePayment");
}
function onPaymentSuccess() {
emit('paymentSuccess')
emit("paymentSuccess");
}
const qrUrl = ref('')
const qrUrl = ref("");
interface Member {
id: number
title: string
price: number
originalPrice: number
desc: string
id: number;
title: string;
price: number;
originalPrice: number;
desc: string;
}
//
const currentActivity = ref(null)
const activityList = ref<Member[]>([])
const currentActivity = ref(null);
const activityList = ref<Member[]>([]);
async function getPromotionList() {
try {
const res = await request.get(`/promotion/promotionList`)
const res = await request.post(`/promotion/myPromotionList`, {
pageNum: 1,
pageSize: 50,
});
if (res.code === 200) {
activityList.value = res.data
activityList.value = res.rows;
}
}
catch (err) {
console.log(err)
} catch (err) {
console.log(err);
}
}
getPromotionList()
getPromotionList();
//
//
// const paymentParams = ref({})
const paymentStatus = ref(1)
const paymentStatus = ref(1);
const paymentParams = ref({
amount: props.info[0].unitPrice,
productId: props.info[0].id,
promotionId: 0,
type: 'member',
})
type: "member",
});
async function getQrCode() {
try {
const res = await request.post(`/ali/pay/doPay`, paymentParams.value)
const res = await request.post(`/ali/pay/doPay`, paymentParams.value);
if (res.code === 200) {
paymentStatus.value = 1
qrUrl.value = res.data.url
pollingTimer && clearTimeout(pollingTimer)
paymentStatus.value = 1;
qrUrl.value = res.data.url;
pollingTimer && clearTimeout(pollingTimer);
pollingTimer = setInterval(async () => {
try {
const res2 = await request.get(`/order/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)
message.success('支付成功!')
onPaymentSuccess()
emit('closePayment')
}
else if (res2.data === 4) {
paymentStatus.value = 4
clearTimeout(pollingTimer)
paymentStatus.value = 2;
clearTimeout(pollingTimer);
message.success("支付成功!");
onPaymentSuccess();
emit("closePayment");
} else if (res2.data === 4) {
paymentStatus.value = 4;
clearTimeout(pollingTimer);
}
} catch (err) {
console.log("object", err);
}
catch (err) {
console.log('object', err)
}
}, 2000)
}, 2000);
}
}
catch (err) {
console.log(err)
} catch (err) {
console.log(err);
}
}
//
async function handleActivityChange(value: number) {
paymentParams.value.promotionId = value
const res1 = await request.get(`/member/calculatePayment?promotionId=${value}&memberLevelId=${paymentParams.value.productId}`)
paymentParams.value.promotionId = value;
const res1 = await request.get(
`/member/calculatePayment?promotionId=${value}&memberLevelId=${paymentParams.value.productId}`
);
if (res1.code === 200) {
paymentParams.value.amount = res1.data
getQrCode()
paymentParams.value.amount = res1.data;
getQrCode();
}
}
// pay Card
async function changeCurrentNeedPayment(index: number) {
currentNeedPayment.value = index
paymentParams.value.productId = props.info[index].id
const res1 = await request.get(`/member/calculatePayment?promotionId=${paymentParams.value.promotionId}&memberLevelId=${paymentParams.value.productId}`)
currentNeedPayment.value = index;
paymentParams.value.productId = props.info[index].id;
const res1 = await request.get(
`/member/calculatePayment?promotionId=${paymentParams.value.promotionId}&memberLevelId=${paymentParams.value.productId}`
);
if (res1.code === 200) {
paymentParams.value.amount = res1.data
getQrCode()
paymentParams.value.amount = res1.data;
getQrCode();
}
}
//
const isVisible = ref(true)
onBeforeMount (() => {
getQrCode()
})
const isVisible = ref(true);
onBeforeMount(() => {
getQrCode();
});
defineExpose({
isVisible,
})
});
onBeforeUnmount(() => {
clearInterval(pollingTimer)
})
clearInterval(pollingTimer);
});
</script>
<template>
@ -161,14 +166,18 @@ onBeforeUnmount(() => {
>
<div class="flex items-center">
<div>
<img :src="userInfo.avatar" class="w-14 h-14 rounded-full mr-4">
<img :src="userInfo.avatar" class="w-14 h-14 rounded-full mr-4" />
</div>
<div class="flex flex-col">
<div class="text-[#814600] text-xl">
{{ userInfo.nickName }}
</div>
<div class="text-[#6a6a6a] text-xs mt-1">
{{ props.isMember.result === '1' ? `会员到期时间: ${props.isMember.endDate}` : '您还不是魔创未来的会员' }}
{{
props.isMember.result === "1"
? `会员到期时间: ${props.isMember.endDate}`
: "您还不是魔创未来的会员"
}}
</div>
</div>
</div>
@ -180,12 +189,14 @@ onBeforeUnmount(() => {
<div
v-for="(item, index) in info"
:key="item"
:style="[currentNeedPayment === index
? {
background: 'linear-gradient(90deg, #fffaf1, #ffeccf)',
border: '1px solid #f7b252',
}
: {}]"
:style="[
currentNeedPayment === index
? {
background: 'linear-gradient(90deg, #fffaf1, #ffeccf)',
border: '1px solid #f7b252',
}
: {},
]"
class="select-none h-44 border-1 border-solid border-[#e9e9e9] rounded-lg bg-[#f9f9f9] flex justify-between items-center flex-col p-4 box-border cursor-pointer"
@click="changeCurrentNeedPayment(index)"
>
@ -197,7 +208,9 @@ onBeforeUnmount(() => {
<div class="card-item">
<span class="text-[#814600] text-[20px] mr-2">¥</span>
<span class="text-[#814600] text-[36px] mr-2">{{ item.unitPrice }}</span>
<span class="text-gray-400 text-[20px] line-through">{{ item.originalPrice }}</span>
<span class="text-gray-400 text-[20px] line-through">{{
item.originalPrice
}}</span>
</div>
<div class="card-item text-[#814600] w-7/10 text-center text-[12px]">
{{ item.subscriptionPeriod }}
@ -205,57 +218,36 @@ onBeforeUnmount(() => {
</div>
</div>
<div class="flex items-center my-4">
<div class="w-[50px] text-right mr-2">
活动:
</div>
<div class="w-[50px] text-right mr-2">活动:</div>
<n-select
v-model:value="currentActivity"
placeholder="请选择活动" class="w-[200px]" label-field="activityName" value-field="id" :options="activityList" @change="handleActivityChange"
placeholder="请选择活动"
class="w-[200px]"
label-field="activityName"
value-field="id"
:options="activityList"
@change="handleActivityChange"
/>
</div>
<!-- <div v-for="(item, index) in activityList" :key="index">
{{ item.activityName }}
</div> -->
<div class="mt-4 px-6">
<div class="flex border-collapse ">
<div class="member-item bg-[#fef9f8]">
基础版VIP
</div>
<div class="member-item">
每月15000点算力
</div>
<div class="member-item">
20G存储空间
</div>
<div class="member-item">
每月800次生图
</div>
<div class="member-item">
2个生图任务并行
</div>
<div class="member-item">
--
</div>
<div class="flex border-collapse">
<div class="member-item bg-[#fef9f8]">基础版VIP</div>
<div class="member-item">每月15000点算力</div>
<div class="member-item">20G存储空间</div>
<div class="member-item">每月800次生图</div>
<div class="member-item">2个生图任务并行</div>
<div class="member-item">--</div>
</div>
<div class="flex border-collapse ">
<div class="member-item bg-[#fef9f8]">
专业版
</div>
<div class="member-item">
每月35000点算力
</div>
<div class="member-item">
50G存储空间
</div>
<div class="member-item">
每月5000次生图
</div>
<div class="member-item">
3个生图任务并行
</div>
<div class="member-item">
可训练XL模型
</div>
<div class="flex border-collapse">
<div class="member-item bg-[#fef9f8]">专业版</div>
<div class="member-item">每月35000点算力</div>
<div class="member-item">50G存储空间</div>
<div class="member-item">每月5000次生图</div>
<div class="member-item">3个生图任务并行</div>
<div class="member-item">可训练XL模型</div>
</div>
</div>
<div class="px-6 mt-1 text-[#9d8c75] text-[12px]">
@ -263,16 +255,18 @@ onBeforeUnmount(() => {
</div>
<div class="flex justify-center items-center my-4">
<div class="w-30 h-30 flex justify-center items-center relative">
<n-qr-code :value="qrUrl" :size="90" style="padding: 0;" />
<div v-if="paymentStatus === 4" class="absolute top-0 left-0 w-full h-full flex cursor-pointer flex-col justify-center items-center bg-opacity-50 bg-black text-white" @click="getQrCode">
<n-qr-code :value="qrUrl" :size="90" style="padding: 0" />
<div
v-if="paymentStatus === 4"
class="absolute top-0 left-0 w-full h-full flex cursor-pointer flex-col justify-center items-center bg-opacity-50 bg-black text-white"
@click="getQrCode"
>
请点击刷新<RotateCcw />
</div>
</div>
<div class="flex justify-center ml-2 flex-col pb-[14px]">
<div class="flex items-baseline">
<div class="text-[#222] font-medium mr-1">
支付
</div>
<div class="text-[#222] font-medium mr-1">支付</div>
<div class="text-[#814600] mr-1">
<span class="text-[16px] mr-1">¥</span>
<span class="text-[40px]">{{ paymentParams.amount }}</span>
@ -282,15 +276,11 @@ onBeforeUnmount(() => {
</div> -->
</div>
<div class="flex items-center mb-1">
<img src="@/assets/img/alipay.png" class="mr-1"> 请扫码完成支付
<img src="@/assets/img/alipay.png" class="mr-1" /> 请扫码完成支付
</div>
<div class="text-[12px]">
<span class="text-[#999]">
开通即代表同意
</span>
<span class="text-[#814600]">
魔创未来会员协议
</span>
<span class="text-[#999]"> 开通即代表同意 </span>
<span class="text-[#814600]"> 魔创未来会员协议 </span>
</div>
</div>
</div>

View File

@ -8,6 +8,7 @@ Play
import { NConfigProvider, NMessageProvider } from "naive-ui";
import { nextTick, ref } from 'vue';
import { useRouter } from 'vue-router';
const message = useMessage()
const props = defineProps({
item: {
@ -28,15 +29,22 @@ const props = defineProps({
const emit = defineEmits(['topedRefresh'])
const router = useRouter()
const isDelete = ref(false)
//
function toDetails() {
if (props.currentType === '0') {
router.push(`/model-details/${props.item.id}`)
if(props.currentState === 'mallProduct'){
router.push(`/model-details/${props.item.id}`)
}else{
router.push(`/model-details/${props.item.modelId}`)
}
}
else if (props.currentType === '1') {
// console.log('object', 111);
router.push(`/workflow-details/${props.item.id}`)
if(props.currentState === 'mallProduct'){
router.push(`/workflow-details/${props.item.id}`)
}else{
router.push(`/workflow-details/${props.item.workFlowId}`)
}
}else if(props.currentType === '2'){
onEditPicture()
}
@ -94,6 +102,7 @@ function handleSelect(event: Event, key: string) {
}
//
const menuRef = ref(null)
interface TopUrlType {
[key: string | number]: string
}
@ -109,6 +118,8 @@ async function handleTop() {
.isTop}`,
)
if (res.code === 200) {
message.success('置顶成功!')
menuRef.value.style.display = 'none';
//
emit('topedRefresh')
}
@ -122,7 +133,11 @@ interface Response {
code: number
}
//
async function handleDelete(): Promise<void> {
isDelete.value = true
}
async function onDelete(){
const { currentType, item } = props
let url: string
@ -142,6 +157,7 @@ async function handleDelete(): Promise<void> {
const res: Response = await request.get(url)
if (res.code === 200) {
//
message.success('删除成功!')
emit('topedRefresh')
}
}
@ -200,7 +216,12 @@ function updateLike(type:number){
props.item.likeNum += 1;
}
}
function showMenu(){
menuRef.value.style.display = 'block';
}
function hiddenMenu(){
menuRef.value.style.display = 'none';
}
</script>
<template>
@ -285,10 +306,13 @@ function updateLike(type:number){
>
<div class="menu-content">
<component
@mouseenter="showMenu"
:is="EllipsisVertical"
class="h-[18px] w-[18px] text-white menu-icon"
class="h-[18px] w-[18px] text-white menu-icon-ellipsis"
/>
<div
@mouseleave="hiddenMenu"
ref="menuRef"
class="menu-group text-[#000000] text-[12px] bg-white rounded-lg text-center w-20 mt-2 hidden"
>
<div class="menu-item" @click="(event) => handleSelect(event, 'edit')">
@ -335,7 +359,7 @@ function updateLike(type:number){
</div>
</div>
<div v-if="currentType !== '2'" class="mt-2 text-[12px] text-[#67787e]">
<div class="text-[#19191c] text-[14px]">
<div class="text-[#19191c] text-[14px] max-w-xs truncate ">
<span v-if="currentType === '0'">
{{ item.modelName }}
</span>
@ -363,10 +387,24 @@ function updateLike(type:number){
<Publish-picture v-if="isShowPublishPicture" type="edit" ref="PublishPictureRef" :form-data="publishPictureData" @close-publish-img="closePublishImg" />
</NMessageProvider>
</NConfigProvider>
<n-modal
v-model:show="isDelete"
:mask-closable="false"
preset="dialog"
title="提示!"
content="确定要将模型删除? 模型删除后无法找回"
negative-text="取消"
positive-text="确认"
@negative-click="isDelete = false"
@positive-click="onDelete"
/>
</div>
</template>
<style lang="scss">
.menu-icon-ellipsis:hover + .menu-group{
display: block;
}
.modelSelectByUserIdModel {
position: absolute;
&:hover {

View File

@ -17,8 +17,10 @@ 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 (props.item) {
// 使modelImageId 使id
let id = props.item.modelImageId || props.item.id
const res = await request.get(`/image/detail?id=${id}`);
if (res.code === 200) {
dataInfo.value = res.data;
const res1 = await request.get(`/attention/selectAttention?userId=${res.data.userId}`)
@ -30,8 +32,8 @@ async function getDetail() {
}
}
getDetail();
const tagsList = ref([]);
//
const tagsList = ref([]);
async function getDictType() {
try {
const res = await commonApi.dictType({ type: "image_label" });

View File

@ -1,5 +1,5 @@
<template>
<div class="flex flex-wrap justify-center">
<div class="flex flex-wrap w-full">
<div class="grid grid-cols-2 lg:grid-cols-4 xl:grid-cols-5 2xl:grid-cols-7 gap-4 p-4">
<div
v-for="item in dataList"
@ -74,13 +74,14 @@
</div>
</div> -->
</div>
<div v-if="!loading && dataList.length === 0">
</div>
<div class="w-full flex justify-center" v-if="!loading && dataList.length === 0">
<Empty></Empty>
</div>
</div>
<div
ref="loadingTrigger"
class="h-20 w-[1000px] text-center text-gray-500 flex justify-center items-center"
class="h-20 w-full text-center text-gray-500 flex justify-center items-center"
>
<div v-if="loading">...</div>
<div v-if="finished && dataList.length >= 20"></div>

View File

@ -14,9 +14,9 @@ const props = defineProps({
default: "",
}
})
debugger
const emit = defineEmits(['closePublishImg'])
const message = useMessage()
const loading = ref(false)
const isVisible = ref(true)
const fileInput = ref<HTMLInputElement | null>(null)
@ -38,11 +38,14 @@ async function handleFileChange(event: Event) {
if (files && files.length > 0) {
try{
loading.value = true
const res = await uploadImagesInBatches(files)
const urlList = res.map(item => item.url)
props.formData.imagePaths.push(...urlList)
}catch(err){
console.log(err);
}finally{
loading.value = false
}
}
target.value = ''
@ -63,6 +66,7 @@ async function getDictType() {
async function onPublish() {
try {
const param = cloneDeep(props.formData)
if(param.imagePaths.length === 0) return message.warning('请上传图片')
param.imagePaths = param.imagePaths.join(',')
param.tags = param.tags.join(',')
if (param.id) {
@ -114,6 +118,8 @@ function closePublishImg() {
</div>
</div>
<div>
<n-spin :show="loading">
<div class="upload-content">
<div class="flex flex-col bg-[#f3f5f9] justify-center items-center w-30 h-30 border border-dashed mt-2 rounded-lg bg-white">
<div class="my-6 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 mt-6" @click="triggerFileInput()">
@ -124,6 +130,8 @@ function closePublishImg() {
</div> -->
</div>
</div>
</n-spin>
<div class="grid grid-cols-3 gap-2.5 mt-4 w-full">
<div v-for="(item, index) in props.formData.imagePaths" :key="index">
<img class="w-full h-[180px] object-cover rounded-lg" :src="item" alt="">

View File

@ -31,9 +31,9 @@ async function onGetUUid() {
// /wx/uuid/get
const res = await request.get('/wx/uuid/get')
if (res.code === 200) {
const appid = 'wx7d0003f44e27fbfd'
const appid = 'wx0a72f196ec9c3a70'
const { uuid } = res
const redirect_uri = `http://a7u3z9.natappfree.cc/wx/uuid/bind/openid?uuid=${uuid}`
const redirect_uri = `http://www.mc158c.com/api/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`

View File

@ -1,5 +1,5 @@
<template>
<div class="flex flex-wrap justify-center">
<div class="flex flex-wrap w-full">
<div class="grid grid-cols-2 lg:grid-cols-4 xl:grid-cols-5 2xl:grid-cols-7 gap-4 p-4">
<div
v-for="item in dataList"
@ -42,7 +42,7 @@
<!-- 作者信息条 -->
<div class="mt-1 px-2 py-1">
<div>
<span class="text-[#19191c] text-[14px]">
<span class="text-[#19191c] text-[14px] max-w-xs truncate ">
{{ item.workflowName }}
</span>
</div>
@ -52,13 +52,13 @@
</div>
</div>
</div>
<div v-if="!loading && dataList.length === 0">
<Empty></Empty>
</div>
</div>
<div class="w-full flex justify-center" v-if="!loading && dataList.length === 0">
<Empty></Empty>
</div>
<div
ref="loadingTrigger"
class="h-20 w-[1000px] text-center text-gray-500 flex justify-center items-center"
class="h-20 w-full text-gray-500 flex justify-center items-center"
>
<div v-if="loading">...</div>
<div v-if="finished && dataList.length >= 20"></div>

View File

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

View File

@ -128,8 +128,17 @@ function handleCategoryUpdateValue(value) {
// localForm.value.modelProduct.category = value.includes('-') ? value : `${value}-0`
// }
}
const isPublicList = [
{
label: "公开",
value: 1,
},
{
label: "仅自己可见",
value: 0,
},
];
// function changeModelType(item){
// debugger
// }
</script>
@ -244,6 +253,24 @@ function handleCategoryUpdateValue(value) {
{{ item.label }}
</div>
</div>
<div class="">权限设置</div>
<div class="mt-1 mb-2 text-gray-400 text-[12px]">可见范围</div>
<div>
<n-radio-group v-model:value="localForm.modelProduct.jurisdiction" name="radiogroup">
<n-space>
<n-radio
v-for="(isPublicItem, isPublicIndex) in isPublicList"
:key="isPublicIndex"
:value="isPublicItem.value"
>
{{ isPublicItem.label }}
</n-radio>
</n-space>
</n-radio-group>
</div>
<div v-if="localForm.modelProduct.isOriginal === 1" class="text-[12px]">
<div class="my-3">
魔创未来原创模型加密保护计划

View File

@ -19,7 +19,7 @@ const emit = defineEmits(["update:modelValue", "nextStep", "prevStep"]);
const acceptTypes =
".safetensors,.ckpt,.pt,.bin,.pth,.zip,.json,.flow,.lightflow,.yaml,.yml,.onnx,.gguf,.sft";
const modelVersionItem = {
objectKey:null,
objectKey: null,
isEncrypt: 0, //0
delFlag: "0", // 0 2
versionName: "", //
@ -29,7 +29,7 @@ const modelVersionItem = {
fileName: "", //
sampleImagePaths: [], // 20,
triggerWords: "", //
isPublic: 1, //
isPublic: null, //
isOnlineUse: 1, //线使
allowFusion: 1, //
isFree: 0, // 0
@ -41,20 +41,11 @@ const modelVersionItem = {
hideImageGenInfo: 0, //
id: null,
};
const isPublicList = [
{
label: "公开",
value: 1,
},
{
label: "仅自己可见",
value: 0,
},
];
defineExpose({
addVersion,
});
const loading = ref(false);
const localForm = computed({
get() {
return props.modelValue;
@ -147,20 +138,25 @@ async function handleFileChange(event: Event) {
const files = target.files;
if (files && files.length > 0) {
const { name, size} = files[0] as { name: string, size: number};
const { name, size } = files[0] as { name: string; size: number };
try {
// 0 1
const res1 = await request.get(`/file/selectFile?type=model&name=${name}`);
if (res1.code == 200) {
if (res1.data === 1) {
try {
loading.value = true;
const res = await uploadFileBatches(files);
localForm.value.modelVersionList[uploadFileIndex.value].filePath = res[0].path;
localForm.value.modelVersionList[uploadFileIndex.value].objectKey = res[0].objectKey;
localForm.value.modelVersionList[uploadFileIndex.value].filePath =
res[0].path;
localForm.value.modelVersionList[uploadFileIndex.value].objectKey =
res[0].objectKey;
localForm.value.modelVersionList[uploadFileIndex.value].fileName = name;
localForm.value.modelVersionList[uploadFileIndex.value].fileSize = size
localForm.value.modelVersionList[uploadFileIndex.value].fileSize = size;
} catch (err) {
console.log(err);
} finally {
loading.value = false;
}
} else {
message.warning("该模型名称已存在");
@ -262,22 +258,24 @@ function onDelete(index: number) {
</div>
</div>
<div v-else>
<div class="upload-content">
<div
class="flex flex-col justify-center items-center w-30 h-40 border border-dashed mt-2 rounded-lg bg-white"
>
<n-spin :show="loading">
<div class="upload-content">
<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)"
class="flex flex-col justify-center items-center w-30 h-40 border border-dashed mt-2 rounded-lg bg-white"
>
上传文件
</div>
<div class="my-3">点击上传文件</div>
<div class="text-[#999999] text-xs">
.safetensors/.ckpt/.pt/.bin/.pth/.zip/.json/.flow/.lightflow/.yaml/.yml/.onnx/.gguf/.sft
<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="text-[#999999] text-xs">
.safetensors/.ckpt/.pt/.bin/.pth/.zip/.json/.flow/.lightflow/.yaml/.yml/.onnx/.gguf/.sft
</div>
</div>
</div>
</div>
</n-spin>
</div>
<div class="flex mt-6">
版本介绍 <Asterisk :size="10" color="#ff0000" class="mt-1" />
@ -308,21 +306,7 @@ function onDelete(index: number) {
</div>
</div> -->
<div class="">权限设置</div>
<div class="mt-1 mb-2 text-gray-400 text-[12px]">可见范围</div>
<div>
<n-radio-group v-model:value="item.isPublic" name="radiogroup">
<n-space>
<n-radio
v-for="(isPublicItem, isPublicIndex) in isPublicList"
:key="isPublicIndex"
:value="isPublicItem.value"
>
{{ isPublicItem.label }}
</n-radio>
</n-space>
</n-radio-group>
</div>
</n-form>
<div v-if="item.isPublic === 1">
<div class="mt-4 mb-1 text-gray-400 text-[12px]">付费设置</div>

View File

@ -17,6 +17,7 @@ const route = useRoute()
const { type } = route.query
const message = useMessage()
const loading = ref(false)
const localForm = computed({
get() {
@ -103,11 +104,14 @@ async function handleFileChange(event: Event) {
if (sum >= 20)
return message.error('最多20张')
try{
loading.value = true
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);
}finally{
loading.value = false
}
}
target.value = ''
@ -145,6 +149,7 @@ function onPositiveClick() {
最多20张图片, 图片不超过30M
</div>
</div>
<n-spin :show="loading">
<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)">
@ -158,6 +163,8 @@ function onPositiveClick() {
</div>
</div>
</div>
</n-spin>
<div class="grid grid-cols-3 gap-2.5 mt-4 w-full">
<div v-for="(subItem, subIndex) in item.sampleImagePaths" :key="subIndex">
<img class="w-full h-[200px] object-cover rounded-lg" :src="subItem" alt="">

View File

@ -13,7 +13,7 @@ const props = defineProps({
},
});
const emit = defineEmits(["update:modelValue", "nextStep", "preStep"]);
const loading = ref(false)
const localForm = computed({
get() {
return props.modelValue;
@ -25,7 +25,7 @@ const localForm = computed({
watch(
() => localForm.value,
(newVal:any) => {
(newVal: any) => {
console.log("newVal", newVal);
emit("update:modelValue", newVal);
},
@ -84,8 +84,8 @@ async function nextStep() {
}
try {
const promises = formRefs.value
.filter((form:any): form is FormInst => form !== null)
.map((form:any) => form.validate());
.filter((form: any): form is FormInst => form !== null)
.map((form: any) => form.validate());
await Promise.all(promises);
emit("nextStep");
@ -116,20 +116,25 @@ async function handleFileChange(event: Event) {
const files = target.files;
if (files && files.length > 0) {
const { name , size} = files[0] as { name: string, size: number};
const { name, size } = files[0] as { name: string; size: number };
try {
const res1 = await request.get(`/file/selectFile?type=workflow&name=${name}`);
if (res1.code == 200) {
if (res1.data === 1) {
//0 1
try {
loading.value = true
const res = await uploadFileBatches(files);
localForm.value.workFlowVersionList[uploadFileIndex.value].filePath = res[0].path;
localForm.value.workFlowVersionList[uploadFileIndex.value].objectKey = res[0].objectKey;
localForm.value.workFlowVersionList[uploadFileIndex.value].fileName = name
localForm.value.workFlowVersionList[uploadFileIndex.value].fileSize = size
localForm.value.workFlowVersionList[uploadFileIndex.value].filePath =
res[0].path;
localForm.value.workFlowVersionList[uploadFileIndex.value].objectKey =
res[0].objectKey;
localForm.value.workFlowVersionList[uploadFileIndex.value].fileName = name;
localForm.value.workFlowVersionList[uploadFileIndex.value].fileSize = size;
} catch (err) {
console.log(err);
}finally{
loading.value = false
}
} else {
message.error("该工作流名称已存在");
@ -143,7 +148,7 @@ async function handleFileChange(event: Event) {
}
function computedDelFlag() {
return localForm.value.workFlowVersionList.filter((item:any) => item.delFlag === "0");
return localForm.value.workFlowVersionList.filter((item: any) => item.delFlag === "0");
}
function onDelete(index: number) {
if (computedDelFlag().length === 1) return;
@ -203,20 +208,22 @@ function onDelete(index: number) {
</div>
</div>
<div v-else>
<div class="upload-content">
<div
class="flex flex-col justify-center items-center w-30 h-40 border border-dashed mt-2 rounded-lg bg-white"
>
<n-spin :show="loading">
<div class="upload-content">
<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)"
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="text-[#999999] text-xs">.json/.zip</div>
</div>
<div class="my-3">点击上传文件</div>
<div class="text-[#999999] text-xs">.json/.zip</div>
</div>
</div>
</n-spin>
</div>
</n-form>
</div>

View File

@ -30,7 +30,7 @@ function preStep() {
emit("preStep");
}
const showSuccessModal = ref(false);
const loading = ref(false)
async function handlePublish() {
for (let i = 0; i < localForm.value.workFlowVersionList.length; i++) {
if (
@ -107,6 +107,7 @@ async function handleFileChange(event: Event) {
files.length;
if (sum >= 20) return message.error("最多20张");
try {
loading.value = true
const res = await uploadImagesInBatches(files);
const urlList = res.map((item) => item.url);
localForm.value.workFlowVersionList[uploadFileIndex.value].imagePaths.push(
@ -114,6 +115,8 @@ async function handleFileChange(event: Event) {
);
} catch (err) {
console.log(err);
}finally{
loading.value = false
}
}
target.value = "";
@ -151,6 +154,7 @@ function onPositiveClick() {
<div class="text-[12px] text-gray-400">最多20张图片图片不超过30M</div>
</div>
<div>
<n-spin :show="loading">
<div
class="flex flex-col justify-center items-center w-30 h-40 border border-dashed mt-2 rounded-lg bg-white"
>
@ -165,6 +169,8 @@ function onPositiveClick() {
请勿上传裸露暴力血腥或其他包含非法信息图片
</div>
</div>
</n-spin>
</div>
<div class="grid grid-cols-3 gap-2.5 mt-4 w-full">
<div v-for="(subItem, subIndex) in item.imagePaths" :key="subIndex">

View File

@ -1,8 +1,8 @@
export const appName = '魔创未来'
export const appDescription = '魔创未来'
export const authRoutes = ['/personal-center', '/publish-model', '/publish-workflow']
export const verifyBlankRoute = ['/member-center', '/int-detail', '/personal-publish']
export const authRoutes = ['/personal-center']
export const verifyBlankRoute = ['/member-center']
export const isOriginalList = [{
label: '原创',
value: 0,

View File

@ -2,14 +2,27 @@
import {
Binary,
Code2,
Crown, Earth, Image,
Crown,
Earth,
Image,
LayoutGrid,
Lightbulb,
Maximize, Network, User,
Maximize,
Network,
User,
Workflow
} from "lucide-vue-next";
import { useRouter } from "vue-router";
const userStore = useUserStore();
// definePageMeta({
// middleware:[
// function (to, from ){
// if(to.path === "/personal-center" && !userStore.isLoggedIn){
// return abortNavigation()
// }
// }
// ]
// })
const modalStore = useModalStore();
const menuStore = useMenuStore();
@ -66,7 +79,7 @@ const menuItems2 = ref({
icon: Network,
text: "在线工作流",
route: "",
desc:'Comfy UI'
desc: "Comfy UI",
},
{
icon: Earth,
@ -92,7 +105,7 @@ const menuItems3 = ref({
});
//
menuStore.menuItems = menuStore.menuItems.map((item:any) => ({
menuStore.menuItems = menuStore.menuItems.map((item: any) => ({
...item,
LucideIcon: iconMap[item.path], // Lucide
}));
@ -109,27 +122,45 @@ function handleSide(event: Event, path: string) {
}
//
// nextTick(() => {
// debugger
// if (route.path !== window.location.pathname) {
// navigateTo(route.path, { replace: true })
// }
// })
} else if (path === "/personal-center" && !userStore.isLoggedIn) {
modalStore.showLoginModal();
} else {
menuStore.setActiveMenu(path);
}
}
const appList = ref([]);
async function getAppList() {
try {
const res = await request.get(`/app/list`);
if (res.code === 200) {
appList.value = res.data;
}
} catch (err) {
console.log(err);
}
}
getAppList();
function toUs(url: string) {
const baseUrl = window.location.origin;
window.open(`${baseUrl}/us/${url}`, "_blank", "noopener,noreferrer");
}
</script>
<template>
<div class="flex h-screen flex-col bg-white dark:bg-dark-800">
<!-- Header -->
<Header />
<!-- Main Content -->
<div class="flex flex-1 overflow-hidden">
<!-- Sidebar -->
<nav
class="w-[220px] border-r border-gray-100 bg-gray-50/50 dark:border-dark-700 dark:bg-dark-800/50"
class="w-[230px] border-r border-gray-100 bg-gray-50/50 dark:border-dark-700 dark:bg-dark-800/50 overflow-y-auto"
>
<div class="space-y-1 px-2">
<div class="text-[#000] p-4">
@ -183,12 +214,11 @@ function handleSide(event: Event, path: string) {
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="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]"
/>
<component :is="item.icon" class="h-[18px] w-[18px] mr-[10px]" />
<div class="text-sm">
{{ item.text }}
</div>
@ -237,6 +267,41 @@ function handleSide(event: Event, path: string) {
</NuxtLink>
</div>
</div>
<div class="px-4">
<div class="text-xs text-gray-500 flex flex-wrap gap-2">
<div
class="cursor-pointer relative group"
v-for="(item, index) in appList"
:key="index"
>
{{ item.name }}
<div
class="flex flex-col justify-center items-center gap-2 absolute bottom-4 left-0 w-[90px] h-[115px] hidden group-hover:block bg-white p-2 z-index-999 border border-solid border-[#ccc] rounded-lg"
>
<div class="text-xs text-center mb-2">扫码关注</div>
<img class="w-[80px] h-[70px]" :src="item.url" alt="" />
</div>
</div>
</div>
<div class="flex justify-between text-xs text-gray-400 mt-2">
<div class="cursor-pointer" @click="toUs('agreement')"></div>
<div class="cursor-pointer" @click="toUs('privacy')"></div>
<div class="cursor-pointer" @click="toUs('aboutUs')"></div>
</div>
<!-- <div class="justify-between text-xs text-gray-400 mt-2 scale-80">
<div class="cursor-pointer scale-80">广州魔创未来科技有限公司</div>
</div>
<div class="justify-between text-xs text-gray-400 mt-2 scale-80">
<div class="cursor-pointer scale-80">京ICP备2023015442号</div>
</div>
<div class="justify-between text-xs text-gray-400 mt-2 scale-80">
<div class="cursor-pointer scale-80">网信算备</div>
<div class="cursor-pointer scale-80">110112129623601230015</div>
</div>
<div class="justify-between text-xs text-gray-400 mt-2 scale-80">
<div class="cursor-pointer scale-80">备案号: Beijing-PianYu-202402</div>
</div> -->
</div>
<!-- <NuxtLink
v-for="item in menuStore.menuItems"
:key="item.path"
@ -282,6 +347,7 @@ function handleSide(event: Event, path: string) {
/* cursor: pointer; */
background: var(--primary);
color: white;
/* position: absolute; */
/* border: dashed; */
}

View File

@ -1,5 +1,6 @@
// middleware/auth.ts
import { authRoutes, verifyBlankRoute } from '@/constants/index'
import { verifyBlankRoute } from '@/constants/index';
// import { useRouter } from 'vue-router'
// const router = useRouter()
@ -14,19 +15,17 @@ import { authRoutes, verifyBlankRoute } from '@/constants/index'
export default defineNuxtRouteMiddleware((to, from) => {
const userStore = useUserStore()
const modalStore = useModalStore()
const menuStore = useMenuStore()
if(to.path !== '/search'){
modalStore.searchQuery = ''
}
const menuStore = useMenuStore()
if (verifyBlankRoute.includes(to.path) && !verifyBlankRoute.includes(from.path)) {
return abortNavigation()
}
// 如果是需要登录的路由,且用户未登录
if (authRoutes.includes(to.path) && !userStore.isLoggedIn) {
// 显示登录模态框
modalStore.showLoginModal()
menuStore.setActiveMenu(from.path)
// return abortNavigation()
// return navigateTo('/model-square')
}
// if(to.path === "/personal-center" && !userStore.isLoggedIn){
// return abortNavigation()
// }
menuStore.setActiveMenu(from.path)
})

View File

@ -1,10 +1,10 @@
<script setup lang="ts">
import { nextTick, onMounted } from 'vue';
import { onMounted, ref } from 'vue';
definePageMeta({
layout: 'header',
})
const activeTab = ref('')
const activeTab = ref('oasis')
// const route = useRoute();
// const { id } = route.params as { id: string };
@ -12,16 +12,30 @@ interface PointsResult {
points: number
memberConsumeList: any[]
}
const pointsResult = ref<PointsResult>(null)
//
const consumePointsFinished = ref(false);
const consumePointsParams = ref({
"pageNum": 1,
"pageSize": 20
})
const pointsResult = ref([])
async function getPoints() {
try {
const res = await request.get('/member/getPoints')
if (consumePointsFinished.value) return
const res = await request.post('/member/getConsumePoints', {
...consumePointsParams.value
})
if (res.code === 200) {
pointsResult.value = res.data as PointsResult
debugger
nextTick(() => {
activeTab.value = 'beatles'
})
if(consumePointsParams.value.pageNum === 1){
pointsResult.value = res.rows
}else{
pointsResult.value = [...pointsResult.value, ...res.rows]
}
if (pointsResult.value.length >= res.total) {
consumePointsFinished.value = true;
}
consumePointsParams.value.pageNum++
}
}
catch (err) {
@ -29,6 +43,40 @@ async function getPoints() {
}
}
getPoints()
//
const rechargePointsFinished = ref(false);
const rechargePointsParams = ref({
"pageNum": 1,
"pageSize": 20
})
const rechargePoints = ref([])
async function getRechargePoints() {
try {
if (rechargePointsFinished.value) return;
const res = await request.post('/member/getRechargePoints', {
...rechargePointsParams.value
})
if (res.code === 200) {
if (rechargePointsParams.value.pageNum === 1) {
rechargePoints.value = res.rows;
} else {
rechargePoints.value = [...rechargePoints.value, ...res.rows];
}
//
if (rechargePoints.value.length >= res.total) {
rechargePointsFinished.value = true;
}
rechargePointsParams.value.pageNum++;
}
}
catch (err) {
console.log(err)
}
}
getRechargePoints()
onMounted(() => {
// nextTick(() => {
// activeTab.value = 'beatles'
@ -40,47 +88,56 @@ onMounted(() => {
<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="oasis" tab="已获取">
<div class="h-[500px] overflow-y-auto">
<div class="mc-table flex w-full">
<n-tab-pane name="oasis" tab="已获取">
<div class="border border-solid border-gray-200 rounded-lg relative">
<div class="mc-table flex w-full bg-gray-200 sticky top-0">
<div class="w-[250px]">
获取时间
</div>
<div class="w-[250px]">
<div class="w-[200px]">
获取来源
</div>
<div class="flex-1">
算力生效时间
</div>
<div class="flex-1">
算力到期时间
</div>
<div class="w-[200px]">
算力值
</div>
</div>
<div v-for="item in pointsResult.memberConsumeList" :key="item" class="mc-table flex w-full">
<div class="w-[250px]">
{{ item.consumeTime }}
积分生效时间
</div>
<div class="w-[250px]">
每日赠送算力清零
积分到期时间
</div>
<div class="flex-1">
-
</div>
<div class="w-[180px]">
{{ item.consumePoints }}
积分值
</div>
</div>
<n-infinite-scroll
style="height: calc(100vh - 300px)"
:distance="10"
@load="getRechargePoints"
>
<div v-for="item in rechargePoints" :key="item" class="mc-table flex w-full">
<div class="w-[250px]">
{{ item.rechargeTime }}
</div>
<div class="w-[200px]">
{{ item.getSource }}
</div>
<div class="w-[250px]">
{{ item.effectStartTime }}
</div>
<div class="w-[250px]">
{{ item.effectEndTime }}
</div>
<div class="flex-1">
{{ item.points }}
</div>
</div>
</n-infinite-scroll>
</div>
</n-tab-pane> -->
</n-tab-pane>
<n-tab-pane name="beatles" tab="已消耗">
<div class="h-[500px] overflow-y-auto">
<div class="mc-table flex w-full">
<div class="border border-solid border-gray-200 rounded-lg relative">
<div class="mc-table flex w-full bg-gray-200 sticky top-0">
<div class="w-[250px]">
消耗时间
</div>
@ -91,10 +148,15 @@ onMounted(() => {
任务详情
</div>
<div class="w-[200px]">
算力
积分
</div>
</div>
<div v-for="item in pointsResult.memberConsumeList" :key="item" class="mc-table flex w-full">
<n-infinite-scroll
style="height: calc(100vh - 300px)"
:distance="10"
@load="getPoints"
>
<div v-for="item in pointsResult" :key="item" class="mc-table flex w-full">
<div class="w-[250px]">
{{ item.consumeTime }}
</div>
@ -108,6 +170,8 @@ onMounted(() => {
{{ item.consumePoints }}
</div>
</div>
</n-infinite-scroll>
</div>
</n-tab-pane>
</n-tabs>
@ -117,10 +181,8 @@ onMounted(() => {
<style lang="scss" scoped>
.mc-table {
> div {
line-height: 40px;
height: 50px;
border-bottom: 1px solid #eee;
}
padding: 10px;
line-height: 40px;
border-bottom: 1px solid #eee;
}
</style>

View File

@ -0,0 +1,145 @@
<script setup lang="ts">
import { onMounted, ref } from "vue";
definePageMeta({
layout: "header",
});
const activeTab = ref("oasis");
// const route = useRoute();
// const { id } = route.params as { id: string };
//
const recordFinished = ref(false)
const recordParams = ref({
"pageNum": 1,
"pageSize": 10
})
const pointsResult = ref([]);
async function getPoints() {
try {
if(recordFinished.value) return
const res = await request.post("/personalCenter/getRecord",{...recordParams.value});
if (res.code === 200) {
if (recordParams.value.pageNum === 1) {
pointsResult.value = res.rows;
} else {
pointsResult.value = [...pointsResult.value, ...res.rows];
}
//
if (pointsResult.value.length >= res.total) {
recordFinished.value = true;
}
recordParams.value.pageNum++;
}
} catch (err) {
console.log(err);
}
}
getPoints();
//
const walletRecordFinished = ref(false)
const walletRecordParams = ref({
"pageNum": 1,
"pageSize": 15
})
const walletRecordList = ref([]);
async function getWalletRecord() {
try {
if(walletRecordFinished.value) return
const res = await request.post("/personalCenter/getWalletRecord", {...walletRecordParams.value});
if (res.code === 200) {
if (walletRecordParams.value.pageNum === 1) {
walletRecordList.value = res.rows;
} else {
walletRecordList.value = [...walletRecordList.value, ...res.rows];
}
//
if (walletRecordList.value.length >= res.total) {
walletRecordFinished.value = true;
}
walletRecordParams.value.pageNum++;
}
} catch (err) {
console.log(err);
}
}
getWalletRecord();
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="oasis" tab="充值记录">
<div class="border border-solid border-gray-200 rounded-lg relative">
<div class="mc-table flex w-full bg-gray-200 sticky top-0">
<div class="w-[250px]">获取时间</div>
<div class="w-[250px]">获取来源</div>
<div class="flex-1">详情</div>
<div class="w-[200px]">金币值</div>
</div>
<n-infinite-scroll
style="height: calc(100vh - 300px);"
:distance="10"
@load="getPoints"
>
<div v-for="item in pointsResult" :key="item" class="mc-table flex w-full">
<div class="w-[250px]">
{{ item.orderTime }}
</div>
<div class="w-[250px]">{{ item.productName }}</div>
<div class="flex-1">-</div>
<div class="w-[200px]">
{{ item.paymentAmount }}
</div>
</div>
</n-infinite-scroll>
</div>
</n-tab-pane>
<n-tab-pane name="beatles" tab="消费记录">
<div class="border border-solid border-gray-200 rounded-lg relative">
<div class="mc-table flex w-full bg-gray-200 sticky top-0">
<div class="w-[250px]">消耗时间</div>
<div class="w-[250px]">消耗类型</div>
<div class="flex-1">详情</div>
<div class="w-[200px]">充值金币值</div>
</div>
<n-infinite-scroll
style="height: calc(100vh - 300px);"
:distance="10"
@load="getWalletRecord"
>
<div v-for="item in walletRecordList" :key="item" class="mc-table flex w-full">
<div class="w-[250px]">
{{ item.consumeDate }}
</div>
<div class="w-[250px]">{{ item.productName }}</div>
<div class="flex-1">-</div>
<div class="w-[200px]">
{{ item.amount }}
</div>
</div>
</n-infinite-scroll>
</div>
</n-tab-pane>
</n-tabs>
</div>
</div>
</template>
<style lang="scss" scoped>
.mc-table {
padding: 10px;
line-height: 40px;
border-bottom: 1px solid #eee;
}
</style>

View File

@ -1,132 +1,212 @@
<script setup lang="ts">
import { CheckmarkCircleSharp, Close } from '@vicons/ionicons5';
import { NConfigProvider, NMessageProvider } from 'naive-ui';
<script setup>
import { CheckmarkCircleSharp, Close } from "@vicons/ionicons5";
import { NConfigProvider, NMessageProvider } from "naive-ui";
const message = useMessage();
definePageMeta({
layout: 'header',
})
layout: "header",
});
//
const needPayment = ref([{
amount: '',
productId: '',
promotionId: '',
type: 'member',
}])
const userStore = useUserStore()
const userInfo = userStore.userInfo as UserInfoType
const needPayment = ref([
{
amount: "",
productId: "",
promotionId: "",
type: "member",
},
]);
const userStore = useUserStore();
const userInfo = userStore.userInfo;
//
interface Payment {
isVisible: boolean
}
// interface Payment {
// isVisible: boolean;
// }
//
const isMember = ref(false)
const isMember = ref(false);
async function getIsMember() {
try {
const res = await request.get('/member/isMember')
const res = await request.get("/member/isMember");
if (res.code === 200) {
isMember.value = res.data
isMember.value = res.data;
}
}
catch (err) {
console.log(err)
} catch (err) {
console.log(err);
}
}
getIsMember()
getIsMember();
//
const MemberBenefitList = ref([])
const MemberBenefitList = ref([]);
async function getMemberBenefitList() {
try {
const res = await request.get('/memberLevel/getMemberBenefitList')
const res = await request.get("/memberLevel/getMemberBenefitList");
if (res.code === 200) {
MemberBenefitList.value = res.data
MemberBenefitList.value = res.data;
}
}
catch (err) {
console.log(err)
} catch (err) {
console.log(err);
}
}
getMemberBenefitList()
getMemberBenefitList();
//
interface memberLevel {
memberName: string
unitPrice: number
originalPrice: number
subscriptionPeriod: number
}
const memberLevelList = ref<memberLevel[]>([])
// interface memberLevel {
// memberName: string;
// unitPrice: number;
// originalPrice: number;
// subscriptionPeriod: number;
// }
const memberLevelList = ref([]);
async function getMemberLevelList() {
try {
const res = await request.get('/memberLevel/list')
const res = await request.get("/memberLevel/list");
if (res.code === 200) {
memberLevelList.value = res.data
memberLevelList.value = res.data;
}
}
catch (err) {
console.log(err)
} catch (err) {
console.log(err);
}
}
getMemberLevelList()
getMemberLevelList();
//
const isShowPayment = ref(false)
const PaymentRef = ref<Payment | null>(null)
function showPayment(info: any) {
const isShowPayment = ref(false);
const PaymentRef = ref(null);
function showPayment(info) {
if (info === 1) {
needPayment.value = memberLevelList.value
needPayment.value = memberLevelList.value;
} else {
needPayment.value = [info];
}
else {
needPayment.value = [info]
}
isShowPayment.value = true
isShowPayment.value = true;
if (PaymentRef.value) {
PaymentRef.value.isVisible = true
PaymentRef.value.isVisible = true;
}
}
//
function closePayment() {
isShowPayment.value = false
isShowPayment.value = false;
if (PaymentRef.value) {
PaymentRef.value.isVisible = false
PaymentRef.value.isVisible = false;
}
}
//
const isShowIntPayment = ref(false)
const isShowIntPayment = ref(false);
const IntPaymentRef = ref<Payment | null>(null)
const IntPaymentRef = ref(null);
function showIntPayment() {
isShowIntPayment.value = true
isShowIntPayment.value = true;
if (IntPaymentRef.value) {
IntPaymentRef.value.isVisible = true
IntPaymentRef.value.isVisible = true;
}
}
//
function closeIntPayment() {
isShowIntPayment.value = false
isShowIntPayment.value = false;
if (IntPaymentRef.value) {
IntPaymentRef.value.isVisible = false
IntPaymentRef.value.isVisible = false;
}
}
//
const isShowGoldPayment = ref(false);
const goldPaymentRef = ref(null);
function closeGoldPayment() {
isShowGoldPayment.value = false;
if (goldPaymentRef.value) {
goldPaymentRef.value.isVisible = false;
}
}
//
function paymentSuccess() {
getIsMember()
getIsMember();
integralGold();
}
//
function toIntDetail() {
const baseUrl = window.location.origin
window.open(`${baseUrl}/int-detail`, '_blank', 'noopener,noreferrer')
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')
//
function toOrderManage() {
const baseUrl = window.location.origin;
window.open(`${baseUrl}/order-management`, "_blank", "noopener,noreferrer");
}
//
function toGoldDetail() {
const baseUrl = window.location.origin;
window.open(`${baseUrl}/gold-detail`, "_blank", "noopener,noreferrer");
}
//
function showGoldPayment() {
isShowGoldPayment.value = true;
if (goldPaymentRef.value) {
goldPaymentRef.value.isVisible = true;
}
}
//
const integralGold = ref({});
async function getIntegralGold() {
try {
const res = await request.post("/personalCenter/getPointAndWallet");
if (res.code === 200) {
integralGold.value = res.data;
}
} catch (err) {
console.log(err);
}
}
getIntegralGold();
const isShowActivity = ref(true);
//
function closeActivityIcon() {
isShowActivity.value = false;
}
//
const activityList = ref([])
const isShowactivityList = ref(false);
async function showActivityList() {
try {
const res = await request.post("/promotion/promotionList", {
pageNum: 1,
pageSize: 50,
});
if (res.code === 200) {
activityList.value = res.rows
isShowactivityList.value = true;
}
} catch (err) {
console.log(err);
}
}
//
async function getActivity(item) {
if(item.isJoin === 1) return
try {
const res = await request.get(`/promotion/joinPromotion?promotionId=${item.id}`);
if (res.code === 200) {
message.success('领取成功')
item.isJoin = 1
}
} catch (err) {
if(err.code === 601){
message.warning(err.msg)
}
}
}
</script>
@ -137,16 +217,23 @@ function toOrderManage(){
<!-- 左侧用户信息 -->
<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" @click="toOrderManage">
<!-- <div class="text-right">
<button
class="text-[#8b8685] text-sm bg-inherit border-none cursor-pointer"
@click="toOrderManage"
>
订阅管理 >
</button>
</div>
</div> -->
<!-- 用户头像和信息 -->
<div class="flex flex-col items-center mt-2">
<client-only>
<img :src="userInfo.avatar" alt="头像" class="w-20 h-20 rounded-full mb-3">
<img
:src="userInfo.avatar"
alt="头像"
class="w-20 h-20 rounded-full mb-3"
/>
<span class="text-white text-sm mb-2">{{ userInfo.nickName }}</span>
</client-only>
<div class="flex items-center text-[#8b8685] text-xs">
@ -160,7 +247,11 @@ function toOrderManage(){
d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"
/>
</svg>
{{ isMember.result === '1' ? `会员到期时间: ${isMember.endDate}` : '您还不是魔创未来的会员' }}
{{
isMember.result === "1"
? `会员到期时间: ${isMember.endDate}`
: "您还不是魔创未来的会员"
}}
</div>
</div>
@ -187,41 +278,49 @@ function toOrderManage(){
<div class="grid grid-cols-3 gap-8">
<!-- 算力余额 -->
<div>
<h3 class="text-[#c3986b] mb-4">
算力余额
</h3>
<h3 class="text-[#c3986b] mb-4">积分余额</h3>
<div class="flex items-center mb-2">
<span class="text-[#c3986b] mr-2">300</span>
<button class="text-[#c3986b] bg-inherit border-none cursor-pointer" @click="showIntPayment">
<span class="text-[#c3986b] mr-2">{{ integralGold.point || 0 }}</span>
<button
class="text-[#c3986b] bg-inherit border-none cursor-pointer"
@click="showIntPayment"
>
充值 >
</button>
</div>
<button class="text-white bg-inherit border-none cursor-pointer p-0" @click="toIntDetail">
算力明细 >
<button
class="text-white bg-inherit border-none cursor-pointer p-0"
@click="toIntDetail"
>
积分明细 >
</button>
</div>
<!-- 生图加速余额 -->
<div>
<h3 class="text-[#c3986b] mb-4">
生图加速余额
</h3>
<h3 class="text-[#c3986b] mb-4">金币余额</h3>
<div class="flex items-center mb-2">
<span class="text-[#c3986b] mr-2">0</span>
<button class="text-[#c3986b] bg-inherit border-none cursor-pointer">
<span class="text-[#c3986b] mr-2"
>{{ integralGold.wallet || 0 }} </span
>
<button
class="text-[#c3986b] bg-inherit border-none cursor-pointer"
@click="showGoldPayment"
>
充值 >
</button>
</div>
<button class="text-white bg-inherit border-none cursor-pointer p-0">
<button
class="text-white bg-inherit border-none cursor-pointer p-0"
@click="toGoldDetail"
>
加速明细 >
</button>
</div>
<!-- 训练加速余额 -->
<div>
<h3 class="text-[#c3986b] mb-4">
训练加速余额
</h3>
<h3 class="text-[#c3986b] mb-4">训练加速余额</h3>
<div class="flex items-center mb-2">
<span class="text-[#c3986b]">0</span>
</div>
@ -244,9 +343,7 @@ function toOrderManage(){
<!-- 进度条 -->
<div class="relative">
<div class="h-1 bg-[#3a322e] rounded-full">
<div class="absolute right-0 -top-6 text-[#8b8685] text-sm">
0G/3G
</div>
<div class="absolute right-0 -top-6 text-[#8b8685] text-sm">0G/3G</div>
</div>
</div>
@ -281,14 +378,17 @@ function toOrderManage(){
<div class="card-item">
<span class="text-[#814600] text-[20px] mr-2">¥</span>
<span class="text-[#814600] text-[40px] mr-2">{{ item.unitPrice }}</span>
<span class="text-gray-400 text-[20px] line-through">¥{{ item.originalPrice }}</span>
<span class="text-gray-400 text-[20px] line-through"
>¥{{ item.originalPrice }}</span
>
</div>
<div class="card-item text-[#e08909] w-7/10 text-center text-[12px]">
{{ item.subscriptionPeriod }}
</div>
<div class="card-item">
<button
class="bg-gradient-to-r from-[#fbdfa4] to-[#f3c180] text-[#4c3d33] w-40 h-10 rounded-full text-[12px] border-none cursor-pointer" @click="showPayment(item)"
class="bg-gradient-to-r from-[#fbdfa4] to-[#f3c180] text-[#4c3d33] w-40 h-10 rounded-full text-[12px] border-none cursor-pointer"
@click="showPayment(item)"
>
立即开通
</button>
@ -297,9 +397,7 @@ function toOrderManage(){
</div>
<div class="py-8">
<div class="flex justify-center mb-4">
<div class="text-xl font-bold">
会员权益
</div>
<div class="text-xl font-bold">会员权益</div>
</div>
<!-- <div class="flex items-center">
<div v-for="(item, index) in MemberBenefitList" :key="index" class="w-1/4 w-full">
@ -315,67 +413,35 @@ function toOrderManage(){
</div> -->
<div class="text-[#525252]">
<div class="flex gap-2">
<div class="member-item bg-[#f7f0ea]">
会员权益
</div>
<div class="member-item bg-[#f5f5f5]">
用户免费
</div>
<div class="member-item bg-[#fdf6ea]">
基础版VIP
</div>
<div class="member-item bg-[#fce6bf]">
专业版VIP
</div>
<div class="member-item bg-[#f7f0ea]">会员权益</div>
<div class="member-item bg-[#f5f5f5]">用户免费</div>
<div class="member-item bg-[#fdf6ea]">基础版VIP</div>
<div class="member-item bg-[#fce6bf]">专业版VIP</div>
</div>
<div class="flex gap-2">
<div class="member-item bg-[#fff]">
算力
</div>
<div class="member-item bg-[#fff]">
每天300点
</div>
<div class="member-item bg-[#fff]">
每月15000点
</div>
<div class="member-item bg-[#fff]member-item">
每月35000点
</div>
<div class="member-item bg-[#fff]">算力</div>
<div class="member-item bg-[#fff]">每天300点</div>
<div class="member-item bg-[#fff]">每月15000点</div>
<div class="member-item bg-[#fff]member-item">每月35000点</div>
</div>
<div class="flex gap-2">
<div class="member-item bg-[#fafafa]">
云端存储空间
</div>
<div class="member-item bg-[#fafafa]">
3GB
</div>
<div class="member-item bg-[#fdf6ea]">
20GB
</div>
<div class="member-item bg-[#fce6bf]">
50GB
</div>
<div class="member-item bg-[#fafafa]">云端存储空间</div>
<div class="member-item bg-[#fafafa]">3GB</div>
<div class="member-item bg-[#fdf6ea]">20GB</div>
<div class="member-item bg-[#fce6bf]">50GB</div>
</div>
<div class="flex gap-2">
<div class="member-item bg-[#fff]">
生图加速特权
</div>
<div class="member-item bg-[#fff]">生图加速特权</div>
<div class="member-item bg-[#fff]member-item">
<n-icon size="20" color="#ed7470">
<Close />
</n-icon>
</div>
<div class="member-item bg-[#fff]">
每月800次
</div>
<div class="member-item bg-[#fff]">
每月5000次
</div>
<div class="member-item bg-[#fff]">每月800次</div>
<div class="member-item bg-[#fff]">每月5000次</div>
</div>
<div class="flex gap-2">
<div class="member-item bg-[#fafafa]">
会员专属模型
</div>
<div class="member-item bg-[#fafafa]">会员专属模型</div>
<div class="member-item bg-[#fafafa]">
<n-icon size="20" color="#ed7470">
<Close />
@ -393,9 +459,7 @@ function toOrderManage(){
</div>
</div>
<div class="flex gap-2">
<div class="member-item bg-[#fff]">
生图高级功能
</div>
<div class="member-item bg-[#fff]">生图高级功能</div>
<div class="member-item bg-[#fff]">
<n-icon size="20" color="#ed7470">
<Close />
@ -413,9 +477,7 @@ function toOrderManage(){
</div>
</div>
<div class="flex gap-2">
<div class="member-item bg-[#fafafa]">
训练XL模型
</div>
<div class="member-item bg-[#fafafa]">训练XL模型</div>
<div class="member-item bg-[#fafafa]">
<n-icon size="20" color="#ed7470">
<Close />
@ -433,9 +495,7 @@ function toOrderManage(){
</div>
</div>
<div class="flex gap-2">
<div class="member-item bg-[#fff]">
图片去水印下载
</div>
<div class="member-item bg-[#fff]">图片去水印下载</div>
<div class="member-item bg-[#fff]">
<n-icon size="20" color="#ed7470">
<Close />
@ -453,46 +513,126 @@ function toOrderManage(){
</div>
</div>
<div class="flex gap-2">
<div class="member-item bg-[#fafafa]">
多任务并行生图
</div>
<div class="member-item bg-[#fafafa]">多任务并行生图</div>
<div class="member-item bg-[#fafafa]">
<n-icon size="20" color="#58c08f">
<CheckmarkCircleSharp />
</n-icon>
</div>
<div class="member-item bg-[#fdf6ea]">
2
</div>
<div class="member-item bg-[#fce6bf] ">
3
</div>
<div class="member-item bg-[#fdf6ea]">2</div>
<div class="member-item bg-[#fce6bf]">3</div>
</div>
</div>
</div>
<div class="text-[#999] text-[12px]">
<div class="mt-1">
会员每月算力和加速特权按月下发有效期31天到期重置会员模型下载次数上限为每月200次
会员每月算力和加速特权按月下发, 有效期31天,
到期重置会员模型下载次数上限为每月200次
</div>
<div class="mt-1">
发票或团队/企业定制需求请点击立即咨询联系我们企业合作需求也可直接联系xxxx
</div>
<div class="mt-1">
更多问题可见帮助中心
发票或团队/企业定制需求, 请点击立即咨询联系我们, 企业合作需求也可直接联系xxxx
</div>
<div class="mt-1">更多问题可见帮助中心</div>
</div>
</div>
</div>
<NConfigProvider>
<NMessageProvider>
<Payment v-if="isShowPayment" ref="PaymentRef" :info="needPayment" :is-member="isMember" @close-payment="closePayment" />
<IntPayment v-if="isShowIntPayment" ref="IntPaymentRef" :is-member="isMember" @payment-success="paymentSuccess" @close-payment="closeIntPayment" />
<Payment
v-if="isShowPayment"
ref="PaymentRef"
:info="needPayment"
:is-member="isMember"
@close-payment="closePayment"
/>
<IntPayment
v-if="isShowIntPayment"
ref="IntPaymentRef"
:is-member="isMember"
@payment-success="paymentSuccess"
@close-payment="closeIntPayment"
/>
<GoldPayment
v-if="isShowGoldPayment"
ref="goldPaymentRef"
:is-member="isMember"
@payment-success="paymentSuccess"
@close-payment="closeGoldPayment"
/>
</NMessageProvider>
</NConfigProvider>
<div class="activity-box" v-if="isShowActivity">
<div class="absolute -top-6 -right-0 cursor-pointer">
<n-icon size="20" color="#bbb" @click="closeActivityIcon">
<Close />
</n-icon>
</div>
<img
class="cursor-pointer"
@click="showActivityList"
src="@/assets/img/activityIcon.png"
alt=""
/>
</div>
<n-modal v-model:show="isShowactivityList" transform-origin="center">
<n-card
style="width: 350px; background: #e65e40"
:bordered="false"
size="huge"
:content-style="{ padding: 0 }"
role="dialog"
aria-modal="true"
>
<div class="p-4 rounded-lg">
<div class="flex justify-end mb-4">
<n-icon
class="cursor-pointer"
@click="isShowactivityList = false"
size="20"
color="#bbb"
>
<Close />
</n-icon>
</div>
<div class="flex flex-col gap-3">
<div
class="px-2 py-4 bg-white h-20 w-full flex rounded-lg"
v-for="(item, index) in activityList"
:key="index"
>
<div class="w-[70%] flex flex-col justify-around">
<div>{{ item.activityName }}</div>
<div class="text-xs text-gray-500">有效期: {{item.startTime}}</div>
<div class="text-xs text-gray-500">失效期: {{item.endTime}}</div>
</div>
<div class="w-[30%] flex items-center justify-center">
<div
@click="getActivity(item)"
class="w-14 h-6 flex items-center justify-center cursor-pointer text-white text-xs bg-[#e9613f] rounded-full"
:style="{backgroundColor: item.isJoin === 0 ? '#e9613f' : '#ccc'}"
>
{{ item.isJoin === 0 ? '领取' : '已领取' }}
</div>
</div>
</div>
</div>
</div>
</n-card>
</n-modal>
</div>
</template>
<style scoped>
/* .n-card__content{
padding:20px !important
} */
.activity-box {
position: fixed;
bottom: 20px;
right: 20px;
justify-content: space-around
}
.card-item {
@apply flex items-center justify-center h-1/4;
}

View File

@ -1,13 +1,17 @@
<script setup lang="ts">
<script setup>
import { commonApi } from "@/api/common";
import { Close, DiamondSharp, PersonAddOutline } from "@vicons/ionicons5";
import {
CircleUser,
Download,
EllipsisVertical, Heart, Play,
EllipsisVertical,
Heart,
Play,
SquareCheck,
SquarePlus
} from "lucide-vue-next";
//
import { formatFileSize } from '@/utils/index.ts';
import { NConfigProvider, NMessageProvider } from "naive-ui";
import { ref } from "vue";
import { useRouter } from "vue-router";
@ -21,11 +25,11 @@ definePageMeta({
});
// const userStore = useUserStore()
const route = useRoute();
const { id } = route.params as { id: string };
const { id } = route.params
const activeTab = ref(null);
const commentHeight = ref(800);
const detailsInfo = ref({});
const currentUserInfo = ref<any>({});
const currentUserInfo = ref({});
const isVisibleReport = ref(false);
//
const versionByWorkInfo = ref([]);
@ -34,7 +38,9 @@ async function getInfo() {
const res = await request.get(`/model/selectModelById?id=${id}`);
if (res.code === 200) {
detailsInfo.value = res.data;
detailsInfo.value.styleList = JSON.parse(res.data.styleList);
if (res.data.tags) {
detailsInfo.value.tagsList = JSON.parse(res.data.tags);
}
// detailsInfo.value.styleList =JSON.parse(res.data.styleList)
// // 1
try {
@ -73,15 +79,15 @@ async function getInfo() {
getInfo();
// //
interface SelectUserInfo {
attention: number;
bean: number;
imageLikeNum: number;
modelDownLoadNum: number;
modelLikeNum: number;
modelRunNum: number;
}
const selectUserInfo = ref<SelectUserInfo>({
// interface SelectUserInfo {
// attention: number;
// bean: number;
// imageLikeNum: number;
// modelDownLoadNum: number;
// modelLikeNum: number;
// modelRunNum: number;
// }
const selectUserInfo = ref({
attention: 0,
bean: 0,
imageLikeNum: 0,
@ -106,8 +112,8 @@ async function getAttention() {
// //
const isDelete = ref(false);
async function handleSelect(event: Event, type: string) {
event.stopPropagation(); //
async function handleSelect(type) {
// event.stopPropagation(); //
if (type === "report") {
isVisibleReport.value = true;
// await request.get(`/WorkFlow/report?id=${id}`) //
@ -183,7 +189,7 @@ async function onLike() {
const reportParams = ref({
reportId: undefined,
text: "",
type:1
type: 1,
});
const reportList = ref([]);
async function getDictType() {
@ -197,7 +203,7 @@ async function getDictType() {
}
}
getDictType();
function handleChange(item: any) {
function handleChange(item) {
reportParams.value.reportId = item.dictValue;
if (item.dictValue !== "5") {
reportParams.value.text = "";
@ -209,30 +215,78 @@ 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){
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()
closeReport();
}
}catch(err){
console.log(err);
} 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')
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"
);
}
}
const currentTabsIndex = ref(0);
function handleTabChange(id) {
for (let i = 0; i < versionByWorkInfo.value.length; i++) {
if (id === versionByWorkInfo.value[i].id) {
currentTabsIndex.value = i;
}
}
}
async function addCollect(){
try {
const params = {
"productId": versionByWorkInfo.value[currentTabsIndex.value].id,
"productType": 0,
}
const res = await request.post("/collect/addCollect", params);
if (res.code === 200) {
versionByWorkInfo.value[currentTabsIndex.value].isCollect = res.data
if(res.data === 0){
message.success("已加入模型库, 可通过在线生图使用");
}else{
message.success("已从模型库中移除");
}
}
} catch (err) {
console.log(err);
}
}
async function handelDown(){
try {
const res = await request.get(`/ModelVersion/modelFileDownload?id=${versionByWorkInfo.value[currentTabsIndex.value].id}`);
if (res.code === 200) {
const link = document.createElement('a');
link.href = res.data;
link.download = res.msg; //
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
} catch (err) {
console.log(err);
}
}
</script>
<template>
@ -270,10 +324,7 @@ function toPersonalCenter(){
<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="" /> -->
<component
:is="Heart"
class="h-[12px] w-[12px] mr-1 text-[#000]"
/>
<component :is="Heart" class="h-[12px] w-[12px] mr-1 text-[#000]" />
<span>{{ detailsInfo.likeNum || 0 }} </span>
</div>
</template>
@ -283,7 +334,7 @@ function toPersonalCenter(){
<div class="flex items-center mt-3 mb-5">
<div
v-for="(item, index) in detailsInfo.styleList"
v-for="(item, index) in detailsInfo.tagsList"
:key="index"
class="text-[12px] bg-[#ebf2fe] p-1 px-2 text-[#557abf] mr-4 rounded-md"
>
@ -293,7 +344,12 @@ function toPersonalCenter(){
<div class="flex w-full gap-1">
<div class="w-2/3">
<div class="w-full">
<n-tabs v-model:value="activeTab" type="line" animated>
<n-tabs
v-model:value="activeTab"
@update:value="handleTabChange"
type="line"
animated
>
<n-tab-pane
v-for="(item, index) in versionByWorkInfo"
:key="index"
@ -471,23 +527,32 @@ function toPersonalCenter(){
</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"
v-if="versionByWorkInfo.length > 0"
@click="addCollect"
class="flex flex-1 items-center justify-center bg-[#eceef4] h-[50px] mt-4 mr-1 rounded-md cursor-pointer"
>
<component
:is="SquarePlus"
:is="
versionByWorkInfo[currentTabsIndex].isCollect === 1
? SquarePlus
: SquareCheck
"
class="h-[20px] w-[20px] text-black menu-icon m-1 text-[#969798]"
/>
<span class="mr-1">加入模型课</span>
<span class="mr-1">
{{ versionByWorkInfo[currentTabsIndex].isCollect === 1 ? '加入模型库' : '已加入'}}
</span>
</div>
<div
@click="handelDown"
class="flex flex-1 items-center bg-gradient-to-r from-[#ffe9c8] to-[#ffd264] justify-center ml-1 mt-4 text-black bg-[#eceef4] w-full rounded-md h-[50px] cursor-pointer"
>
<component
:is="Download"
class="h-[20px] w-[20px] text-black menu-icon m-1 text-[#969798]"
/>
<span class="mr-1"> 下载 (122.22MB) </span>
<span class="mr-1" v-if="versionByWorkInfo.length > 0"> {{ formatFileSize(versionByWorkInfo[currentTabsIndex].fileSize) }} </span>
</div>
</div>
@ -505,7 +570,7 @@ function toPersonalCenter(){
content="确定要将模型删除? 模型删除后无法找回"
negative-text="取消"
positive-text="确认"
@negative-click="onDelete"
@negative-click="isDelete = false"
@positive-click="onDelete"
/>
@ -539,7 +604,9 @@ function toPersonalCenter(){
{{ item.dictLabel }}
</n-radio>
<n-input
v-if="reportParams.reportId !== undefined && reportParams.reportId === '5'"
v-if="
reportParams.reportId !== undefined && reportParams.reportId === '5'
"
v-model:value="reportParams.text"
placeholder="点击输入"
type="textarea"
@ -549,12 +616,10 @@ function toPersonalCenter(){
}"
/>
<div
@click="onReport"
@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]',
reportParams.reportId !== undefined ? 'bg-[#4c79ee]' : 'bg-[#cccccc]',
]"
>
确认
@ -571,7 +636,7 @@ function toPersonalCenter(){
</div>
</template>
<style lang="scss">
<style lang="scss" scoped>
.header-num {
@apply flex items-center bg-[#f4f5f9] px-2 rounded-full;
}
@ -599,9 +664,9 @@ function toPersonalCenter(){
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);
opacity 0.3s var(--n-bezier), background-color 0.3s var(--n-bezier);
}
.original{
.original {
margin: 2px 0;
padding: 2px 0;
display: flex;

View File

@ -8,6 +8,8 @@ import { useUserStore } from "@/stores/user";
import { formatDate } from "@/utils/index.ts";
import { NConfigProvider, NMessageProvider } from "naive-ui";
import { nextTick, onMounted, onUnmounted, ref } from "vue";
let pollingTimer: ReturnType<typeof setInterval> | undefined
const route = useRoute();
const { type, status } = route.query as { type: string; status: string };
@ -16,6 +18,9 @@ const finished = ref(false);
const total = ref(0); //
const loadingTrigger = ref(null);
import { useRouter } from "vue-router";
const router = useRouter();
const observer = ref<IntersectionObserver | null>(null);
definePageMeta({
layout: "default",
@ -58,7 +63,7 @@ const typeList = ref([
// form
const publishParams = ref({
pageNum: 1,
pageSize: 12,
pageSize: 20,
status: "0",
orderByColumn: "create_time",
date: null,
@ -69,7 +74,7 @@ const publishParams = ref({
function initPublishParams() {
publishParams.value = {
pageNum: 1,
pageSize: 12,
pageSize: 20,
status: "0",
orderByColumn: "create_time",
date: null,
@ -81,14 +86,14 @@ function initPublishParams() {
// form
const likesParams = ref({
pageNum: 1,
pageSize: 12,
pageSize: 20,
orderByColumn: "create_time",
});
function initLikesParams() {
likesParams.value = {
pageNum: 1,
pageSize: 12,
pageSize: 20,
orderByColumn: "create_time",
};
}
@ -245,7 +250,7 @@ getAttention();
// Banner
const bannerStyle = {
backgroundImage:
"url('https://liblibai-web-static.liblib.cloud/liblibai_v4_online/static/_next/static/images/defaultBgImg.381282c0f2b01780c83d8fe6dc0aa90a.png')",
"url('https://img.zcool.cn/community/special_cover/3a9a64d3628c000c2a1000657eec.jpg')",
};
//
@ -362,7 +367,7 @@ const attentionFinished = ref(false);
const attentionList = ref([]);
const attentionListParams = ref({
pageNumber: 1,
pageSize: 15,
pageSize: 20,
});
async function getAttentionList() {
try {
@ -397,7 +402,8 @@ const likeFinished = ref(false);
const likeList = ref([]);
const likeListParams = ref({
pageNumber: 1,
pageSize: 15,
pageSize: 20,
type:null
});
async function getLikeList() {
try {
@ -434,6 +440,10 @@ function closefanList() {
// /
async function onAttention(item: any) {
try {
const userId = userStore.userInfo.userId
if(userId === item.userId){
return message.warning('自己不能关注自己')
}
const res = await request.get(`/attention/addAttention?userId=${item.userId}`);
if (res.code === 200) {
if (res.data) {
@ -490,101 +500,7 @@ function handlePositiveClick() {
const activeTab = ref('like')
//
const invitationList = ref({
totalAmount: 2889,
earningsDisplayList: [
{
user: {
userId: 2,
userName: "ry",
avatar:
"https://img1.baidu.com/it/u=728383910,3448060628&fm=253&fmt=auto&app=120&f=JPEG?w=800&h=800",
},
count: 1,
},
{
user: {
userId: 105,
userName: "默认用户:oKwIrhqh",
avatar:
"https://img1.baidu.com/it/u=728383910,3448060628&fm=253&fmt=auto&app=120&f=JPEG?w=800&h=800",
},
count: 2,
},
{
user: {
userId: 105,
userName: "默认用户:oKwIrhqh",
avatar:
"https://img1.baidu.com/it/u=728383910,3448060628&fm=253&fmt=auto&app=120&f=JPEG?w=800&h=800",
},
count: 2,
},
{
user: {
userId: 105,
userName: "默认用户:oKwIrhqh",
avatar:
"https://img1.baidu.com/it/u=728383910,3448060628&fm=253&fmt=auto&app=120&f=JPEG?w=800&h=800",
},
count: 2,
},
{
user: {
userId: 105,
userName: "默认用户:oKwIrhqh",
avatar:
"https://img1.baidu.com/it/u=728383910,3448060628&fm=253&fmt=auto&app=120&f=JPEG?w=800&h=800",
},
count: 2,
},
{
user: {
userId: 105,
userName: "默认用户:oKwIrhqh",
avatar:
"https://img1.baidu.com/it/u=728383910,3448060628&fm=253&fmt=auto&app=120&f=JPEG?w=800&h=800",
},
count: 2,
},
{
user: {
userId: 105,
userName: "默认用户:oKwIrhqh",
avatar:
"https://img1.baidu.com/it/u=728383910,3448060628&fm=253&fmt=auto&app=120&f=JPEG?w=800&h=800",
},
count: 2,
},
{
user: {
userId: 105,
userName: "默认用户:oKwIrhqh",
avatar:
"https://img1.baidu.com/it/u=728383910,3448060628&fm=253&fmt=auto&app=120&f=JPEG?w=800&h=800",
},
count: 2,
},
{
user: {
userId: 105,
userName: "默认用户:oKwIrhqh",
avatar:
"https://img1.baidu.com/it/u=728383910,3448060628&fm=253&fmt=auto&app=120&f=JPEG?w=800&h=800",
},
count: 2,
},
{
user: {
userId: 107,
userName: "默认用户:hQDEthgT",
avatar:
"https://img1.baidu.com/it/u=728383910,3448060628&fm=253&fmt=auto&app=120&f=JPEG?w=800&h=800",
},
count: 0,
},
],
});
const invitationList = ref({});
async function handleNegativeClick() {
try {
const res = await request.get(`/invitation/earningsDisplay`);
@ -600,13 +516,64 @@ const showLike = (type:string) =>{
isShowFan.value= true
activeTab.value = type
}
const toWallet = () => {
router.push({
path: `/wallet`,
});
}
//
const zfbStatus = ref('0')
async function getBindStatus(){
const res = await request.get(`/ali/pay/queryBindStatus`)
if (res.data === '1') { //'1 0
zfbStatus.value = res.data
message.success('绑定成功!')
}
}
getBindStatus()
//
const qrUrl = ref('')
const isShowBindingModal = ref(false)
const showBinding = async() =>{
try {
const res = await request.get(`/ali/pay/generateQrCode`);
if (res.code === 200) {
qrUrl.value = res.data;
isShowBindingModal.value = true
pollingTimer && clearTimeout(pollingTimer)
pollingTimer = setInterval(async () => {
try {
const res2 = await request.get(`/ali/pay/queryBindStatus`)
if (res2.data === '1') {
closeBindingModal()
message.success('绑定成功!')
}
}
catch (err) {
closeBindingModal()
message.warning('绑定失败,请稍后再试!')
}
}, 2000)
}
} catch (err) {
console.log(err);
}
}
const closeBindingModal = () =>{
pollingTimer && clearTimeout(pollingTimer)
isShowBindingModal.value = false
}
</script>
<template>
<div class="mx-auto">
<div class="mx-auto relative">
<!-- Banner Section -->
<div class="banner-content h-32 bg-blue bg-cover bg-center" :style="bannerStyle" />
<!-- User Info Section -->
<div class="info-content mt-[-50px] p-5">
<div class="edit-info-content flex items-center">
@ -662,6 +629,15 @@ const showLike = (type:string) =>{
邀请码: {{ invitationCode }}
</n-popconfirm>
</div>
<div class="ml-4 cursor-pointer" @click="toWallet()">
<img src="@/assets/img/wallet.png" alt="">
</div>
<div v-if="zfbStatus === '1'" class="bg-[#3875f6] rounded-full px-4 py-2">
已绑定支付宝
</div>
<div v-else @click="showBinding" class="text-xs px-3 py-2 border border-solid border-[#ccc] rounded-full ml-4 bg-white cursor-pointer">
绑定支付宝
</div>
</div>
<!-- User Details -->
@ -946,6 +922,26 @@ const showLike = (type:string) =>{
</div>
</n-card>
</n-modal>
<div v-if="isShowBindingModal" class="fan-centent">
<div class="relative flex flex-col items-center">
<div class="bg-[#000] py-10 px-20 flex flex-col items-center justify-center rounded-lg">
<div class="text-xl text-white mb-4">
扫码绑定
</div>
<n-qr-code :value="qrUrl" :size="150" style="padding: 0;" />
<div class="text-base text-white mt-4">
请用手机支付宝扫码
</div>
</div>
<n-icon
size="30"
class="cursor-pointer mt-4 text-white"
@click="closeBindingModal"
>
<Close />
</n-icon>
</div>
</div>
</div>
</template>

View File

@ -140,7 +140,7 @@
<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)">
<div class="bg-[#f4f5f9] px-4 py-2 rounded-full cursor-pointer" @click="onAttention(item, 'attention')">
{{ item.attention ? '已关注' : '未关注' }}
</div>
</div>
@ -161,7 +161,7 @@
<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)">
<div class="bg-[#f4f5f9] px-4 py-2 rounded-full cursor-pointer" @click="onAttention(item, 'like')">
{{ item.attention ? '已关注' : '未关注' }}
</div>
</div>
@ -182,7 +182,7 @@ import { nextTick, onMounted, onUnmounted, ref } from "vue";
import { useRoute } from "vue-router";
const observer = ref<IntersectionObserver | null>(null);
const message = useMessage()
const userStore = useUserStore();
const route = useRoute();
const { userId } = route.query;
const loading = ref(false);
@ -191,9 +191,9 @@ const total = ref(0); // 总条数
const loadingTrigger = ref(null);
const urlList = ref({
"0": "/model/selectByUserIdModel",
"1": "/model/selectByUserIdWorkFlow",
"2": "/model/selectByUserIdImage",
"0": "/personalCenter/selectByUserIdModel",
"1": "/personalCenter/selectByUserIdWorkFlow",
"2": "/personalCenter/selectByUserIdImage",
});
const currentType = ref("0");
const typeList = ref([
@ -222,12 +222,12 @@ function closefanList() {
const bannerStyle = {
backgroundImage:
"url('https://liblibai-web-static.liblib.cloud/liblibai_v4_online/static/_next/static/images/defaultBgImg.381282c0f2b01780c83d8fe6dc0aa90a.png')",
"url('https://img.zcool.cn/community/special_cover/3a9a64d3628c000c2a1000657eec.jpg')",
};
const publishParams = ref({
pageNum: 1,
pageSize: 12,
pageSize: 20,
orderByColumn: "create_time",
userId: userId,
});
@ -287,6 +287,10 @@ getIsAttention()
// /
async function onAttention(item:any){
const myUserId = userStore.userInfo.userId
if(myUserId === item.userId){
return message.warning('自己不能关注自己')
}
let paramsUserId
if(item.userId){
paramsUserId = item.userId

View File

@ -110,7 +110,7 @@ function changeCategory(item: any) {
</MenuFold>
</div>
</div>
<div class="flex flex-wrap">
<div class="w-full">
<NConfigProvider>
<NMessageProvider>
<PictureList ref="listRef" :params="params" />

View File

@ -19,6 +19,7 @@ async function initFormData() {
if (type === "add") {
formData.value = {
modelProduct: {
jurisdiction:1, //
modelName: "",
modelType: null, // ,
category: null, //
@ -102,10 +103,10 @@ const timeLineList = ref([
},
]);
async function nextStep() {
if(currentStep.value === 1){
if(currentStep.value === 1 && type === 'add'){
const name = formData.value.modelProduct.modelName
try {
const res = await request.get(`/file/selectFile?type=model&name=${name}`);
const res = await request.get(`/model/selectModelByName?name=${name}`);
if (res.code == 200) {
if(res.data === 1){ //0 1
currentStep.value += 1;

View File

@ -5,10 +5,10 @@ import UploadImg from "@/components/publishWorkFlow/UploadImg.vue";
import { CirclePlus } from "lucide-vue-next";
import { NConfigProvider, NMessageProvider } from "naive-ui";
import { useRoute } from "vue-router";
const message = useMessage();
const route = useRoute();
const { type, id } = route.query;
const formData = ref();
async function initFormData() {
@ -73,12 +73,16 @@ function handleAddVersion() {
}
async function nextStep() {
// currentStep.value += 1;
if(currentStep.value === 1){
if(currentStep.value === 1 && type === 'add'){
const name = formData.value.workFlow.workflowName
try {
const res = await request.get(`/file/selectFile?type=workflow&name=${name}`);
const res = await request.get(`/WorkFlow/selectWorkFlowByName?name=${name}`);
if (res.code == 200) {
currentStep.value += 1;
if(res.data === 0 ){
currentStep.value += 1;
}else{
message.warning('该工作流名称已存在')
}
}
} catch (err) {
console.log(err);

View File

@ -67,7 +67,6 @@ const imageParams = ref({
if(type != 'undefined'){
currentType.value = type
}
// debugger
// if(keyword){
// modelParams.value.name = keyword;
// imageParams.value.name = keyword;

View File

@ -0,0 +1,19 @@
<template>
<div class="max-w-4xl mx-auto bg-white rounded-xl shadow-md overflow-hidden">
<div class="p-8">
<h1
class="text-3xl font-bold text-center text-blue-600 mb-10 pb-6 border-b border-gray-200"
>
关于魔创未来
</h1>
</div>
</div>
</template>
<script setup lang="ts">
definePageMeta({
layout: "header",
});
</script>
<style scoped></style>

View File

@ -0,0 +1,19 @@
<template>
<div class="max-w-4xl mx-auto bg-white rounded-xl shadow-md overflow-hidden">
<div class="p-8">
<h1
class="text-3xl font-bold text-center text-blue-600 mb-10 pb-6 border-b border-gray-200"
>
用户协议
</h1>
</div>
</div>
</template>
<script setup lang="ts">
definePageMeta({
layout: "header",
});
</script>
<style scoped></style>

View File

@ -0,0 +1,119 @@
<template>
<div class="min-h-screen bg-gray-50 py-12 px-4 sm:px-6 lg:px-8">
<div class="max-w-4xl mx-auto bg-white rounded-xl shadow-md overflow-hidden">
<div class="p-8">
<h1 class="text-3xl font-bold text-center text-blue-600 mb-10 pb-6 border-b border-gray-200">
隐私声明
</h1>
<div class="space-y-8">
<!-- 声明内容 -->
<section class="hover:bg-gray-50 p-6 rounded-lg transition duration-300">
<p class="text-gray-600 leading-relaxed">
我们重视您的隐私本网站承诺对您的个人信息进行严格保密未经您的许可我们不会向任何第三方透露您的个人信息
</p>
</section>
<!-- 信息收集范围 -->
<section class="hover:bg-gray-50 p-6 rounded-lg transition duration-300">
<h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
<div class="w-1 h-6 bg-blue-500 rounded mr-3"></div>
信息收集范围
</h2>
<p class="text-gray-600 mb-4">在您浏览本网站时我们可能会收集以下信息</p>
<ul class="list-disc list-inside text-gray-600 space-y-2">
<li>必要的访问日志IP地址访问时间</li>
<li>浏览器类型操作系统等基本设备信息</li>
<li>访问页面的记录</li>
</ul>
</section>
<!-- 信息用途 -->
<section class="hover:bg-gray-50 p-6 rounded-lg transition duration-300">
<h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
<div class="w-1 h-6 bg-blue-500 rounded mr-3"></div>
信息用途
</h2>
<p class="text-gray-600 mb-4">我们收集这些信息的目的是</p>
<ul class="list-disc list-inside text-gray-600 space-y-2">
<li>优化网站性能和用户体验</li>
<li>进行网站安全维护</li>
<li>提供更好的服务支持</li>
</ul>
</section>
<!-- Cookie说明 -->
<section class="hover:bg-gray-50 p-6 rounded-lg transition duration-300">
<h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
<div class="w-1 h-6 bg-blue-500 rounded mr-3"></div>
Cookie说明
</h2>
<p class="text-gray-600">
本网站使用Cookie来改善您的浏览体验这些Cookie不会收集您的个人身份信息您可以通过浏览器设置来管理或禁用Cookie
</p>
</section>
<!-- 安全措施 -->
<section class="hover:bg-gray-50 p-6 rounded-lg transition duration-300">
<h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
<div class="w-1 h-6 bg-blue-500 rounded mr-3"></div>
安全措施
</h2>
<p class="text-gray-600">
我们采用业界标准的安全措施来保护您的信息安全包括但不限于SSL加密传输数据访问控制等
</p>
</section>
<!-- 免责声明 -->
<section class="hover:bg-gray-50 p-6 rounded-lg transition duration-300">
<h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
<div class="w-1 h-6 bg-blue-500 rounded mr-3"></div>
免责声明
</h2>
<p class="text-gray-600">
对于通过本网站链接到的第三方网站我们不对其隐私保护措施负责建议您在访问这些网站时查看其隐私政策
</p>
</section>
<!-- 更新提醒 -->
<section class="hover:bg-gray-50 p-6 rounded-lg transition duration-300">
<h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
<div class="w-1 h-6 bg-blue-500 rounded mr-3"></div>
更新提醒
</h2>
<p class="text-gray-600">
我们保留随时更新本隐私声明的权利更新后的声明将在本页面公布请您定期查看
</p>
</section>
<!-- 联系方式 -->
<section class="hover:bg-gray-50 p-6 rounded-lg transition duration-300">
<h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
<div class="w-1 h-6 bg-blue-500 rounded mr-3"></div>
联系方式
</h2>
<div class="bg-gray-50 p-6 rounded-lg">
<p class="text-gray-600">如您对本隐私声明有任何疑问请通过以下方式联系我们</p>
<p class="text-gray-600 mt-2">📧 邮箱contact@example.com</p>
</div>
</section>
<!-- 更新日期 -->
<div class="text-right text-gray-500 pt-6 border-t border-gray-200">
最后更新日期2024年3月8日
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
definePageMeta({
layout: "header",
});
</script>
<style scoped>
</style>

View File

@ -0,0 +1,224 @@
<template>
<div>
<div class="p-4 flex text-white gap-3">
<div
class="w-60 h-28 bg-[#a494f7] px-8 py-6 rounded-lg flex flex-col justify-around"
>
<div class="text-xl">累计收入金额</div>
<div class="text-base">¥ {{ totalAmount || 0 }}</div>
</div>
<div
class="w-60 h-28 bg-[#e87988] px-8 py-6 rounded-lg flex flex-col justify-around"
>
<div class="text-xl flex justify-between items-center">
<div>可提现金额</div>
<div
class="text-sm cursor-pointer select-none text-[#524f4f]"
@click="showModal"
>
提现 >
</div>
</div>
<div class="text-base">¥ {{ integralGold.wallet || 0 }}</div>
</div>
</div>
<div class="p-4 text-[#06186d]">
<n-tabs v-model:value="activeTab" type="line" animated>
<!-- <n-tab-pane name="allDetail" tab="全部明细">
<div
class="border border-solid border-gray-200 rounded-lg relative text-[#06186d]"
>
<div class="mc-table flex w-full bg-gray-100 sticky top-0">
<div class="w-[250px]">获取时间</div>
<div class="w-[250px]">获取来源</div>
<div class="flex-1">详情</div>
<div class="w-[200px]">金币值</div>
</div>
<n-infinite-scroll
style="height: calc(100vh - 300px)"
:distance="10"
@load="getPoints"
>
<div v-for="item in allDetailList" :key="item" class="mc-table flex w-full">
<div class="w-[250px]">
{{ item.orderTime }}
</div>
<div class="w-[250px]">{{ item.productName }}</div>
<div class="flex-1">-</div>
<div class="w-[200px]">
{{ item.paymentAmount }}
</div>
</div>
</n-infinite-scroll>
</div>
</n-tab-pane> -->
<n-tab-pane name="withdrawDetail" tab="提现明细">
<div class="border border-solid border-gray-200 rounded-lg relative">
<div class="mc-table flex w-full bg-[#e5ecf4] sticky top-0">
<div class="w-[250px]">提现时间</div>
<div class="w-[250px]">账户类型</div>
<div class="flex-1">详情</div>
<div class="w-[200px]">提现金额</div>
</div>
<n-infinite-scroll
style="height: calc(100vh - 300px)"
:distance="10"
@load="getWithdrawDetail"
>
<div
v-for="item in withdrawDetailList"
:key="item"
class="mc-table flex w-full"
>
<div class="w-[250px]">
{{ item.createTime }}
</div>
<div class="w-[250px]">{{ item.account }}</div>
<div class="flex-1">-</div>
<div class="w-[200px]">
{{ item.amount }}
</div>
</div>
</n-infinite-scroll>
</div>
</n-tab-pane>
</n-tabs>
</div>
<n-modal v-model:show="showWalletModal">
<n-card
style="width: 600px"
:bordered="false"
size="huge"
role="dialog"
aria-modal="false"
preset="dialog"
>
<div class="flex justify-between">
<div class="text-xl">
提现
</div>
<n-icon size="20" class="mr-2 cursor-pointer" @click="closeWalletModal">
<Close />
</n-icon>
</div>
<div class="py-4">
<div class="text-sm text-gray-600">
可提现金额: ¥ {{ integralGold.wallet || 0 }}
</div>
<div class="mt-6">
<n-input-number
placeholder="输入要提现的金额"
v-model:value="needWalletNum"
:precision="2"
clearable
/>
</div>
</div>
<div class="flex justify-center mt-6">
<n-button type="error" @click="closeWalletModal"> </n-button>
<n-button type="primary" class="ml-8" @click="handleWallet"> </n-button>
</div>
</n-card>
</n-modal>
</div>
</template>
<script setup>
import { isAmount } from '@/utils/index.ts';
import { Close } from "@vicons/ionicons5";
import { ref } from "vue";
const activeTab = ref("withdrawDetail");
const showWalletModal = ref(false);
const showModal = () => {
showWalletModal.value = true;
};
const closeWalletModal = () => {
showWalletModal.value = false;
needWalletNum.value = 0
};
// const allDetailList = ref([]);
//
const integralGold = ref({});
async function getIntegralGold() {
try {
const res = await request.post("/personalCenter/getPointAndWallet");
if (res.code === 200) {
integralGold.value = res.data;
}
} catch (err) {
console.log(err);
}
}
getIntegralGold();
//
const needWalletNum = ref(0)
const handleWallet = async() =>{
if(isAmount(needWalletNum.value)){
try {
const res = await request.get(`/ali/pay/fetch?amount=${needWalletNum.value}`);
if (res.code === 200) {
closeWalletModal()
getIntegralGold()
}
} catch (err) {
console.log(err);
}
}else{
message.warning('请输入正确的金额')
}
}
//
const totalAmount = ref(0);
async function getTotalAmount() {
try {
const res = await request.get("/invitation/totalAmount");
if (res.code === 200) {
totalAmount.value = res.data;
}
} catch (err) {
console.log(err);
}
}
getTotalAmount();
//
const withdrawFinished = ref(false);
const withdrawDetailList = ref([]);
const withdrawParams = ref({
pageNum: 1,
pageSize: 10,
});
async function getWithdrawDetail() {
try {
if (withdrawFinished.value) return;
const res = await request.post("/invitation/withdrawalRecord", withdrawParams.value);
if (res.code === 200) {
// withdrawDetailList.value = res.data;
if (withdrawParams.value.pageNum === 1) {
withdrawDetailList.value = res.rows;
} else {
withdrawDetailList.value = [...withdrawDetailList.value, ...res.rows];
}
//
if (withdrawDetailList.value.length >= res.total) {
withdrawFinished.value = true;
}
withdrawParams.value.pageNum++;
}
} catch (err) {
console.log(err);
}
}
getWithdrawDetail();
</script>
<style scoped>
.mc-table {
padding: 10px;
line-height: 40px;
border-bottom: 1px solid #eee;
}
</style>

View File

@ -109,7 +109,7 @@ function changeCategory(item: any) {
</MenuFold>
</div>
</div>
<div class="flex flex-wrap">
<div class="w-full">
<NConfigProvider>
<NMessageProvider>
<WorkFlowList ref="listRef" :params="params" />

View File

@ -1,11 +1,12 @@
<script setup lang="ts">
<script setup>
import { commonApi } from "@/api/common";
import { formatFileSize } from '@/utils/index.ts';
import { Close, DiamondSharp, PersonAddOutline } from '@vicons/ionicons5';
import {
CircleUser,
Download,
EllipsisVertical, Heart, Play
EllipsisVertical, Heart, Play, SquareCheck, SquarePlus
} from 'lucide-vue-next';
// import { NConfigProvider, NMessageProvider } from 'naive-ui';
import { nextTick, ref } from 'vue';
@ -20,11 +21,11 @@ definePageMeta({
})
// const userStore = useUserStore()
const route = useRoute()
const { id } = route.params as { id: string }
const { id } = route.params
const activeTab = ref(null)
const commentHeight = ref(800)
const detailsInfo = ref({})
const currentUserInfo = ref<any>({})
const currentUserInfo = ref({})
const isVisibleReport = ref(false);
//
@ -74,13 +75,13 @@ async function getInfo() {
getInfo()
// //
interface SelectUserInfo {
likeCount: number
bean: number
download: number
attention: number
}
const selectUserInfo = ref<SelectUserInfo>({
// interface SelectUserInfo {
// likeCount: number
// bean: number
// download: number
// attention: number
// }
const selectUserInfo = ref({
likeCount: 0,
bean: 0,
download: 0,
@ -102,8 +103,7 @@ async function getAttention() {
// //
const isDelete = ref(false)
async function handleSelect(event: Event, type: string) {
event.stopPropagation() //
async function handleSelect(type) {
if (type === 'report') {
// await request.get(`/WorkFlow/report?id=${id}`) //
isVisibleReport.value = true;
@ -195,7 +195,7 @@ async function getDictType() {
}
}
getDictType();
function handleChange(item: any) {
function handleChange(item) {
reportParams.value.reportId = item.dictValue;
if (item.dictValue !== "5") {
reportParams.value.text = "";
@ -230,6 +230,50 @@ function toPersonalCenter(){
window.open(`${baseUrl}/personal-publish?userId=${detailsInfo.value.userId}`, '_blank', 'noopener,noreferrer')
}
}
const currentTabsIndex = ref(0);
function handleTabChange(id) {
for (let i = 0; i < versionByWorkInfo.value.length; i++) {
if (id === versionByWorkInfo.value[i].id) {
currentTabsIndex.value = i;
}
}
}
async function addCollect(){
try {
const params = {
"productId": versionByWorkInfo.value[currentTabsIndex.value].id,
"productType": 1,
}
const res = await request.post("/collect/addCollect", params);
if (res.code === 200) {
versionByWorkInfo.value[currentTabsIndex.value].isCollect = res.data
if(res.data === 0){
message.success("已加入收藏");
}else{
message.success("已取消收藏");
}
}
} catch (err) {
console.log(err);
}
}
async function handelDown(){
try {
const res = await request.get(`/WorkFlowVersion/workFlowFileDownload?id=${versionByWorkInfo.value[currentTabsIndex.value].id}`);
if (res.code === 200) {
const link = document.createElement('a');
link.href = res.data;
link.download = res.msg; //
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
} catch (err) {
console.log(err);
}
}
</script>
<template>
@ -290,7 +334,9 @@ function toPersonalCenter(){
<div class="flex w-full gap-1">
<div class="w-2/3">
<div class="w-full">
<n-tabs v-model:value="activeTab" type="line" animated>
<n-tabs v-model:value="activeTab" type="line" animated
@update:value="handleTabChange"
>
<n-tab-pane
v-for="(item, index) in versionByWorkInfo"
:key="index"
@ -462,7 +508,7 @@ function toPersonalCenter(){
<span class="mr-1"> 立即生图 </span>
</div>
<div
<!-- <div
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
@ -470,8 +516,37 @@ function toPersonalCenter(){
class="h-[20px] w-[20px] text-black menu-icon m-1 text-[#969798]"
/>
<span class="mr-1"> 下载 (122.22MB) </span>
</div>
</div> -->
<div class="flex gap-y-2">
<div
v-if="versionByWorkInfo.length > 0"
@click="addCollect"
class="flex flex-1 items-center justify-center bg-[#eceef4] h-[50px] mt-4 mr-1 rounded-md cursor-pointer"
>
<component
:is="
versionByWorkInfo[currentTabsIndex].isCollect === 1
? SquarePlus
: SquareCheck
"
class="h-[20px] w-[20px] text-black menu-icon m-1 text-[#969798]"
/>
<span class="mr-1">
{{ versionByWorkInfo[currentTabsIndex].isCollect === 1 ? '加入收藏' : '已收藏'}}
</span>
</div>
<div
@click="handelDown"
class="flex flex-1 items-center bg-gradient-to-r from-[#ffe9c8] to-[#ffd264] justify-center ml-1 mt-4 text-black bg-[#eceef4] w-full rounded-md h-[50px] cursor-pointer"
>
<component
:is="Download"
class="h-[20px] w-[20px] text-black menu-icon m-1 text-[#969798]"
/>
<span class="mr-1" v-if="versionByWorkInfo.length > 0"> {{ formatFileSize(versionByWorkInfo[currentTabsIndex].fileSize) }} </span>
</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">
@ -486,7 +561,7 @@ function toPersonalCenter(){
content="确定要将工作流删除? 工作流删除后无法找回"
negative-text="取消"
positive-text="确认"
@negative-click="onDelete"
@negative-click="isDelete = false"
@positive-click="onDelete"
/>
@ -550,7 +625,7 @@ function toPersonalCenter(){
</div>
</template>
<style lang="scss">
<style lang="scss" scoped>
.header-num {
@apply flex items-center bg-[#f4f5f9] px-2 rounded-full;
}

View File

@ -24,7 +24,9 @@ export const useUserStore = defineStore('user', () => {
function setUserInfo(info: any) {
userInfo.value = info
debugger
if(!info.avatar){
userInfo.value.avatar = defaultAvatar
}
}
async function getUserInfo() {
const res = await request.get('/system/user/selectUserById', {
@ -37,7 +39,6 @@ export const useUserStore = defineStore('user', () => {
}
// 登出
function logout() {
console.log('object-------out');
isLoggedIn.value = false
token.value = ''
userInfo.value = {} as UserInfoType
@ -97,11 +98,9 @@ export const useUserStore = defineStore('user', () => {
// actions: {
// setToken(token: string) {
// this.token = token
// debugger
// },
// setUserInfo(userInfo: Record<string, any>) {
// this.userInfo = userInfo
// debugger
// },
// // logout() {
// // getLogout().then(() => {

View File

@ -5,3 +5,24 @@ export async function formatDate(timestamp: string) {
const day = String(date.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
}
export function formatFileSize(bytes:number = 0, decimals = 2) {
if (bytes === 0) return '0 B';
const k = 1024; // 1 KB = 1024 B
const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
const i = Math.floor(Math.log(bytes) / Math.log(k)); // 计算单位索引
// 转换为合适的单位并保留指定小数位数
return parseFloat((bytes / Math.pow(k, i)).toFixed(decimals)) + ' ' + sizes[i];
}
export function isAmount(str:any) {
const amountRegex = /^\d+(\.\d{1,2})?$/;
return amountRegex.test(str);
}
// function isAmount(str) {
// // 正则表达式
// }

View File

@ -3,7 +3,6 @@ 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'])
// 定义响应数据接口
@ -105,7 +104,7 @@ class RequestHttp {
message.error('请求参数错误')
break
case 401:
// message.error('未登录或登录已过期')
message.error('未登录或登录已过期')
break
case 403:
message.error('没有权限')

View File

@ -28,9 +28,9 @@ export default defineNuxtConfig({
head: {
viewport: 'width=device-width,initial-scale=1',
link: [
{ rel: 'icon', href: '/favicon.ico', sizes: 'any' },
{ rel: 'icon', type: 'image/svg+xml', href: '/nuxt.svg' },
{ rel: 'apple-touch-icon', href: '/apple-touch-icon.png' },
// { rel: 'icon', href: '/favicon.ico', sizes: 'any' },
// { rel: 'icon', type: 'image/svg+xml', href: '/nuxt.svg' },
// { rel: 'apple-touch-icon', href: '/apple-touch-icon.png' },
],
meta: [
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
@ -80,11 +80,12 @@ export default defineNuxtConfig({
compatibilityDate: '2025-01-23',
nitro: {
preset: 'node-server',
devProxy: {
'/api': {
// target: 'http://1.13.246.108:8080', // 线上
// target: 'http://192.168.2.10:8080', // 代
target: 'http://192.168.2.7:8080', // 嗨
target: 'http://192.168.2.10:8080', // 代
// target: 'http://192.168.2.7:8080', // 嗨
// target: 'https://2d1a399f.r27.cpolar.top', // 嗨
changeOrigin: true,
prependPath: true,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

BIN
public/favicon1.ico 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
public/favicon2.ico 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 387 B