项目相关功能完善

This commit is contained in:
2025-05-08 14:12:27 +08:00
parent 7cd1a58cac
commit ba19bdd984
6 changed files with 221 additions and 84 deletions

View File

@@ -27,6 +27,6 @@
"devDependencies": {
"@vitejs/plugin-vue": "^5.2.2",
"sass": "^1.71.0",
"vite": "^6.3.1"
"vite": "6.3.4"
}
}

22
pnpm-lock.yaml generated
View File

@@ -16,7 +16,7 @@ importers:
version: 7.0.1(vue@3.5.13)
'@tailwindcss/vite':
specifier: ^4.1.4
version: 4.1.4(vite@6.3.3(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0))
version: 4.1.4(vite@6.3.4(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0))
'@vueuse/head':
specifier: ^2.0.0
version: 2.0.0(vue@3.5.13)
@@ -53,13 +53,13 @@ importers:
devDependencies:
'@vitejs/plugin-vue':
specifier: ^5.2.2
version: 5.2.3(vite@6.3.3(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0))(vue@3.5.13)
version: 5.2.3(vite@6.3.4(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0))(vue@3.5.13)
sass:
specifier: ^1.71.0
version: 1.87.0
vite:
specifier: ^6.3.1
version: 6.3.3(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0)
specifier: 6.3.4
version: 6.3.4(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0)
packages:
@@ -1231,8 +1231,8 @@ packages:
unhead@1.11.20:
resolution: {integrity: sha512-3AsNQC0pjwlLqEYHLjtichGWankK8yqmocReITecmpB1H0aOabeESueyy+8X1gyJx4ftZVwo9hqQ4O3fPWffCA==}
vite@6.3.3:
resolution: {integrity: sha512-5nXH+QsELbFKhsEfWLkHrvgRpTdGJzqOZ+utSdmPTvwHmvU6ITTm3xx+mRusihkcI8GeC7lCDyn3kDtiki9scw==}
vite@6.3.4:
resolution: {integrity: sha512-BiReIiMS2fyFqbqNT/Qqt4CVITDU9M9vE+DKcVAsB+ZV0wvTKd+3hMbkpxz1b+NmEDMegpVbisKiAZOnvO92Sw==}
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
hasBin: true
peerDependencies:
@@ -1959,12 +1959,12 @@ snapshots:
'@tailwindcss/oxide-win32-arm64-msvc': 4.1.4
'@tailwindcss/oxide-win32-x64-msvc': 4.1.4
'@tailwindcss/vite@4.1.4(vite@6.3.3(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0))':
'@tailwindcss/vite@4.1.4(vite@6.3.4(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0))':
dependencies:
'@tailwindcss/node': 4.1.4
'@tailwindcss/oxide': 4.1.4
tailwindcss: 4.1.4
vite: 6.3.3(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0)
vite: 6.3.4(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0)
'@types/estree@1.0.7': {}
@@ -2009,9 +2009,9 @@ snapshots:
'@vavt/util@2.1.0': {}
'@vitejs/plugin-vue@5.2.3(vite@6.3.3(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0))(vue@3.5.13)':
'@vitejs/plugin-vue@5.2.3(vite@6.3.4(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0))(vue@3.5.13)':
dependencies:
vite: 6.3.3(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0)
vite: 6.3.4(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0)
vue: 3.5.13
'@vue/compiler-core@3.5.13':
@@ -2558,7 +2558,7 @@ snapshots:
'@unhead/shared': 1.11.20
hookable: 5.5.3
vite@6.3.3(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0):
vite@6.3.4(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0):
dependencies:
esbuild: 0.25.3
fdir: 6.4.4(picomatch@4.0.2)

View File

@@ -22,4 +22,7 @@ export function deleteProjectApi(credentials) {
}
export function changeContentProjectApi(credentials) {
return post(`${prefix}/change-content`, credentials)
}
export function changeTypeProjectApi(credentials) {
return post(`${prefix}/change-type`, credentials)
}

