src/components/AppHeader.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/router/index.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/IndustrialSoftware.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/Login.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/ProductDetail.vue | ●●●●● 补丁 | 查看 | 原始文档 | 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>