工作流/图片的发布、编辑、详情
parent
21e94f048c
commit
654a427e48
|
@ -7,28 +7,22 @@ export {}
|
|||
/* prettier-ignore */
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
NAtePicker: typeof import('naive-ui')['NAtePicker']
|
||||
NAvatar: typeof import('naive-ui')['NAvatar']
|
||||
NBadge: typeof import('naive-ui')['NBadge']
|
||||
NButton: typeof import('naive-ui')['NButton']
|
||||
NCard: typeof import('naive-ui')['NCard']
|
||||
NCascader: typeof import('naive-ui')['NCascader']
|
||||
NCheckbox: typeof import('naive-ui')['NCheckbox']
|
||||
NCheckboxGroup: typeof import('naive-ui')['NCheckboxGroup']
|
||||
NConfigProvider: typeof import('naive-ui')['NConfigProvider']
|
||||
NDatePicker: typeof import('naive-ui')['NDatePicker']
|
||||
NDropdown: typeof import('naive-ui')['NDropdown']
|
||||
NDynamicTags: typeof import('naive-ui')['NDynamicTags']
|
||||
NFor: typeof import('naive-ui')['NFor']
|
||||
NForm: typeof import('naive-ui')['NForm']
|
||||
NFormItem: typeof import('naive-ui')['NFormItem']
|
||||
NFormItemGi: typeof import('naive-ui')['NFormItemGi']
|
||||
NFormTtem: typeof import('naive-ui')['NFormTtem']
|
||||
NGrid: typeof import('naive-ui')['NGrid']
|
||||
NIcon: typeof import('naive-ui')['NIcon']
|
||||
NInfiniteScroll: typeof import('naive-ui')['NInfiniteScroll']
|
||||
NInput: typeof import('naive-ui')['NInput']
|
||||
NInputgroup: typeof import('naive-ui')['NInputgroup']
|
||||
NInputGroup: typeof import('naive-ui')['NInputGroup']
|
||||
NInputNumber: typeof import('naive-ui')['NInputNumber']
|
||||
NMessageProvider: typeof import('naive-ui')['NMessageProvider']
|
||||
NModal: typeof import('naive-ui')['NModal']
|
||||
NQrCode: typeof import('naive-ui')['NQrCode']
|
||||
|
@ -36,14 +30,10 @@ declare module 'vue' {
|
|||
NRadioButton: typeof import('naive-ui')['NRadioButton']
|
||||
NRadioGroup: typeof import('naive-ui')['NRadioGroup']
|
||||
NSelect: typeof import('naive-ui')['NSelect']
|
||||
NSlider: typeof import('naive-ui')['NSlider']
|
||||
NSpace: typeof import('naive-ui')['NSpace']
|
||||
NSwitch: typeof import('naive-ui')['NSwitch']
|
||||
NTabPane: typeof import('naive-ui')['NTabPane']
|
||||
NTabs: typeof import('naive-ui')['NTabs']
|
||||
NTimePicker: typeof import('naive-ui')['NTimePicker']
|
||||
NTooltip: typeof import('naive-ui')['NTooltip']
|
||||
NTransfer: typeof import('naive-ui')['NTransfer']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
}
|
||||
|
|
|
@ -1,77 +1,79 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
|
||||
const message = useMessage()
|
||||
const userStore = useUserStore()
|
||||
const userInfo = userStore.userInfo
|
||||
const isVisible = ref(false)
|
||||
|
||||
const rules = ref({
|
||||
name: [
|
||||
{
|
||||
required: true,
|
||||
validator( value: string) {
|
||||
if (!value) {
|
||||
return new Error('请填写姓名')
|
||||
}
|
||||
else if (!/^(?:[\u4e00-\u9fa5·]{2,16})$/.test(value)) {
|
||||
return new Error('输入正确的姓名')
|
||||
}
|
||||
return true
|
||||
},
|
||||
trigger:'blur'
|
||||
},
|
||||
name: [
|
||||
{
|
||||
required: true,
|
||||
validator(value: string) {
|
||||
if (!value) {
|
||||
return new Error('请填写姓名')
|
||||
}
|
||||
else if (!/^[\u4E00-\u9FA5·]{2,16}$/.test(value)) {
|
||||
return new Error('输入正确的姓名')
|
||||
}
|
||||
return true
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
idCard: [
|
||||
{
|
||||
required: true,
|
||||
validator( value: string) {
|
||||
if (!value) {
|
||||
return new Error('请填身份证号')
|
||||
}
|
||||
else if (!/(^\d{8}(0\d|10|11|12)([0-2]\d|30|31)\d{3}$)|(^\d{6}(18|19|20)\d{2}(0\d|10|11|12)([0-2]\d|30|31)\d{3}(\d|X|x)$)/.test(value)) {
|
||||
return new Error('输入正确的身份证号')
|
||||
}
|
||||
return true
|
||||
},
|
||||
trigger:'blur'
|
||||
{
|
||||
required: true,
|
||||
validator(value: string) {
|
||||
if (!value) {
|
||||
return new Error('请填身份证号')
|
||||
}
|
||||
else if (!/(^\d{8}(0\d|10|11|12)([0-2]\d|30|31)\d{3}$)|(^\d{6}(18|19|20)\d{2}(0\d|10|11|12)([0-2]\d|30|31)\d{3}([\dX])$)/i.test(value)) {
|
||||
return new Error('输入正确的身份证号')
|
||||
}
|
||||
return true
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
const ruleForm = ref({
|
||||
name: '',
|
||||
idCard:'',
|
||||
userId: userInfo.userId
|
||||
name: '',
|
||||
idCard: '',
|
||||
userId: userInfo.userId,
|
||||
})
|
||||
const formRef = ref(null)
|
||||
const saveInfo = async(e: MouseEvent) => {
|
||||
e.preventDefault()
|
||||
formRef.value?.validate(async(errors) => {
|
||||
if (!errors) {
|
||||
// try{
|
||||
// const res = await request.post('/system/user/updateIdCard',ruleForm.value)
|
||||
// if(res.code === 200){
|
||||
// const data = await userStore.getUserInfo()
|
||||
// message.success('认证成功')
|
||||
// ruleForm.value.name = ''
|
||||
// ruleForm.value.idCard = ''
|
||||
// onCloseModel()
|
||||
// }
|
||||
// }catch(err) {
|
||||
// console.log('err',err)
|
||||
// }
|
||||
const res = await request.post('/system/user/updateIdCard',ruleForm.value)
|
||||
const data = await userStore.getUserInfo()
|
||||
isVisible.value = false
|
||||
}
|
||||
else {
|
||||
}
|
||||
})
|
||||
async function saveInfo(e: MouseEvent) {
|
||||
e.preventDefault()
|
||||
formRef.value?.validate(async (errors) => {
|
||||
if (!errors) {
|
||||
// try{
|
||||
// const res = await request.post('/system/user/updateIdCard',ruleForm.value)
|
||||
// if(res.code === 200){
|
||||
// const data = await userStore.getUserInfo()
|
||||
// message.success('认证成功')
|
||||
// ruleForm.value.name = ''
|
||||
// ruleForm.value.idCard = ''
|
||||
// onCloseModel()
|
||||
// }
|
||||
// }catch(err) {
|
||||
// console.log('err',err)
|
||||
// }
|
||||
await request.post('/system/user/updateIdCard', ruleForm.value)
|
||||
await userStore.getUserInfo()
|
||||
isVisible.value = false
|
||||
}
|
||||
else {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const isVisible = ref(false)
|
||||
function onCloseModel() {
|
||||
isVisible.value = false
|
||||
ruleForm.value.name = ''
|
||||
ruleForm.value.idCard = ''
|
||||
ruleForm.value.name = ''
|
||||
ruleForm.value.idCard = ''
|
||||
}
|
||||
defineExpose({
|
||||
isVisible,
|
||||
|
@ -92,16 +94,16 @@ onMounted(() => {
|
|||
>
|
||||
<n-form ref="formRef" :model="ruleForm" :rules="rules">
|
||||
<n-form-item path="name" label="姓名">
|
||||
<n-input placeholder="请输入姓名" v-model:value="ruleForm.name" @keydown.enter.prevent />
|
||||
<n-input v-model:value="ruleForm.name" placeholder="请输入姓名" @keydown.enter.prevent />
|
||||
</n-form-item>
|
||||
<n-form-item path="idCard" label="身份证号">
|
||||
<n-input placeholder="请输入身份证号" v-model:value="ruleForm.idCard" @keydown.enter.prevent />
|
||||
<n-input v-model:value="ruleForm.idCard" placeholder="请输入身份证号" @keydown.enter.prevent />
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<div class="flex justify-center items-center ">
|
||||
<button class="w-1/2 flex justify-center mx-1 bg-[#213df5] py-3 rounded-lg align-middle color-[#fff] border-0 cursor-pointer" @click="saveInfo">
|
||||
实名认证
|
||||
</button>
|
||||
</button>
|
||||
</div>
|
||||
</NModal>
|
||||
</template>
|
||||
|
|
|
@ -0,0 +1,328 @@
|
|||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
height: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
dataList: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
userInfo: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
productId: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
})
|
||||
|
||||
const message = useMessage()
|
||||
|
||||
// 获取评论列表
|
||||
const commentList = ref([])
|
||||
async function getCommentList() {
|
||||
try {
|
||||
const res = await request.get(`/WorkFlowComment/comment/${props.productId}`)
|
||||
for (let i = 0; i < res.data.length; i++) {
|
||||
res.data[i].isShowInput = false
|
||||
res.data[i].isShowSend = false
|
||||
if (res.data[i].contentList.length > 0) {
|
||||
for (let j = 0; j < res.data[i].contentList.length; j++) {
|
||||
res.data[i].contentList[j].isShowInput = false
|
||||
res.data[i].contentList[j].isShowSend = false
|
||||
}
|
||||
}
|
||||
}
|
||||
commentList.value = res.data
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
getCommentList()
|
||||
// const $props = defineProps(['headUrl', 'dataList', 'height'])
|
||||
// const $emit = defineEmits(['sendMessage'])
|
||||
// const props = defineProps
|
||||
const isShowSend = ref(false)
|
||||
const publicWord = ref('')
|
||||
// const message = useMessage()
|
||||
|
||||
function handleBlur(ele) {
|
||||
ele.isShowInput = false
|
||||
// 默认评价
|
||||
if (!ele) {
|
||||
isShowSend.value = !!publicWord.value
|
||||
}
|
||||
else {
|
||||
ele.isShowSend = !!ele.word
|
||||
}
|
||||
}
|
||||
|
||||
// 发布评论
|
||||
const commentParams = ref({
|
||||
content: '',
|
||||
parentId: '',
|
||||
userId: props.userInfo.userId,
|
||||
workFlowId: props.productId,
|
||||
})
|
||||
//
|
||||
async function sendMessage(data, ele) {
|
||||
debugger
|
||||
try {
|
||||
if (commentParams.value.content) {
|
||||
const res = await request.post('WorkFlowComment/comment', commentParams.value)
|
||||
if (res.code === 200) {
|
||||
message.success('评论成功!')
|
||||
}
|
||||
}
|
||||
else {
|
||||
message.error('评论不能为空!')
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
// if(!publicWord.value){
|
||||
// return message.info(
|
||||
// '请输入评论',
|
||||
// { duration: 3000 }
|
||||
// )
|
||||
// }
|
||||
if (!data) {
|
||||
// $props.dataList.push({
|
||||
// headUrl: 'https://avatars.githubusercontent.com/u/19239641?s=60&v=4', // 头像
|
||||
// name: '星辰流连', // 名称
|
||||
// id: 6,
|
||||
// des: publicWord.value, // 评论
|
||||
// time: '2025/02/08 14:52:06', // 时间
|
||||
// isAuthor: false, // 是否是作者
|
||||
// isShowInput: false, // 是否显示回复框
|
||||
// isFocus: true, // 是否点赞
|
||||
// focusNum: 2, // 点赞数量
|
||||
// word: '', // 评论语
|
||||
// isShowSend: false, // 是否显示发送按钮
|
||||
// })
|
||||
|
||||
publicWord.value = ''
|
||||
// isShowSend.value = false
|
||||
}
|
||||
else {
|
||||
data.push({
|
||||
headUrl: 'https://avatars.githubusercontent.com/u/19239641?s=60&v=4', // 头像
|
||||
name: '星辰流连', // 名称
|
||||
id: 7,
|
||||
des: ele.word, // 评论
|
||||
time: '2025/02/08 14:52:06', // 时间
|
||||
isAuthor: false, // 是否是作者
|
||||
isShowInput: false, // 是否显示回复框
|
||||
isFocus: true, // 是否点赞
|
||||
focusNum: 2, // 点赞数量
|
||||
word: '', // 评论语
|
||||
isShowSend: false, // 是否显示发送按钮
|
||||
})
|
||||
|
||||
ele.word = ''
|
||||
ele.isShowInput = false
|
||||
}
|
||||
|
||||
// 发送数据
|
||||
$emit('sendMessage', data)
|
||||
}
|
||||
|
||||
// 目前点赞都在这边,注意区分
|
||||
function handleFocus(item) {
|
||||
item.isFocus = !item.isFocus
|
||||
}
|
||||
|
||||
function handleMessage(item) {
|
||||
debugger
|
||||
if (!item.isShowInput) {
|
||||
item.word = ''
|
||||
}
|
||||
item.isShowInput = !item.isShowInput
|
||||
}
|
||||
|
||||
function handleDel(ele, item) {
|
||||
const index = item.findIndex(el => ele.id === el.id)
|
||||
item.splice(index, 1)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="base-comment">
|
||||
<!-- 头部评论框 -->
|
||||
<div class="flex justify-between mb-4">
|
||||
<div v-if="props.userInfo.avatar" class="w-11 h-11 rounded-full mr-4 border border-[#2d28ff] border-solid">
|
||||
<img class="w-10 h-10 rounded-full p-1" alt="avatar" :src="props.userInfo.avatar">
|
||||
</div>
|
||||
<div class="input-wrap flex items-center leading-normal rounded-lg text-sm bg-[#f2f5f9] px-4 py-2 flex-1">
|
||||
<NConfigProvider inline-theme-disabled class="w-full">
|
||||
<n-input
|
||||
v-model:value="commentParams.content"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 1 }"
|
||||
placeholder="善语结善缘,恶言伤人心~"
|
||||
@focus="isShowSend = true"
|
||||
@blur="handleBlur"
|
||||
/>
|
||||
</NConfigProvider>
|
||||
<div
|
||||
class="mx-4 flex-shrink-0 text-sm cursor-pointer text-gray-400 hover:text-gray-900"
|
||||
:class="{ 'text-gray-900': commentParams.content }"
|
||||
@click="sendMessage"
|
||||
>
|
||||
<span v-if="isShowSend">发送sendMessage</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 评论列表 -->
|
||||
<NInfiniteScroll :style="{ height: `${height}px` }" :distance="10" @load="handleLoad">
|
||||
<div v-for="(item, index) in commentList" :key="index">
|
||||
<!-- 主评论 -->
|
||||
<div class="flex text-sm">
|
||||
<div class="w-10 h-10 rounded-full mr-3 flex-shrink-0">
|
||||
<img :src="item.userAvatar" class="w-full h-full rounded-full">
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<div class="mt-[10px] mb-[7px] font-medium text-gray-700">
|
||||
{{ item.userName }}
|
||||
</div>
|
||||
<div class="leading-[1.25]">
|
||||
{{ item.content }}
|
||||
</div>
|
||||
<div class="mt-1 flex items-center justify-between">
|
||||
<span class="text-xs text-gray-400">{{ item.createTime }}</span>
|
||||
<div class="text-xs text-gray-400 flex items-center cursor-pointer">
|
||||
<div class="flex items-center mr-4">
|
||||
<img v-if="item.focus" src="@/assets/img/heart.png" class="w-4 h-4 mr-[3px]">
|
||||
<img v-else src="@/assets/img/heart.png" class="w-4 h-4 mr-[3px]" @click="handleFocus(item)">
|
||||
<span class="align-middle">{{ item.likeNum }}</span>
|
||||
</div>
|
||||
<span class="mr-4" @click="handleMessage(item)">回复</span>
|
||||
<span @click="handleDel(item, dataList)">删除</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 评论回复框 -->
|
||||
<div v-if="item.isShowInput" class="input-wrap mt-[10px] flex items-center rounded-lg text-sm bg-[#f2f5f9] px-3 py-2">
|
||||
<NConfigProvider inline-theme-disabled class="w-full">
|
||||
<n-input
|
||||
v-model:value="item.word"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 1 }"
|
||||
:placeholder="`回复: @${item.userName}`"
|
||||
@focus="item.isShowSend = true"
|
||||
@blur="handleBlur(item)"
|
||||
/>
|
||||
</NConfigProvider>
|
||||
<div
|
||||
class="mx-4 flex-shrink-0 text-sm cursor-pointer text-gray-400 hover:text-gray-900"
|
||||
:class="{ 'text-gray-900': item.word }"
|
||||
@click="sendMessage(item.children, item)"
|
||||
>
|
||||
<span v-if="item.isShowSend">发送sendMessage</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 子评论 -->
|
||||
<div class="pl-[52px]">
|
||||
<div v-for="(ele, subIndex) in item.contentList" :key="subIndex" class="flex text-sm mt-4">
|
||||
<div class="w-6 h-6 rounded-full mr-3 flex-shrink-0">
|
||||
<img src="https://avatars.githubusercontent.com/u/20943608?s=60&v=4" class="w-full h-full rounded-full">
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<div class="mb-[7px] font-medium text-gray-700 flex items-center">
|
||||
{{ ele.userName }}
|
||||
<div v-if="ele.userAvatar" class="ml-2 px-1 py-[3px] text-xs leading-[12px] text-white rounded bg-gradient-to-r from-[#2d28ff] to-[#1a7dff]">
|
||||
作者
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<span>回复</span>
|
||||
<span class="text-[#1880ff] mr-[6px]">@{{ ele.userName }}</span>
|
||||
{{ ele.des }}
|
||||
</div>
|
||||
<div class="mt-1 flex items-center justify-between">
|
||||
<span class="text-xs text-gray-400">{{ ele.createTime }}</span>
|
||||
<div class="text-xs text-gray-400 flex items-center cursor-pointer">
|
||||
<div class="flex items-center mr-4">
|
||||
<img v-if="ele.isFocus" src="@/assets/img/heart.png" class="w-4 h-4 mr-[3px]" @click="handleFocus(ele, 'cancel')">
|
||||
<img v-else src="@/assets/img/heart.png" class="w-4 h-4 mr-[3px]" @click="handleFocus(ele, 'add')">
|
||||
<span class="align-middle">1</span>
|
||||
</div>
|
||||
<span class="mr-4" @click="handleMessage(ele)">回复</span>
|
||||
<span @click="handleDel(ele, item.contentList)">删除</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 子评论回复框 -->
|
||||
<div v-if="ele.isShowInput" class="input-wrap mt-[10px] flex items-center rounded-lg text-sm bg-[#f2f5f9] px-3 py-2">
|
||||
<NConfigProvider inline-theme-disabled class="w-full">
|
||||
<n-input
|
||||
v-model:value="ele.word"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 1 }"
|
||||
:placeholder="`回复: @${ele.userName}`"
|
||||
@focus="ele.isShowSend = true"
|
||||
@blur="handleBlur(ele)"
|
||||
/>
|
||||
</NConfigProvider>
|
||||
<div
|
||||
class="mx-4 flex-shrink-0 text-sm cursor-pointer text-gray-400 hover:text-gray-900"
|
||||
:class="{ 'text-gray-900': ele.word }"
|
||||
@click="sendMessage(item.children, ele)"
|
||||
>
|
||||
<span v-if="ele.isShowSend">发送sendMessage</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 加载更多 -->
|
||||
<div class="text-sm text-gray-400 text-center py-[46px] pb-[118px]">
|
||||
暂时没有更多评论
|
||||
</div>
|
||||
</NInfiniteScroll>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.input-wrap {
|
||||
:deep(.n-input) {
|
||||
--n-padding-left: 0 !important;
|
||||
--n-border: 0 !important;
|
||||
--n-border-hover: 0 !important;
|
||||
--n-border-focus: 0 !important;
|
||||
--n-box-shadow-focus: unset;
|
||||
--n-padding-vertical: 0px !important;
|
||||
}
|
||||
&::hover {
|
||||
border: 0;
|
||||
}
|
||||
&:active,
|
||||
&:focus {
|
||||
background-color: #f2f5f9;
|
||||
|
||||
border: 0 !important;
|
||||
}
|
||||
background-color: #f2f5f9;
|
||||
}
|
||||
.n-input--textarea {
|
||||
background-color: #f2f5f9;
|
||||
}
|
||||
.n-input:not(.n-input--disabled).n-input--foucs {
|
||||
background-color: #f2f5f9 !important;
|
||||
}
|
||||
.n-input--focus {
|
||||
background-color: #f2f5f9 !important;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,569 @@
|
|||
<script setup lang="ts">
|
||||
// import { NConfigProvider, NInfiniteScroll, NInput } from 'naive-ui'
|
||||
import {
|
||||
ThumbsUp,
|
||||
} from 'lucide-vue-next'
|
||||
|
||||
const props = defineProps({
|
||||
height: {
|
||||
type: Number,
|
||||
default: 800,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
detailsInfo: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
})
|
||||
|
||||
// const $props = defineProps(['headUrl', 'dataList', 'height'])
|
||||
|
||||
const userStore = useUserStore()
|
||||
const message = useMessage()
|
||||
|
||||
// 发布评论
|
||||
const commentParams = ref({
|
||||
content: '',
|
||||
parentId: '',
|
||||
replyUserId: '',
|
||||
userId: userStore.userInfo.userId,
|
||||
workFlowId: props.detailsInfo.id,
|
||||
})
|
||||
function commentParamsInit() {
|
||||
commentParams.value.content = ''
|
||||
commentParams.value.replyUserId = ''
|
||||
commentParams.value.parentId = ''
|
||||
}
|
||||
|
||||
const isShowSend = ref(false)
|
||||
const publicWord = ref('')
|
||||
const sortType = ref(1)
|
||||
|
||||
// 获取列表
|
||||
const urlList = ref({
|
||||
workflow: '/WorkFlowComment/comment?',
|
||||
})
|
||||
// 点赞
|
||||
const likeList = ref({ // 点赞
|
||||
workflow: '/WorkFlowComment/commentLike?',
|
||||
})
|
||||
// 发送评论
|
||||
const sendMessageList = ref({ // 点赞
|
||||
workflow: '/WorkFlowComment/comment',
|
||||
})
|
||||
// 删除
|
||||
const deleteList = ref({ // 点赞
|
||||
workflow: '/WorkFlowComment/commentDelete?',
|
||||
})
|
||||
// 查条数
|
||||
const commentNumUrl = ref({ // 点赞
|
||||
workflow: '/WorkFlowComment/commentCount?workFlowId',
|
||||
})
|
||||
|
||||
const commentCount = ref(0)
|
||||
// 评论列表
|
||||
const commentList = ref([])
|
||||
async function getCommentList() {
|
||||
try {
|
||||
const res = await request.get(`${urlList.value[props.type]}commentId=${props.detailsInfo.id}&sortType=${sortType.value}`)
|
||||
for (let i = 0; i < res.data.length; i++) {
|
||||
res.data[i].isShowInput = false
|
||||
res.data[i].isShowSend = false
|
||||
if (res.data[i].contentList.length > 0) {
|
||||
for (let j = 0; j < res.data[i].contentList.length; j++) {
|
||||
res.data[i].contentList[j].isShowInput = false
|
||||
res.data[i].contentList[j].isShowSend = false
|
||||
}
|
||||
}
|
||||
}
|
||||
commentList.value = res.data
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
getCommentList()
|
||||
|
||||
function handleBlur(ele) {
|
||||
// 默认评价
|
||||
if (!ele) {
|
||||
isShowSend.value = !!publicWord.value
|
||||
}
|
||||
else {
|
||||
ele.isShowSend = !!ele.word
|
||||
}
|
||||
}
|
||||
// 发送评论
|
||||
async function sendMessage(ele, index) {
|
||||
if (ele && ele.userId) {
|
||||
try {
|
||||
if (ele.word) {
|
||||
commentParams.value.content = ele.word
|
||||
commentParams.value.parentId = commentList.value[index].commentId
|
||||
commentParams.value.replyUserId = ele.commentId
|
||||
const res = await request.post(sendMessageList.value[props.type], commentParams.value)
|
||||
if (res.code === 200) {
|
||||
message.success('评论成功!')
|
||||
getCommentList()
|
||||
getCommentNum()
|
||||
commentParamsInit()
|
||||
}
|
||||
}
|
||||
else {
|
||||
message.warning('评论不能为空!')
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
if (publicWord.value) {
|
||||
commentParams.value.parentId = ''
|
||||
commentParams.value.content = publicWord.value
|
||||
commentParams.value.replyUserId = ''
|
||||
const res = await request.post('WorkFlowComment/comment', commentParams.value)
|
||||
if (res.code === 200) {
|
||||
message.success('评论成功!')
|
||||
publicWord.value = ''
|
||||
getCommentList()
|
||||
getCommentNum()
|
||||
commentParamsInit()
|
||||
}
|
||||
}
|
||||
else {
|
||||
message.warning('评论不能为空!')
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function getCommentNum() {
|
||||
try {
|
||||
const res = await request.get(`${commentNumUrl.value[props.type]}=${props.detailsInfo.id}`)
|
||||
if (res.code === 200) {
|
||||
commentCount.value = res.data
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
getCommentNum()
|
||||
// 点赞/取消点赞
|
||||
async function handleFocus(item) {
|
||||
await request.get(`${likeList.value[props.type]}commentId=${item.commentId}`)
|
||||
if (item.isLike === 0) {
|
||||
item.isLike = 1
|
||||
item.likeNum++
|
||||
message.success('点赞成功!')
|
||||
}
|
||||
else {
|
||||
item.isLike = 0
|
||||
item.likeNum--
|
||||
message.success('取消点赞成功!')
|
||||
}
|
||||
}
|
||||
|
||||
// 显示回复框
|
||||
function handleMessage(item) {
|
||||
if (!item.isShowInput) {
|
||||
item.word = ''
|
||||
}
|
||||
item.isShowInput = !item.isShowInput
|
||||
}
|
||||
// 删除评论
|
||||
async function handleDel(item) {
|
||||
try {
|
||||
const res = await request.get(`${deleteList.value[props.type]}commentId=${item.commentId}`)
|
||||
if (res.code === 200) {
|
||||
message.success('删除成功!')
|
||||
getCommentList()
|
||||
getCommentNum()
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
function changeType(type: string) {
|
||||
sortType.value = type
|
||||
getCommentList()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="base-comment">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<div class="flex items-center">
|
||||
<div class="left text-[20px] mr-2">
|
||||
讨论
|
||||
</div>
|
||||
<div class="text-[#999]">
|
||||
{{ commentCount }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<div class="cursor-pointer" :class="sortType === 0 ? '' : 'text-[#999]'" @click="changeType(0)">
|
||||
最热
|
||||
</div>|
|
||||
<div class="cursor-pointer" :class="sortType === 1 ? '' : 'text-[#999]'" @click="changeType(1)">
|
||||
最新
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-wrap">
|
||||
<div v-if="userStore.userInfo.avatar" class="left">
|
||||
<img
|
||||
alt="avatar"
|
||||
:src="userStore.userInfo.avatar"
|
||||
>
|
||||
</div>
|
||||
<div class="input-wrap">
|
||||
<NConfigProvider inline-theme-disabled style="width:100%">
|
||||
<NInput
|
||||
v-model:value="publicWord"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 1 }"
|
||||
placeholder="善语结善缘,恶言伤人心~"
|
||||
class="text"
|
||||
@focus="isShowSend = true"
|
||||
@blur="handleBlur"
|
||||
/>
|
||||
</NConfigProvider>
|
||||
|
||||
<div class="send-btn" :class="{ active: publicWord }" @click="sendMessage">
|
||||
<span v-if="isShowSend">发送</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<NInfiniteScroll :style="{ height: `${height}px` }" :distance="10" @load="handleLoad">
|
||||
<div
|
||||
v-for="(item, index) in commentList"
|
||||
:key="index"
|
||||
class="px-4"
|
||||
>
|
||||
<div class="nav-wrap">
|
||||
<div class="left-img">
|
||||
<img :src="item.userAvatar">
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="name">
|
||||
{{ item.userName }}
|
||||
</div>
|
||||
<div class="des">
|
||||
{{ item.content }}
|
||||
</div>
|
||||
<div class="star-wrap">
|
||||
<span class="time">{{ item.createTime }}</span>
|
||||
<div class="star-operator">
|
||||
<div class="icon-wrap">
|
||||
<!-- <img v-if="item.focus" src="@/assets/img/heart.png" alt=""> -->
|
||||
<ThumbsUp size="16" class="mr-1" :color="item.isLike !== 0 ? '#ff0000' : '#000000'" @click="handleFocus(item)" />
|
||||
|
||||
<!-- <img v-else src="@/assets/img/heart.png" alt="" @click="handleFocus(item)"> -->
|
||||
<span style="vertical-align: middle">{{ item.likeNum }}</span>
|
||||
</div>
|
||||
<span class="cursor-pointer m-r16" @click="handleMessage(item)">回复</span>
|
||||
<span v-if="item.userId === userStore.userInfo.userId" class="cursor-pointer" @click="handleDel(item)">删除</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 父项评论回复操作 -->
|
||||
<div v-if="item.isShowInput" class="input-wrap" style="margin-top: 10px;">
|
||||
<NConfigProvider inline-theme-disabled style="width:100%">
|
||||
<NInput
|
||||
v-model:value="item.word"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 1 }"
|
||||
:placeholder="`回复: @${item.userName}`"
|
||||
class="text"
|
||||
@focus="item.isShowSend = true"
|
||||
@blur="handleBlur(item)"
|
||||
/>
|
||||
</NConfigProvider>
|
||||
<div class="send-btn" :class="{ active: publicWord }" @click="sendMessage(item, index)">
|
||||
<span v-if="item.isShowSend">发送</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="child-wrap">
|
||||
<div v-for="(ele, subIndex) in item.contentList" :key="subIndex" class="child-wrap-item">
|
||||
<div class="left-img">
|
||||
<img :src="ele.userAvatar">
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="name">
|
||||
{{ ele.userName }}
|
||||
<div v-if="ele.userId === props.detailsInfo.userId" class="author">
|
||||
作者
|
||||
</div>
|
||||
</div>
|
||||
<div class="des">
|
||||
<span>回复</span>
|
||||
<span class="u-name">@{{ ele.userName }}</span>
|
||||
{{ ele.content }}
|
||||
</div>
|
||||
<div class="star-wrap">
|
||||
<span class="time">{{ ele.createTime }}</span>
|
||||
<div class="star-operator">
|
||||
<div class="icon-wrap">
|
||||
<ThumbsUp size="16" class="mr-1" :color="ele.isLike !== 0 ? '#ff0000' : '#000000'" @click="handleFocus(ele)" />
|
||||
<span style="vertical-align: middle">{{ ele.likeNum }}</span>
|
||||
</div>
|
||||
<span class="cursor-pointer m-r16" @click="handleMessage(ele)">回复</span>
|
||||
<span v-if="item.userId === userStore.userInfo.userId" class="cursor-pointer" @click="handleDel(ele)">删除</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 子项评论回复操作 -->
|
||||
<div v-if="ele.isShowInput" class="input-wrap" style="margin-top: 10px;">
|
||||
<NConfigProvider inline-theme-disabled style="width:100%">
|
||||
<NInput
|
||||
v-model:value="ele.word"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 1 }"
|
||||
:placeholder="`回复: @${ele.userName}`"
|
||||
class="text"
|
||||
@focus="ele.isShowSend = true"
|
||||
@blur="handleBlur(ele)"
|
||||
/>
|
||||
</NConfigProvider>
|
||||
<div class="send-btn" :class="{ active: publicWord }" @click="sendMessage(ele, index)">
|
||||
<span v-if="ele.isShowSend">发送</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="no-more">
|
||||
暂时没有更多评论
|
||||
</div>
|
||||
</NInfiniteScroll>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.header-wrap {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 20px;
|
||||
.left {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
margin-right: 12px;
|
||||
border: 1px solid #2d28ff;
|
||||
img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
.right {
|
||||
}
|
||||
}
|
||||
|
||||
.input-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 1.55;
|
||||
border-radius: 8px;
|
||||
caret-color: #999;
|
||||
font-size: 14px;
|
||||
background: #f2f5f9;
|
||||
padding: 10px 12px;
|
||||
flex: 1;
|
||||
|
||||
:deep(.n-input) {
|
||||
--n-padding-left: 0 !important;
|
||||
--n-border: 0 !important;
|
||||
--n-border-hover: 0 !important;
|
||||
--n-border-focus: 0 !important;
|
||||
--n-box-shadow-focus: unset;
|
||||
--n-padding-vertical: 0px !important;
|
||||
|
||||
&::hover {
|
||||
border: 0;
|
||||
}
|
||||
&:active,
|
||||
&:focus {
|
||||
border: 0 !important;
|
||||
}
|
||||
background-color: transparent;
|
||||
}
|
||||
.send-btn {
|
||||
margin-left: 16px;
|
||||
margin-right: 16px;
|
||||
flex-shrink: 0;
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
&.active {
|
||||
color: #222;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nav-wrap {
|
||||
margin: 10px 0;
|
||||
display: flex;
|
||||
font-size: 14px;
|
||||
// align-items: center;
|
||||
.left-img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
margin-right: 12px;
|
||||
img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
.right {
|
||||
width: 100%;
|
||||
.name {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 7px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.des {
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.star-wrap {
|
||||
margin-top: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
.time {
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
.star-operator {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
.icon-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 16px;
|
||||
cursor: pointer;
|
||||
img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.m-r16 {
|
||||
margin-right: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.child-wrap {
|
||||
padding-left: 52px;
|
||||
.child-wrap-item {
|
||||
display: flex;
|
||||
font-size: 14px;
|
||||
margin-top: 16px;
|
||||
// align-items: center;
|
||||
.left-img {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 50%;
|
||||
margin-right: 12px;
|
||||
img {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
.right {
|
||||
width: 100%;
|
||||
.name {
|
||||
margin-bottom: 7px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.author {
|
||||
margin-left: 8px;
|
||||
color: #fff;
|
||||
background: linear-gradient(90deg, #2d28ff, #1a7dff);
|
||||
padding: 3px 4px;
|
||||
font-size: 12px;
|
||||
line-height: 12px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.des {
|
||||
line-height: 1.5;
|
||||
// display: flex;
|
||||
align-items: center;
|
||||
.u-name {
|
||||
color: #1880ff;
|
||||
margin-right: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.star-wrap {
|
||||
margin-top: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
.time {
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
.star-operator {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
.icon-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 16px;
|
||||
cursor: pointer;
|
||||
img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.m-r16 {
|
||||
margin-right: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.no-more {
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
padding: 46px 0 118px;
|
||||
}
|
||||
</style>
|
|
@ -1,5 +1,4 @@
|
|||
<script setup lang="ts">
|
||||
import defaultAvatar from '@/assets/img/default-avatar.png'
|
||||
import { ref } from 'vue'
|
||||
import { uploadImagesInBatches } from '../utils/uploadImg.ts'
|
||||
|
||||
|
@ -46,8 +45,8 @@ async function handlePictureChange(event: Event) {
|
|||
|
||||
try {
|
||||
const pictureResultList = await uploadImagesInBatches(imageFiles)
|
||||
ruleForm.value.avatar = pictureResultList[0].url
|
||||
event.target.value = ''
|
||||
ruleForm.value.avatar = pictureResultList[0]
|
||||
}
|
||||
catch (error: any) {
|
||||
message.error('图片上传失败')
|
||||
|
@ -60,6 +59,19 @@ async function saveInfo() {
|
|||
onCloseModel()
|
||||
}
|
||||
|
||||
watch(
|
||||
() => userStore.userInfo, // 监听 userInfo
|
||||
(newUserInfo) => {
|
||||
if (newUserInfo) {
|
||||
ruleForm.value.nickName = newUserInfo.nickName
|
||||
ruleForm.value.avatar = newUserInfo.avatar
|
||||
ruleForm.value.brief = newUserInfo.brief
|
||||
ruleForm.value.userId = newUserInfo.userId
|
||||
}
|
||||
},
|
||||
{ immediate: true }, // 立即执行一次,初始化 ruleForm
|
||||
)
|
||||
|
||||
const isVisible = ref(false)
|
||||
function onCloseModel() {
|
||||
isVisible.value = false
|
||||
|
@ -84,7 +96,7 @@ onMounted(() => {
|
|||
>
|
||||
<div class="rounded-full flex justify-center overflow-hidden mb-4">
|
||||
<client-only>
|
||||
<img class="block w-[60px] h-[60px] rounded-full" :src="ruleForm.avatar || defaultAvatar" alt="编辑">
|
||||
<img class="block w-[60px] h-[60px] rounded-full" :src="ruleForm.avatar" alt="编辑">
|
||||
</client-only>
|
||||
</div>
|
||||
<div class="flex justify-center mb-2">
|
||||
|
@ -123,7 +135,7 @@ onMounted(() => {
|
|||
暂不修改
|
||||
</div> -->
|
||||
|
||||
<button class="w-1/2 flex justify-center mx-1 bg-[#213df5] py-3 rounded-lg align-middle color-[#fff] border-0 cursor-pointer" @click="saveInfo">
|
||||
<button class="w-1/2 flex justify-center mx-1 bg-[#213df5] py-3 rounded-lg align-middle text-[#fff] border-0 cursor-pointer" @click="saveInfo">
|
||||
确定修改
|
||||
</button>
|
||||
<!-- <div class="w-1/2 flex justify-center mx-1 bg-[#213df5] py-3 rounded-lg align-middle color-[#fff]">
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import defaultAvatar from '@/assets/img/default-avatar.png'
|
||||
// 输入框搜索
|
||||
import { headerRole } from '@/constants/index'
|
||||
import {
|
||||
Bell,
|
||||
CirclePlus,
|
||||
|
@ -9,17 +10,36 @@ import {
|
|||
Monitor,
|
||||
Workflow,
|
||||
} from 'lucide-vue-next'
|
||||
import { NConfigProvider, NMessageProvider } from 'naive-ui'
|
||||
|
||||
// import { AtCircle } from '@vicons/ionicons5'
|
||||
import { NIcon } from 'naive-ui'
|
||||
import { onMounted, ref, watch } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const userStore = useUserStore()
|
||||
const modalStore = useModalStore()
|
||||
|
||||
// 输入框搜索
|
||||
const currentUseRoute = ref('')
|
||||
const isShowPublishPicture = ref<boolean>(false)
|
||||
const PublishPictureRef = ref<Payment | null>(null)
|
||||
const publishPicture = ref({
|
||||
title: '',
|
||||
tags: [],
|
||||
description: '',
|
||||
imagePaths: [],
|
||||
})
|
||||
watch(
|
||||
() => route.path, // 监听 route.path 的变化
|
||||
(newPath) => {
|
||||
currentUseRoute.value = newPath
|
||||
},
|
||||
{ immediate: true }, // 立即执行一次
|
||||
)
|
||||
function hasItem(path: string, list: any) {
|
||||
return !list.includes(path)
|
||||
}
|
||||
const searchText = ref('')
|
||||
function onSearch(value: any) {
|
||||
console.log('搜索:', value)
|
||||
|
@ -101,18 +121,31 @@ async function handleUserSelect(key: string) {
|
|||
// 发布下拉选项
|
||||
async function handlePublishSelect(key: string) {
|
||||
if (key === 'picture') {
|
||||
debugger
|
||||
isShowPublishPicture.value = true
|
||||
if (PublishPictureRef.value) {
|
||||
PublishPictureRef.value.isVisible = true
|
||||
}
|
||||
}
|
||||
else {
|
||||
router.push({
|
||||
path: `/${key}`,
|
||||
query: {
|
||||
type: 'add',
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
function closePublishImg() {
|
||||
isShowPublishPicture.value = false
|
||||
if (PublishPictureRef.value) {
|
||||
PublishPictureRef.value.isVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
function handleLogin() {
|
||||
modalStore.showLoginModal()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
})
|
||||
</script>
|
||||
|
@ -136,21 +169,10 @@ onMounted(() => {
|
|||
|
||||
<!-- <HeaderSearchInput /> -->
|
||||
<HeaderSearchInput
|
||||
v-if="hasItem(currentUseRoute, headerRole.inputSearch)"
|
||||
v-model="searchText"
|
||||
@search="onSearch"
|
||||
/>
|
||||
<!-- Search -->
|
||||
<!-- <n-input class="w-[580px]" size="large" placeholder="搜索模型/图片/创作者寻找灵感" round /> -->
|
||||
<!-- <NInput
|
||||
round
|
||||
clearable
|
||||
placeholder="搜索模型/图片/创作者寻找灵感"
|
||||
class="w-[580px]"
|
||||
>
|
||||
<template #prefix>
|
||||
<Search class="h-4 w-4 text-gray-400" />
|
||||
</template>
|
||||
</NInput> -->
|
||||
</div>
|
||||
|
||||
<!-- Right Actions -->
|
||||
|
@ -200,11 +222,7 @@ onMounted(() => {
|
|||
class="cursor-pointer w-10 h-10"
|
||||
round
|
||||
size="small"
|
||||
:src="
|
||||
userStore.userInfo && userStore.userInfo.avatar
|
||||
? userStore.userInfo.avatar
|
||||
: defaultAvatar
|
||||
"
|
||||
:src="userStore.userInfo.avatar"
|
||||
/>
|
||||
</NDropdown>
|
||||
<div
|
||||
|
@ -218,6 +236,13 @@ onMounted(() => {
|
|||
</div>
|
||||
</NSpace>
|
||||
</header>
|
||||
<div>
|
||||
<NConfigProvider>
|
||||
<NMessageProvider>
|
||||
<Publish-picture v-if="isShowPublishPicture" ref="PublishPictureRef" :form-data="publishPicture" @close-publish-img="closePublishImg" />
|
||||
</NMessageProvider>
|
||||
</NConfigProvider>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -0,0 +1,238 @@
|
|||
<script setup lang="ts">
|
||||
import { RotateCcw, X } from 'lucide-vue-next'
|
||||
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: 'points',
|
||||
})
|
||||
|
||||
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(`/web/pay/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="mt-4 px-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>
|
|
@ -1,77 +1,175 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { X, RotateCcw } from "lucide-vue-next";
|
||||
const userStore = useUserStore();
|
||||
import { RotateCcw, X } from 'lucide-vue-next'
|
||||
import { useMessage } from 'naive-ui'
|
||||
import { defineProps, onBeforeMount, onBeforeUnmount, ref } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
info: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
isMember: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['closePayment', 'paymentSuccess'])
|
||||
|
||||
const message = useMessage()
|
||||
|
||||
let pollingTimer: ReturnType<typeof setInterval> | undefined
|
||||
|
||||
const currentNeedPayment = ref<number>(0)
|
||||
// const isShowPayment = ref(false)
|
||||
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
|
||||
|
||||
const isVisible = ref(false);
|
||||
function onCloseModel() {
|
||||
isVisible.value = false;
|
||||
emit('closePayment')
|
||||
}
|
||||
function onPaymentSuccess() {
|
||||
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 memberList = ref<Member[]>([])
|
||||
const currentMember = ref<Member>({
|
||||
id: 1,
|
||||
title: "基础会员",
|
||||
price: 39,
|
||||
originalPrice: 50,
|
||||
desc: "次月续费¥39",
|
||||
})
|
||||
// 二维码是否过去
|
||||
const bindTimeout = ref(false)
|
||||
|
||||
// 活动列表
|
||||
const currentActivity = ref(null)
|
||||
const activityList = ref<Member[]>([])
|
||||
async function getPromotionList() {
|
||||
try {
|
||||
const res = await request.get(`/promotion/promotionList`)
|
||||
if (res.code === 200) {
|
||||
activityList.value = res.data
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
getPromotionList()
|
||||
// 支付
|
||||
|
||||
// 初始化获取支付二维码
|
||||
// const paymentParams = ref({})
|
||||
const paymentStatus = ref(1)
|
||||
|
||||
const paymentParams = ref({
|
||||
amount: props.info[0].unitPrice,
|
||||
productId: props.info[0].id,
|
||||
promotionId: 0,
|
||||
type: 'member',
|
||||
})
|
||||
async function getQrCode() {
|
||||
try {
|
||||
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(`/web/pay/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)
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.log('object', err)
|
||||
}
|
||||
}, 2000)
|
||||
}
|
||||
}
|
||||
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}`)
|
||||
if (res1.code === 200) {
|
||||
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}`)
|
||||
if (res1.code === 200) {
|
||||
paymentParams.value.amount = res1.data
|
||||
getQrCode()
|
||||
}
|
||||
}
|
||||
|
||||
// 二维码是否过去
|
||||
const isVisible = ref(true)
|
||||
onBeforeMount (() => {
|
||||
getQrCode()
|
||||
})
|
||||
defineExpose({
|
||||
isVisible,
|
||||
});
|
||||
// 生命周期钩子
|
||||
onMounted(() => {
|
||||
// initFormData()
|
||||
});
|
||||
})
|
||||
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 h-14 bg-gradient-to-r from-[#fcf2da] to-[#f9db9f]"
|
||||
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" />
|
||||
<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">您还不是会员</div>
|
||||
<div class="text-[#6a6a6a] text-xs mt-1">
|
||||
{{ props.isMember.result === '1' ? `会员到期时间: ${props.isMember.endDate}` : '您还不是魔创未来的会员' }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div @click="onCloseModel">
|
||||
|
@ -80,39 +178,84 @@ onMounted(() => {
|
|||
</div>
|
||||
<div class="grid grid-cols-4 gap-1 mt-4 px-6">
|
||||
<div
|
||||
v-for="item in 4"
|
||||
v-for="(item, index) in info"
|
||||
:key="item"
|
||||
: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)"
|
||||
>
|
||||
<!-- bg-gradient-to-b from-[#fdf0dd] to-[#fef8ef] -->
|
||||
<!-- 1px solid #f7b252; -->
|
||||
<div class="text-[#814600] card-item">基本版本Vip连续包月</div>
|
||||
<!-- bg-gradient-to-b from-[#fdf0dd] to-[#fef8ef] -->
|
||||
<!-- 1px solid #f7b252; -->
|
||||
<div class="text-[#814600] card-item">
|
||||
{{ item.memberName }}
|
||||
</div>
|
||||
<div class="card-item">
|
||||
<span class="text-[#814600] text-[20px] mr-2">¥</span>
|
||||
<span class="text-[#814600] text-[36px] mr-2">39</span>
|
||||
<span class="text-gray-400 text-[20px] line-through">¥50</span>
|
||||
<span class="text-[#814600] text-[36px] mr-2">{{ item.unitPrice }}</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]">
|
||||
次月续费¥39
|
||||
{{ item.subscriptionPeriod }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center my-4">
|
||||
<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"
|
||||
/>
|
||||
</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="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="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]">
|
||||
|
@ -120,34 +263,40 @@ onMounted(() => {
|
|||
</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="80" class="p-0" />
|
||||
<div v-if="bindTimeout" 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">
|
||||
请点击刷新<rotate-ccw/>
|
||||
<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]">39</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 class="flex items-baseline">
|
||||
<div class="text-[#222] font-medium mr-1">
|
||||
支付
|
||||
</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 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 class="bg-[#fefaee] text-center text-[#AF7F1A] text-[12px] py-1 rounded-b-lg">
|
||||
需支付差价,计算规则为:专业版年包价格-剩余未下发基础版年包月数*基础版年包购买价格/12
|
||||
</div>
|
||||
<div class="bg-[#fefaee] text-center text-[#AF7F1A] text-[12px] py-1 rounded-b-lg">需支付差价,计算规则为:专业版年包价格-剩余未下发基础版年包月数*基础版年包购买价格/12</div>
|
||||
</div>
|
||||
</n-modal>
|
||||
</template>
|
||||
|
|
|
@ -39,6 +39,22 @@ function toDetails() {
|
|||
}
|
||||
}
|
||||
|
||||
// 获取图片详情进行编辑
|
||||
const publishPictureData = ref<any>({})
|
||||
async function getPublishPicture() {
|
||||
try {
|
||||
const res = await request.get(`/image/detail?id=${props.item.id}`)
|
||||
if (res.code === 200) {
|
||||
publishPictureData.value = res.data
|
||||
publishPictureData.value.imagePaths = res.data.imagePaths.split(',')
|
||||
// publishPictureData.value.tags = res.data.tags.split(',')
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
|
||||
// 处理下拉菜单选项 编辑/删除/置顶
|
||||
function handleSelect(event: Event, key: string) {
|
||||
event.stopPropagation() // 阻止事件冒泡
|
||||
|
@ -48,6 +64,21 @@ function handleSelect(event: Event, key: string) {
|
|||
else if (key === 'delete') {
|
||||
handleDelete()
|
||||
}
|
||||
else if (key === 'edit') {
|
||||
if (props.currentType === '2') {
|
||||
getPublishPicture()
|
||||
showPublishImg()
|
||||
}
|
||||
else if (props.currentType === '1') {
|
||||
router.push({
|
||||
path: `/publish-workflow`,
|
||||
query: {
|
||||
type: 'edit',
|
||||
id: props.item.id,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 置顶
|
||||
|
@ -112,6 +143,23 @@ function getFirstImagePath(imagePaths: string): string {
|
|||
return ''
|
||||
return imagePaths.split(',')[0] || ''
|
||||
}
|
||||
// 关闭图片
|
||||
const isShowPublishPicture = ref<boolean>(false)
|
||||
const PublishPictureRef = ref<Payment | null>(null)
|
||||
|
||||
function showPublishImg() {
|
||||
isShowPublishPicture.value = true
|
||||
if (PublishPictureRef.value) {
|
||||
PublishPictureRef.value.isVisible = true
|
||||
}
|
||||
}
|
||||
|
||||
function closePublishImg() {
|
||||
isShowPublishPicture.value = false
|
||||
if (PublishPictureRef.value) {
|
||||
PublishPictureRef.value.isVisible = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -155,7 +203,7 @@ function getFirstImagePath(imagePaths: string): string {
|
|||
>
|
||||
<img v-if="currentType === '0'" class="w-full h-full object-cover block" :src="item.surfaceUrl" alt="">
|
||||
<img v-if="currentType === '1'" class="w-full h-full object-cover block" :src="item.coverPath" alt="">
|
||||
<img v-if="currentType === '2'" class="w-full h-full object-cover block" :src="item.imagePaths" alt="">
|
||||
<img v-if="currentType === '2'" class="w-full h-full object-cover block" :src="getFirstImagePath(item.imagePaths)" alt="">
|
||||
<div
|
||||
v-if="currentState === 'mallProduct' && item.isTop === 1"
|
||||
class="text-[#58c08e] border-[#58c08e] border-solid border-[1px] bg-white rounded-lg px-1 w-10 text-[12px] ml-2 text-center absolute top-4 right-8"
|
||||
|
@ -164,14 +212,14 @@ function getFirstImagePath(imagePaths: string): string {
|
|||
</div>
|
||||
<!-- 在发布中 auditStatus等于代表没有审批通过 -->
|
||||
<div
|
||||
v-if="currentState === 'mallProduct' && item.auditStatus === 4"
|
||||
v-if="currentState === 'mallProduct' && item.auditStatus === 4 || item.auditStatus === 3"
|
||||
class="absolute top-0 left-0 w-full h-full text-gray-400 bg-black/50 flex justify-center items-center flex-col"
|
||||
>
|
||||
<component
|
||||
:is="CircleAlert"
|
||||
class="h-[40px] w-[40px] text-white menu-icon m-1 text-gray-400"
|
||||
/>
|
||||
未通过
|
||||
{{ item.auditStatus === 3 ? '审核中' : '未通过' }}
|
||||
</div>
|
||||
<div
|
||||
class="modelSelectByUserIdModel w-full h-full top-0 left-0 flex px-4 py-4 box-border"
|
||||
|
@ -266,6 +314,11 @@ function getFirstImagePath(imagePaths: string): string {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<NConfigProvider>
|
||||
<NMessageProvider>
|
||||
<Publish-picture v-if="isShowPublishPicture" ref="PublishPictureRef" :form-data="publishPictureData" @close-publish-img="closePublishImg" />
|
||||
</NMessageProvider>
|
||||
</NConfigProvider>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -0,0 +1,183 @@
|
|||
<script setup lang="ts">
|
||||
import { commonApi } from '@/api/common'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { useMessage } from 'naive-ui'
|
||||
import { defineProps, ref } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
formData: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
})
|
||||
const emit = defineEmits(['closePublishImg'])
|
||||
const message = useMessage()
|
||||
|
||||
const isVisible = ref(true)
|
||||
const fileInput = ref<HTMLInputElement | null>(null)
|
||||
const rules = {
|
||||
title: {
|
||||
required: true,
|
||||
message: '',
|
||||
trigger: 'blur',
|
||||
},
|
||||
}
|
||||
function triggerFileInput() {
|
||||
(fileInput.value as HTMLInputElement)?.click()
|
||||
}
|
||||
|
||||
async function handleFileChange(event: Event) {
|
||||
// console.log('object', formData)
|
||||
const target = event.target as HTMLInputElement
|
||||
const files = target.files
|
||||
|
||||
if (files && files.length > 0) {
|
||||
const res = await uploadImagesInBatches(files)
|
||||
const urlList = res.map(item => item.url)
|
||||
props.formData.imagePaths.push(...urlList)
|
||||
}
|
||||
target.value = ''
|
||||
}
|
||||
// 获取图片标签
|
||||
const imgLabelList = ref([])
|
||||
async function getDictType() {
|
||||
try {
|
||||
const res = await commonApi.dictType({ type: 'image_label' })
|
||||
imgLabelList.value = res.data
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
// 发布
|
||||
async function onPublish() {
|
||||
try {
|
||||
const param = cloneDeep(props.formData)
|
||||
param.imagePaths = param.imagePaths.join(',')
|
||||
param.tags = param.tags.join(',')
|
||||
if (param.id) {
|
||||
const res = await request.post('/image/update', param)
|
||||
if (res.code === 200) {
|
||||
message.success('发布成功')
|
||||
emit('closePublishImg')
|
||||
}
|
||||
}
|
||||
else {
|
||||
const res = await request.post('/image/publish', param)
|
||||
if (res.code === 200) {
|
||||
message.success('发布成功')
|
||||
emit('closePublishImg')
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
getDictType()
|
||||
defineExpose({
|
||||
isVisible,
|
||||
})
|
||||
function closePublishImg() {
|
||||
emit('closePublishImg')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<n-modal
|
||||
v-model:show="isVisible"
|
||||
:preset="null"
|
||||
transform-origin="center"
|
||||
:mask-closable="false"
|
||||
class="custom-modal"
|
||||
>
|
||||
<div class="bg-white p-4 rounded-lg w-[600px]">
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="text-[18px]">
|
||||
上传我的图片
|
||||
</div>
|
||||
<div
|
||||
class="w-[20px] h-[20px] text-[#999] text-center cursor-pointer" @click="closePublishImg"
|
||||
>
|
||||
X
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<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="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()">
|
||||
上传文件
|
||||
</div>
|
||||
<div class="my-3">
|
||||
点击上传文件
|
||||
</div>
|
||||
<!-- <div class="text-[#999999] text-xs">
|
||||
.json/.zip
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
<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="">
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="flex justify-center items-center my-2 gap-1 flex-wrap">
|
||||
<div v-for="(item, index) in formData.imagePaths" :key="index" class="w-1/3">
|
||||
<img :src="item" alt="" class="w-full h-[200px]">
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="mt-2">
|
||||
<n-form
|
||||
:label-width="80"
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
size="large"
|
||||
>
|
||||
<n-form-item label="图片标题" path="title">
|
||||
<n-input v-model:value="props.formData.title" placeholder="好的标题可以获得更好的曝光率" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="图片标签" path="tags" class="w-full">
|
||||
<n-select
|
||||
v-model:value="props.formData.tags"
|
||||
placeholder="选择你的图片类型,比如 男生, 机械, 建筑设计 等"
|
||||
multiple label-field="dictLabel"
|
||||
value-field="dictValue" :options="imgLabelList"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="描述信息" path="description">
|
||||
<n-input
|
||||
v-model:value="props.formData.description"
|
||||
placeholder="填写更全面的描述信息"
|
||||
type="textarea"
|
||||
:autosize="{
|
||||
minRows: 3,
|
||||
maxRows: 5,
|
||||
}"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-center items-center mt-5 text-white w-30 h-10 rounded-lg bg-[#3162ff] cursor-pointer" @click="onPublish">
|
||||
发布
|
||||
</div>
|
||||
</div>
|
||||
</n-modal>
|
||||
<input
|
||||
ref="fileInput"
|
||||
type="file"
|
||||
class="hidden"
|
||||
accept="image/*"
|
||||
multiple
|
||||
@change="handleFileChange"
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,33 @@
|
|||
<script setup lang="ts">
|
||||
const props = defineProps({
|
||||
timeLineList: {
|
||||
type: Array, // 类型校验
|
||||
required: true, // 必传
|
||||
},
|
||||
currentStep: {
|
||||
type: Number,
|
||||
default: 0, // 默认值
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex justify-between items-center">
|
||||
<div v-for="(item, index) in props.timeLineList" :key="index" class="flex items-center text-[18px]">
|
||||
<div
|
||||
:style="props.currentStep >= item.index ? { border: '2px solid #203df5' } : {}"
|
||||
class="w-[40px] h-[40px] rounded-full bg-[#eee] text-center flex items-center justify-center"
|
||||
>
|
||||
{{ item.index }}
|
||||
</div>
|
||||
<div
|
||||
class="ml-2 flex items-center font-bold"
|
||||
:style="props.currentStep >= item.index ? { color: '#203df5' } : {}"
|
||||
>
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style></style>
|
|
@ -1,49 +1,117 @@
|
|||
<script setup>
|
||||
import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
||||
import WangEditor from 'wangeditor'
|
||||
import { uploadImagesInBatches } from '@/utils/uploadImg.ts'
|
||||
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
|
||||
|
||||
import { onBeforeUnmount, onMounted, shallowRef } from 'vue'
|
||||
import '@wangeditor/editor/dist/css/style.css'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: '',
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
|
||||
// 引入 css
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
const editorRef = ref(null)
|
||||
let editor = null
|
||||
|
||||
onMounted(() => {
|
||||
editor = new WangEditor(editorRef.value)
|
||||
editor.config.placeholder = '请输入内容...'
|
||||
editor.config.height = 130
|
||||
editor.config.onchange = (newHtml) => {
|
||||
emit('update:modelValue', newHtml)
|
||||
}
|
||||
editor.create()
|
||||
editor.txt.html(props.modelValue)
|
||||
const mode = 'default'
|
||||
// 编辑器实例,必须用 shallowRef
|
||||
const editorRef = shallowRef()
|
||||
const localForm = computed({
|
||||
get() {
|
||||
return props.modelValue
|
||||
},
|
||||
set(value) {
|
||||
emit('update:modelValue', value)
|
||||
},
|
||||
})
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newValue) => {
|
||||
if (editor && newValue !== editor.txt.html()) {
|
||||
editor.txt.html(newValue)
|
||||
() => localForm.value,
|
||||
(newVal) => {
|
||||
emit('update:modelValue', newVal)
|
||||
},
|
||||
{ immediate: true, deep: true },
|
||||
)
|
||||
// 内容 HTML
|
||||
const valueHtml = ref('')
|
||||
|
||||
// 模拟 ajax 异步获取内容
|
||||
onMounted(() => {
|
||||
// setTimeout(() => {
|
||||
// valueHtml.value = '<p>模拟 Ajax 异步设置内容</p>'
|
||||
// }, 1500)
|
||||
})
|
||||
|
||||
const toolbarConfig = {
|
||||
|
||||
}
|
||||
const editorConfig = {
|
||||
placeholder: '请输入内容...',
|
||||
MENU_CONF: {},
|
||||
}
|
||||
|
||||
editorConfig.MENU_CONF.uploadImage = {
|
||||
// 自定义上传
|
||||
async customUpload(file, insertFn) {
|
||||
try {
|
||||
const files = [file]
|
||||
const res = await uploadImagesInBatches(files)
|
||||
for (let i = 0; i < res.length; i++) {
|
||||
insertFn(res[i].url)
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.log('error', error)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
// 组件销毁时,也及时销毁编辑器
|
||||
onBeforeUnmount(() => {
|
||||
if (editor) {
|
||||
editor.destroy()
|
||||
editor = null
|
||||
}
|
||||
const editor = editorRef.value
|
||||
if (editor == null)
|
||||
return
|
||||
editor.destroy()
|
||||
})
|
||||
|
||||
function handleCreated(editor) {
|
||||
editorRef.value = editor // 记录 editor 实例,重要!
|
||||
}
|
||||
|
||||
function handleChange(editor) {
|
||||
const dom = editor.getHtml()
|
||||
emit('update:modelValue', dom)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div ref="editorRef" />
|
||||
<client-only>
|
||||
<Toolbar
|
||||
style="border-bottom: 1px solid rgb(240 240 240)"
|
||||
:editor="editorRef"
|
||||
:default-config="toolbarConfig"
|
||||
:mode="mode"
|
||||
/>
|
||||
<Editor
|
||||
v-model="localForm"
|
||||
class="editor"
|
||||
style="max-height: 500px; min-height: 100px; overflow-y: auto;"
|
||||
:default-config="editorConfig"
|
||||
:mode="mode"
|
||||
@on-created="handleCreated"
|
||||
@on-change="handleChange"
|
||||
/>
|
||||
</client-only>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang='scss'>
|
||||
.editor .w-e-text {
|
||||
line-height: 1.2; /* 行高为字体大小的 2 倍 */
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -56,18 +56,6 @@ async function onGetUUid() {
|
|||
})
|
||||
userStore.setUserInfo(res1.user)
|
||||
window.location.href = '/'
|
||||
// const parent = getCurrentInstance().parent
|
||||
// parent.exposed.onCloseLogin()
|
||||
// store.userInfo = res.data
|
||||
// router.push('./home')
|
||||
|
||||
// store.dispatch("uuidLogin", res)
|
||||
// that.$store.dispatch("uuidLogin", res)
|
||||
// setTimeout(() => {
|
||||
// that.$router.push({
|
||||
// path: that.redirect || "/"
|
||||
// }).catch(() => {});
|
||||
// }, 1500)
|
||||
}
|
||||
}).catch(() => {
|
||||
clearTimeout(pollingTimer)
|
||||
|
|
|
@ -14,24 +14,25 @@ const props = defineProps({
|
|||
})
|
||||
const emit = defineEmits(['update:modelValue', 'createModelsNext'])
|
||||
const acceptTypes = '.safetensors,.ckpt,.pt,.bin,.pth,.zip,.json,.flow,.lightflow,.yaml,.yml,.onnx,.gguf,.sft'
|
||||
const isDataReady = ref(false)
|
||||
const modelVersionItem = {
|
||||
versionName: '1.0', // 版本名称
|
||||
modelId: 1, // 基础模型
|
||||
versionName: '', // 版本名称
|
||||
modelId: null, // 基础模型
|
||||
versionDescription: '"<p>这是一个描述</p><p><img src=\"https://img1.baidu.com/it/u=3001150338,397170470&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=1422\" /></p><p>这是两张图片之间的一些文字说明</p><p><img src=\"https://img12.iqilu.com/10339/clue/202405/29/68ec17f5-9621-461f-ad22-a6820a3f9cf5.jpg\" /></p>"', // 版本描述
|
||||
filePath: 'https://ybl2112.oss-cn-beijing.aliyuncs.com/2025/JANUARY/2/19/4/877e449c-3c0d-4630-a304-91ec110499f2.png', // 文件路径
|
||||
fileName: 'ddefd反问句说的', // 文档里没有 ,表里没有
|
||||
filePath: '', // 文件路径
|
||||
fileName: '', // 文档里没有 ,表里没有
|
||||
sampleImagePaths: 'https://ybl2112.oss-cn-beijing.aliyuncs.com/2025/JANUARY/2/19/4/877e449c-3c0d-4630-a304-91ec110499f2.png,https://ybl2112.oss-cn-beijing.aliyuncs.com/2025/JANUARY/2/19/4/877e449c-3c0d-4630-a304-91ec110499f2.png,https://ybl2112.oss-cn-beijing.aliyuncs.com/2025/JANUARY/2/19/4/877e449c-3c0d-4630-a304-91ec110499f2.png', // 第三部的图片路径最多20张,切割
|
||||
triggerWords: '触发词', // 触发词
|
||||
triggerWords: '', // 触发词
|
||||
isPublic: 1, // 权限是否公开权限 1公开 2自见
|
||||
allowFusion: 1, // 待确定
|
||||
allowDownloadImage: 1, // 允许下载生图
|
||||
allowUsage: 1, // 是否允许使用
|
||||
isFree: 0, // 是否免费 0免费 1会员 ????
|
||||
isOnlineUse: 1, // 是否允许在线使用
|
||||
allowDownloadImage: 1, // 允许下载生图
|
||||
allowSoftwareUse: 1, // 允许在软件旗下使用
|
||||
allowFusion: 1, // 是否允许融合
|
||||
allowCommercialUse: 1, // 是否允许商用
|
||||
|
||||
// allowUsage: 1, // 是否允许使用
|
||||
// 允许模型转售或者融合手出售字段没找到?
|
||||
isExclusiveModel: 1, // 是否为独家模型这个字段
|
||||
isExclusiveModel: 0, // 是否为独家模型这个字段
|
||||
}
|
||||
const isPublicList = [
|
||||
{
|
||||
|
@ -46,12 +47,7 @@ const isPublicList = [
|
|||
defineExpose({
|
||||
addVersion,
|
||||
})
|
||||
onMounted(() => {
|
||||
// 确保数据初始化完成
|
||||
nextTick(() => {
|
||||
isDataReady.value = true
|
||||
})
|
||||
})
|
||||
|
||||
const localForm = computed({
|
||||
get() {
|
||||
return props.modelValue
|
||||
|
@ -74,17 +70,22 @@ const formRef = ref<FormInst | null>(null)
|
|||
const rules = {
|
||||
versionName: {
|
||||
required: true,
|
||||
message: '请输入模型名称',
|
||||
message: '',
|
||||
trigger: 'blur',
|
||||
},
|
||||
modelId: {
|
||||
required: true,
|
||||
message: '',
|
||||
trigger: 'blur',
|
||||
},
|
||||
triggerWords: {
|
||||
required: true,
|
||||
message: '请输入模型名称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
}
|
||||
function addVersion() {
|
||||
localForm.value.modelVersionList.push(modelVersionItem)
|
||||
localForm.value.modelVersionList.unshift(modelVersionItem)
|
||||
}
|
||||
const originalBtnList = ref([
|
||||
{
|
||||
|
@ -132,165 +133,198 @@ async function handleFileChange(event: Event) {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div v-for="(item, index) in localForm.modelVersionList" :key="index">
|
||||
<n-form
|
||||
ref="formRef"
|
||||
:label-width="80"
|
||||
:model="localForm"
|
||||
:rules="rules"
|
||||
size="large"
|
||||
>
|
||||
<n-form-item label="版本名称" path="versionName">
|
||||
<n-input v-model:value="item.versionName" placeholder="请输入版本名" />
|
||||
</n-form-item>
|
||||
<n-form-item label="基础模型" path="modelId">
|
||||
<n-select
|
||||
v-model:value="item.modelId"
|
||||
label-field="dictLabel"
|
||||
value-field="dictValue"
|
||||
placeholder="请选择基础模型"
|
||||
:options="model_category"
|
||||
/>
|
||||
</n-form-item>
|
||||
<div class="flex">
|
||||
上传文件 <Asterisk :size="10" color="#ff0000" class="mt-1" />
|
||||
</div>
|
||||
<div v-if="item.fileName" class="flex justify-between items-center bg-white p-3 mt-2 rounded-lg">
|
||||
<div class="bg-[#d8e5fd] text-[12px] text-[#3162ff] w-16 h-7 rounded-lg flex justify-center items-center">
|
||||
100%
|
||||
<div>
|
||||
<div v-for="(item, index) in localForm.modelVersionList" :key="index" class="bg-gray-100 p-4 rounded-lg">
|
||||
<n-form
|
||||
ref="formRef"
|
||||
:label-width="80"
|
||||
:model="localForm"
|
||||
:rules="rules"
|
||||
size="large"
|
||||
>
|
||||
<n-form-item label="版本名称" path="versionName">
|
||||
<n-input v-model:value="item.versionName" placeholder="请输入版本名" />
|
||||
</n-form-item>
|
||||
<n-form-item label="基础模型" path="modelId">
|
||||
<n-select
|
||||
v-model:value="item.modelId"
|
||||
label-field="dictLabel"
|
||||
value-field="dictValue"
|
||||
placeholder="请选择基础模型"
|
||||
:options="model_category"
|
||||
/>
|
||||
</n-form-item>
|
||||
<div class="flex">
|
||||
上传文件 <Asterisk :size="10" color="#ff0000" class="mt-1" />
|
||||
</div>
|
||||
<div class="flex-1 flex items-center line-clamp">
|
||||
{{
|
||||
item.fileName
|
||||
}}
|
||||
<div v-if="item.fileName" class="flex justify-between items-center bg-white p-3 mt-2 rounded-lg">
|
||||
<div class="bg-[#d8e5fd] text-[12px] text-[#3162ff] w-16 h-7 rounded-lg flex justify-center items-center">
|
||||
100%
|
||||
</div>
|
||||
<div class="flex-1 flex items-center line-clamp">
|
||||
{{
|
||||
item.fileName
|
||||
}}
|
||||
</div>
|
||||
<div>
|
||||
<Trash class="cursor-pointer" @click="item.fileName = '', item.filePath = ''" />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<Trash class="cursor-pointer" @click="item.fileName = '', item.filePath = ''" />
|
||||
</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">
|
||||
<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 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">
|
||||
<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>
|
||||
</div>
|
||||
<div class="flex mt-6">
|
||||
版本介绍 <Asterisk :size="10" color="#ff0000" class="mt-1" />
|
||||
</div>
|
||||
<div class="bg-white p-3 mt-2 rounded-lg">
|
||||
<client-only>
|
||||
<WangEditor v-model="item.versionDesc" />
|
||||
<!-- <WangEditor
|
||||
ref="editorRef"
|
||||
v-model="content"
|
||||
:height="400"
|
||||
placeholder="请输入文章内容..."
|
||||
:disabled="isDisabled"
|
||||
:upload-img-server="/model/file"
|
||||
:upload-img-headers="uploadHeaders"
|
||||
@change="handleContentChange"
|
||||
@focus="handleFocus"
|
||||
@blur="handleBlur"
|
||||
@upload-success="handleUploadSuccess"
|
||||
@upload-error="handleUploadError"
|
||||
/> -->
|
||||
</client-only>
|
||||
</div>
|
||||
<!-- <div class="mt-4 space-x-4">
|
||||
<n-button @click="toggleDisabled">
|
||||
{{ isDisabled ? '启用编辑器' : '禁用编辑器' }}
|
||||
</n-button>
|
||||
|
||||
<n-button @click="clearContent">
|
||||
清空内容
|
||||
</n-button>
|
||||
|
||||
<n-button @click="setContent">
|
||||
设置内容
|
||||
</n-button>
|
||||
</div> -->
|
||||
|
||||
<!-- 预览区域 -->
|
||||
<!-- <div class="mt-4">
|
||||
<h3 class="text-lg font-bold">
|
||||
预览内容:
|
||||
</h3>
|
||||
<div
|
||||
class="p-4 border rounded-lg mt-2"
|
||||
v-html="content"
|
||||
/>
|
||||
</div> -->
|
||||
<div class="mt-6">
|
||||
触发词
|
||||
</div>
|
||||
<div class="-mb-5 text-gray-400 text-[12px]">
|
||||
请输入您用来训练的单词
|
||||
</div>
|
||||
<n-form-item path="triggerWords">
|
||||
<n-input v-model:value="item.triggerWords" placeholder="例如: 1boy" />
|
||||
</n-form-item>
|
||||
<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>
|
||||
<div class="flex justify-center items-center bg-white h-10 rounded-lg">
|
||||
<div
|
||||
v-for="(subItem, subIndex) in originalBtnList"
|
||||
:key="subIndex"
|
||||
:style="{
|
||||
backgroundColor:
|
||||
item.isFree === subItem.value
|
||||
? 'rgba(49, 98, 255, 0.1)'
|
||||
: '#fff',
|
||||
color: item.isFree === subItem.value ? '#3162ff' : '#000',
|
||||
}" class="flex-1 rounded-lg h-full flex items-center justify-center cursor-pointer" @click="handleIsFree(index, subItem.value)"
|
||||
>
|
||||
{{ subItem.label }}
|
||||
<div class="flex mt-6">
|
||||
版本介绍 <Asterisk :size="10" color="#ff0000" class="mt-1" />
|
||||
</div>
|
||||
<div class="bg-white p-3 mt-2 rounded-lg">
|
||||
<client-only>
|
||||
<WangEditor v-model="item.versionDesc" />
|
||||
</client-only>
|
||||
</div>
|
||||
<div v-html="item.versionDesc" />
|
||||
<div class="mt-6">
|
||||
触发词
|
||||
</div>
|
||||
<div class="-mb-5 text-gray-400 text-[12px]">
|
||||
请输入您用来训练的单词
|
||||
</div>
|
||||
<n-form-item path="triggerWords">
|
||||
<n-input v-model:value="item.triggerWords" placeholder="例如: 1boy" />
|
||||
</n-form-item>
|
||||
<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>
|
||||
<div class="flex justify-center items-center bg-white h-10 rounded-lg">
|
||||
<div
|
||||
v-for="(subItem, subIndex) in originalBtnList"
|
||||
:key="subIndex"
|
||||
:style="{
|
||||
backgroundColor:
|
||||
item.isFree === subItem.value
|
||||
? 'rgba(49, 98, 255, 0.1)'
|
||||
: '#fff',
|
||||
color: item.isFree === subItem.value ? '#3162ff' : '#000',
|
||||
}" class="flex-1 rounded-lg h-full flex items-center justify-center cursor-pointer" @click="handleIsFree(index, subItem.value)"
|
||||
>
|
||||
{{ subItem.label }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-1 mb-2 text-gray-500 text-[12px]">
|
||||
选择会员专属或会员下载视为您已经阅读 <span class="text-[#3162ff] cursor-pointer underline">《会员模型许可协议》</span> 并同意其中条款
|
||||
</div>
|
||||
<div v-if="item.isFree === 1" class="text-[12px]">
|
||||
<div>会员下载模型</div>
|
||||
<div class="text-gray-500">
|
||||
下载模型需购买会员,在线生图对所有人开放,无生图次数限制;会员下载的模型版本生成图片默认可商用。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-1 mb-2 text-gray-500 text-[12px]">
|
||||
选择会员专属或会员下载视为您已经阅读 <span class="text-[#3162ff] cursor-pointer underline">《会员模型许可协议》</span> 并同意其中条款
|
||||
<div class="text-gray-400 text-[12px] my-4">
|
||||
许可范围
|
||||
</div>
|
||||
<div v-if="item.isFree === 1" class="text-[12px]">
|
||||
<div>会员下载模型</div>
|
||||
<div class="text-gray-500">
|
||||
下载模型需购买会员,在线生图对所有人开放,无生图次数限制;会员下载的模型版本生成图片默认可商用。
|
||||
<div class="flex flex-wrap">
|
||||
<div class="w-[50%] mb-2">
|
||||
<n-checkbox
|
||||
v-model:checked="item.isOnlineUse"
|
||||
:checked-value="1"
|
||||
:unchecked-value="0" label="允许在魔创未来在线使用"
|
||||
/>
|
||||
</div>
|
||||
<div class="w-[50%] mb-2">
|
||||
<n-checkbox
|
||||
v-model:checked="item.allowDownloadImage"
|
||||
:checked-value="1"
|
||||
:unchecked-value="0" label="允许下载生图"
|
||||
/>
|
||||
</div>
|
||||
<div class="w-[50%] mb-2">
|
||||
<n-checkbox
|
||||
v-model:checked="item.allowSoftwareUse"
|
||||
:checked-value="1"
|
||||
:unchecked-value="0" label="允许在魔创未来旗下其他产品在线使用"
|
||||
/>
|
||||
</div>
|
||||
<div class="w-[50%] mb-2">
|
||||
<n-checkbox
|
||||
v-model:checked="item.allowFusion"
|
||||
:checked-value="1"
|
||||
:unchecked-value="0" label="允许进行融合"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-gray-400 text-[12px] my-4">
|
||||
商用许可范围
|
||||
</div>
|
||||
<div class="flex flex-wrap">
|
||||
<div class="w-[50%] mb-2">
|
||||
<n-checkbox
|
||||
v-model:checked="item.allowCommercialUse"
|
||||
:checked-value="1"
|
||||
:unchecked-value="0" label="生成图片可出售或用于商业目的"
|
||||
/>
|
||||
</div>
|
||||
<div class="w-[50%] mb-2">
|
||||
<n-checkbox
|
||||
v-model:checked="item.allowDownloadImage"
|
||||
:checked-value="1"
|
||||
:unchecked-value="0" label="允许模型转售或融合后出售"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<div class="text-gray-400 text-[12px] my-4">
|
||||
独家设置
|
||||
</div>
|
||||
<div class="flex items-center mb-2">
|
||||
<n-checkbox
|
||||
v-model:checked="item.isExclusiveModel"
|
||||
:checked-value="1"
|
||||
:unchecked-value="0"
|
||||
/>
|
||||
<div class="ml-3 text-[12px] text-gray-500">
|
||||
此版本为魔创未来独家模型 *获取更多流量:独家模型规则
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-gray-400 text-[12px] mt-4">
|
||||
许可范围
|
||||
</div>
|
||||
<div>
|
||||
<div />
|
||||
</div>
|
||||
<div class="flex justify-center items-center mt-5 text-white w-30 h-10 rounded-lg bg-[#3162ff] cursor-pointer" @click="nextStep">
|
||||
下一步
|
||||
<div class="flex items-center justify-center mt-5">
|
||||
<div class="flex justify-center items-center mt-5 w-[20%] mx-2 h-10 rounded-lg bg-[#f1f2f7] cursor-pointer" @click="nextStep">
|
||||
上一步
|
||||
</div>
|
||||
<div class="flex justify-center items-center mt-5 text-white mx-2 w-[20%] h-10 rounded-lg bg-[#3162ff] cursor-pointer" @click="nextStep">
|
||||
下一步
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<input
|
||||
|
|
|
@ -0,0 +1,220 @@
|
|||
<script setup lang="ts">
|
||||
import type { FormInst } from 'naive-ui'
|
||||
import { uploadFileBatches } from '@/utils/uploadImg.ts'
|
||||
import { Asterisk, Trash } from 'lucide-vue-next'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
|
||||
// 可接受的文件类型
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
const emit = defineEmits(['update:modelValue', 'nextStep', 'preStep'])
|
||||
|
||||
const localForm = computed({
|
||||
get() {
|
||||
return props.modelValue
|
||||
},
|
||||
set(value) {
|
||||
emit('update:modelValue', value)
|
||||
},
|
||||
})
|
||||
|
||||
watch(
|
||||
() => localForm.value,
|
||||
(newVal) => {
|
||||
console.log('newVal', newVal)
|
||||
emit('update:modelValue', newVal)
|
||||
},
|
||||
{ immediate: true, deep: true },
|
||||
)
|
||||
const message = useMessage()
|
||||
|
||||
const acceptTypes = '.json,.zip'
|
||||
|
||||
defineExpose({
|
||||
addVersion,
|
||||
})
|
||||
|
||||
const modelVersionItem = {
|
||||
versionName: '',
|
||||
versionDescription: '', // 富文本
|
||||
filePath: '', // 文件路径
|
||||
fileName: '', // 文件名
|
||||
delFlag: '0',
|
||||
imagePaths: [],
|
||||
}
|
||||
const rules = {
|
||||
versionName: {
|
||||
required: true,
|
||||
message: '',
|
||||
trigger: 'blur',
|
||||
},
|
||||
}
|
||||
function addVersion() {
|
||||
localForm.value.workFlowVersionList.unshift(modelVersionItem)
|
||||
}
|
||||
|
||||
const formRefs = ref<(FormInst | null)[]>([])
|
||||
function setFormRef(el: FormInst | null, index: number) {
|
||||
if (el) {
|
||||
formRefs.value[index] = el
|
||||
}
|
||||
}
|
||||
async function nextStep() {
|
||||
for (let i = 0; i < localForm.value.workFlowVersionList.length; i++) {
|
||||
if (localForm.value.workFlowVersionList[i].delFlag === '0' && localForm.value.workFlowVersionList[i].fileName === '') {
|
||||
return message.error('请上传文件')
|
||||
}
|
||||
const regex = /[\u4E00-\u9FA5]/ // 匹配汉字的正则表达式
|
||||
if (localForm.value.workFlowVersionList[i].delFlag === '0' && !regex.test(localForm.value.workFlowVersionList[i].versionDescription)) {
|
||||
return message.error('请用中文填写版本介绍')
|
||||
}
|
||||
}
|
||||
try {
|
||||
const promises = formRefs.value
|
||||
.filter((form): form is FormInst => form !== null)
|
||||
.map(form => form.validate())
|
||||
|
||||
await Promise.all(promises)
|
||||
emit('nextStep')
|
||||
}
|
||||
catch (errors) {
|
||||
console.error('部分表单验证失败:', errors)
|
||||
}
|
||||
// formRef.value?.validate((errors) => {
|
||||
// if (!errors) {
|
||||
// emit('nextStep')
|
||||
// }
|
||||
// else {
|
||||
// console.log('error', errors)
|
||||
// }
|
||||
// })
|
||||
}
|
||||
function preStep() {
|
||||
emit('preStep')
|
||||
}
|
||||
// 上传文件
|
||||
const uploadFileIndex = ref(0)
|
||||
const fileInput = ref<HTMLInputElement | null>(null)
|
||||
function triggerFileInput(index: number) {
|
||||
(fileInput.value as HTMLInputElement)?.click()
|
||||
uploadFileIndex.value = index
|
||||
}
|
||||
async function handleFileChange(event: Event) {
|
||||
const target = event.target as HTMLInputElement
|
||||
const files = target.files
|
||||
|
||||
if (files && files.length > 0) {
|
||||
const res = await uploadFileBatches(files)
|
||||
localForm.value.workFlowVersionList[uploadFileIndex.value].filePath = res[0].url
|
||||
localForm.value.workFlowVersionList[uploadFileIndex.value].fileName = res[0].fileName
|
||||
}
|
||||
target.value = ''
|
||||
}
|
||||
|
||||
function computedDelFlag() {
|
||||
return localForm.value.workFlowVersionList.filter(item => item.delFlag === '0')
|
||||
}
|
||||
function onDelete(index: number) {
|
||||
if (computedDelFlag().length === 1)
|
||||
return
|
||||
localForm.value.workFlowVersionList[index].delFlag = '2'
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex justify-center items-center">
|
||||
<div class="w-[960px]">
|
||||
<template v-for="(item, index) in localForm.workFlowVersionList" :key="index">
|
||||
<div v-if="item.delFlag === '0'" class="bg-gray-100 p-4 rounded-lg mt-4 relative">
|
||||
<div class="absolute -right-10 top-4 cursor-pointer">
|
||||
<Trash class="cursor-pointer" @click="onDelete(index)" />
|
||||
</div>
|
||||
<n-form
|
||||
:ref="(el) => setFormRef(el, index)"
|
||||
:label-width="80"
|
||||
:model="localForm.workFlowVersionList[index]"
|
||||
:rules="rules"
|
||||
size="large"
|
||||
>
|
||||
<n-form-item label="版本名称" path="versionName">
|
||||
<n-input v-model:value="item.versionName" placeholder="请输入版本名" />
|
||||
</n-form-item>
|
||||
<div class="flex">
|
||||
版本介绍 <Asterisk :size="10" color="#ff0000" class="mt-1" />
|
||||
</div>
|
||||
<div class="text-gray-400 text-[12px]">
|
||||
填写类别可让模型获得更精准的流量, 平台也有权基于标准修改你的类别标签
|
||||
</div>
|
||||
<div class="bg-white p-3 mt-2 rounded-lg">
|
||||
<client-only>
|
||||
<WangEditor v-model="item.versionDescription" />
|
||||
</client-only>
|
||||
</div>
|
||||
<div class="flex mt-4">
|
||||
上传文件 <Asterisk :size="10" color="#ff0000" class="mt-1" />
|
||||
</div>
|
||||
<div v-if="item.fileName" class="flex justify-between items-center bg-white p-3 mt-2 rounded-lg">
|
||||
<div class="bg-[#d8e5fd] text-[12px] text-[#3162ff] w-16 h-7 rounded-lg flex justify-center items-center">
|
||||
100%
|
||||
</div>
|
||||
<div class="flex-1 flex items-center line-clamp">
|
||||
{{
|
||||
item.fileName
|
||||
}}
|
||||
</div>
|
||||
<div>
|
||||
<Trash class="cursor-pointer" @click="item.fileName = '', item.filePath = ''" />
|
||||
</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">
|
||||
<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>
|
||||
</div>
|
||||
</n-form>
|
||||
</div>
|
||||
</template>
|
||||
<div class="flex items-center justify-center mt-5">
|
||||
<div class="flex justify-center items-center mt-5 w-[20%] mx-2 h-10 rounded-lg bg-[#f1f2f7] cursor-pointer" @click="preStep">
|
||||
上一步
|
||||
</div>
|
||||
<div class="flex justify-center items-center mt-5 text-white mx-2 w-[20%] h-10 rounded-lg bg-[#3162ff] cursor-pointer" @click="nextStep">
|
||||
下一步
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input
|
||||
ref="fileInput"
|
||||
type="file"
|
||||
class="hidden"
|
||||
:accept="acceptTypes"
|
||||
@change="handleFileChange"
|
||||
>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.line-clamp {
|
||||
margin: 0 10px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-size: 12px;
|
||||
color: rgb(72, 71, 71);
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,328 @@
|
|||
<script setup lang="ts">
|
||||
import type { FormInst } from 'naive-ui'
|
||||
import { commonApi } from '@/api/common'
|
||||
import { isOriginalList, isPublicList } from '@/constants/index'
|
||||
import { Asterisk } from 'lucide-vue-next'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Object,
|
||||
required: true,
|
||||
default: () => ({ workFlow: {}, workFlowVersionList: [] }),
|
||||
},
|
||||
})
|
||||
const emit = defineEmits(['update:modelValue', 'nextStep'])
|
||||
const message = useMessage()
|
||||
|
||||
const formRef = ref<FormInst | null>(null)
|
||||
const rules = {
|
||||
'workFlow.workflowName': {
|
||||
required: true,
|
||||
message: '',
|
||||
trigger: 'blur',
|
||||
},
|
||||
'workFlow.modelType': {
|
||||
required: true,
|
||||
message: '',
|
||||
trigger: 'blur',
|
||||
},
|
||||
}
|
||||
function handleValidateClick() {
|
||||
formRef.value?.validate((errors) => {
|
||||
if (!errors) {
|
||||
emit('nextStep')
|
||||
}
|
||||
else {
|
||||
console.log(errors)
|
||||
}
|
||||
})
|
||||
}
|
||||
const activityList = ref([])
|
||||
async function getActivityList() {
|
||||
try {
|
||||
const res = await request.post('/ToActivity/list', {})
|
||||
activityList.value = res.rows
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
getActivityList()
|
||||
|
||||
const localForm = computed({
|
||||
get() {
|
||||
return props.modelValue
|
||||
},
|
||||
set(value) {
|
||||
emit('update:modelValue', value)
|
||||
},
|
||||
})
|
||||
|
||||
watch(
|
||||
() => localForm.value,
|
||||
(newVal) => {
|
||||
emit('update:modelValue', newVal)
|
||||
},
|
||||
{ immediate: true, deep: true },
|
||||
)
|
||||
function handleIsPublic(value: number) {
|
||||
localForm.value.workFlow.jurisdiction = value
|
||||
}
|
||||
function handleIsOriginal(value: number) {
|
||||
localForm.value.workFlow.original = value
|
||||
if (value === 0) {
|
||||
localForm.value.workFlow.authorName = ''
|
||||
}
|
||||
}
|
||||
|
||||
// 内容类别
|
||||
interface DictItem {
|
||||
dictLabel: string
|
||||
dictValue: string | number
|
||||
children?: DictItem[]
|
||||
}
|
||||
|
||||
// interface FormData {
|
||||
// workFlow: {
|
||||
// type: (string | number)[]
|
||||
// }
|
||||
// }
|
||||
|
||||
// // 表单数据
|
||||
// const localForm = ref<FormData>({
|
||||
// workFlow: {
|
||||
// type: [],
|
||||
// },
|
||||
// })
|
||||
const workFlowTypeList = ref<DictItem[]>([])
|
||||
async function getDictType() {
|
||||
try {
|
||||
const [res1, res2] = await Promise.all([
|
||||
commonApi.dictType({ type: 'work_flow_type' }),
|
||||
commonApi.dictType({ type: 'work_flow_type_child' }),
|
||||
])
|
||||
|
||||
// modelPartCategory.value = res1.data
|
||||
workFlowTypeList.value = res1.data
|
||||
// 遍历第一个数据数组,检查是否有子项
|
||||
workFlowTypeList.value.forEach((item: any) => {
|
||||
// 给每个对象添加一个children属性,初始化为空数组
|
||||
item.children = []
|
||||
// 遍历第二个数据数组
|
||||
res2.data.forEach((child: any) => {
|
||||
// 检查parentId是否与dictValue相等
|
||||
if (child.partId === item.dictCode) {
|
||||
// 将符合条件的子项放入children数组中
|
||||
item.children.push(child)
|
||||
}
|
||||
})
|
||||
})
|
||||
console.log('object', workFlowTypeList.value)
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
getDictType()
|
||||
function handleUpdateValue(value: any) {
|
||||
localForm.value.workFlow.typeList = value
|
||||
if (value.length > 2) {
|
||||
message.error('最多只能选择两项')
|
||||
value = value.splice(0, 2)
|
||||
localForm.value.workFlow.typeList = value
|
||||
}
|
||||
else {
|
||||
localForm.value.workFlow.typeList = value
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex justify-center mx-auto mt-10">
|
||||
<div class="w-[1137px] flex items-start">
|
||||
<div class="bg-gray-100 p-4 h-auto w-[60%] mr-2 rounded-lg">
|
||||
<n-form
|
||||
ref="formRef"
|
||||
:label-width="80"
|
||||
:model="localForm"
|
||||
:rules="rules"
|
||||
size="large"
|
||||
>
|
||||
<n-form-item label="工作流名称" path="workFlow.workflowName">
|
||||
<n-input v-model:value="localForm.workFlow.workflowName" placeholder="简单描述用途, 如: 图像一键放大" />
|
||||
</n-form-item>
|
||||
<div>
|
||||
内容类别
|
||||
</div>
|
||||
<div class="text-gray-400 -mb-4 text-[12px]">
|
||||
填写类别可让工作流获得更精准的流量,平台也有权基于标准修改你的类别标签
|
||||
</div>
|
||||
<n-form-item path="workFlow.activityId">
|
||||
<!-- <n-select
|
||||
v-model:value="localForm.workFlow.typeList" label-field="dictLabel"
|
||||
value-field="dictValue" filterable :options="workFlowTypeList"
|
||||
@update:value="handleUpdateValue"
|
||||
placeholder="请选择类型"
|
||||
/> -->
|
||||
<n-cascader
|
||||
v-model:value="localForm.workFlow.typeList"
|
||||
multiple
|
||||
clearable
|
||||
placeholder="请选择类型"
|
||||
max-tag-count="responsive"
|
||||
:options="workFlowTypeList"
|
||||
check-strategy="child"
|
||||
label-field="dictLabel"
|
||||
value-field="dictValue"
|
||||
@update:value="handleUpdateValue"
|
||||
/>
|
||||
</n-form-item>
|
||||
<div>
|
||||
参与活动
|
||||
</div>
|
||||
<div class="text-gray-400 -mb-4 text-[12px]">
|
||||
参与特定活动或比赛,下拉选择
|
||||
</div>
|
||||
<n-form-item path="workFlow.activityParticipation">
|
||||
<n-select
|
||||
v-model:value="localForm.workFlow.activityParticipation"
|
||||
label-field="activityName"
|
||||
value-field="id"
|
||||
placeholder="请选择参与哪个活动"
|
||||
:options="activityList"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</div>
|
||||
<div class="w-[40%]">
|
||||
<div class=" bg-gray-100 p-4 rounded-lg">
|
||||
<div class="flex -mb-2">
|
||||
是否公开<Asterisk :size="10" color="#ff0000" class="mt-1" />
|
||||
</div>
|
||||
<div class="flex justify-center items-center mt-5 bg-white h-10 rounded-lg">
|
||||
<div
|
||||
v-for="(item, index) in isPublicList"
|
||||
:key="index"
|
||||
:style="{
|
||||
backgroundColor:
|
||||
localForm.workFlow.jurisdiction === item.value
|
||||
? 'rgba(49, 98, 255, 0.1)'
|
||||
: '#fff',
|
||||
color: localForm.workFlow.jurisdiction === item.value ? '#3162ff' : '#000',
|
||||
}" class="flex-1 rounded-lg h-full flex items-center justify-center cursor-pointer" @click="handleIsPublic(item.value)"
|
||||
>
|
||||
{{ item.label }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-gray-400 text-[12px] mt-2">
|
||||
<div v-if="localForm.workFlow.jurisdiction === 1">
|
||||
公开状态: 对网站所有人可见
|
||||
</div>
|
||||
<div v-if="localForm.workFlow.jurisdiction === 2">
|
||||
非公开状态: 仅自己可见,可在“在线生图”自用
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex -mb-2 mt-2">
|
||||
是否原创<Asterisk :size="10" color="#ff0000" class="mt-1" />
|
||||
</div>
|
||||
<div class="flex justify-center items-center mt-5 bg-white h-10 rounded-lg">
|
||||
<div
|
||||
v-for="(item, index) in isOriginalList"
|
||||
:key="index"
|
||||
:style="{
|
||||
backgroundColor:
|
||||
localForm.workFlow.original === item.value
|
||||
? 'rgba(49, 98, 255, 0.1)'
|
||||
: '#fff',
|
||||
color: localForm.workFlow.original === item.value ? '#3162ff' : '#000',
|
||||
}" class="flex-1 rounded-lg h-full flex items-center justify-center cursor-pointer" @click="handleIsOriginal(item.value)"
|
||||
>
|
||||
{{ item.label }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="localForm.workFlow.original === 0" class="text-gray-400 text-[12px] mt-2">
|
||||
发布原创模型拿收益:<span class="text-[#3162ff] cursor-pointer">创作者激励计划</span>
|
||||
</div>
|
||||
<n-form
|
||||
v-if="localForm.workFlow.original === 1"
|
||||
:label-width="80"
|
||||
:model="localForm"
|
||||
:rules="rules"
|
||||
size="large"
|
||||
>
|
||||
<n-form-item path="workFlow.authorName">
|
||||
<n-input v-model:value="localForm.workFlow.authorName" placeholder="请输入原创作者" />
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 bg-gray-100 p-4 rounded-lg">
|
||||
<div class="text-[#3162ff] mb-4">
|
||||
用户使用时, 我授予用户以下权限
|
||||
</div>
|
||||
<div>
|
||||
<div class="flex mb-2">
|
||||
<n-checkbox
|
||||
v-model:checked="localForm.workFlow.onlineUse"
|
||||
:checked-value="0"
|
||||
:unchecked-value="1"
|
||||
/>
|
||||
<div class="text-[12px] ml-2">
|
||||
<div class="text-gray-600">
|
||||
允许在线使用
|
||||
</div>
|
||||
<div class="text-gray-400">
|
||||
您的工作流为公开状态时,默认同意此条款,他人不能随意转载
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex mb-2">
|
||||
<n-checkbox
|
||||
v-model:checked="localForm.workFlow.download"
|
||||
:checked-value="0"
|
||||
:unchecked-value="1"
|
||||
/>
|
||||
<div class="text-[12px] ml-2">
|
||||
<div class="text-gray-600">
|
||||
允许下载工作流
|
||||
</div>
|
||||
<div class="text-gray-400">
|
||||
允许下载后,您的工作流可能会被他人转载,我们无法控制该行为
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-[#3162ff] mb-4">
|
||||
用户使用时,我授予用户以下商业用途权限:
|
||||
</div>
|
||||
<div>
|
||||
<div class="flex mb-2">
|
||||
<n-checkbox
|
||||
v-model:checked="localForm.workFlow.sell"
|
||||
:checked-value="0"
|
||||
:unchecked-value="1"
|
||||
/>
|
||||
<div class="text-[12px] ml-2">
|
||||
<div class="text-gray-600">
|
||||
生成图片可出售或用于商业目的
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex justify-center items-center mt-5 text-white w-30 h-10 rounded-lg bg-[#3162ff] cursor-pointer" @click="handleValidateClick"
|
||||
>
|
||||
下一步
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,198 @@
|
|||
<script setup lang="ts">
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { Asterisk } from 'lucide-vue-next'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
const emit = defineEmits(['update:modelValue', 'preStep'])
|
||||
const router = useRouter()
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const { type } = route.query
|
||||
|
||||
const message = useMessage()
|
||||
|
||||
const localForm = computed({
|
||||
get() {
|
||||
return props.modelValue
|
||||
},
|
||||
set(value) {
|
||||
emit('update:modelValue', value)
|
||||
},
|
||||
})
|
||||
function preStep() {
|
||||
emit('preStep')
|
||||
}
|
||||
const showSuccessModal = ref(false)
|
||||
|
||||
async function handlePublish() {
|
||||
for (let i = 0; i < localForm.value.workFlowVersionList.length; i++) {
|
||||
if (localForm.value.workFlowVersionList[i].delFlag === '0' && localForm.value.workFlowVersionList[i].imagePaths.length === 0) {
|
||||
return message.error('请上传图片')
|
||||
}
|
||||
}
|
||||
try {
|
||||
const param = cloneDeep(localForm.value)
|
||||
if (param.workFlow.typeList.length !== 0) {
|
||||
param.workFlow.type = param.workFlow.typeList.join(',')
|
||||
}
|
||||
else {
|
||||
param.workFlow.type = ''
|
||||
}
|
||||
for (let i = 0; i < param.workFlowVersionList.length; i++) {
|
||||
if (param.workFlowVersionList[i].imagePaths.length !== 0) {
|
||||
param.workFlowVersionList[i].imagePaths = param.workFlowVersionList[i].imagePaths.join(',')
|
||||
}
|
||||
else {
|
||||
param.workFlowVersionList[i].imagePaths = ''
|
||||
}
|
||||
}
|
||||
// await request.post('/WorkFlow/addWorkFlow', param)
|
||||
if (type === 'add') {
|
||||
try {
|
||||
const res = await request.post('/WorkFlow/addWorkFlow', param)
|
||||
if (res.code === 200) {
|
||||
showSuccessModal.value = true
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
const res = await request.post('/WorkFlow/updateWorkFlow', param)
|
||||
if (res.code === 200) {
|
||||
showSuccessModal.value = true
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
watch(
|
||||
() => localForm.value,
|
||||
(newVal) => {
|
||||
emit('update:modelValue', newVal)
|
||||
},
|
||||
{ immediate: true, deep: true },
|
||||
)
|
||||
const fileInput = ref<HTMLInputElement | null>(null)
|
||||
const uploadFileIndex = ref(0)
|
||||
|
||||
function triggerFileInput(index: number) {
|
||||
(fileInput.value as HTMLInputElement)?.click()
|
||||
uploadFileIndex.value = index
|
||||
}
|
||||
async function handleFileChange(event: Event) {
|
||||
const target = event.target as HTMLInputElement
|
||||
const files = target.files
|
||||
|
||||
if (files && files.length > 0) {
|
||||
const sum = localForm.value.workFlowVersionList[uploadFileIndex.value].imagePaths.length + files.length
|
||||
if (sum >= 20)
|
||||
return message.error('最多20张')
|
||||
const res = await uploadImagesInBatches(files)
|
||||
const urlList = res.map(item => item.url)
|
||||
localForm.value.workFlowVersionList[uploadFileIndex.value].imagePaths.push(...urlList)
|
||||
}
|
||||
target.value = ''
|
||||
}
|
||||
|
||||
function onPositiveClick() {
|
||||
showSuccessModal.value = false
|
||||
router.push('/personal-center')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="mx-auto mt-10">
|
||||
<div class="w-[960px] items-start rounded-lg">
|
||||
<template v-for="(item, index) in localForm.workFlowVersionList" :key="index">
|
||||
<div v-if="item.delFlag === '0'" class="w-full bg-gray-100 p-4 rounded-lg mt-2">
|
||||
<div class="flex justify-between items-center">
|
||||
<div>
|
||||
版本名: <span>{{ item.versionName }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<n-checkbox
|
||||
v-model:checked="item.hideGenInfo"
|
||||
:checked-value="1" :unchecked-value="0"
|
||||
/>
|
||||
隐藏图片生成信息
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between items-center mt-4">
|
||||
<div class="flex">
|
||||
添加版本示例图片
|
||||
<Asterisk :size="10" color="#ff0000" class="mt-1" />
|
||||
</div>
|
||||
<div class="text-[12px] text-gray-400">
|
||||
最多20张图片,图片不超过30M
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="flex flex-col justify-center items-center w-30 h-40 border border-dashed mt-2 rounded-lg bg-white">
|
||||
<div class="w-24 bg-gradient-to-r from-[#2D28FF] to-[#1A7DFF] h-8 text-white rounded-sm bg-[#3162ff] cursor-pointer flex justify-center items-center" @click="triggerFileInput(index)">
|
||||
上传文件
|
||||
</div>
|
||||
<div class="my-3">
|
||||
点击上传文件
|
||||
</div>
|
||||
<div class="text-[#999999] text-xs">
|
||||
请勿上传裸露、暴力、血腥或其他包含非法信息图片
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-3 gap-2.5 mt-4 w-full">
|
||||
<div v-for="(subItem, subIndex) in item.imagePaths" :key="subIndex">
|
||||
<img class="w-full h-[200px] object-cover rounded-lg" :src="subItem" alt="">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="flex items-center justify-center mt-5">
|
||||
<div class="flex justify-center items-center mt-5 w-[20%] mx-2 h-10 rounded-lg bg-[#f1f2f7] cursor-pointer" @click="preStep">
|
||||
上一步
|
||||
</div>
|
||||
<div class="flex justify-center items-center mt-5 text-white mx-2 w-[20%] h-10 rounded-lg bg-[#3162ff] cursor-pointer" @click="handlePublish">
|
||||
发布
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<input
|
||||
ref="fileInput"
|
||||
type="file"
|
||||
class="hidden"
|
||||
accept="image/*"
|
||||
multiple
|
||||
@change="handleFileChange"
|
||||
>
|
||||
|
||||
<!-- 成功之后的弹框 -->
|
||||
<n-modal
|
||||
v-model:show="showSuccessModal"
|
||||
:mask-closable="false"
|
||||
preset="dialog"
|
||||
title="发布成功!"
|
||||
content="工作流发布成功, 可至个人中心查看状态"
|
||||
positive-text="确认"
|
||||
@positive-click="onPositiveClick"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -1,4 +1,23 @@
|
|||
import type { SearchCheckIcon } from 'lucide-vue-next'
|
||||
|
||||
export const appName = '魔创未来'
|
||||
export const appDescription = '魔创未来'
|
||||
export const authRoutes = ['/personal-center', '/publish-model', '/publish-workflow']
|
||||
export const verifyBlankRoute = ['/member-center']
|
||||
export const verifyBlankRoute = ['/member-center', 'int-detail']
|
||||
export const isOriginalList = [{
|
||||
label: '原创',
|
||||
value: 0,
|
||||
}, {
|
||||
label: '转载',
|
||||
value: 1,
|
||||
}]
|
||||
export const isPublicList = [{
|
||||
label: '公开',
|
||||
value: 1,
|
||||
}, {
|
||||
label: '自己',
|
||||
value: 2,
|
||||
}]
|
||||
export const headerRole = { // 包括就隐藏
|
||||
inputSearch: ['/model-square'],
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ function handleSide(event: Event, path: string) {
|
|||
<!-- Main Content -->
|
||||
<div class="flex flex-1 overflow-hidden">
|
||||
<!-- Sidebar -->
|
||||
<nav class="w-[240px] border-r border-gray-100 bg-gray-50/50 py-2 dark:border-dark-700 dark:bg-dark-800/50">
|
||||
<nav class="w-[200px] border-r border-gray-100 bg-gray-50/50 py-2 dark:border-dark-700 dark:bg-dark-800/50">
|
||||
<div class="space-y-1 px-2">
|
||||
<NuxtLink
|
||||
v-for="item in menuStore.menuItems"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import { NButton, NInput, NDataTable, useMessage } from 'naive-ui'
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { NButton, NDataTable, NInput, useMessage } from 'naive-ui'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import request from '~/utils/request'
|
||||
|
||||
definePageMeta({
|
||||
|
@ -34,23 +34,23 @@ const userData = ref<UserData[]>([])
|
|||
const columns = [
|
||||
{
|
||||
title: 'ID',
|
||||
key: 'id'
|
||||
key: 'id',
|
||||
},
|
||||
{
|
||||
title: '姓名',
|
||||
key: 'name'
|
||||
key: 'name',
|
||||
},
|
||||
{
|
||||
title: '邮箱',
|
||||
key: 'email'
|
||||
key: 'email',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
key: 'status',
|
||||
render: (row: UserData) => {
|
||||
return row.status === 1 ? '激活' : '禁用'
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
// 获取用户列表
|
||||
|
@ -59,19 +59,22 @@ async function fetchUserList() {
|
|||
try {
|
||||
const response = await request.get<ApiResponse<UserData[]>>('/api/users', {
|
||||
params: {
|
||||
keyword: searchText.value
|
||||
}
|
||||
keyword: searchText.value,
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
if (response.code === 200) {
|
||||
// userData.value = response.data
|
||||
message.success('数据加载成功')
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
message.error(response.message || '获取数据失败')
|
||||
}
|
||||
} catch (error: any) {
|
||||
}
|
||||
catch (error: any) {
|
||||
message.error(error.message || '请求出错')
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
@ -87,16 +90,18 @@ async function handleAddUser() {
|
|||
const response = await request.post<ApiResponse<UserData>>('/api/users', {
|
||||
name: '测试用户',
|
||||
email: 'test@example.com',
|
||||
status: 1
|
||||
status: 1,
|
||||
})
|
||||
|
||||
|
||||
if (response.code === 200) {
|
||||
message.success('添加成功')
|
||||
fetchUserList() // 刷新列表
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
message.error(response.message || '添加失败')
|
||||
}
|
||||
} catch (error: any) {
|
||||
}
|
||||
catch (error: any) {
|
||||
message.error(error.message || '请求出错')
|
||||
}
|
||||
}
|
||||
|
@ -110,21 +115,21 @@ onMounted(() => {
|
|||
<template>
|
||||
<div class="p-4">
|
||||
<div class="mb-4 flex gap-4 items-center">
|
||||
<n-input
|
||||
v-model:value="searchText"
|
||||
placeholder="请输入搜索关键词"
|
||||
<NInput
|
||||
v-model:value="searchText"
|
||||
placeholder="请输入搜索关键词"
|
||||
class="w-64"
|
||||
@keyup.enter="handleSearch"
|
||||
/>
|
||||
<n-button type="primary" :loading="loading" @click="handleSearch">
|
||||
<NButton type="primary" :loading="loading" @click="handleSearch">
|
||||
搜索
|
||||
</n-button>
|
||||
<n-button type="info" @click="handleAddUser">
|
||||
</NButton>
|
||||
<NButton type="info" @click="handleAddUser">
|
||||
添加用户
|
||||
</n-button>
|
||||
</NButton>
|
||||
</div>
|
||||
|
||||
<n-data-table
|
||||
<NDataTable
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:data="userData"
|
||||
|
@ -153,4 +158,4 @@ onMounted(() => {
|
|||
.w-64 {
|
||||
width: 16rem;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
<script setup lang="ts">
|
||||
import { nextTick, onMounted } from 'vue'
|
||||
|
||||
definePageMeta({
|
||||
layout: 'header',
|
||||
})
|
||||
const activeTab = ref('')
|
||||
|
||||
// const route = useRoute();
|
||||
// const { id } = route.params as { id: string };
|
||||
interface PointsResult {
|
||||
points: number
|
||||
memberConsumeList: any[]
|
||||
}
|
||||
const pointsResult = ref<PointsResult>(null)
|
||||
async function getPoints() {
|
||||
try {
|
||||
const res = await request.get('/member/getPoints')
|
||||
if (res.code === 200) {
|
||||
pointsResult.value = res.data as PointsResult
|
||||
nextTick(() => {
|
||||
activeTab.value = 'beatles'
|
||||
})
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
getPoints()
|
||||
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="h-[500px] overflow-y-auto">
|
||||
<div class="mc-table flex w-full">
|
||||
<div class="w-[250px]">
|
||||
获取时间
|
||||
</div>
|
||||
<div class="w-[250px]">
|
||||
获取来源
|
||||
</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>
|
||||
</div>
|
||||
</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="w-[250px]">
|
||||
消耗时间
|
||||
</div>
|
||||
<div class="w-[250px]">
|
||||
消耗类型
|
||||
</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>
|
||||
</div>
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.mc-table {
|
||||
> div {
|
||||
line-height: 40px;
|
||||
height: 50px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,20 +1,24 @@
|
|||
<script setup lang="ts">
|
||||
import { CheckmarkCircleSharp, Close } from '@vicons/ionicons5'
|
||||
import { NConfigProvider, NMessageProvider } from 'naive-ui'
|
||||
|
||||
definePageMeta({
|
||||
layout: 'header',
|
||||
})
|
||||
|
||||
// 订单
|
||||
const needPayment = ref([{
|
||||
amount: '',
|
||||
productId: '',
|
||||
promotionId: '',
|
||||
type: 'member',
|
||||
}])
|
||||
const userStore = useUserStore()
|
||||
const userInfo = userStore.userInfo as UserInfoType
|
||||
// 显示支付弹框
|
||||
interface Payment {
|
||||
isVisible: boolean
|
||||
}
|
||||
const PaymentRef = ref<Payment | null>(null)
|
||||
function showPayment() {
|
||||
if (PaymentRef.value) {
|
||||
PaymentRef.value.isVisible = true
|
||||
}
|
||||
}
|
||||
|
||||
// 是否是会员
|
||||
const isMember = ref(false)
|
||||
|
@ -29,22 +33,7 @@ async function getIsMember() {
|
|||
console.log(err)
|
||||
}
|
||||
}
|
||||
// getIsMember()
|
||||
|
||||
// 获取积分余额和历史记录
|
||||
const points = ref(0)
|
||||
async function getPoints() {
|
||||
try {
|
||||
const res = await request.get('/member/getPoints')
|
||||
if (res.code === 200) {
|
||||
points.value = res.data
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
// getPoints()
|
||||
getIsMember()
|
||||
|
||||
// 获取会员等级及权益列表
|
||||
const MemberBenefitList = ref([])
|
||||
|
@ -59,7 +48,7 @@ async function getMemberBenefitList() {
|
|||
console.log(err)
|
||||
}
|
||||
}
|
||||
// getMemberBenefitList()
|
||||
getMemberBenefitList()
|
||||
|
||||
// 获取会员等级列表
|
||||
interface memberLevel {
|
||||
|
@ -81,6 +70,59 @@ async function getMemberLevelList() {
|
|||
}
|
||||
}
|
||||
getMemberLevelList()
|
||||
|
||||
// 显示会员支付的弹框
|
||||
const isShowPayment = ref(false)
|
||||
const PaymentRef = ref<Payment | null>(null)
|
||||
function showPayment(info: any) {
|
||||
if (info === 1) {
|
||||
needPayment.value = memberLevelList.value
|
||||
}
|
||||
else {
|
||||
needPayment.value = [info]
|
||||
}
|
||||
isShowPayment.value = true
|
||||
if (PaymentRef.value) {
|
||||
PaymentRef.value.isVisible = true
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭开通会员弹框
|
||||
function closePayment() {
|
||||
isShowPayment.value = false
|
||||
if (PaymentRef.value) {
|
||||
PaymentRef.value.isVisible = false
|
||||
}
|
||||
}
|
||||
// 显示积分的弹框
|
||||
const isShowIntPayment = ref(false)
|
||||
|
||||
const IntPaymentRef = ref<Payment | null>(null)
|
||||
function showIntPayment() {
|
||||
isShowIntPayment.value = true
|
||||
if (IntPaymentRef.value) {
|
||||
IntPaymentRef.value.isVisible = true
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭充值积分弹框
|
||||
function closeIntPayment() {
|
||||
isShowIntPayment.value = false
|
||||
if (IntPaymentRef.value) {
|
||||
IntPaymentRef.value.isVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
// 支付成功后刷新会员信息
|
||||
function paymentSuccess() {
|
||||
getIsMember()
|
||||
}
|
||||
|
||||
// 跳转到积分详情页
|
||||
function toIntDetail() {
|
||||
const baseUrl = window.location.origin
|
||||
window.open(`${baseUrl}/int-detail`, '_blank', 'noopener,noreferrer')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -88,7 +130,7 @@ getMemberLevelList()
|
|||
<div class="test bg-[#403833] flex justify-center items-center h-90">
|
||||
<div class="flex gap-6 w-[1145px]">
|
||||
<!-- 左侧用户信息 -->
|
||||
<div class="w-60 bg-[#2b2421] rounded-lg p-6">
|
||||
<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">
|
||||
|
@ -113,14 +155,14 @@ getMemberLevelList()
|
|||
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}` : '您还不是魔创未来的会员' }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 开通会员按钮 -->
|
||||
<button
|
||||
class="w-full bg-[#f2d5bc] text-[#6b4f3f] rounded-full py-2.5 mt-8 font-medium cursor-pointer"
|
||||
@click="showPayment"
|
||||
@click="showPayment(1)"
|
||||
>
|
||||
开通会员
|
||||
</button>
|
||||
|
@ -136,7 +178,7 @@ getMemberLevelList()
|
|||
<!-- 右侧内容 -->
|
||||
<div class="flex-1 space-y-4">
|
||||
<!-- 余额信息卡片 -->
|
||||
<div class="bg-[#2b2421] rounded-lg p-6">
|
||||
<div class="bg-[#2b2421] rounded-lg p-6 mt-3">
|
||||
<div class="grid grid-cols-3 gap-8">
|
||||
<!-- 算力余额 -->
|
||||
<div>
|
||||
|
@ -145,11 +187,11 @@ getMemberLevelList()
|
|||
</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">
|
||||
<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">
|
||||
<button class="text-white bg-inherit border-none cursor-pointer p-0" @click="toIntDetail">
|
||||
算力明细 >
|
||||
</button>
|
||||
</div>
|
||||
|
@ -226,7 +268,7 @@ getMemberLevelList()
|
|||
<div
|
||||
v-for="(item, index) in memberLevelList"
|
||||
:key="index"
|
||||
class="h-56 border-1 border-solid border-[#fff] rounded-lg bg-gradient-to-b from-[#fdf0dd] to-[#fef8ef] flex justify-between items-center flex-col p-4 box-border"
|
||||
class="h-56 border-2 border-solid border-[#fff] rounded-lg bg-gradient-to-b from-[#f7e8d3] to-[#fef8ef] flex justify-between items-center flex-col p-4 box-border"
|
||||
>
|
||||
<div class="text-[#e08909] card-item">
|
||||
{{ item.memberName }}
|
||||
|
@ -241,7 +283,7 @@ getMemberLevelList()
|
|||
</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"
|
||||
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>
|
||||
|
@ -254,74 +296,172 @@ getMemberLevelList()
|
|||
会员权益
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<div class="w-1/4 h-20 bg-[#f7f0ea] flex justify-center items-center">
|
||||
会员权益
|
||||
<!-- <div class="flex items-center">
|
||||
<div v-for="(item, index) in MemberBenefitList" :key="index" class="w-1/4 w-full">
|
||||
<div class="flex items-center justify-center">
|
||||
{{ item.memberLevelName }}
|
||||
</div>
|
||||
<div v-for="(item2, index2) in item.memberBenefitList" :key="index2" class="flex w-full">
|
||||
<div class="h-20 bg-[#f7f0ea] flex justify-center items-center w-full">
|
||||
{{ item2.benefitName ? item2.benefitName : '无' }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-1/4 h-20 bg-[#f5f5f5] flex justify-center items-center">
|
||||
用户免费
|
||||
</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>
|
||||
<div class="w-1/4 h-20 bg-[#fdf6ea] flex justify-center items-center">
|
||||
基础版VIP
|
||||
<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>
|
||||
<div class="w-1/4 h-20 bg-[#fce6bf] flex justify-center items-center">
|
||||
专业版VIP
|
||||
<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>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<div class="w-1/4 h-10 bg-[#fff] flex justify-center items-center">
|
||||
算力
|
||||
<div class="flex gap-2">
|
||||
<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>
|
||||
<div class="w-1/4 h-10 bg-[#fff] flex justify-center items-center">
|
||||
每天300点
|
||||
<div class="flex gap-2">
|
||||
<div class="member-item bg-[#fafafa]">
|
||||
会员专属模型
|
||||
</div>
|
||||
<div class="member-item bg-[#fafafa]">
|
||||
<n-icon size="20" color="#ed7470">
|
||||
<Close />
|
||||
</n-icon>
|
||||
</div>
|
||||
<div class="member-item bg-[#fdf6ea]">
|
||||
<n-icon size="20" color="#58c08f">
|
||||
<CheckmarkCircleSharp />
|
||||
</n-icon>
|
||||
</div>
|
||||
<div class="member-item bg-[#fce6bf]">
|
||||
<n-icon size="20" color="#58c08f">
|
||||
<CheckmarkCircleSharp />
|
||||
</n-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-1/4 h-10 bg-[#fff] flex justify-center items-center">
|
||||
每月15000点
|
||||
<div class="flex gap-2">
|
||||
<div class="member-item bg-[#fff]">
|
||||
生图高级功能
|
||||
</div>
|
||||
<div class="member-item bg-[#fff]">
|
||||
<n-icon size="20" color="#ed7470">
|
||||
<Close />
|
||||
</n-icon>
|
||||
</div>
|
||||
<div class="member-item bg-[#fff]">
|
||||
<n-icon size="20" color="#58c08f">
|
||||
<CheckmarkCircleSharp />
|
||||
</n-icon>
|
||||
</div>
|
||||
<div class="member-item bg-[#fff]">
|
||||
<n-icon size="20" color="#58c08f">
|
||||
<CheckmarkCircleSharp />
|
||||
</n-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-1/4 h-10 bg-[#fff] flex justify-center items-center">
|
||||
每月35000点
|
||||
<div class="flex gap-2">
|
||||
<div class="member-item bg-[#fafafa]">
|
||||
训练XL模型
|
||||
</div>
|
||||
<div class="member-item bg-[#fafafa]">
|
||||
<n-icon size="20" color="#ed7470">
|
||||
<Close />
|
||||
</n-icon>
|
||||
</div>
|
||||
<div class="member-item bg-[#fdf6ea]">
|
||||
<n-icon size="20" color="#ed7470">
|
||||
<Close />
|
||||
</n-icon>
|
||||
</div>
|
||||
<div class="member-item bg-[#fce6bf]">
|
||||
<n-icon size="20" color="#58c08f">
|
||||
<CheckmarkCircleSharp />
|
||||
</n-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<div class="w-1/4 h-10 bg-[#f7f0ea] flex justify-center items-center">
|
||||
算力
|
||||
<div class="flex gap-2">
|
||||
<div class="member-item bg-[#fff]">
|
||||
图片去水印下载
|
||||
</div>
|
||||
<div class="member-item bg-[#fff]">
|
||||
<n-icon size="20" color="#ed7470">
|
||||
<Close />
|
||||
</n-icon>
|
||||
</div>
|
||||
<div class="member-item bg-[#fff]">
|
||||
<n-icon size="20" color="#58c08f">
|
||||
<CheckmarkCircleSharp />
|
||||
</n-icon>
|
||||
</div>
|
||||
<div class="member-item bg-[#fff]">
|
||||
<n-icon size="20" color="#58c08f">
|
||||
<CheckmarkCircleSharp />
|
||||
</n-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-1/4 h-10 bg-[#f5f5f5] flex justify-center items-center">
|
||||
每天300点
|
||||
</div>
|
||||
<div class="w-1/4 h-10 bg-[#fdf6ea] flex justify-center items-center">
|
||||
每月15000点
|
||||
</div>
|
||||
<div class="w-1/4 h-10 bg-[#fce6bf] flex justify-center items-center">
|
||||
每月35000点
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<div class="w-1/4 h-10 bg-[#fff] flex justify-center items-center">
|
||||
算力
|
||||
</div>
|
||||
<div class="w-1/4 h-10 bg-[#fff] flex justify-center items-center">
|
||||
每天300点
|
||||
</div>
|
||||
<div class="w-1/4 h-10 bg-[#fff] flex justify-center items-center">
|
||||
每月15000点
|
||||
</div>
|
||||
<div class="w-1/4 h-10 bg-[#fff] flex justify-center items-center">
|
||||
每月35000点
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<div class="w-1/4 h-10 bg-[#f7f0ea] flex justify-center items-center">
|
||||
算力
|
||||
</div>
|
||||
<div class="w-1/4 h-10 bg-[#f5f5f5] flex justify-center items-center">
|
||||
每天300点
|
||||
</div>
|
||||
<div class="w-1/4 h-10 bg-[#fdf6ea] flex justify-center items-center">
|
||||
每月15000点
|
||||
</div>
|
||||
<div class="w-1/4 h-10 bg-[#fce6bf] flex justify-center items-center">
|
||||
每月35000点
|
||||
<div class="flex gap-2">
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -330,7 +470,7 @@ getMemberLevelList()
|
|||
会员每月算力和加速特权按月下发,有效期31天,到期重置。会员模型下载次数上限为每月200次
|
||||
</div>
|
||||
<div class="mt-1">
|
||||
发票或团队/企业定制需求,请点击立即咨询联系我们,企业合作需求也可直接联系chujie@liblib.ai
|
||||
发票或团队/企业定制需求,请点击立即咨询联系我们,企业合作需求也可直接联系xxxx
|
||||
</div>
|
||||
<div class="mt-1">
|
||||
更多问题可见帮助中心
|
||||
|
@ -338,7 +478,12 @@ getMemberLevelList()
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Payment ref="PaymentRef" />
|
||||
<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" />
|
||||
</NMessageProvider>
|
||||
</NConfigProvider>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -346,4 +491,7 @@ getMemberLevelList()
|
|||
.card-item {
|
||||
@apply flex items-center justify-center h-1/4;
|
||||
}
|
||||
.member-item {
|
||||
@apply w-1/4 h-12 flex justify-center items-center;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
<script setup lang="ts">
|
||||
import { Heart } from '@vicons/ionicons5'
|
||||
import {
|
||||
Download,
|
||||
Play,
|
||||
} from 'lucide-vue-next'
|
||||
|
||||
definePageMeta({
|
||||
layout: 'default',
|
||||
})
|
||||
import {
|
||||
Play,
|
||||
Download,
|
||||
} from "lucide-vue-next";
|
||||
// const route = useRoute<'publishDetails-id'>()
|
||||
|
||||
// const id = route.params.id
|
||||
|
@ -14,20 +16,22 @@ import {
|
|||
<template>
|
||||
<div class="flex justify-center">
|
||||
<div class="w-[1125px]">
|
||||
<div class="flex items-center">
|
||||
<div class="text-[26px] font-bold mr-2">名称</div>
|
||||
<component :is="Play" class="h-[14px] w-[14px] text-white menu-icon m-1" />
|
||||
<span>
|
||||
<!-- {{ item.reals }} -->0
|
||||
</span>
|
||||
<component
|
||||
:is="Download"
|
||||
class="h-[14px] w-[14px] text-white menu-icon m-1"
|
||||
/>
|
||||
<span>
|
||||
<!-- {{ item.numbers }} -->0
|
||||
</span>
|
||||
<div class="flex items-center">
|
||||
<div class="text-[26px] font-bold mr-2">
|
||||
名称
|
||||
</div>
|
||||
<component :is="Play" class="h-[14px] w-[14px] text-white menu-icon m-1" />
|
||||
<span>
|
||||
<!-- {{ item.reals }} -->0
|
||||
</span>
|
||||
<component
|
||||
:is="Download"
|
||||
class="h-[14px] w-[14px] text-white menu-icon m-1"
|
||||
/>
|
||||
<span>
|
||||
<!-- {{ item.numbers }} -->0
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
<script setup lang="ts">
|
||||
import { debug } from 'node:console'
|
||||
import { commonApi } from '@/api/common'
|
||||
import defaultAvatar from '@/assets/img/default-avatar.png'
|
||||
import EditUserInfo from '@/components/EditUserInfo.vue'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { formatDate } from '@/utils/index.ts'
|
||||
import { debounce } from 'lodash-es'
|
||||
import { nextTick, onMounted, onUnmounted, ref } from 'vue'
|
||||
|
||||
const loading = ref(false)
|
||||
|
@ -334,6 +331,16 @@ async function topedRefresh() {
|
|||
}
|
||||
initPageNUm()
|
||||
}
|
||||
|
||||
// 关注/粉丝列表模态框
|
||||
const currentAttentionType = ref<string>('attention')
|
||||
const attentionIsVisible = ref<boolean>(false)
|
||||
// function onShowAttentionModel(type: string) {
|
||||
// attentionIsVisible.value = true
|
||||
// }
|
||||
function onCloseAttentionModel() {
|
||||
attentionIsVisible.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -350,12 +357,12 @@ async function topedRefresh() {
|
|||
<div class="mc-head-inner h-18 w-18 m-1 rounded-full bg-blue-200">
|
||||
<client-only>
|
||||
<img
|
||||
v-if="userInfo.avatar"
|
||||
class="head-img m-1 h-16 w-16 rounded-full bg-white"
|
||||
:src="userInfo.avatar ? userInfo.avatar : defaultAvatar"
|
||||
:src="userStore.userInfo.avatar"
|
||||
alt="User Avatar"
|
||||
>
|
||||
</client-only>
|
||||
<!-- {{ userStore.userInfo.avatar }} -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -384,20 +391,21 @@ async function topedRefresh() {
|
|||
|
||||
<!-- User Details -->
|
||||
<div class="user-info mt-4">
|
||||
<div v-if="userInfo.nickName" class="nickname text-2xl font-bold">
|
||||
{{ userInfo.nickName }}
|
||||
<div v-if="userStore.userInfo" class="nickname text-2xl font-bold">
|
||||
{{ userStore.userInfo.nickName }}
|
||||
<!-- {{ userInfo.nickName }} -->
|
||||
</div>
|
||||
<div v-if="userInfo.brief" class="info-desc mt-1 text-sm text-gray-700">
|
||||
{{ userInfo.brief }}
|
||||
<div v-if="userStore.userInfo.brief" class="info-desc mt-1 text-sm text-gray-700">
|
||||
{{ userStore.userInfo.brief }}
|
||||
</div>
|
||||
<div class="production-state mt-4 flex text-sm text-gray-700">
|
||||
<div class="production-state-item mr-5">
|
||||
<div class="production-state-item mr-5 cursor-pointer" @click="onShowAttentionModel('bean')">
|
||||
<span class="production-state-number font-bold">{{
|
||||
selectUserInfo.bean ? selectUserInfo.bean : 0
|
||||
}}</span>
|
||||
粉丝
|
||||
</div>
|
||||
<div class="production-state-item mr-5">
|
||||
<div class="production-state-item mr-5 cursor-pointer" @click="onShowAttentionModel('attention')">
|
||||
<span class="production-state-number font-bold">{{
|
||||
selectUserInfo.attention ? selectUserInfo.attention : 0
|
||||
}}</span>
|
||||
|
@ -526,6 +534,20 @@ async function topedRefresh() {
|
|||
没有更多数据了
|
||||
</div>
|
||||
</div>
|
||||
<NModal
|
||||
v-model:show="attentionIsVisible"
|
||||
:on-after-leave="onCloseAttentionModel"
|
||||
preset="card"
|
||||
style="width: 400px"
|
||||
:mask-closable="false"
|
||||
>
|
||||
<div>
|
||||
<div class="">
|
||||
<div>粉丝</div>
|
||||
<div>关注</div>
|
||||
</div>
|
||||
</div>
|
||||
</NModal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -30,12 +30,13 @@ const formData = ref({
|
|||
isPublic: 1, // 权限是否公开权限 1公开 2自见
|
||||
isFree: 0, // 0免费
|
||||
allowFusion: 1, // 待确定
|
||||
isOnlineUse: 0, // 是否允许在线使用
|
||||
allowDownloadImage: 1, // 允许下载生图
|
||||
allowUsage: 1, // 是否允许使用
|
||||
allowSoftwareUse: 1, // 允许在软件旗下使用
|
||||
allowCommercialUse: 1, // 是否允许商用
|
||||
// 允许模型转售或者融合手出售字段没找到?
|
||||
isExclusiveModel: 1, // 是否为独家模型这个字段
|
||||
isExclusiveModel: 0, // 是否为独家模型这个字段
|
||||
},
|
||||
],
|
||||
})
|
||||
|
@ -119,7 +120,7 @@ function handleAddVersion() {
|
|||
添加版本
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-container bg-gray-100 p-4 rounded-lg">
|
||||
<div class="form-container">
|
||||
<div v-if="currentStep === 1" class="first-step">
|
||||
<CreateModels v-model="formData" @create-models-next="createModelsNext" />
|
||||
</div>
|
||||
|
@ -132,6 +133,13 @@ function handleAddVersion() {
|
|||
3
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="flex items-center justify-center mt-4">
|
||||
<div>
|
||||
<div class="flex justify-center items-center mt-5 text-white w-30 h-10 rounded-lg bg-[#3162ff] cursor-pointer" @click="nextStep">
|
||||
下一步
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
<!-- <n-form
|
||||
ref="formRef"
|
||||
|
|
|
@ -1,182 +1,132 @@
|
|||
<template>
|
||||
<n-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
label-placement="left"
|
||||
label-width="auto"
|
||||
require-mark-placement="right-hanging"
|
||||
size="large"
|
||||
:style="{
|
||||
maxWidth: '640px',
|
||||
}"
|
||||
>
|
||||
<n-form-item label="工作流名称" path="inputValue">
|
||||
<n-input v-model:value="formData.inputValue" placeholder="Input" />
|
||||
</n-form-item>
|
||||
<n-form-item label="工作流名称" path="inputValue">
|
||||
<!-- <n-input v-model:value="model.inputValue" placeholder="Input" /> -->
|
||||
<n-select v-model:value="formData.value" :options="cuileioptions" />
|
||||
</n-form-item>
|
||||
<n-form-item label="Checkbox Group" path="checkboxGroupValue">
|
||||
<n-checkbox-group v-model:value="formData.checkboxGroupValue">
|
||||
<n-space>
|
||||
<n-checkbox value="Option 1"> Option 1 </n-checkbox>
|
||||
<n-checkbox value="Option 2"> Option 2 </n-checkbox>
|
||||
<n-checkbox value="Option 3"> Option 3 </n-checkbox>
|
||||
</n-space>
|
||||
</n-checkbox-group>
|
||||
</n-form-item>
|
||||
<n-form-item label="Radio Group" path="radioGroupValue">
|
||||
<n-radio-group v-model:value="formData.radioGroupValue" name="radiogroup1">
|
||||
<n-space>
|
||||
<n-radio value="Radio 1"> Radio 1 </n-radio>
|
||||
<n-radio value="Radio 2"> Radio 2 </n-radio>
|
||||
<n-radio value="Radio 3"> Radio 3 </n-radio>
|
||||
</n-space>
|
||||
</n-radio-group>
|
||||
</n-form-item>
|
||||
<n-form-item label="Radio Button Group" path="radioGroupValue">
|
||||
<n-radio-group v-model:value="formData.radioGroupValue" name="radiogroup2">
|
||||
<n-radio-button value="Radio 1"> Radio 1 </n-radio-button>
|
||||
<n-radio-button value="Radio 2"> Radio 2 </n-radio-button>
|
||||
<n-radio-button value="Radio 3"> Radio 3 </n-radio-button>
|
||||
</n-radio-group>
|
||||
</n-form-item>
|
||||
<div style="display: flex; justify-content: flex-end">
|
||||
<n-button round type="primary" @click="addWorkflow"> 验证 </n-button>
|
||||
</div>
|
||||
</n-form>
|
||||
|
||||
<!-- <pre
|
||||
>{{ JSON.stringify(model, null, 2) }}
|
||||
</pre> -->
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { FormInst, FormItemRule } from "naive-ui";
|
||||
import { useMessage } from "naive-ui";
|
||||
import { defineComponent, ref } from "vue";
|
||||
import { commonApi } from "@/api/common";
|
||||
const formRef = ref<FormInst | null>(null);
|
||||
const cuileioptions = ref([
|
||||
{ label: "Option 1", value: "Option 1" },
|
||||
{ label: "Option 2", value: "Option 1" },
|
||||
{ label: "Option 3", value: "Option 1" },
|
||||
]);
|
||||
const message = useMessage();
|
||||
const rules: Record<string, FormItemRule[]> = {
|
||||
|
||||
}
|
||||
const formData = ref({
|
||||
inputValue: null,
|
||||
textareaValue: null,
|
||||
selectValue: null,
|
||||
multipleSelectValue: null,
|
||||
datetimeValue: null,
|
||||
nestedValue: {
|
||||
path1: null,
|
||||
path2: null,
|
||||
},
|
||||
switchValue: false,
|
||||
checkboxGroupValue: null,
|
||||
radioGroupValue: null,
|
||||
radioButtonGroupValue: null,
|
||||
inputNumberValue: null,
|
||||
timePickerValue: null,
|
||||
transferValue: null,
|
||||
})
|
||||
const addWorkflow = async() => {
|
||||
try {
|
||||
const params = {
|
||||
workFlow:{
|
||||
workflowName:'工作流名称',
|
||||
category:'1', //垂类
|
||||
theme:'1', //主体
|
||||
style:'1', //风格
|
||||
functions:'1', //功能
|
||||
activityParticipation:'1', //参与活动
|
||||
jurisdiction:1, //是否公开权限 1公开 2自见
|
||||
original:1, //0代表原创 1代表转载
|
||||
authorName:'作者名称', //原文作者名字
|
||||
onlineUse:0, //是否允许在线使用0允许 1不允许
|
||||
download: 1, //是否允许下载工作流0允许 1不允许
|
||||
sell:1, //是否允许出售或商用(0允许 1不允许)
|
||||
},
|
||||
|
||||
workFlowVersionList:[
|
||||
{
|
||||
versionName:'1.0', // 版本名称
|
||||
versionDescription:'"<p>这是一个描述</p><p><img src=\"https://img1.baidu.com/it/u=3001150338,397170470&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=1422\" /></p><p>这是两张图片之间的一些文字说明</p><p><img src=\"https://img12.iqilu.com/10339/clue/202405/29/68ec17f5-9621-461f-ad22-a6820a3f9cf5.jpg\" /></p>"', //版本描述
|
||||
filePath:'https://ybl2112.oss-cn-beijing.aliyuncs.com/2025/JANUARY/2/19/4/877e449c-3c0d-4630-a304-91ec110499f2.png', //文件路径
|
||||
fileName:'文件名称其实是个图片', //文件名称
|
||||
imagePaths:'https://ybl2112.oss-cn-beijing.aliyuncs.com/2025/JANUARY/2/19/4/877e449c-3c0d-4630-a304-91ec110499f2.png,https://ybl2112.oss-cn-beijing.aliyuncs.com/2025/JANUARY/2/19/4/877e449c-3c0d-4630-a304-91ec110499f2.png,https://ybl2112.oss-cn-beijing.aliyuncs.com/2025/JANUARY/2/19/4/877e449c-3c0d-4630-a304-91ec110499f2.png', //第三部的图片路径最多20张,切割
|
||||
hideGenInfo:0, //是否隐藏生成信息 0隐藏 1不隐藏
|
||||
},
|
||||
{
|
||||
versionName:'2.0', // 版本名称
|
||||
versionDescription:'"<p>这是一个描述</p><p><img src=\"https://img1.baidu.com/it/u=3001150338,397170470&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=1422\" /></p><p>这是两张图片之间的一些文字说明</p><p><img src=\"https://img12.iqilu.com/10339/clue/202405/29/68ec17f5-9621-461f-ad22-a6820a3f9cf5.jpg\" /></p>"', //版本描述
|
||||
filePath:'https://ybl2112.oss-cn-beijing.aliyuncs.com/2025/JANUARY/2/19/4/877e449c-3c0d-4630-a304-91ec110499f2.png', //文件路径
|
||||
fileName:'文件名称其实是个图片', //文件名称
|
||||
imagePaths:'https://ybl2112.oss-cn-beijing.aliyuncs.com/2025/JANUARY/2/19/4/877e449c-3c0d-4630-a304-91ec110499f2.png,https://ybl2112.oss-cn-beijing.aliyuncs.com/2025/JANUARY/2/19/4/877e449c-3c0d-4630-a304-91ec110499f2.png,https://ybl2112.oss-cn-beijing.aliyuncs.com/2025/JANUARY/2/19/4/877e449c-3c0d-4630-a304-91ec110499f2.png', //第三部的图片路径最多20张,切割
|
||||
hideGenInfo:0, //是否隐藏生成信息 0隐藏 1不隐藏
|
||||
}
|
||||
]
|
||||
}
|
||||
const res = await request.post("/WorkFlow/addWorkFlow", params);
|
||||
}catch (error) {
|
||||
console.log(error);
|
||||
import EditVersion from '@/components/publishWorkFlow/EditVersion.vue'
|
||||
import EditWorkFlow from '@/components/publishWorkFlow/EditWorkFlow.vue'
|
||||
import UploadImg from '@/components/publishWorkFlow/UploadImg.vue'
|
||||
import { CirclePlus } from 'lucide-vue-next'
|
||||
import { NConfigProvider, NMessageProvider } from 'naive-ui'
|
||||
import { useRoute } from 'vue-router'
|
||||
// definePageMeta({
|
||||
// middleware: [
|
||||
// function (to, from) {
|
||||
// initFormData(to.query.type)
|
||||
// },
|
||||
// ],
|
||||
// })
|
||||
const route = useRoute()
|
||||
const { type, id } = route.query
|
||||
|
||||
const formData = ref()
|
||||
|
||||
async function initFormData() {
|
||||
if (type === 'add') {
|
||||
formData.value = {
|
||||
workFlow: {
|
||||
jurisdiction: 1, // auditStatus (0全部状态 1已发布-公开 2已发布-仅自己可见 3审核中 4审核未通过)
|
||||
original: 0, // original 0原创 1转载
|
||||
onlineUse: 0, // 是否允许在线使用(0允许 1不允许)
|
||||
download: 0, // 是否允许下载工作流(0允许 1不允许)
|
||||
sell: 1, // 是否允许出售或商用(0允许 1不允许)
|
||||
typeList: [],
|
||||
},
|
||||
workFlowVersionList: [
|
||||
{
|
||||
versionName: '',
|
||||
hideGenInfo: 0, // 是否隐藏图片生成信息
|
||||
versionDescription: '', // 富文本
|
||||
filePath: '', // 文件路径
|
||||
fileName: '', // 文件名
|
||||
delFlag: '0', // 是否删除 0存在 2删除
|
||||
imagePaths: [],
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
// const handleValidateButtonClick = (e: MouseEvent) => {
|
||||
// e.preventDefault();
|
||||
// formRef.value?.validate((errors) => {
|
||||
// if (!errors) {
|
||||
// message.success("验证成功");
|
||||
// } else {
|
||||
// console.log(errors);
|
||||
// message.error("验证失败");
|
||||
// }
|
||||
// });
|
||||
// };
|
||||
|
||||
const modelPartCategory = ref([]); //垂类一级
|
||||
const modelChildCategory = ref([]); //垂类一级
|
||||
const workFlowFunctions = ref([]); //垂类一级
|
||||
|
||||
const getDictType = async() => {
|
||||
// model_part_category:[], //垂类一级
|
||||
// model_child_category:[], //垂类二级
|
||||
// work_flow_functions:[], //功能
|
||||
try {
|
||||
const [res1, res2, res3, res4] = await Promise.all([
|
||||
commonApi.dictType({ type: "model_part_category" }),
|
||||
commonApi.dictType({ type: "model_child_category" }),
|
||||
commonApi.dictType({ type: "work_flow_functions" }),
|
||||
commonApi.dictType({ type: "work_flow_style" }), //风格
|
||||
]);
|
||||
|
||||
modelPartCategory.value = res1.data;
|
||||
modelChildCategory.value = res2.data;
|
||||
workFlowFunctions.value = res3.data;
|
||||
let categoryList = modelPartCategory;
|
||||
// 遍历第一个数据数组,检查是否有子项
|
||||
categoryList.value.forEach((item) => {
|
||||
// 给每个对象添加一个children属性,初始化为空数组
|
||||
item.children = [];
|
||||
// 遍历第二个数据数组
|
||||
modelChildCategory.value.forEach((child) => {
|
||||
// 检查parentId是否与dictValue相等
|
||||
if (child.partId === item.dictCode) {
|
||||
// 将符合条件的子项放入children数组中
|
||||
item.children.push(child);
|
||||
}
|
||||
});
|
||||
});
|
||||
categoryList = categoryList;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
};
|
||||
getDictType()
|
||||
else {
|
||||
// type参数 1翻译
|
||||
try {
|
||||
const res = await request.get(`/WorkFlow/selectWorkFlowVersionById?id=${id}`)
|
||||
formData.value = res.data
|
||||
if (formData.value.workFlow.type) {
|
||||
formData.value.workFlow.typeList = formData.value.workFlow.type.split(',')
|
||||
}
|
||||
else {
|
||||
formData.value.workFlow.typeList = []
|
||||
}
|
||||
if (formData.value.workFlow.activityParticipation) {
|
||||
formData.value.workFlow.activityParticipation = Number(formData.value.workFlow.activityParticipation)
|
||||
}
|
||||
for (let i = 0; i < formData.value.workFlowVersionList.length; i++) {
|
||||
if (formData.value.workFlowVersionList[i].imagePaths) {
|
||||
formData.value.workFlowVersionList[i].imagePaths = formData.value.workFlowVersionList[i].imagePaths.split(',')
|
||||
}
|
||||
}
|
||||
// else {
|
||||
// formData.value.workFlow.activityParticipationList = []
|
||||
// }
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
initFormData()
|
||||
const EditVersionRef = ref()
|
||||
const currentStep = ref(1)
|
||||
|
||||
function handleAddVersion() {
|
||||
EditVersionRef.value.addVersion()
|
||||
}
|
||||
function nextStep() {
|
||||
currentStep.value += 1
|
||||
}
|
||||
function preStep() {
|
||||
currentStep.value -= 1
|
||||
}
|
||||
const timeLineList = ref([
|
||||
{
|
||||
name: '创建模版',
|
||||
index: 1,
|
||||
},
|
||||
{
|
||||
name: '编辑版本',
|
||||
index: 2,
|
||||
},
|
||||
{
|
||||
name: '上传图片',
|
||||
index: 3,
|
||||
},
|
||||
])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="mx-auto py-6">
|
||||
<div class="mx-auto flex justify-center">
|
||||
<div class="form-container mx-auto">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="w-[60%]">
|
||||
<TimeLine :time-line-list="timeLineList" :current-step="currentStep" />
|
||||
</div>
|
||||
<div v-if="currentStep === 2" class="cursor-pointer flex items-center justify-center rounded-full border border-solid border-[#000] px-4 py-1" @click="handleAddVersion">
|
||||
<CirclePlus class="mr-2" />
|
||||
添加版本
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<NConfigProvider>
|
||||
<NMessageProvider>
|
||||
<div v-if="currentStep === 1" class="first-step mx-auto">
|
||||
<EditWorkFlow v-model="formData" @next-step="nextStep" />
|
||||
</div>
|
||||
<div v-if="currentStep === 2" class="second-step">
|
||||
<EditVersion ref="EditVersionRef" v-model="formData" @pre-step="preStep" @next-step="nextStep" />
|
||||
</div>
|
||||
|
||||
<div v-if="currentStep === 3" class="third-step">
|
||||
<UploadImg v-model="formData" @pre-step="preStep" />
|
||||
</div>
|
||||
</NMessageProvider>
|
||||
</NConfigProvider>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import defaultAvatar from '@/assets/img/default-avatar.png'
|
||||
import { Heart, PersonAddOutline } from '@vicons/ionicons5'
|
||||
|
||||
import {
|
||||
CircleUser,
|
||||
Download,
|
||||
|
@ -7,19 +8,26 @@ import {
|
|||
HardDriveUpload,
|
||||
Play,
|
||||
} from 'lucide-vue-next'
|
||||
import { NConfigProvider, NMessageProvider } from 'naive-ui'
|
||||
import { nextTick, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const message = useMessage()
|
||||
|
||||
const router = useRouter()
|
||||
// 用于版本tabs当前选中的选项卡
|
||||
definePageMeta({
|
||||
layout: 'default',
|
||||
})
|
||||
const userStore = useUserStore()
|
||||
// const userStore = useUserStore()
|
||||
const route = useRoute()
|
||||
const { id } = route.params as { id: string }
|
||||
const activeTab = ref(null)
|
||||
|
||||
const commentHeight = ref(800)
|
||||
const detailsInfo = ref({})
|
||||
// 版本信息
|
||||
const currentUserInfo = ref<any>({})
|
||||
|
||||
// 先获取用户信息 再获取版本信息
|
||||
const versionByWorkInfo = ref([])
|
||||
async function getInfo() {
|
||||
try {
|
||||
|
@ -27,18 +35,34 @@ async function getInfo() {
|
|||
if (res.code === 200) {
|
||||
detailsInfo.value = res.data
|
||||
// 1翻译
|
||||
const res1 = await request.get(
|
||||
`/WorkFlowVersion/selectVersionByWorkId?workId=${res.data.id}`,
|
||||
)
|
||||
if (res1.code === 200 && res1.data.length > 0) {
|
||||
versionByWorkInfo.value = res1.data
|
||||
versionByWorkInfo.value.forEach((item) => {
|
||||
item.imagePathsList = item.imagePaths.split(',')
|
||||
})
|
||||
nextTick(() => {
|
||||
activeTab.value = versionByWorkInfo.value[0].id
|
||||
})
|
||||
const commentRes = await request.get(`/WorkFlowComment/comment/${res.data.id}`)
|
||||
try {
|
||||
const res1 = await request.get(
|
||||
`/WorkFlowVersion/selectVersionByWorkId?workId=${res.data.id}`, // 获取版本
|
||||
)
|
||||
if (res1.code === 200 && res1.data.length > 0) {
|
||||
versionByWorkInfo.value = res1.data
|
||||
versionByWorkInfo.value.forEach((item) => {
|
||||
item.imagePathsList = item.imagePaths.split(',')
|
||||
})
|
||||
nextTick(() => {
|
||||
activeTab.value = versionByWorkInfo.value[0].id
|
||||
})
|
||||
// const commentRes = await request.get(`/WorkFlowComment/comment/${res.data.id}`)
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
|
||||
// 获取当前作品的用户信息
|
||||
try {
|
||||
const res = await request.get(`/system/user/selectUserById?id=${detailsInfo.value.userId}`)
|
||||
if (res.code === 200) {
|
||||
currentUserInfo.value = res.data
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -76,32 +100,80 @@ async function getAttention() {
|
|||
}
|
||||
getAttention()
|
||||
|
||||
function handleSelect(event: Event, id: string) {
|
||||
// 举报/编辑/删除
|
||||
const isDelete = ref(false)
|
||||
async function handleSelect(event: Event, type: string) {
|
||||
event.stopPropagation() // 阻止事件冒泡
|
||||
|
||||
console.log(id)
|
||||
if (type === 'report') {
|
||||
await request.get(`/WorkFlow/report?id=${id}`) // 举报
|
||||
}
|
||||
else if (type === 'edit') {
|
||||
router.push({
|
||||
path: `/publish-workflow`,
|
||||
query: {
|
||||
type: 'edit',
|
||||
id: detailsInfo.value.id,
|
||||
},
|
||||
})
|
||||
}
|
||||
else {
|
||||
isDelete.value = true
|
||||
}
|
||||
}
|
||||
// async function getAttention() {
|
||||
// try {
|
||||
// const res = await request.get("/WorkFlowComment/comment/{modelId}");
|
||||
// if (res.code === 200) {
|
||||
// selectUserInfo.value = res.data;
|
||||
// }
|
||||
// } catch (err) {
|
||||
// console.log(err);
|
||||
// }
|
||||
// }
|
||||
// getAttention();
|
||||
|
||||
// async function getVersionByWork() {
|
||||
// try {
|
||||
// if (res.code === 200) {
|
||||
// }
|
||||
// } catch (err) {
|
||||
// console.log(err);
|
||||
// }
|
||||
// }
|
||||
// getVersionByWork();
|
||||
// 删除
|
||||
async function onDelete() {
|
||||
try {
|
||||
const res = await request.get(`/WorkFlow/deleteWorkFlow?id=${detailsInfo.value.id}`)
|
||||
if (res.code === 200) {
|
||||
message.success('删除成功')
|
||||
isDelete.value = false
|
||||
router.push('/personal-center')
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
|
||||
// 关注用户/取消关注
|
||||
async function onChangeAttention() {
|
||||
try {
|
||||
const res = await request.get(`/attention/addAttention?userId=${detailsInfo.value.userId}`)
|
||||
if (res.code === 200) {
|
||||
if (res.data) {
|
||||
detailsInfo.value.isAttention = 1
|
||||
message.success('关注成功')
|
||||
}
|
||||
else {
|
||||
detailsInfo.value.isAttention = 0
|
||||
message.success('取消关注成功')
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
|
||||
// 点赞
|
||||
async function onLike() {
|
||||
try {
|
||||
const res = await request.get(`/WorkFlowComment/like?workFlowId=${detailsInfo.value.id}`)
|
||||
if (res.code === 200) {
|
||||
detailsInfo.value.isLike === 0 ? detailsInfo.value.isLike = 1 : detailsInfo.value.isLike = 0
|
||||
if (detailsInfo.value.isLike === 0) {
|
||||
message.success('取消点赞成功')
|
||||
}
|
||||
else {
|
||||
message.success('点赞成功')
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -148,7 +220,7 @@ function handleSelect(event: Event, id: string) {
|
|||
|
||||
<div class="flex items-center mt-3 mb-5">
|
||||
<div
|
||||
v-for="(item, index) in detailsInfo.styleList"
|
||||
v-for="(item, index) in detailsInfo.typeList"
|
||||
:key="index"
|
||||
class="text-[12px] bg-[#ebf2fe] p-1 px-2 text-[#557abf] mr-4 rounded-md"
|
||||
>
|
||||
|
@ -168,8 +240,8 @@ function handleSelect(event: Event, id: string) {
|
|||
<!-- 显示最后一步上传图片的图片 -->
|
||||
<div class="grid grid-cols-2 gap-2.5 box-border">
|
||||
<img
|
||||
v-for="(subItem, index) in item.imagePathsList"
|
||||
:key="index"
|
||||
v-for="(subItem, subIndex) in item.imagePathsList"
|
||||
:key="subIndex"
|
||||
:src="subItem"
|
||||
class="w-full h-[300px]"
|
||||
alt=""
|
||||
|
@ -186,12 +258,21 @@ function handleSelect(event: Event, id: string) {
|
|||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<div style="padding: 20px">
|
||||
<NConfigProvider>
|
||||
<NMessageProvider>
|
||||
<BaseComment v-if="detailsInfo.id" type="workflow" :height="commentHeight" :details-info="detailsInfo" />
|
||||
</NMessageProvider>
|
||||
</NConfigProvider>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-1/3 mt-3">
|
||||
<div
|
||||
class="flex justify-between text-[#a3a1a1] text-[12px] items-center -ml-60"
|
||||
>
|
||||
<div class="flexm justify-end">
|
||||
<div class="flex justify-end">
|
||||
<div v-if="detailsInfo.createTime" class="mr-2">
|
||||
首发时间{{ detailsInfo.createTime }}
|
||||
</div>
|
||||
|
@ -201,11 +282,14 @@ function handleSelect(event: Event, id: string) {
|
|||
</div>
|
||||
|
||||
<div class="flex items-center relative">
|
||||
<img
|
||||
<!-- <img
|
||||
src="@/assets/img/heart.png"
|
||||
class="w-[14px] h-[14px] cursor-pointer"
|
||||
alt=""
|
||||
>
|
||||
> -->
|
||||
<n-icon size="20" :color="detailsInfo.isLike === 0 ? '#ccc' : '#ff0000'" @click="onLike">
|
||||
<Heart class="cursor-pointer" />
|
||||
</n-icon>
|
||||
<div class="group relative">
|
||||
<component
|
||||
:is="EllipsisVertical"
|
||||
|
@ -244,24 +328,33 @@ function handleSelect(event: Event, id: string) {
|
|||
class="w-full h-full mr-2 block"
|
||||
round
|
||||
size="small"
|
||||
:src="
|
||||
userStore.userInfo && userStore.userInfo.avatar
|
||||
? userStore.userInfo.avatar
|
||||
: defaultAvatar
|
||||
"
|
||||
:src="currentUserInfo.avatar"
|
||||
/>
|
||||
</client-only>
|
||||
</div>
|
||||
<div>
|
||||
<client-only>
|
||||
<div class="text[20px] font-bold">
|
||||
{{ userStore.userInfo.nickName }}
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex-1">
|
||||
<client-only>
|
||||
<div class="text[20px] font-bold">
|
||||
{{ currentUserInfo.nickName }}
|
||||
</div>
|
||||
</client-only>
|
||||
<!-- 0代表原创 1代表转载 -->
|
||||
<div v-if="detailsInfo.original === 0" class="text-[14px]">
|
||||
原创作者
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1 flex justify-end">
|
||||
<div class="flex items-center font-bold px-1 justify-center w-24 h-10 rounded-full text-[#426af7] border-2 border-[#426af7] border-solid cursor-pointer" @click="onChangeAttention">
|
||||
<n-icon v-if="detailsInfo.isAttention === 0" size="20" class="mr-2">
|
||||
<PersonAddOutline />
|
||||
</n-icon>
|
||||
{{ detailsInfo.isAttention === 1 ? '已关注' : '关注' }}
|
||||
</div>
|
||||
</div>
|
||||
</client-only>
|
||||
<!-- 0代表原创 1代表转载 -->
|
||||
<div v-if="detailsInfo.original === 0" class="text-[14px]">
|
||||
原创作者
|
||||
</div>
|
||||
|
||||
<div class="flex items-center text-[#969798]">
|
||||
<component
|
||||
:is="CircleUser"
|
||||
|
@ -313,7 +406,17 @@ function handleSelect(event: Event, id: string) {
|
|||
下载客户端
|
||||
</span>
|
||||
</div> -->
|
||||
|
||||
<n-modal
|
||||
v-model:show="isDelete"
|
||||
:mask-closable="false"
|
||||
preset="dialog"
|
||||
title="提示!"
|
||||
content="确定要将模型删除? 模型删除后无法找回"
|
||||
negative-text="取消"
|
||||
positive-text="确认"
|
||||
@negative-click="onDelete"
|
||||
@positive-click="onDelete"
|
||||
/>
|
||||
<div />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
|
||||
|
||||
export default defineNuxtPlugin((nuxt) => {
|
||||
nuxt.vueApp.component('WeEditor', Editor)
|
||||
nuxt.vueApp.component('WeToolbar', Toolbar)
|
||||
})
|
|
@ -1,5 +1,7 @@
|
|||
import defaultAvatar from '@/assets/img/default-avatar.png'
|
||||
// stores/user.ts
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
import { ref } from 'vue'
|
||||
import {
|
||||
parse,
|
||||
|
@ -32,6 +34,7 @@ export const useUserStore = defineStore('user', () => {
|
|||
token: token.value,
|
||||
})
|
||||
if (res.code === 200) {
|
||||
res.data.avatar = res.data.avatar || defaultAvatar
|
||||
setUserInfo(res.data)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import type { ApiResponse } from '~/types/api'
|
|||
* @returns {Promise<{ success: boolean, message: string, data: any[] }>} - 返回上传结果
|
||||
*/
|
||||
|
||||
export async function uploadImagesInBatches(files, batchSize = 3) {
|
||||
export async function uploadImagesInBatches(files: File[], batchSize = 3) {
|
||||
const uploadResults = []
|
||||
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
|
@ -20,13 +20,15 @@ export async function uploadImagesInBatches(files, batchSize = 3) {
|
|||
|
||||
// 上传当前图片
|
||||
try {
|
||||
const res = await request.post<ApiResponse<{ url: string }>>('/model/file', formData, {
|
||||
const res = await request.post<ApiResponse<{ url: string }>>('/file/imgUpload', formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
})
|
||||
// const res = await mallProductFile(formData)
|
||||
uploadResults.push(res.data)
|
||||
if (res && res.code === 200) {
|
||||
uploadResults.push(res.data)
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.error(`图片上传失败: ${file.name}`, error)
|
||||
|
@ -35,3 +37,31 @@ export async function uploadImagesInBatches(files, batchSize = 3) {
|
|||
}
|
||||
return uploadResults
|
||||
}
|
||||
|
||||
export async function uploadFileBatches(files, batchSize = 3) {
|
||||
const uploadResults = []
|
||||
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i]
|
||||
|
||||
// 创建 FormData 对象
|
||||
const formData = new FormData()
|
||||
formData.append('file', file) // 假设后端接收字段是 `file`
|
||||
|
||||
// 上传当前图片
|
||||
try {
|
||||
const res = await request.post<ApiResponse<{ url: string }>>('/file/fileUpload', formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
})
|
||||
// const res = await mallProductFile(formData)
|
||||
uploadResults.push(res.data)
|
||||
}
|
||||
catch (error) {
|
||||
console.error(`文件上传失败: ${file.name}`, error)
|
||||
uploadResults.push({ success: false, error })
|
||||
}
|
||||
}
|
||||
return uploadResults
|
||||
}
|
||||
|
|
|
@ -83,9 +83,10 @@ export default defineNuxtConfig({
|
|||
nitro: {
|
||||
devProxy: {
|
||||
'/api': {
|
||||
// target: 'http://1.13.246.108:8080', 线上
|
||||
// target: 'http://192.168.2.22:8080', // 代
|
||||
target: 'http://192.168.1.69:8080', // 嗨
|
||||
// target: 'http://1.13.246.108:8080', // 线上
|
||||
target: 'http://192.168.2.10:8080', // 代
|
||||
// target: 'http://192.168.1.69:8080', // 嗨
|
||||
// target: 'https://2d1a399f.r27.cpolar.top', // 嗨
|
||||
changeOrigin: true,
|
||||
prependPath: true,
|
||||
},
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@vicons/ionicons5": "^0.13.0",
|
||||
"@wangeditor/editor": "^5.1.12",
|
||||
"@wangeditor/editor-for-vue": "^5.1.12",
|
||||
"axios": "^1.7.9",
|
||||
"date-fns-tz": "^3.2.0",
|
||||
|
|
423
pnpm-lock.yaml
423
pnpm-lock.yaml
|
@ -13,9 +13,12 @@ dependencies:
|
|||
'@vicons/ionicons5':
|
||||
specifier: ^0.13.0
|
||||
version: 0.13.0
|
||||
'@wangeditor/editor':
|
||||
specifier: ^5.1.12
|
||||
version: 5.1.23
|
||||
'@wangeditor/editor-for-vue':
|
||||
specifier: ^5.1.12
|
||||
version: 5.1.12
|
||||
version: 5.1.12(@wangeditor/editor@5.1.23)
|
||||
axios:
|
||||
specifier: ^1.7.9
|
||||
version: 1.7.9
|
||||
|
@ -3022,6 +3025,10 @@ packages:
|
|||
string.prototype.matchall: 4.0.12
|
||||
dev: true
|
||||
|
||||
/@transloadit/prettier-bytes@0.0.7:
|
||||
resolution: {integrity: sha512-VeJbUb0wEKbcwaSlj5n+LscBl9IPgLPkHVGBkh00cztv6X4L/TJXK58LzFuBKX7/GAfiGhIwH67YTLTlzvIzBA==}
|
||||
dev: false
|
||||
|
||||
/@trysound/sax@0.2.0:
|
||||
resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
|
@ -3051,6 +3058,10 @@ packages:
|
|||
/@types/estree@1.0.6:
|
||||
resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==}
|
||||
|
||||
/@types/event-emitter@0.3.5:
|
||||
resolution: {integrity: sha512-zx2/Gg0Eg7gwEiOIIh5w9TrhKKTeQh7CPCOPNc0el4pLSwzebA8SmnHwZs2dWlLONvyulykSwGSQxQHLhjGLvQ==}
|
||||
dev: false
|
||||
|
||||
/@types/http-proxy@1.17.15:
|
||||
resolution: {integrity: sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==}
|
||||
dependencies:
|
||||
|
@ -3271,6 +3282,47 @@ packages:
|
|||
vue: 3.5.13(typescript@5.7.3)
|
||||
dev: true
|
||||
|
||||
/@uppy/companion-client@2.2.2:
|
||||
resolution: {integrity: sha512-5mTp2iq97/mYSisMaBtFRry6PTgZA6SIL7LePteOV5x0/DxKfrZW3DEiQERJmYpHzy7k8johpm2gHnEKto56Og==}
|
||||
dependencies:
|
||||
'@uppy/utils': 4.1.3
|
||||
namespace-emitter: 2.0.1
|
||||
dev: false
|
||||
|
||||
/@uppy/core@2.3.4:
|
||||
resolution: {integrity: sha512-iWAqppC8FD8mMVqewavCz+TNaet6HPXitmGXpGGREGrakZ4FeuWytVdrelydzTdXx6vVKkOmI2FLztGg73sENQ==}
|
||||
dependencies:
|
||||
'@transloadit/prettier-bytes': 0.0.7
|
||||
'@uppy/store-default': 2.1.1
|
||||
'@uppy/utils': 4.1.3
|
||||
lodash.throttle: 4.1.1
|
||||
mime-match: 1.0.2
|
||||
namespace-emitter: 2.0.1
|
||||
nanoid: 3.3.8
|
||||
preact: 10.25.4
|
||||
dev: false
|
||||
|
||||
/@uppy/store-default@2.1.1:
|
||||
resolution: {integrity: sha512-xnpTxvot2SeAwGwbvmJ899ASk5tYXhmZzD/aCFsXePh/v8rNvR2pKlcQUH7cF/y4baUGq3FHO/daKCok/mpKqQ==}
|
||||
dev: false
|
||||
|
||||
/@uppy/utils@4.1.3:
|
||||
resolution: {integrity: sha512-nTuMvwWYobnJcytDO3t+D6IkVq/Qs4Xv3vyoEZ+Iaf8gegZP+rEyoaFT2CK5XLRMienPyqRqNbIfRuFaOWSIFw==}
|
||||
dependencies:
|
||||
lodash.throttle: 4.1.1
|
||||
dev: false
|
||||
|
||||
/@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4):
|
||||
resolution: {integrity: sha512-YWOQ6myBVPs+mhNjfdWsQyMRWUlrDLMoaG7nvf/G6Y3GKZf8AyjFDjvvJ49XWQ+DaZOftGkHmF1uh/DBeGivJQ==}
|
||||
peerDependencies:
|
||||
'@uppy/core': ^2.3.3
|
||||
dependencies:
|
||||
'@uppy/companion-client': 2.2.2
|
||||
'@uppy/core': 2.3.4
|
||||
'@uppy/utils': 4.1.3
|
||||
nanoid: 3.3.8
|
||||
dev: false
|
||||
|
||||
/@vercel/nft@0.27.10(rollup@4.34.0):
|
||||
resolution: {integrity: sha512-zbaF9Wp/NsZtKLE4uVmL3FyfFwlpDyuymQM1kPbeT0mVOHKDQQNjnnfslB3REg3oZprmNFJuh3pkHBk2qAaizg==}
|
||||
engines: {node: '>=16'}
|
||||
|
@ -3618,11 +3670,189 @@ packages:
|
|||
- typescript
|
||||
dev: true
|
||||
|
||||
/@wangeditor/editor-for-vue@5.1.12:
|
||||
/@wangeditor/basic-modules@1.1.7(@wangeditor/core@1.1.19)(dom7@3.0.0)(lodash.throttle@4.1.1)(nanoid@3.3.8)(slate@0.72.8)(snabbdom@3.6.2):
|
||||
resolution: {integrity: sha512-cY9CPkLJaqF05STqfpZKWG4LpxTMeGSIIF1fHvfm/mz+JXatCagjdkbxdikOuKYlxDdeqvOeBmsUBItufDLXZg==}
|
||||
peerDependencies:
|
||||
'@wangeditor/core': 1.x
|
||||
dom7: ^3.0.0
|
||||
lodash.throttle: ^4.1.1
|
||||
nanoid: ^3.2.0
|
||||
slate: ^0.72.0
|
||||
snabbdom: ^3.1.0
|
||||
dependencies:
|
||||
'@wangeditor/core': 1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3)(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.8)(slate@0.72.8)(snabbdom@3.6.2)
|
||||
dom7: 3.0.0
|
||||
is-url: 1.2.4
|
||||
lodash.throttle: 4.1.1
|
||||
nanoid: 3.3.8
|
||||
slate: 0.72.8
|
||||
snabbdom: 3.6.2
|
||||
dev: false
|
||||
|
||||
/@wangeditor/code-highlight@1.0.3(@wangeditor/core@1.1.19)(dom7@3.0.0)(slate@0.72.8)(snabbdom@3.6.2):
|
||||
resolution: {integrity: sha512-iazHwO14XpCuIWJNTQTikqUhGKyqj+dUNWJ9288Oym9M2xMVHvnsOmDU2sgUDWVy+pOLojReMPgXCsvvNlOOhw==}
|
||||
peerDependencies:
|
||||
'@wangeditor/core': 1.x
|
||||
dom7: ^3.0.0
|
||||
slate: ^0.72.0
|
||||
snabbdom: ^3.1.0
|
||||
dependencies:
|
||||
'@wangeditor/core': 1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3)(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.8)(slate@0.72.8)(snabbdom@3.6.2)
|
||||
dom7: 3.0.0
|
||||
prismjs: 1.29.0
|
||||
slate: 0.72.8
|
||||
snabbdom: 3.6.2
|
||||
dev: false
|
||||
|
||||
/@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3)(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.8)(slate@0.72.8)(snabbdom@3.6.2):
|
||||
resolution: {integrity: sha512-KevkB47+7GhVszyYF2pKGKtCSj/YzmClsD03C3zTt+9SR2XWT5T0e3yQqg8baZpcMvkjs1D8Dv4fk8ok/UaS2Q==}
|
||||
peerDependencies:
|
||||
'@uppy/core': ^2.1.1
|
||||
'@uppy/xhr-upload': ^2.0.3
|
||||
dom7: ^3.0.0
|
||||
is-hotkey: ^0.2.0
|
||||
lodash.camelcase: ^4.3.0
|
||||
lodash.clonedeep: ^4.5.0
|
||||
lodash.debounce: ^4.0.8
|
||||
lodash.foreach: ^4.5.0
|
||||
lodash.isequal: ^4.5.0
|
||||
lodash.throttle: ^4.1.1
|
||||
lodash.toarray: ^4.4.0
|
||||
nanoid: ^3.2.0
|
||||
slate: ^0.72.0
|
||||
snabbdom: ^3.1.0
|
||||
dependencies:
|
||||
'@types/event-emitter': 0.3.5
|
||||
'@uppy/core': 2.3.4
|
||||
'@uppy/xhr-upload': 2.1.3(@uppy/core@2.3.4)
|
||||
dom7: 3.0.0
|
||||
event-emitter: 0.3.5
|
||||
html-void-elements: 2.0.1
|
||||
i18next: 20.6.1
|
||||
is-hotkey: 0.2.0
|
||||
lodash.camelcase: 4.3.0
|
||||
lodash.clonedeep: 4.5.0
|
||||
lodash.debounce: 4.0.8
|
||||
lodash.foreach: 4.5.0
|
||||
lodash.isequal: 4.5.0
|
||||
lodash.throttle: 4.1.1
|
||||
lodash.toarray: 4.4.0
|
||||
nanoid: 3.3.8
|
||||
scroll-into-view-if-needed: 2.2.31
|
||||
slate: 0.72.8
|
||||
slate-history: 0.66.0(slate@0.72.8)
|
||||
snabbdom: 3.6.2
|
||||
dev: false
|
||||
|
||||
/@wangeditor/editor-for-vue@5.1.12(@wangeditor/editor@5.1.23):
|
||||
resolution: {integrity: sha512-0Ds3D8I+xnpNWezAeO7HmPRgTfUxHLMd9JKcIw+QzvSmhC5xUHbpCcLU+KLmeBKTR/zffnS5GQo6qi3GhTMJWQ==}
|
||||
peerDependencies:
|
||||
'@wangeditor/editor': '>=5.1.0'
|
||||
vue: ^3.0.5
|
||||
dependencies:
|
||||
'@wangeditor/editor': 5.1.23
|
||||
dev: false
|
||||
|
||||
/@wangeditor/editor@5.1.23:
|
||||
resolution: {integrity: sha512-0RxfeVTuK1tktUaPROnCoFfaHVJpRAIE2zdS0mpP+vq1axVQpLjM8+fCvKzqYIkH0Pg+C+44hJpe3VVroSkEuQ==}
|
||||
dependencies:
|
||||
'@uppy/core': 2.3.4
|
||||
'@uppy/xhr-upload': 2.1.3(@uppy/core@2.3.4)
|
||||
'@wangeditor/basic-modules': 1.1.7(@wangeditor/core@1.1.19)(dom7@3.0.0)(lodash.throttle@4.1.1)(nanoid@3.3.8)(slate@0.72.8)(snabbdom@3.6.2)
|
||||
'@wangeditor/code-highlight': 1.0.3(@wangeditor/core@1.1.19)(dom7@3.0.0)(slate@0.72.8)(snabbdom@3.6.2)
|
||||
'@wangeditor/core': 1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3)(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.8)(slate@0.72.8)(snabbdom@3.6.2)
|
||||
'@wangeditor/list-module': 1.0.5(@wangeditor/core@1.1.19)(dom7@3.0.0)(slate@0.72.8)(snabbdom@3.6.2)
|
||||
'@wangeditor/table-module': 1.1.4(@wangeditor/core@1.1.19)(dom7@3.0.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(nanoid@3.3.8)(slate@0.72.8)(snabbdom@3.6.2)
|
||||
'@wangeditor/upload-image-module': 1.0.2(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3)(@wangeditor/basic-modules@1.1.7)(@wangeditor/core@1.1.19)(dom7@3.0.0)(lodash.foreach@4.5.0)(slate@0.72.8)(snabbdom@3.6.2)
|
||||
'@wangeditor/video-module': 1.1.4(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3)(@wangeditor/core@1.1.19)(dom7@3.0.0)(nanoid@3.3.8)(slate@0.72.8)(snabbdom@3.6.2)
|
||||
dom7: 3.0.0
|
||||
is-hotkey: 0.2.0
|
||||
lodash.camelcase: 4.3.0
|
||||
lodash.clonedeep: 4.5.0
|
||||
lodash.debounce: 4.0.8
|
||||
lodash.foreach: 4.5.0
|
||||
lodash.isequal: 4.5.0
|
||||
lodash.throttle: 4.1.1
|
||||
lodash.toarray: 4.4.0
|
||||
nanoid: 3.3.8
|
||||
slate: 0.72.8
|
||||
snabbdom: 3.6.2
|
||||
dev: false
|
||||
|
||||
/@wangeditor/list-module@1.0.5(@wangeditor/core@1.1.19)(dom7@3.0.0)(slate@0.72.8)(snabbdom@3.6.2):
|
||||
resolution: {integrity: sha512-uDuYTP6DVhcYf7mF1pTlmNn5jOb4QtcVhYwSSAkyg09zqxI1qBqsfUnveeDeDqIuptSJhkh81cyxi+MF8sEPOQ==}
|
||||
peerDependencies:
|
||||
'@wangeditor/core': 1.x
|
||||
dom7: ^3.0.0
|
||||
slate: ^0.72.0
|
||||
snabbdom: ^3.1.0
|
||||
dependencies:
|
||||
'@wangeditor/core': 1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3)(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.8)(slate@0.72.8)(snabbdom@3.6.2)
|
||||
dom7: 3.0.0
|
||||
slate: 0.72.8
|
||||
snabbdom: 3.6.2
|
||||
dev: false
|
||||
|
||||
/@wangeditor/table-module@1.1.4(@wangeditor/core@1.1.19)(dom7@3.0.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(nanoid@3.3.8)(slate@0.72.8)(snabbdom@3.6.2):
|
||||
resolution: {integrity: sha512-5saanU9xuEocxaemGdNi9t8MCDSucnykEC6jtuiT72kt+/Hhh4nERYx1J20OPsTCCdVr7hIyQenFD1iSRkIQ6w==}
|
||||
peerDependencies:
|
||||
'@wangeditor/core': 1.x
|
||||
dom7: ^3.0.0
|
||||
lodash.isequal: ^4.5.0
|
||||
lodash.throttle: ^4.1.1
|
||||
nanoid: ^3.2.0
|
||||
slate: ^0.72.0
|
||||
snabbdom: ^3.1.0
|
||||
dependencies:
|
||||
'@wangeditor/core': 1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3)(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.8)(slate@0.72.8)(snabbdom@3.6.2)
|
||||
dom7: 3.0.0
|
||||
lodash.isequal: 4.5.0
|
||||
lodash.throttle: 4.1.1
|
||||
nanoid: 3.3.8
|
||||
slate: 0.72.8
|
||||
snabbdom: 3.6.2
|
||||
dev: false
|
||||
|
||||
/@wangeditor/upload-image-module@1.0.2(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3)(@wangeditor/basic-modules@1.1.7)(@wangeditor/core@1.1.19)(dom7@3.0.0)(lodash.foreach@4.5.0)(slate@0.72.8)(snabbdom@3.6.2):
|
||||
resolution: {integrity: sha512-z81lk/v71OwPDYeQDxj6cVr81aDP90aFuywb8nPD6eQeECtOymrqRODjpO6VGvCVxVck8nUxBHtbxKtjgcwyiA==}
|
||||
peerDependencies:
|
||||
'@uppy/core': ^2.0.3
|
||||
'@uppy/xhr-upload': ^2.0.3
|
||||
'@wangeditor/basic-modules': 1.x
|
||||
'@wangeditor/core': 1.x
|
||||
dom7: ^3.0.0
|
||||
lodash.foreach: ^4.5.0
|
||||
slate: ^0.72.0
|
||||
snabbdom: ^3.1.0
|
||||
dependencies:
|
||||
'@uppy/core': 2.3.4
|
||||
'@uppy/xhr-upload': 2.1.3(@uppy/core@2.3.4)
|
||||
'@wangeditor/basic-modules': 1.1.7(@wangeditor/core@1.1.19)(dom7@3.0.0)(lodash.throttle@4.1.1)(nanoid@3.3.8)(slate@0.72.8)(snabbdom@3.6.2)
|
||||
'@wangeditor/core': 1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3)(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.8)(slate@0.72.8)(snabbdom@3.6.2)
|
||||
dom7: 3.0.0
|
||||
lodash.foreach: 4.5.0
|
||||
slate: 0.72.8
|
||||
snabbdom: 3.6.2
|
||||
dev: false
|
||||
|
||||
/@wangeditor/video-module@1.1.4(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3)(@wangeditor/core@1.1.19)(dom7@3.0.0)(nanoid@3.3.8)(slate@0.72.8)(snabbdom@3.6.2):
|
||||
resolution: {integrity: sha512-ZdodDPqKQrgx3IwWu4ZiQmXI8EXZ3hm2/fM6E3t5dB8tCaIGWQZhmqd6P5knfkRAd3z2+YRSRbxOGfoRSp/rLg==}
|
||||
peerDependencies:
|
||||
'@uppy/core': ^2.1.4
|
||||
'@uppy/xhr-upload': ^2.0.7
|
||||
'@wangeditor/core': 1.x
|
||||
dom7: ^3.0.0
|
||||
nanoid: ^3.2.0
|
||||
slate: ^0.72.0
|
||||
snabbdom: ^3.1.0
|
||||
dependencies:
|
||||
'@uppy/core': 2.3.4
|
||||
'@uppy/xhr-upload': 2.1.3(@uppy/core@2.3.4)
|
||||
'@wangeditor/core': 1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3)(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.8)(slate@0.72.8)(snabbdom@3.6.2)
|
||||
dom7: 3.0.0
|
||||
nanoid: 3.3.8
|
||||
slate: 0.72.8
|
||||
snabbdom: 3.6.2
|
||||
dev: false
|
||||
|
||||
/abbrev@3.0.0:
|
||||
|
@ -4277,6 +4507,10 @@ packages:
|
|||
readable-stream: 4.7.0
|
||||
dev: true
|
||||
|
||||
/compute-scroll-into-view@1.0.20:
|
||||
resolution: {integrity: sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==}
|
||||
dev: false
|
||||
|
||||
/concat-map@0.0.1:
|
||||
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
|
||||
dev: true
|
||||
|
@ -4505,6 +4739,14 @@ packages:
|
|||
/csstype@3.1.3:
|
||||
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
|
||||
|
||||
/d@1.0.2:
|
||||
resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==}
|
||||
engines: {node: '>=0.12'}
|
||||
dependencies:
|
||||
es5-ext: 0.10.64
|
||||
type: 2.7.3
|
||||
dev: false
|
||||
|
||||
/data-view-buffer@1.0.2:
|
||||
resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
@ -4759,6 +5001,12 @@ packages:
|
|||
entities: 4.5.0
|
||||
dev: true
|
||||
|
||||
/dom7@3.0.0:
|
||||
resolution: {integrity: sha512-oNlcUdHsC4zb7Msx7JN3K0Nro1dzJ48knvBOnDPKJ2GV9wl1i5vydJZUSyOfrkKFDZEud/jBsTk92S/VGSAe/g==}
|
||||
dependencies:
|
||||
ssr-window: 3.0.0
|
||||
dev: false
|
||||
|
||||
/domelementtype@2.3.0:
|
||||
resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
|
||||
dev: true
|
||||
|
@ -4963,6 +5211,33 @@ packages:
|
|||
is-symbol: 1.1.1
|
||||
dev: true
|
||||
|
||||
/es5-ext@0.10.64:
|
||||
resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==}
|
||||
engines: {node: '>=0.10'}
|
||||
requiresBuild: true
|
||||
dependencies:
|
||||
es6-iterator: 2.0.3
|
||||
es6-symbol: 3.1.4
|
||||
esniff: 2.0.1
|
||||
next-tick: 1.1.0
|
||||
dev: false
|
||||
|
||||
/es6-iterator@2.0.3:
|
||||
resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==}
|
||||
dependencies:
|
||||
d: 1.0.2
|
||||
es5-ext: 0.10.64
|
||||
es6-symbol: 3.1.4
|
||||
dev: false
|
||||
|
||||
/es6-symbol@3.1.4:
|
||||
resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==}
|
||||
engines: {node: '>=0.12'}
|
||||
dependencies:
|
||||
d: 1.0.2
|
||||
ext: 1.7.0
|
||||
dev: false
|
||||
|
||||
/esbuild@0.24.2:
|
||||
resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==}
|
||||
engines: {node: '>=18'}
|
||||
|
@ -5460,6 +5735,16 @@ packages:
|
|||
- supports-color
|
||||
dev: true
|
||||
|
||||
/esniff@2.0.1:
|
||||
resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==}
|
||||
engines: {node: '>=0.10'}
|
||||
dependencies:
|
||||
d: 1.0.2
|
||||
es5-ext: 0.10.64
|
||||
event-emitter: 0.3.5
|
||||
type: 2.7.3
|
||||
dev: false
|
||||
|
||||
/espree@10.3.0:
|
||||
resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
@ -5519,6 +5804,13 @@ packages:
|
|||
engines: {node: '>= 0.6'}
|
||||
dev: true
|
||||
|
||||
/event-emitter@0.3.5:
|
||||
resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==}
|
||||
dependencies:
|
||||
d: 1.0.2
|
||||
es5-ext: 0.10.64
|
||||
dev: false
|
||||
|
||||
/event-target-shim@5.0.1:
|
||||
resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
@ -5562,6 +5854,12 @@ packages:
|
|||
strip-final-newline: 3.0.0
|
||||
dev: true
|
||||
|
||||
/ext@1.7.0:
|
||||
resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==}
|
||||
dependencies:
|
||||
type: 2.7.3
|
||||
dev: false
|
||||
|
||||
/externality@1.0.2:
|
||||
resolution: {integrity: sha512-LyExtJWKxtgVzmgtEHyQtLFpw1KFhQphF9nTG8TpAIVkiI/xQ3FJh75tRFLYl4hkn7BNIIdLJInuDAavX35pMw==}
|
||||
dependencies:
|
||||
|
@ -6075,6 +6373,10 @@ packages:
|
|||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/html-void-elements@2.0.1:
|
||||
resolution: {integrity: sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==}
|
||||
dev: false
|
||||
|
||||
/http-assert@1.5.0:
|
||||
resolution: {integrity: sha512-uPpH7OKX4H25hBmU6G1jWNaqJGpTXxey+YOUizJUAgu0AjLUeC8D73hTrhvDS5D+GJN1DN1+hhc/eF/wpxtp0w==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
@ -6144,6 +6446,12 @@ packages:
|
|||
engines: {node: '>=16.17.0'}
|
||||
dev: true
|
||||
|
||||
/i18next@20.6.1:
|
||||
resolution: {integrity: sha512-yCMYTMEJ9ihCwEQQ3phLo7I/Pwycf8uAx+sRHwwk5U9Aui/IZYgQRyMqXafQOw5QQ7DM1Z+WyEXWIqSuJHhG2A==}
|
||||
dependencies:
|
||||
'@babel/runtime': 7.26.7
|
||||
dev: false
|
||||
|
||||
/idb@7.1.1:
|
||||
resolution: {integrity: sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==}
|
||||
dev: true
|
||||
|
@ -6164,6 +6472,10 @@ packages:
|
|||
resolution: {integrity: sha512-K6acvFaelNxx8wc2VjbIzXKDVB0Khs0QT35U6NkGfTdCmjLNcO2945m7RFNR9/RPVFm48hq7QPzK8uGH18HCGw==}
|
||||
dev: true
|
||||
|
||||
/immer@9.0.21:
|
||||
resolution: {integrity: sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==}
|
||||
dev: false
|
||||
|
||||
/immutable@5.0.3:
|
||||
resolution: {integrity: sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==}
|
||||
dev: true
|
||||
|
@ -6384,6 +6696,10 @@ packages:
|
|||
dependencies:
|
||||
is-extglob: 2.1.1
|
||||
|
||||
/is-hotkey@0.2.0:
|
||||
resolution: {integrity: sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw==}
|
||||
dev: false
|
||||
|
||||
/is-inside-container@1.0.0:
|
||||
resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==}
|
||||
engines: {node: '>=14.16'}
|
||||
|
@ -6431,6 +6747,11 @@ packages:
|
|||
engines: {node: '>=12'}
|
||||
dev: true
|
||||
|
||||
/is-plain-object@5.0.0:
|
||||
resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: false
|
||||
|
||||
/is-reference@1.2.1:
|
||||
resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==}
|
||||
dependencies:
|
||||
|
@ -6504,6 +6825,10 @@ packages:
|
|||
which-typed-array: 1.1.18
|
||||
dev: true
|
||||
|
||||
/is-url@1.2.4:
|
||||
resolution: {integrity: sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==}
|
||||
dev: false
|
||||
|
||||
/is-weakmap@2.0.2:
|
||||
resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
@ -6886,18 +7211,34 @@ packages:
|
|||
resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
|
||||
dev: false
|
||||
|
||||
/lodash.camelcase@4.3.0:
|
||||
resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==}
|
||||
dev: false
|
||||
|
||||
/lodash.clonedeep@4.5.0:
|
||||
resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==}
|
||||
dev: false
|
||||
|
||||
/lodash.debounce@4.0.8:
|
||||
resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
|
||||
dev: true
|
||||
|
||||
/lodash.defaults@4.2.0:
|
||||
resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==}
|
||||
dev: true
|
||||
|
||||
/lodash.foreach@4.5.0:
|
||||
resolution: {integrity: sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ==}
|
||||
dev: false
|
||||
|
||||
/lodash.isarguments@3.1.0:
|
||||
resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==}
|
||||
dev: true
|
||||
|
||||
/lodash.isequal@4.5.0:
|
||||
resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
|
||||
deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead.
|
||||
dev: false
|
||||
|
||||
/lodash.memoize@4.1.2:
|
||||
resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==}
|
||||
dev: true
|
||||
|
@ -6910,6 +7251,14 @@ packages:
|
|||
resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==}
|
||||
dev: true
|
||||
|
||||
/lodash.throttle@4.1.1:
|
||||
resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==}
|
||||
dev: false
|
||||
|
||||
/lodash.toarray@4.4.0:
|
||||
resolution: {integrity: sha512-QyffEA3i5dma5q2490+SgCvDN0pXLmRGSyAANuVi0HQ01Pkfr9fuoKQW8wm1wGBnJITs/mS7wQvS6VshUEBFCw==}
|
||||
dev: false
|
||||
|
||||
/lodash.uniq@4.5.0:
|
||||
resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==}
|
||||
dev: true
|
||||
|
@ -7378,6 +7727,12 @@ packages:
|
|||
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
/mime-match@1.0.2:
|
||||
resolution: {integrity: sha512-VXp/ugGDVh3eCLOBCiHZMYWQaTNUHv2IJrut+yXA6+JbLPXHglHwfS/5A5L0ll+jkCY7fIzRJcH6OIunF+c6Cg==}
|
||||
dependencies:
|
||||
wildcard: 1.1.2
|
||||
dev: false
|
||||
|
||||
/mime-types@2.1.35:
|
||||
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
@ -7546,11 +7901,14 @@ packages:
|
|||
vueuc: 0.4.64
|
||||
dev: false
|
||||
|
||||
/namespace-emitter@2.0.1:
|
||||
resolution: {integrity: sha512-N/sMKHniSDJBjfrkbS/tpkPj4RAbvW3mr8UAzvlMHyun93XEm83IAvhWtJVHo+RHn/oO8Job5YN4b+wRjSVp5g==}
|
||||
dev: false
|
||||
|
||||
/nanoid@3.3.8:
|
||||
resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==}
|
||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/nanoid@5.0.9:
|
||||
resolution: {integrity: sha512-Aooyr6MXU6HpvvWXKoVoXwKMs/KyVakWwg7xQfv5/S/RIgJMy0Ifa45H9qqYy7pTCszrHzP21Uk4PZq2HpEM8Q==}
|
||||
|
@ -7584,6 +7942,10 @@ packages:
|
|||
resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
|
||||
dev: true
|
||||
|
||||
/next-tick@1.1.0:
|
||||
resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==}
|
||||
dev: false
|
||||
|
||||
/nitropack@2.10.4(typescript@5.7.3):
|
||||
resolution: {integrity: sha512-sJiG/MIQlZCVSw2cQrFG1H6mLeSqHlYfFerRjLKz69vUfdu0EL2l0WdOxlQbzJr3mMv/l4cOlCCLzVRzjzzF/g==}
|
||||
engines: {node: ^16.11.0 || >=17.0.0}
|
||||
|
@ -8713,6 +9075,10 @@ packages:
|
|||
source-map-js: 1.2.1
|
||||
dev: true
|
||||
|
||||
/preact@10.25.4:
|
||||
resolution: {integrity: sha512-jLdZDb+Q+odkHJ+MpW/9U5cODzqnB+fy2EiHSZES7ldV5LK7yjlVzTp7R8Xy6W6y75kfK8iWYtFVH7lvjwrCMA==}
|
||||
dev: false
|
||||
|
||||
/prelude-ls@1.2.1:
|
||||
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
|
@ -8741,6 +9107,11 @@ packages:
|
|||
engines: {node: ^14.13.1 || >=16.0.0}
|
||||
dev: true
|
||||
|
||||
/prismjs@1.29.0:
|
||||
resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==}
|
||||
engines: {node: '>=6'}
|
||||
dev: false
|
||||
|
||||
/process-nextick-args@2.0.1:
|
||||
resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
|
||||
dev: true
|
||||
|
@ -9174,6 +9545,12 @@ packages:
|
|||
'@parcel/watcher': 2.5.1
|
||||
dev: true
|
||||
|
||||
/scroll-into-view-if-needed@2.2.31:
|
||||
resolution: {integrity: sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==}
|
||||
dependencies:
|
||||
compute-scroll-into-view: 1.0.20
|
||||
dev: false
|
||||
|
||||
/scslre@0.3.0:
|
||||
resolution: {integrity: sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==}
|
||||
engines: {node: ^14.0.0 || >=16.0.0}
|
||||
|
@ -9384,10 +9761,32 @@ packages:
|
|||
resolution: {integrity: sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA==}
|
||||
dev: true
|
||||
|
||||
/slate-history@0.66.0(slate@0.72.8):
|
||||
resolution: {integrity: sha512-6MWpxGQZiMvSINlCbMW43E2YBSVMCMCIwQfBzGssjWw4kb0qfvj0pIdblWNRQZD0hR6WHP+dHHgGSeVdMWzfng==}
|
||||
peerDependencies:
|
||||
slate: '>=0.65.3'
|
||||
dependencies:
|
||||
is-plain-object: 5.0.0
|
||||
slate: 0.72.8
|
||||
dev: false
|
||||
|
||||
/slate@0.72.8:
|
||||
resolution: {integrity: sha512-/nJwTswQgnRurpK+bGJFH1oM7naD5qDmHd89JyiKNT2oOKD8marW0QSBtuFnwEbL5aGCS8AmrhXQgNOsn4osAw==}
|
||||
dependencies:
|
||||
immer: 9.0.21
|
||||
is-plain-object: 5.0.0
|
||||
tiny-warning: 1.0.3
|
||||
dev: false
|
||||
|
||||
/smob@1.5.0:
|
||||
resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==}
|
||||
dev: true
|
||||
|
||||
/snabbdom@3.6.2:
|
||||
resolution: {integrity: sha512-ig5qOnCDbugFntKi6c7Xlib8bA6xiJVk8O+WdFrV3wxbMqeHO0hXFQC4nAhPVWfZfi8255lcZkNhtIBINCc4+Q==}
|
||||
engines: {node: '>=12.17.0'}
|
||||
dev: false
|
||||
|
||||
/source-map-js@1.2.1:
|
||||
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
@ -9455,6 +9854,10 @@ packages:
|
|||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/ssr-window@3.0.0:
|
||||
resolution: {integrity: sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA==}
|
||||
dev: false
|
||||
|
||||
/stable-hash@0.0.4:
|
||||
resolution: {integrity: sha512-LjdcbuBeLcdETCrPn9i8AYAZ1eCtu4ECAWtP7UleOiZ9LzVxRzzUZEoZ8zB24nhkQnDWyET0I+3sWokSDS3E7g==}
|
||||
dev: true
|
||||
|
@ -9844,6 +10247,10 @@ packages:
|
|||
resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
|
||||
dev: true
|
||||
|
||||
/tiny-warning@1.0.3:
|
||||
resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==}
|
||||
dev: false
|
||||
|
||||
/tinyexec@0.3.2:
|
||||
resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==}
|
||||
|
||||
|
@ -9958,6 +10365,10 @@ packages:
|
|||
mime-types: 2.1.35
|
||||
dev: true
|
||||
|
||||
/type@2.7.3:
|
||||
resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==}
|
||||
dev: false
|
||||
|
||||
/typed-array-buffer@1.0.3:
|
||||
resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
@ -10852,6 +11263,10 @@ packages:
|
|||
isexe: 2.0.0
|
||||
dev: true
|
||||
|
||||
/wildcard@1.1.2:
|
||||
resolution: {integrity: sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng==}
|
||||
dev: false
|
||||
|
||||
/word-wrap@1.2.5:
|
||||
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
|
Loading…
Reference in New Issue