View File

@@ -196,7 +196,7 @@ const navigateTo = (path) => {
</div>
</template>
<style scoped>
<style>
/* 自定义样式 */
.admin-layout {
min-width: 100vh;
@@ -207,4 +207,26 @@ const navigateTo = (path) => {
button, a, [role="button"], .cursor-pointer {
cursor: pointer;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background-color: rgba(156, 163, 175, 0.5);
border-radius: 20px;
}
::-webkit-scrollbar-thumb:hover {
background-color: rgba(156, 163, 175, 0.7);
}
/* 暗黑模式滚动条 */
.dark ::-webkit-scrollbar-thumb {
background-color: rgba(75, 85, 99, 0.5);
}
.dark ::-webkit-scrollbar-thumb:hover {
background-color: rgba(75, 85, 99, 0.7);
}
</style>

View File

@@ -6,7 +6,7 @@ import {message, Upload, Select} from "ant-design-vue"
import {labelOptionApi} from "@/api/request/label.js";
import {categoryOptionApi} from "@/api/request/category.js";
import {
changeContentProjectApi,
changeContentProjectApi, changeTypeProjectApi,
createProjectApi,
deleteProjectApi,
projectDetailApi,
@@ -562,6 +562,17 @@ const handleMdImageUpload = async (
callback(urls);
};
const changeTypeProject = (id, type, index, feild) => {
changeTypeProjectApi({
id: id,
type: type
}).then((res) => {
message.success("操作成功")
console.log(paginatedData.value[index][feild])
paginatedData.value[index][feild] = paginatedData.value[index][feild] === 1 ? 0 : 1
})
}
</script>
<template>
@@ -604,6 +615,18 @@ const handleMdImageUpload = async (
class="px-6 py-3 text-left text-xs font-medium text-gray-700 dark:text-gray-300 uppercase tracking-wider">
价格
</th>
<th scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-700 dark:text-gray-300 uppercase tracking-wider">
出售
</th>
<th scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-700 dark:text-gray-300 uppercase tracking-wider">
精选
</th>
<th scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-700 dark:text-gray-300 uppercase tracking-wider">
轮播图
</th>
<th scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-700 dark:text-gray-300 uppercase tracking-wider">
状态
@@ -625,7 +648,7 @@ const handleMdImageUpload = async (
<!-- 表格内容 -->
<tbody class="bg-white dark:bg-gray-800 divide-y divide-gray-200 dark:divide-gray-700">
<tr v-for="item in paginatedData" :key="item.id"
<tr v-for="(item, index) in paginatedData" :key="item.id"
class="hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors">
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900 dark:text-white">
<div class="flex items-center space-x-3">
@@ -654,6 +677,45 @@ const handleMdImageUpload = async (
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900 dark:text-white">
{{ formatPrice(item.price) }}
</td>
<!-- 是否出售 -->
<td class="px-6 py-4 whitespace-nowrap">
<span
@click="changeTypeProject(item.id, 1, index, 'is_sold')"
:class="`px-2 py-1 text-xs font-medium rounded-full ${
item.is_sold === 1
? 'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-300'
: 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-300'
} cursor-pointer`"
>
{{ item.is_sold === 0 ? '非卖品' : '出售' }}
</span>
</td>
<!-- 是否精选 -->
<td class="px-6 py-4 whitespace-nowrap">
<span
@click="changeTypeProject(item.id, 2, index, 'is_selected')"
:class="`px-2 py-1 text-xs font-medium rounded-full ${
item.is_selected === 1
? 'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-300'
: 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-300'
} cursor-pointer`"
>
{{ item.is_selected === 0 ? '否' : '是' }}
</span>
</td>
<!-- 是否为轮播图 -->
<td class="px-6 py-4 whitespace-nowrap">
<span
@click="changeTypeProject(item.id, 3, index, 'is_carousel')"
:class="`px-2 py-1 text-xs font-medium rounded-full ${
item.is_carousel === 1
? 'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-300'
: 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-300'
} cursor-pointer`"
>
{{ item.is_carousel === 0 ? '否' : '是' }}
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span
:class="`px-2 py-1 text-xs font-medium rounded-full ${
@@ -662,7 +724,7 @@ const handleMdImageUpload = async (
: item.status === 2
? 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-300'
: 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300'
}`"
} cursor-pointer`"
>
{{ item.status_text }}
</span>
@@ -1251,6 +1313,7 @@ const handleMdImageUpload = async (
</div>
</div>
</div>
<!-- 项目表单模态框 -->
<div v-if="showContentModal" class="fixed inset-0 z-50 overflow-y-scroll" aria-labelledby="modal-title" role="dialog"
aria-modal="true">

View File

@@ -1,8 +1,8 @@
<script setup>
import { ref, onMounted,reactive, nextTick, inject } from 'vue'
import { useRoute } from 'vue-router'
import { Swiper, SwiperSlide } from 'swiper/vue'
import { Autoplay, Pagination, Navigation, EffectFade } from 'swiper/modules'
import {ref, onMounted, reactive, nextTick, inject} from 'vue'
import {useRoute} from 'vue-router'
import {Swiper, SwiperSlide} from 'swiper/vue'
import {Autoplay, Pagination, Navigation, EffectFade} from 'swiper/modules'
import AOS from 'aos'
import 'aos/dist/aos.css'
import 'swiper/css'
@@ -14,7 +14,7 @@ import {DollarSign, User, X} from "lucide-vue-next";
import {createCollectionApi, unCollectionApi} from "@/api/request/collection.js";
import {message, Image} from "ant-design-vue";
import {useUserStore} from "@/stores/user.js";
import { MdPreview } from 'md-editor-v3';
import {MdPreview} from 'md-editor-v3';
import 'md-editor-v3/lib/style.css';
const route = useRoute()
@@ -32,19 +32,19 @@ onMounted(() => {
// 分类数据
const categories = [
{ id: 1, name: 'Web应用', value: 'Web应用' },
{ id: 2, name: '移动端', value: '移动端' },
{ id: 3, name: '小程序', value: '小程序' },
{ id: 4, name: '企业系统', value: '企业系统' }
{id: 1, name: 'Web应用', value: 'Web应用'},
{id: 2, name: '移动端', value: '移动端'},
{id: 3, name: '小程序', value: '小程序'},
{id: 4, name: '企业系统', value: '企业系统'}
]
// 标签数据
const allTags = [
{ id: 1, name: 'Vue3' },
{ id: 2, name: 'Node.js' },
{ id: 3, name: 'TypeScript' },
{ id: 4, name: 'MongoDB' },
{ id: 5, name: 'Docker' }
{id: 1, name: 'Vue3'},
{id: 2, name: 'Node.js'},
{id: 3, name: 'TypeScript'},
{id: 4, name: 'MongoDB'},
{id: 5, name: 'Docker'}
]
const project = ref()
@@ -97,7 +97,7 @@ const swiperOptions = {
}
const formatPrice = (price) => {
return '¥ ' + price.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
return '¥ ' + price.toLocaleString('zh-CN', {minimumFractionDigits: 2, maximumFractionDigits: 2})
}
getDetail();
@@ -165,7 +165,6 @@ const unCollection = () => {
</h1>
<div class="max-w-3xl">
<div class="flex flex-wrap gap-2 mb-3" data-aos="fade-up" data-aos-delay="200">
<span
@@ -250,9 +249,12 @@ const unCollection = () => {
<div>
<h3 class="text-xl font-bold mb-4 text-gray-900 dark:text-white flex items-center">
<span class="w-8 h-8 rounded-full bg-rose-100 dark:bg-rose-900/30 text-rose-600 dark:text-rose-400 flex items-center justify-center mr-3">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4" />
<span
class="w-8 h-8 rounded-full bg-rose-100 dark:bg-rose-900/30 text-rose-600 dark:text-rose-400 flex items-center justify-center mr-3">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"/>
</svg>
</span>
技术栈
@@ -273,9 +275,11 @@ const unCollection = () => {
<li
class="flex items-center bg-gray-50 dark:bg-gray-700/50 rounded-lg p-3"
>
<div class="flex-shrink-0 w-5 h-5 rounded-full bg-rose-100 dark:bg-rose-900/30 flex items-center justify-center text-rose-600 dark:text-rose-400 mr-3">
<svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
<div
class="flex-shrink-0 w-5 h-5 rounded-full bg-rose-100 dark:bg-rose-900/30 flex items-center justify-center text-rose-600 dark:text-rose-400 mr-3">
<svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
</svg>
</div>
<span class="text-gray-700 dark:text-gray-300">前端技术栈 {{ project.front }}</span>
@@ -283,9 +287,11 @@ const unCollection = () => {
<li
class="flex items-center bg-gray-50 dark:bg-gray-700/50 rounded-lg p-3"
>
<div class="flex-shrink-0 w-5 h-5 rounded-full bg-rose-100 dark:bg-rose-900/30 flex items-center justify-center text-rose-600 dark:text-rose-400 mr-3">
<svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
<div
class="flex-shrink-0 w-5 h-5 rounded-full bg-rose-100 dark:bg-rose-900/30 flex items-center justify-center text-rose-600 dark:text-rose-400 mr-3">
<svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
</svg>
</div>
<span class="text-gray-700 dark:text-gray-300">后端技术栈 {{ project.service }}</span>
@@ -293,9 +299,11 @@ const unCollection = () => {
<li
class="flex items-center bg-gray-50 dark:bg-gray-700/50 rounded-lg p-3"
>
<div class="flex-shrink-0 w-5 h-5 rounded-full bg-rose-100 dark:bg-rose-900/30 flex items-center justify-center text-rose-600 dark:text-rose-400 mr-3">
<svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
<div
class="flex-shrink-0 w-5 h-5 rounded-full bg-rose-100 dark:bg-rose-900/30 flex items-center justify-center text-rose-600 dark:text-rose-400 mr-3">
<svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
</svg>
</div>
<span class="text-gray-700 dark:text-gray-300">部署架构 {{ project.deploy }}</span>
@@ -305,9 +313,11 @@ const unCollection = () => {
<div>
<h3 class="text-xl font-bold mb-4 text-gray-900 dark:text-white flex items-center">
<span class="w-8 h-8 rounded-full bg-rose-100 dark:bg-rose-900/30 text-rose-600 dark:text-rose-400 flex items-center justify-center mr-3">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
<span
class="w-8 h-8 rounded-full bg-rose-100 dark:bg-rose-900/30 text-rose-600 dark:text-rose-400 flex items-center justify-center mr-3">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
</svg>
</span>
核心功能
@@ -318,9 +328,11 @@ const unCollection = () => {
:key="index"
class="flex items-start"
>
<div class="flex-shrink-0 w-5 h-5 rounded-full bg-rose-100 dark:bg-rose-900/30 flex items-center justify-center text-rose-600 dark:text-rose-400 mr-3 mt-0.5">
<svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
<div
class="flex-shrink-0 w-5 h-5 rounded-full bg-rose-100 dark:bg-rose-900/30 flex items-center justify-center text-rose-600 dark:text-rose-400 mr-3 mt-0.5">
<svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
</svg>
</div>
<span class="text-gray-700 dark:text-gray-300">{{ feature.name }}</span>
@@ -330,14 +342,18 @@ const unCollection = () => {
<div>
<h3 class="text-xl font-bold mb-4 text-gray-900 dark:text-white flex items-center">
<span class="w-8 h-8 rounded-full bg-rose-100 dark:bg-rose-900/30 text-rose-600 dark:text-rose-400 flex items-center justify-center mr-3">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
<span
class="w-8 h-8 rounded-full bg-rose-100 dark:bg-rose-900/30 text-rose-600 dark:text-rose-400 flex items-center justify-center mr-3">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
</span>
项目描述
</h3>
<p class="text-gray-600 dark:text-gray-300 leading-relaxed" style="text-indent: 2em">{{ project.description }}</p>
<p class="text-gray-600 dark:text-gray-300 leading-relaxed" style="text-indent: 2em">
{{ project.description }}</p>
</div>
</div>
@@ -389,18 +405,21 @@ const unCollection = () => {
class="relative group rounded-xl overflow-hidden cursor-pointer"
>
<div class=" text-center text-gray-500 dark:text-gray-400 items-center" style="margin: 200px auto;">
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 mx-auto mb-4 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
作者没有上传
</div>
<div class=" text-center text-gray-500 dark:text-gray-400 items-center" style="margin: 200px auto;">
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 mx-auto mb-4 text-gray-400" fill="none"
viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
作者没有上传
</div>
</div>
<div
v-else
class="relative group rounded-xl overflow-hidden cursor-pointer"
>
<Image :src="project.module_image" class="w-full h-full object-cover transition-transform duration-300" />
<Image :src="project.module_image"
class="w-full h-full object-cover transition-transform duration-300"/>
</div>
</div>
<div v-else-if="activeTab === '5'">
@@ -410,8 +429,10 @@ const unCollection = () => {
>
<div class=" text-center text-gray-500 dark:text-gray-400 items-center" style="margin: 200px auto;">
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 mx-auto mb-4 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 mx-auto mb-4 text-gray-400" fill="none"
viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
作者没有上传
</div>
@@ -420,7 +441,7 @@ const unCollection = () => {
v-else
class="relative group rounded-xl overflow-hidden cursor-pointer"
>
<Image :src="project.flowchart" class="w-full h-full object-cover transition-transform duration-300" />
<Image :src="project.flowchart" class="w-full h-full object-cover transition-transform duration-300"/>
</div>
</div>
<div v-else-if="activeTab === '6'">
@@ -429,8 +450,10 @@ const unCollection = () => {
class="relative group rounded-xl overflow-hidden cursor-pointer"
>
<div class=" text-center text-gray-500 dark:text-gray-400 items-center" style="margin: 200px auto;">
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 mx-auto mb-4 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 mx-auto mb-4 text-gray-400" fill="none"
viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
作者没有上传
</div>
@@ -450,22 +473,33 @@ const unCollection = () => {
<div>
<div class="bg-white dark:bg-gray-800 rounded-3xl shadow-xl p-8 sticky top-8">
<div class="mb-6">
<h3 class="text-lg font-semibold text-white flex items-center">
<DollarSign class="w-5 h-5 mr-1.5 text-rose-500"/>
项目价格
</h3>
<!-- <p class="text-3xl font-bold text-rose-600 dark:text-rose-400">{{ formatPrice(project.price) }}</p>-->
<div v-if="project.preferential_price" class="flex items-center text-3xl font-bold text-rose-600 dark:text-rose-400">
<!-- <p class="text-3xl font-bold text-rose-600 dark:text-rose-400">{{ formatPrice(project.price) }}</p>-->
<div v-if="project.is_sold === 1">
<h3 class="text-lg font-semibold text-white flex items-center">
<DollarSign class="w-5 h-5 mr-1.5 text-rose-500"/>
项目价格
</h3>
<div v-if="project.preferential_price"
class="flex items-center text-3xl font-bold text-rose-600 dark:text-rose-400">
<span class="text-2xl font-bold text-rose-400">
{{ formatPrice(project.preferential_price) }}
</span>
<span v-if="project.preferential_price !== project.price" class="ml-2 text-sm text-gray-400 line-through">
<span v-if="project.preferential_price !== project.price"
class="ml-2 text-sm text-gray-400 line-through">
{{ formatPrice(project.price) }}
</span>
</div>
<div v-else class="text-2xl font-bold text-white">
{{ formatPrice(project.price) }}
</div>
</div>
<div v-else>
<h3 class="text-lg font-semibold text-gray-600 flex items-center line-through">
<DollarSign class="w-5 h-5 mr-1.5 text-rose-500"/>
非卖品
</h3>
</div>
</div>
<div class="mb-6">
@@ -489,19 +523,30 @@ const unCollection = () => {
</div>
<div class="space-y-4">
<button class="w-full py-3 bg-rose-600 hover:bg-rose-700 text-white rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 flex items-center justify-center cursor-pointer">
<button v-if="project.is_sold === 1" :disabled="true"
class="w-full py-3 bg-rose-600 hover:bg-rose-700 text-white rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 flex items-center justify-center cursor-pointer">
<span>立即咨询</span>
</button>
<button v-else
class="w-full py-3 bg-rose-600 hover:bg-rose-700 text-white rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 flex items-center justify-center cursor-pointer">
<span>立即咨询</span>
</button>
<button v-if="project.is_collection === false" @click="collection" class="w-full py-3 bg-white dark:bg-gray-700 text-rose-600 dark:text-rose-400 border border-rose-200 dark:border-rose-800/30 rounded-xl shadow-md hover:shadow-lg transition-all duration-300 flex items-center justify-center cursor-pointer">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" />
<button v-if="project.is_collection === false" @click="collection"
class="w-full py-3 bg-white dark:bg-gray-700 text-rose-600 dark:text-rose-400 border border-rose-200 dark:border-rose-800/30 rounded-xl shadow-md hover:shadow-lg transition-all duration-300 flex items-center justify-center cursor-pointer">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"/>
</svg>
<span>收藏项目</span>
</button>
<button v-else @click="unCollection" class="w-full py-3 bg-rose-600 hover:bg-rose-700 text-white rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 flex items-center justify-center cursor-pointer">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="gold" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" />
<button v-else @click="unCollection"
class="w-full py-3 bg-rose-600 hover:bg-rose-700 text-white rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 flex items-center justify-center cursor-pointer">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="gold" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"/>
</svg>
<span>取消收藏</span>
</button>
@@ -526,7 +571,8 @@ const unCollection = () => {
<h2 class="text-2xl md:text-3xl font-bold mb-8 text-gray-900 dark:text-white">
<span class="relative">
相关项目
<span class="absolute -bottom-2 left-0 w-1/4 h-1 bg-gradient-to-r from-rose-400 to-rose-600 rounded-full"></span>
<span
class="absolute -bottom-2 left-0 w-1/4 h-1 bg-gradient-to-r from-rose-400 to-rose-600 rounded-full"></span>
</span>
</h2>
@@ -543,7 +589,8 @@ const unCollection = () => {
class="w-full h-full object-cover transform transition-transform duration-700 group-hover:scale-110"
:alt="related.title"
/>
<div class="absolute inset-0 bg-gradient-to-t from-black/60 via-black/20 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
<div
class="absolute inset-0 bg-gradient-to-t from-black/60 via-black/20 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
</div>
<div class="p-6">
@@ -564,8 +611,9 @@ const unCollection = () => {
<div class="flex justify-between items-center">
<p class="font-bold text-rose-600 dark:text-rose-400">{{ formatPrice(related.price) }}</p>
<button class="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3" />
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3"/>
</svg>
</button>
</div>
@@ -629,6 +677,7 @@ const unCollection = () => {
background: linear-gradient(135deg, #1a1d23 0%, #111827 100%);
}
}
/* 自定义样式 */
.cursor-grab {
cursor: grab;