tanghaolin
2025-02-13 91eccc205cc66b5962852ecfcff27556a44faee0
Merge branch 'master' of http://47.103.154.90:83/r/IEE/Web.V1
已修改4个文件
已添加1个文件
388 ■■■■■ 文件已修改
src/components/AppHeader.vue 31 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/index.ts 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/IndustrialSoftware.vue 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/Login.vue 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/ProductDetail.vue 260 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/AppHeader.vue
@@ -30,9 +30,15 @@
                    </el-input>
                    <div class="flex items-center text-gray-600 text-sm text-nowrap">
                        <a href="#" class="hover:text-blue-500">注册</a>
                        <span class="mx-2">·</span>
                        <router-link to="/login" class="hover:text-blue-500">登录</router-link>
                        <template v-if="!userInfo">
                            <a href="#" class="hover:text-blue-500">注册</a>
                            <span class="mx-2">·</span>
                            <router-link to="/login" class="hover:text-blue-500">登录</router-link>
                        </template>
                        <template v-else>
                            <span class="text-blue-500 mr-2">{{ userInfo.username }}</span>
                            <a href="#" class="hover:text-blue-500" @click.prevent="handleLogout">退出</a>
                        </template>
                    </div>
                </div>
            </div>
@@ -43,12 +49,29 @@
<script setup lang="ts">
import headerLogo from '@/assets/logo/header_logo.png';
import { Search } from '@element-plus/icons-vue';
import { ElMessage } from 'element-plus';
import { computed, ref } from 'vue';
import { useRoute } from 'vue-router';
import { useRoute, useRouter } from 'vue-router';
const route = useRoute();
const router = useRouter();
const searchQuery = ref('');
const activeRoute = computed(() => route.path);
// èŽ·å–ç”¨æˆ·ä¿¡æ¯
const userInfo = computed(() => {
    const info = localStorage.getItem('userInfo');
    return info ? JSON.parse(info) : null;
});
// å¤„理登出
const handleLogout = () => {
    localStorage.removeItem('userInfo');
    ElMessage.success('已退出登录');
    router.push('/login');
};
const linkClick = (url) => {
    window.open(url, '_blank');
};
src/router/index.ts
@@ -48,6 +48,11 @@
            name: 'subsidy-application',
            component: () => import('../views/SubsidyApplication.vue'),
        },
        {
            path: '/product/:id',
            name: 'product-detail',
            component: () => import('../views/ProductDetail.vue'),
        },
    ],
});
src/views/IndustrialSoftware.vue
@@ -3,16 +3,21 @@
        style="margin-top: 20px;padding-top:15px ;">
        <div class=" w-100 h-100" style="background-color: #fff;">
            <!-- é¡¶éƒ¨åˆ†ç±»èœå• -->
            <div class=" rounded-lg shadow " style="background-color: #f6f7f9;margin-bottom: 10px;">
            <div class="rounded-lg shadow" style="background-color: #f6f7f9; margin-bottom: 10px">
                <!-- ç±»åž‹ -->
                <div class="border-b p-4  border-bottom-dashed-1 box-border" style="padding: 10px;">
                <div class="border-b p-4 border-bottom-dashed-1 box-border" style="padding: 10px">
                    <div class="flex items-center">
                        <span class="text-gray-500 ">类型:</span>
                        <span class="text-gray-500">类型:</span>
                        <div class="flex flex-1">
                            <span v-for="item in type" class="ant-tag !px-4"
                                :class="typeSelect === item.tag ? 'ant-tag-checked' : ''" :key="item.tag"
                            <span
                                v-for="item in type"
                                class="ant-tag !px-4"
                                :class="typeSelect === item.tag ? 'ant-tag-checked' : ''"
                                :key="item.tag"
                                @click="changeSelectType(item.tag)"
                                :type="typeSelect === item.tag ? 'primary' : 'default'" size="small">
                                :type="typeSelect === item.tag ? 'primary' : 'default'"
                                size="small"
                            >
                                {{ item.name }}
                            </span>
                        </div>
@@ -20,14 +25,19 @@
                </div>
                <!-- åނ商 -->
                <div class="border-b p-4 border-bottom-dashed-1 box-border" style="padding: 10px;">
                    <div class="flex items-center ">
                <div class="border-b p-4 border-bottom-dashed-1 box-border" style="padding: 10px">
                    <div class="flex items-center">
                        <span class="text-gray-500">厂商:</span>
                        <div class="flex flex-1">
                            <span v-for="item in factory" :key="item.tag" class="ant-tag !px-4"
                            <span
                                v-for="item in factory"
                                :key="item.tag"
                                class="ant-tag !px-4"
                                :class="factorySelect === item.tag ? 'ant-tag-checked' : ''"
                                :type="factorySelect === item.tag ? 'primary' : 'default'"
                                @click="factorySelect = item.tag" size="small">
                                @click="factorySelect = item.tag"
                                size="small"
                            >
                                {{ item.name }}
                            </span>
                        </div>
@@ -35,11 +45,13 @@
                </div>
                <!-- èƒ½æ•ˆç­‰çº§ -->
                <div class="flex eec-filter-sortbar" style="background-color: #ecedee;">
                <div class="flex eec-filter-sortbar" style="background-color: #ecedee">
                    <ul>
                        <li v-for="sort in EecClass" :key="sort.tag" size="small" @click="handleEecLevel(sort.tag)"
                            :type="EecSelect === sort.tag ? 'primary' : 'default'"
                            :class="EecSelect == sort.tag ? 'eec-filter-currentOrder' : ''" class="!px-6">
                            :class="EecSelect == sort.tag ? 'eec-filter-currentOrder' : ''"
                            class="!px-6"
                        >
                            {{ sort.name }}
                        </li>
                    </ul>
@@ -73,7 +85,7 @@
                            <span class="text-gray-400 text-sm">{{ app.date }}</span>
                        </div> -->
                            <div class="link-btn">立即购入</div>
                            <div class="link-btn" @click="handleBuyClick(app.id)">立即购入</div>
                        </div>
                        <template #content>
                            <div class="goods-tip-content" style="white-space: pre-wrap;">{{ app.Tip }}</div>
@@ -94,10 +106,13 @@
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import axios from 'axios';
import EecLevel1 from '@/assets/icons/energy_level_1.svg'
import EecLevel2 from '@/assets/icons/energy_level_2.svg'
import EecLevel1 from '@/assets/icons/energy_level_1.svg';
import EecLevel2 from '@/assets/icons/energy_level_2.svg';
import { onMounted, ref } from 'vue';
import { useRouter } from 'vue-router';
const router = useRouter();
// åˆ†ç±»é€‰é¡¹
const type = [
    { name: "æ³µ", tag: 1 },
@@ -109,7 +124,7 @@
    { name: "电机", tag: 7 },
];
const factory = [
    { name: "全部", tag: "全部" },
    { name: '全部', tag: '全部' },
    { name: '凯泉', tag: '凯泉' },
];
const EecClass = [
@@ -125,11 +140,10 @@
const factorySelect = ref('全部');
const EecSelect = ref(0);
const EecLevelEnum = {
    1: { name: '一级能效', icon: EecLevel1 },
    2: { name: '二级能效', icon: EecLevel2 },
}
};
const m_RequestDataObj = {
    1: { requestPath: "static/EecProductData/Pump.json" },
@@ -233,6 +247,17 @@
const changeSelectType = (tag: number) => {
    typeSelect.value = tag;
    initData();
};
const handleBuyClick = (productId: string) => {
    // æ‰¾åˆ°å½“前点击的产品
    const currentProduct = dispEecProduct.value.find((item) => item.id === productId);
    if (currentProduct) {
        // ä¿å­˜äº§å“ä¿¡æ¯åˆ°localStorage
        localStorage.setItem('currentProduct', JSON.stringify(currentProduct));
    }
    router.push(`/product/${productId}`);
};
const handleEecLevel = (tag: number) => {
    EecSelect.value = tag;
@@ -262,13 +287,13 @@
    box-sizing: border-box;
    /* transition: border-color .1s ease; */
    border-radius: 5px;
    transition: all .3s;
    transition: all 0.3s;
    margin-top: 10px;
}
.goods-warp-item:hover {
    border-color: rgba(0, 0, 0, .09);
    box-shadow: 0 2px 8px rgba(0, 0, 0, .2)
    border-color: rgba(0, 0, 0, 0.09);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}
.bg-grey {
@@ -292,7 +317,7 @@
}
.industrial-soft-style::after {
    content: "";
    content: '';
    position: absolute;
    top: 0;
    left: 0;
@@ -333,7 +358,7 @@
    color: #999;
    line-height: 16px;
    overflow: hidden;
    text-align: left
    text-align: left;
}
.link-btn {
@@ -382,12 +407,12 @@
.ant-tag {
    box-sizing: border-box;
    color: rgba(0, 0, 0, .65);
    color: rgba(0, 0, 0, 0.65);
    font-size: 14px;
    font-variant: tabular-nums;
    line-height: 1.5;
    list-style: none;
    font-feature-settings: "tnum";
    font-feature-settings: 'tnum';
    display: inline-block;
    height: auto;
    margin: 0 8px 0 0;
@@ -397,7 +422,7 @@
    white-space: nowrap;
    cursor: default;
    opacity: 1;
    transition: all .3s cubic-bezier(.78, .14, .15, .86);
    transition: all 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
    margin-right: 24px;
    font-size: 14px;
}
@@ -444,10 +469,8 @@
}
.eec-filter-currentOrder {
    border-bottom: 4px solid #1c97b7;
    color: #1c97b7;
}
.eec-filter-currentOrder:hover {
@@ -479,8 +502,6 @@
    color: #fff;
    font-size: 12px;
}
:deep(.el-button--default) {
    --el-button-bg-color: transparent;
src/views/Login.vue
@@ -80,7 +80,12 @@
const handleLogin = () => {
    formRef.value.validate((valid: boolean) => {
        if (valid) {
            // è¿™é‡Œæ·»åŠ ç™»å½•é€»è¾‘
            // ä¿å­˜ç”¨æˆ·ä¿¡æ¯åˆ°localStorage
            const userInfo = {
                username: loginForm.username,
                isLogin: true,
            };
            localStorage.setItem('userInfo', JSON.stringify(userInfo));
            ElMessage.success('登录成功');
            router.push('/');
        } else {
src/views/ProductDetail.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,260 @@
<template>
    <div class="container mx-auto px-4 py-8 bg-white">
        <!-- é¢åŒ…屑导航 -->
        <div class="mb-6 text-gray-500">
            <el-breadcrumb separator="/">
                <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
                <el-breadcrumb-item :to="{ path: '/certified-products' }">认证产品</el-breadcrumb-item>
                <el-breadcrumb-item>产品详情</el-breadcrumb-item>
            </el-breadcrumb>
        </div>
        <div class="flex gap-8">
            <!-- å·¦ä¾§å•†å“å›¾ç‰‡ -->
            <div class="w-[400px] flex-shrink-0">
                <el-image :src="product.image" fit="contain" :preview-src-list="[product.image]" class="w-full h-[400px] border rounded-lg" />
            </div>
            <!-- å³ä¾§å•†å“ä¿¡æ¯ -->
            <div class="flex-1">
                <h1 class="text-2xl font-medium mb-4">{{ product.name }}</h1>
                <!-- è®¢è´§ä¿¡æ¯ -->
                <div class="bg-gray-50 p-4 rounded-lg mb-4">
                    <div class="text-gray-500 mb-2">订货编码:{{ product.applicationCode }}</div>
                    <div class="flex items-center gap-2">
                        <span class="text-gray-500">能效等级:</span>
                        <div class="flex items-center">
                            <img :src="product.eecLevelIcon" class="h-8" />
                            <span class="text-white relative right-[42px] top-[-1px]">1</span>
                            <span class="text-white relative right-[30px] top-[-1px] text-sm">一级能效</span>
                        </div>
                    </div>
                </div>
                <!-- ä»·æ ¼åŒºåŸŸ -->
                <div class="mb-6">
                    <div class="flex items-baseline gap-2">
                        <span class="text-gray-500">价格:</span>
                        <span class="text-2xl font-bold text-red-500">Â¥{{ product.price }}</span>
                    </div>
                </div>
                <!-- æœåŠ¡æ‰¿è¯º -->
                <div class="border-t border-b py-4 mb-6">
                    <div class="flex items-center gap-6">
                        <div class="flex items-center gap-2">
                            <el-icon class="text-green-500"><Check /></el-icon>
                            <span>正品保证</span>
                        </div>
                        <div class="flex items-center gap-2">
                            <el-icon class="text-green-500"><Check /></el-icon>
                            <span>极速发货</span>
                        </div>
                        <div class="flex items-center gap-2">
                            <el-icon class="text-green-500"><Check /></el-icon>
                            <span>售后无忧</span>
                        </div>
                    </div>
                </div>
                <!-- è´­ä¹°æŒ‰é’® -->
                <div class="flex gap-4">
                    <el-button type="primary" size="large" @click="handleBuyNow">立即购买</el-button>
                    <el-button size="large" @click="handleAddToCart">加入购物车</el-button>
                </div>
            </div>
        </div>
        <!-- å•†å“è¯¦æƒ… -->
        <div class="mt-8">
            <el-tabs v-model="activeTab">
                <el-tab-pane label="商品介绍" name="intro">
                    <div class="p-6">
                        <h3 class="text-lg font-medium mb-4">产品参数</h3>
                        <el-descriptions :column="2" border>
                            <el-descriptions-item label="品牌">{{ product.brand }}</el-descriptions-item>
                            <el-descriptions-item label="型号">{{ product.model }}</el-descriptions-item>
                            <el-descriptions-item label="功率">{{ product.power }}</el-descriptions-item>
                            <el-descriptions-item label="电压">{{ product.voltage }}</el-descriptions-item>
                            <el-descriptions-item label="转速">{{ product.speed }}</el-descriptions-item>
                            <el-descriptions-item label="防护等级">{{ product.protection }}</el-descriptions-item>
                        </el-descriptions>
                        <div class="mt-8">
                            <h3 class="text-lg font-medium mb-4">产品详情</h3>
                            <div class="space-y-4">
                                <img v-for="(img, index) in product.detailImages" :key="index" :src="img" class="w-full" alt="产品详情图" />
                            </div>
                        </div>
                    </div>
                </el-tab-pane>
                <el-tab-pane label="规格参数" name="params">
                    <div class="p-6">
                        <el-descriptions :column="1" border>
                            <el-descriptions-item v-for="(value, key) in product.specifications" :key="key" :label="key">
                                {{ value }}
                            </el-descriptions-item>
                        </el-descriptions>
                    </div>
                </el-tab-pane>
                <el-tab-pane label="包装售后" name="service">
                    <div class="p-6">
                        <h3 class="text-lg font-medium mb-4">包装清单</h3>
                        <p class="text-gray-600">{{ product.package }}</p>
                        <h3 class="text-lg font-medium mt-6 mb-4">售后服务</h3>
                        <div class="text-gray-600">
                            <p>1. æœ¬äº§å“å…¨å›½è”保,享受三包服务</p>
                            <p>2. è´¨ä¿æœŸï¼š12个月</p>
                            <p>3. å¯¹äºŽè´¨é‡é—®é¢˜ï¼Œæä¾›å…è´¹ç»´ä¿®æœåŠ¡</p>
                        </div>
                    </div>
                </el-tab-pane>
            </el-tabs>
        </div>
    </div>
    <!-- è´­ä¹°ç¡®è®¤å¯¹è¯æ¡† -->
    <el-dialog v-model="showBuyDialog" title="确认订单" width="500px">
        <div class="p-4">
            <div class="flex items-center gap-4 mb-6">
                <el-image :src="product.image" class="w-20 h-20" />
                <div>
                    <div class="font-medium">{{ product.name }}</div>
                    <div class="text-red-500 mt-2">Â¥{{ product.price }}</div>
                </div>
            </div>
            <el-form :model="orderForm" label-width="100px">
                <el-form-item label="收货人">
                    <el-input v-model="orderForm.name" placeholder="请输入收货人姓名" />
                </el-form-item>
                <el-form-item label="联系电话">
                    <el-input v-model="orderForm.phone" placeholder="请输入联系电话" />
                </el-form-item>
                <el-form-item label="收货地址">
                    <el-input v-model="orderForm.address" type="textarea" placeholder="请输入详细地址" />
                </el-form-item>
            </el-form>
        </div>
        <template #footer>
            <div class="flex justify-between items-center">
                <div class="text-lg">
                    å®žä»˜æ¬¾ï¼š<span class="text-red-500 font-medium">Â¥{{ product.price }}</span>
                </div>
                <div class="flex gap-2">
                    <el-button @click="showBuyDialog = false">取消</el-button>
                    <el-button type="primary" @click="confirmOrder">提交订单</el-button>
                </div>
            </div>
        </template>
    </el-dialog>
</template>
<script setup lang="ts">
import EecLevel1 from '@/assets/icons/energy_level_1.svg';
import { Check } from '@element-plus/icons-vue';
import { ElMessage } from 'element-plus';
import { onMounted, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
const route = useRoute();
const router = useRouter();
const activeTab = ref('intro');
const showBuyDialog = ref(false);
const orderForm = ref({
    name: '',
    phone: '',
    address: '',
});
// ä»ŽlocalStorage获取产品信息
const product = ref({
    id: '',
    name: '',
    applicationCode: '',
    price: '',
    image: '',
    brand: '',
    model: '',
    power: '',
    voltage: '',
    speed: '',
    protection: '',
    eecLevelIcon: EecLevel1,
    package: '电机 Ã— 1, è¯´æ˜Žä¹¦ Ã— 1, åˆæ ¼è¯ Ã— 1',
    specifications: {
        äº§å“åž‹å·: '',
        é¢å®šåŠŸçŽ‡: '',
        é¢å®šç”µåŽ‹: '',
        é˜²æŠ¤ç­‰çº§: '',
        ç»ç¼˜ç­‰çº§: 'F级',
        æ•ˆçŽ‡ç­‰çº§: '一级能效',
        é‡é‡: '约12kg',
    },
    detailImages: [],
});
const handleBuyNow = () => {
    showBuyDialog.value = true;
};
const handleAddToCart = () => {
    ElMessage.success('已添加到购物车');
};
const confirmOrder = () => {
    if (!orderForm.value.name || !orderForm.value.phone || !orderForm.value.address) {
        ElMessage.warning('请填写完整的收货信息');
        return;
    }
    ElMessage.success('订单提交成功');
    showBuyDialog.value = false;
    // è¿™é‡Œå¯ä»¥æ·»åŠ è·³è½¬åˆ°è®¢å•è¯¦æƒ…é¡µçš„é€»è¾‘
};
onMounted(() => {
    // ä»ŽlocalStorage获取产品信息
    const savedProduct = localStorage.getItem('currentProduct');
    if (savedProduct) {
        const productData = JSON.parse(savedProduct);
        // åˆå¹¶é»˜è®¤å€¼å’Œä¿å­˜çš„产品数据
        product.value = {
            ...product.value,
            id: productData.id,
            name: productData.name,
            applicationCode: productData.applicationCode,
            price: productData.price,
            image: productData.logo || productData.image,
            brand: productData.brand || productData.name.split(' ')[0],
            model: productData.model || '',
            power: productData.power || '',
            voltage: productData.voltage || '',
            speed: productData.speed || '',
            protection: productData.protection || '',
            detailImages: productData.detailImages || [productData.logo || productData.image],
            specifications: {
                ...product.value.specifications,
                äº§å“åž‹å·: productData.model || '',
                é¢å®šåŠŸçŽ‡: productData.power || '',
                é¢å®šç”µåŽ‹: productData.voltage || '',
                é˜²æŠ¤ç­‰çº§: productData.protection || '',
            },
        };
    }
});
</script>
<style scoped>
:deep(.el-tabs__nav-wrap::after) {
    height: 1px;
}
:deep(.el-descriptions__label) {
    width: 120px;
    font-weight: normal;
}
</style>