This commit is contained in:
ping 2025-12-16 18:05:34 +08:00
commit 89b29980de
22 changed files with 1966 additions and 334 deletions

View File

@ -90,8 +90,10 @@ async def email_info(msg, indent=0):
index = find_data.index("<")
name = find_data[:index]
if price and name:
mail_code_sql = """SELECT * FROM mail_code WHERE LOCATE(mailcode, '%s') > 0 and del_flg = '0';""" % name
mail_code = await sor.sqlExe(mail_code_sql, {})
mail_code_sql = """SELECT * FROM mail_code WHERE mailcode= ${mailcode}$ and del_flg = '0';"""
mail_code = await sor.sqlExe(mail_code_sql, {'mailcode': name})
if len(mail_code) < 1:
raise Exception(f'{name}不是合法的编码,数据库中没有找到')
# mail_code = await sor.R('mail_code',{'mailcode':name,'del_flg':'0'})
date = await get_business_date(sor=None)
recharge_log = {'customerid': mail_code[0]['customer_id'], 'recharge_amt': price,
@ -119,4 +121,4 @@ async def email_info(msg, indent=0):
msg = Parser().parsestr(msg_content)
ret = await email_info(msg)
return ret
return ret

View File

@ -6,7 +6,7 @@
<transition name="slide">
<div v-show="windowsHidden" style="font-size: 14px">
<div class="new-floating" style="z-index: 9999;">
<div class="new-floating" style="z-index: 99;">
<img src="./img/head.png" alt="">
<div class="cloud-contact-us " @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave">
<!-- <span class="cloud-contact-us-i"></span>-->
@ -789,7 +789,7 @@ export default {
top: -28px;
width: 40px;
height: 40px;
z-index: 9999;
z-index: 99;
}
position: relative;

View File

@ -171,7 +171,7 @@ Vue.use(HappyScroll)
// });
// console.log(element);
// console.clear(); // 清除测试日志
// console.clear(); // 清除测试日志
// }
// // 方法4: 检查Eruda等移动端调试工具
@ -345,6 +345,77 @@ window.addEventListener('beforeunload', function () {
Object.keys(filters).forEach(key => {
Vue.filter(key, filters[key])
})
// 在 main.js 的 router.beforeEach 中添加
router.beforeEach((to, from, next) => {
// 清空面包屑状态的代码
// store.commit('tagsView/resetBreadcrumbState');
// 新增:检测是否为移动设备
const userAgent = navigator.userAgent;
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent);
// 如果是移动设备且访问的是根路径,重定向到移动端首页
if (isMobile && to.path === '/') {
next('/h5HomePage');
return;
}
// 如果是移动设备且访问的不是移动端页面,重定向到移动端首页
if (isMobile && !to.meta?.isMobile && to.path !== '/h5HomePage' && !to.path.startsWith('/h5HomePage/')) {
next('/h5HomePage');
return;
}
// 如果已登录且有token但Vuex状态丢失从sessionStorage恢复
if (store.getters.token && (!store.getters.user || !store.getters.userType)) {
console.log("检测到状态丢失从sessionStorage恢复用户状态");
const user = sessionStorage.getItem('user');
const auths = sessionStorage.getItem('auths');
const userType = sessionStorage.getItem('userType');
const orgType = sessionStorage.getItem('orgType');
if (user) {
store.commit('user/SET_USER', user);
}
if (auths) {
store.commit('user/SET_AUTHS', JSON.parse(auths));
}
if (userType) {
store.commit('user/SET_USER_TYPE', userType);
}
if (orgType) {
store.commit('user/SET_ORG_TYPE', parseInt(orgType));
}
// 重新生成路由
try {
const accessRoutes = store.dispatch('permission/generateRoutes', {
user: store.getters.user,
auths: store.getters.auths,
userType: store.getters.userType,
orgType: store.getters.orgType
});
// 重新添加路由
router.addRoutes(accessRoutes);
// 重定向到当前路由以确保路由更新
next({ ...to, replace: true });
return;
} catch (error) {
console.error('重新生成路由失败:', error);
}
}
onOverflow.forEach(element => {
if (to.path == element) {
document.querySelector("body").setAttribute("style", "overflow: auto !important;")
}
});
next();
});
Vue.config.productionTip = false

View File

@ -6,8 +6,83 @@ const userAgent = window.navigator.userAgent;
// 判断是否为移动设备
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent);
// 如果是移动设备,添加移动端首页路由和根路径重定向
if (isMobile) {
console.log("检测到移动设备,添加移动端路由");
// 先添加根路径重定向到移动端首页
constantRoutes.unshift({
path: '/',
redirect: '/h5HomePage',
hidden: true
});
// 添加移动端首页路由
constantRoutes.push({
path: '/h5HomePage',
name: 'H5HomePage',
title: 'H5首页',
component: () => import('@/views/H5/index.vue'),
hidden: true,
redirect: "/h5HomePage/index",
meta: { isMobile: true },
children: [
{
path: "index",
title: 'H5首页',
component: () => import('@/views/H5/official/index.vue'),
meta: {
title: "H5首页",
fullPath: "/h5HomePage/index",
isMobile: true
},
},
{
path: "cloud",
title: '云',
component: () => import('@/views/H5/cloud/index.vue'),
meta: {
title: "云",
fullPath: "/h5HomePage/cloud",
isMobile: true
},
},
{
path: "calculate",
title: '算',
component: () => import('@/views/H5/calculate/index.vue'),
meta: {
title: "算",
fullPath: "/h5HomePage/calculate",
isMobile: true
},
},
{
path: "net",
title: '网',
component: () => import('@/views/H5/net/index.vue'),
meta: {
title: "网",
fullPath: "/h5HomePage/net",
isMobile: true
},
},
{
path: "use",
title: '用',
component: () => import('@/views/H5/use/index.vue'),
meta: {
title: "用",
fullPath: "/h5HomePage/use",
isMobile: true
},
},
]
});
}
// 修复:更全面的路由过滤逻辑
function filterAsyncRoutes(routes, permissions, userRoles = []) {
function filterAsyncRoutes(routes, permissions, userRoles = [], deviceType = 'pc') {
const res = [];
// 定义需要客户角色才能访问的路由
@ -35,6 +110,14 @@ function filterAsyncRoutes(routes, permissions, userRoles = []) {
return; // 跳过当前路由
}
// 新增:根据设备类型过滤路由
if (deviceType === 'mobile' && !(route.meta?.isMobile || route.meta?.isMobile === true)) {
return; // 移动设备跳过非移动端路由
}
if (deviceType === 'pc' && route.meta?.isMobile === true) {
return; // PC设备跳过移动端路由
}
// 如果当前路由有权限,则加入结果
if (hasPermission) {
res.push(tmpRoute);
@ -45,7 +128,7 @@ function filterAsyncRoutes(routes, permissions, userRoles = []) {
}
// 如果没有直接权限,但有子路由,递归处理子路由
else if (tmpRoute.children) {
const filteredChildren = filterAsyncRoutes(tmpRoute.children, permissions, userRoles);
const filteredChildren = filterAsyncRoutes(tmpRoute.children, permissions, userRoles, deviceType);
if (filteredChildren.length > 0) {
tmpRoute.children = filteredChildren;
res.push(tmpRoute); // 即使父路由本身没有权限,只要有子路由有权限,也要保留父路由
@ -57,7 +140,7 @@ function filterAsyncRoutes(routes, permissions, userRoles = []) {
}
// 新增:为普通用户添加订单管理和资源管理路由
function addUserRoutes(routes, userType, orgType, userRoles = []) {
function addUserRoutes(routes, userType, orgType, userRoles = [], deviceType = 'pc') {
console.log("addUserRoutes - userType:", userType, "orgType:", orgType, "userRoles:", userRoles);
const userRoutes = [];
@ -67,12 +150,13 @@ function addUserRoutes(routes, userType, orgType, userRoles = []) {
const orderManagementRoute = routes.find(route => route.path === "/orderManagement");
const resourceManagementRoute = routes.find(route => route.path === "/resourceManagement");
if (orderManagementRoute) {
// 新增:根据设备类型过滤
if (orderManagementRoute && (deviceType === 'pc' || orderManagementRoute.meta?.isMobile === true)) {
console.log("添加订单管理路由");
userRoutes.push(JSON.parse(JSON.stringify(orderManagementRoute))); // 深拷贝
}
if (resourceManagementRoute) {
if (resourceManagementRoute && (deviceType === 'pc' || resourceManagementRoute.meta?.isMobile === true)) {
console.log("添加资源管理路由");
userRoutes.push(JSON.parse(JSON.stringify(resourceManagementRoute))); // 深拷贝
}
@ -85,10 +169,10 @@ function addUserRoutes(routes, userType, orgType, userRoles = []) {
routes.find(route => route.path === "/rechargeManagement"),
routes.find(route => route.path === "/invoiceManagement"),
routes.find(route => route.path === "/workOrderManagement")
].filter(route => {
// 过滤掉undefined并且只有客户角色才能看到这些路由
return route && userRoles.includes('客户');
return route && userRoles.includes('客户') &&
(deviceType === 'pc' || route.meta?.isMobile === true);
});
console.log("添加新的客户菜单路由:", newCustomerRoutes.map(r => r.path));
@ -97,38 +181,11 @@ function addUserRoutes(routes, userType, orgType, userRoles = []) {
return userRoutes;
}
function filterRoutesMobile(routes) {
return routes.filter(route => {
if (route.children && route.children.length) {
route.children = filterRoutesMobile(route.children);
return route.children.length > 0;
}
if (route.meta?.isMobile || route.meta?.isMobile === true) {
return true;
} else {
return false;
}
});
}
function filterRoutesPc(routes) {
return routes.filter(route => {
if (route.children && route.children.length) {
route.children = filterRoutesPc(route.children);
return route.children.length > 0;
}
if (!route.meta?.isMobile || route.meta?.isMobile === false) {
return true;
} else {
return false;
}
});
}
const state = {
routes: [],
addRoutes: [],
users: []
users: [],
isMobile: isMobile // 保存设备类型状态
};
const mutations = {
@ -136,11 +193,15 @@ const mutations = {
console.log("MUTATION SET_ROUTES - received routes:", routes);
state.addRoutes = routes;
sessionStorage.setItem("routes", JSON.stringify(routes));
// 将移动端首页路由也包含在内
state.routes = constantRoutes.concat(routes);
console.log("MUTATION SET_ROUTES - final state.routes:", state.routes);
},
SETUSERS: (state, user) => {
state.users = user;
},
SET_DEVICE_TYPE: (state, isMobile) => {
state.isMobile = isMobile;
}
};
@ -161,7 +222,7 @@ const actions = {
* @param {Object} [params.user] - 用户信息对象
* @returns {Promise<Array>} 解析后的动态路由数组
*/
generateRoutes({ commit, rootState }, params) {
generateRoutes({ commit, rootState, state }, params) {
console.log("ACTION generateRoutes - params:", params);
return new Promise((resolve) => {
let accessedRoutes;
@ -176,10 +237,18 @@ const actions = {
console.log("用户类型:", userType, "orgType:", orgType);
// 确定设备类型
const deviceType = state.isMobile ? 'mobile' : 'pc';
console.log("设备类型:", deviceType);
// 修复:包含 orgType 为 2 和 3 的情况
if (params.user && params.user.includes("admin") && orgType != 2 && orgType != 3) {
// 管理员:只显示超级管理员菜单
accessedRoutes = asyncRoutes.filter(item => item.path === '/superAdministrator');
// 管理员只显示超级管理员菜单仅PC端
if (deviceType === 'pc') {
accessedRoutes = asyncRoutes.filter(item => item.path === '/superAdministrator');
} else {
accessedRoutes = [];
}
} else {
const auths = params.auths ? JSON.parse(JSON.stringify(params.auths)) : [];
console.log("ACTION generateRoutes - auths:", auths);
@ -195,8 +264,8 @@ const actions = {
// 如果权限列表包含空路径,认为用户有所有权限
accessedRoutes = asyncRoutes || [];
} else {
// 使用修复后的过滤函数,传入用户角色
accessedRoutes = filterAsyncRoutes(asyncRoutes, auths, userRoles);
// 使用修复后的过滤函数,传入用户角色和设备类型
accessedRoutes = filterAsyncRoutes(asyncRoutes, auths, userRoles, deviceType);
}
} else {
// 如果没有权限列表,不显示任何动态路由
@ -205,7 +274,7 @@ const actions = {
// 新增:为普通用户添加订单管理和资源管理路由以及新的五个客户菜单
console.log("为用户添加特定路由");
const userSpecificRoutes = addUserRoutes(asyncRoutes, userType, orgType, userRoles);
const userSpecificRoutes = addUserRoutes(asyncRoutes, userType, orgType, userRoles, deviceType);
// 确保不重复添加路由,同时检查角色权限
userSpecificRoutes.forEach(route => {

View File

@ -4,7 +4,22 @@
<div class="top-tit">
开元云
</div>
<!-- 搜索 -->
<div class="search">
<div class="search-box">
<div class="input">
<input
type="text"
placeholder="请输入产品名称"
v-model="searchValue"
@keyup.enter="handleSearch"
/>
</div>
<div class="search-btn" @click="handleSearch">
搜索
</div>
</div>
</div>
<!-- 供应商 -->
<div v-if="cloudData.secMenu && cloudData.secMenu.length > 0" class="supplier-container">
<div
@ -32,6 +47,7 @@
v-for="product in thrMenu.value"
:key="product.id"
class="box-item"
v-show="shouldShowProduct(product)"
>
<!-- 标题 -->
<div class="item-tit">
@ -83,6 +99,8 @@ export default {
return {
cloudData: {},
activeSupplierIndex: 0, //
searchValue: '', //
isSearching: false, //
//
showConsultDialog: false,
@ -116,6 +134,26 @@ export default {
}
},
//
handleSearch() {
this.isSearching = !!this.searchValue.trim()
// API
console.log('搜索关键词:', this.searchValue)
},
//
shouldShowProduct(product) {
if (!this.isSearching) {
return true
}
//
const keyword = this.searchValue.toLowerCase().trim()
return (
(product.name && product.name.toLowerCase().includes(keyword)) ||
(product.description && product.description.toLowerCase().includes(keyword))
)
},
//
selectSupplier(index) {
this.activeSupplierIndex = index

View File

@ -4,6 +4,22 @@
<div class="top-tit">
开元云
</div>
<!-- 搜索 -->
<div class="search">
<div class="search-box">
<div class="input">
<input
type="text"
placeholder="请输入产品名称"
v-model="searchValue"
@keyup.enter="handleSearch"
/>
</div>
<div class="search-btn" @click="handleSearch">
搜索
</div>
</div>
</div>
<!-- 供应商 -->
<div class="supplier-container">
@ -19,7 +35,7 @@
<!-- 只显示当前选中的供应商的产品 -->
<template v-if="cloudData.secMenu && cloudData.secMenu.length > 0 && activeSupplierIndex >= 0">
<template v-for="thrMenu in cloudData.secMenu[activeSupplierIndex].thrMenu">
<div v-for="product in thrMenu.value" :key="product.id" class="box-item">
<div v-for="product in thrMenu.value" :key="product.id" class="box-item" v-show="shouldShowProduct(product)">
<!-- 标题 -->
<div class="item-tit">
{{ product.name }}
@ -67,6 +83,8 @@ export default {
return {
cloudData: {},
activeSupplierIndex: 0, //
searchValue: '', //
isSearching: false, //
//
showConsultDialog: false,
@ -98,6 +116,27 @@ export default {
}
},
methods: {
//
handleSearch() {
this.isSearching = !!this.searchValue.trim()
console.log('搜索关键词:', this.searchValue)
},
//
shouldShowProduct(product) {
if (!this.isSearching) {
return true
}
//
const keyword = this.searchValue.toLowerCase().trim()
return (
(product.name && product.name.toLowerCase().includes(keyword)) ||
(product.description && product.description.toLowerCase().includes(keyword)) ||
(product.label && product.label.toLowerCase().includes(keyword)) ||
(product.ssecTitle && product.ssecTitle.toLowerCase().includes(keyword))
)
},
//
showProductDesc(product) {
// label

Binary file not shown.

After

Width:  |  Height:  |  Size: 595 KiB

View File

@ -2,23 +2,33 @@
<div class="h5-container">
<!-- 主要内容区域 -->
<div ref="mainContent" class="main" @scroll="handleScroll">
<router-view></router-view>
<transition :name="transitionName" mode="out-in">
<router-view></router-view>
</transition>
</div>
<div style="height: 1.4rem;"></div>
<!-- 返回顶部按钮 -->
<transition name="fade">
<transition name="fade-scale">
<div
v-show="showBackToTop"
class="back-to-top"
@click="scrollToTop"
>
<div class="back-to-top-icon"></div>
<div class="back-to-top-text">顶部</div>
<div class="back-to-top-icon">
<svg viewBox="0 0 24 24" fill="none">
<path d="M12 5L12 19M12 5L6 11M12 5L18 11"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"/>
</svg>
</div>
<div class="back-to-top-text">回顶部</div>
</div>
</transition>
<!-- 底部导航栏 -->
<!-- 底部导航栏 -->
<div class="tabBar">
<!-- 首页 -->
<div
@ -27,14 +37,20 @@
@click="switchTab('index')"
>
<div class="item-img">
<img
:src="activeTab === 'index' ? require('./images/tabBar/homeColor.png') : require('./images/tabBar/home.png')"
alt="首页"
/>
<transition name="icon-bounce" mode="out-in">
<img
:key="activeTab === 'index'"
:src="activeTab === 'index' ? require('./images/tabBar/homeColor.png') : require('./images/tabBar/home.png')"
alt="首页"
/>
</transition>
</div>
<div class="item-text">
首页
<transition name="text-slide" mode="out-in">
<span :key="activeTab === 'index'">首页</span>
</transition>
</div>
<div class="active-indicator" v-if="activeTab === 'index'"></div>
</div>
<!-- -->
@ -44,14 +60,20 @@
@click="switchTab('cloud')"
>
<div class="item-img">
<img
:src="activeTab === 'cloud' ? require('./images/tabBar/cloudColor.png') : require('./images/tabBar/cloud.png')"
alt="云"
/>
<transition name="icon-bounce" mode="out-in">
<img
:key="activeTab === 'cloud'"
:src="activeTab === 'cloud' ? require('./images/tabBar/cloudColor.png') : require('./images/tabBar/cloud.png')"
alt="云"
/>
</transition>
</div>
<div class="item-text">
<transition name="text-slide" mode="out-in">
<span :key="activeTab === 'cloud'"></span>
</transition>
</div>
<div class="active-indicator" v-if="activeTab === 'cloud'"></div>
</div>
<!-- -->
@ -61,14 +83,20 @@
@click="switchTab('calculate')"
>
<div class="item-img">
<img
:src="activeTab === 'calculate' ? require('./images/tabBar/calculateColor.png') : require('./images/tabBar/calculate.png')"
alt="算"
/>
<transition name="icon-bounce" mode="out-in">
<img
:key="activeTab === 'calculate'"
:src="activeTab === 'calculate' ? require('./images/tabBar/calculateColor.png') : require('./images/tabBar/calculate.png')"
alt="算"
/>
</transition>
</div>
<div class="item-text">
<transition name="text-slide" mode="out-in">
<span :key="activeTab === 'calculate'"></span>
</transition>
</div>
<div class="active-indicator" v-if="activeTab === 'calculate'"></div>
</div>
<!-- -->
@ -78,14 +106,20 @@
@click="switchTab('net')"
>
<div class="item-img">
<img
:src="activeTab === 'net' ? require('./images/tabBar/netColor.png') : require('./images/tabBar/net.png')"
alt="网"
/>
<transition name="icon-bounce" mode="out-in">
<img
:key="activeTab === 'net'"
:src="activeTab === 'net' ? require('./images/tabBar/netColor.png') : require('./images/tabBar/net.png')"
alt="网"
/>
</transition>
</div>
<div class="item-text">
<transition name="text-slide" mode="out-in">
<span :key="activeTab === 'net'"></span>
</transition>
</div>
<div class="active-indicator" v-if="activeTab === 'net'"></div>
</div>
<!-- -->
@ -95,14 +129,20 @@
@click="switchTab('use')"
>
<div class="item-img">
<img
:src="activeTab === 'use' ? require('./images/tabBar/userColor.png') : require('./images/tabBar/user.png')"
alt="用"
/>
<transition name="icon-bounce" mode="out-in">
<img
:key="activeTab === 'use'"
:src="activeTab === 'use' ? require('./images/tabBar/userColor.png') : require('./images/tabBar/user.png')"
alt="用"
/>
</transition>
</div>
<div class="item-text">
<transition name="text-slide" mode="out-in">
<span :key="activeTab === 'use'"></span>
</transition>
</div>
<div class="active-indicator" v-if="activeTab === 'use'"></div>
</div>
</div>
</div>
@ -124,6 +164,8 @@ export default {
],
showBackToTop: false, //
scrollThreshold: 200, //
transitionName: 'fade', //
isSwitching: false, //
};
},
watch: {
@ -142,8 +184,11 @@ export default {
* @param {string} tabId - 标签ID
*/
switchTab(tabId) {
//
if (this.activeTab === tabId) return;
//
if (this.isSwitching || this.activeTab === tabId) return;
//
this.isSwitching = true;
//
this.activeTab = tabId;
@ -151,7 +196,39 @@ export default {
// tabId
const tab = this.tabList.find(item => item.id === tabId);
if (tab) {
this.$router.push(tab.path);
//
this.animateTabClick(tabId);
//
setTimeout(() => {
this.$router.push(tab.path);
//
setTimeout(() => {
this.isSwitching = false;
}, 300);
}, 150);
} else {
this.isSwitching = false;
}
},
/**
* 执行Tab点击动画
* @param {string} tabId - 标签ID
*/
animateTabClick(tabId) {
// tab
const tabIndex = this.tabList.findIndex(item => item.id === tabId);
const tabs = document.querySelectorAll('.tabBar-item');
if (tabs[tabIndex]) {
//
tabs[tabIndex].classList.add('click-animation');
//
setTimeout(() => {
tabs[tabIndex].classList.remove('click-animation');
}, 300);
}
},
@ -186,6 +263,15 @@ export default {
*/
scrollToTop() {
if (this.$refs.mainContent) {
//
const btn = document.querySelector('.back-to-top');
if (btn) {
btn.classList.add('clicked');
setTimeout(() => {
btn.classList.remove('clicked');
}, 300);
}
this.$refs.mainContent.scrollTo({
top: 0,
behavior: 'smooth' //
@ -208,120 +294,5 @@ window.onresize = adapter()
</script>
<style lang="less" scoped>
.h5-container {
display: flex;
flex-direction: column;
height: 100vh;
overflow: hidden;
position: relative;
}
.main {
flex: 1;
overflow-y: auto;
-webkit-overflow-scrolling: touch; /* 为iOS添加平滑滚动 */
}
/* 返回顶部按钮样式 */
.back-to-top {
position: fixed;
right: 0.4rem;
bottom: 1.5rem; /* 在底部导航栏上方 */
z-index: 999;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 1.1rem;
height: 1.1rem;
background: linear-gradient(90deg, #275AFF 0%, #2EBDFA 100%);
border-radius: 50%;
box-shadow: 0 0.04rem 0.12rem rgba(0, 0, 0, 0.3);
cursor: pointer;
transition: all 0.3s ease;
&:active {
transform: scale(0.95);
box-shadow: 0 0.02rem 0.06rem rgba(0, 0, 0, 0.2);
}
&:hover {
background: linear-gradient(90deg, #275AFF 0%, #2EBDFA 100%);
}
.back-to-top-icon {
color: white;
font-size: 0.4rem;
font-weight: bold;
// line-height: 0.5rem;
}
.back-to-top-text {
color: white;
font-size: 0.26rem;
line-height: 0.2rem;
// margin-top: -0.04rem;
}
}
/* 淡入淡出动画 */
.fade-enter-active, .fade-leave-active {
transition: opacity 0.3s, transform 0.3s;
}
.fade-enter, .fade-leave-to {
opacity: 0;
transform: translateY(0.2rem);
}
.tabBar {
padding: .2rem 0;
background-color: #fff;
width: 100%;
display: flex;
justify-content: space-around;
align-items: center;
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 1000;
box-shadow: 0 -0.02rem .1rem rgba(0, 0, 0, 0.1);
.tabBar-item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.3s ease;
&:hover {
opacity: 0.8;
}
&.active {
.item-text {
color: #1890ff;
font-weight: bold;
}
}
}
.item-img {
margin-bottom: .1rem;
img {
width: .5rem;
height: .5rem;
display: block;
transition: transform 0.3s ease;
}
}
.item-text {
font-size: .24rem;
color: #666;
transition: color 0.3s ease;
}
}
@import url('./less/home/index.less');
</style>

View File

@ -110,9 +110,128 @@
}
.search {
width: 100%;
margin: 0.2rem 0;
margin: 0.3rem 0;
padding: 0 0.3rem;
}
.search .search-box {
display: flex;
justify-content: space-between;
background-color: #f8f9fa;
border-radius: 0.3rem;
overflow: hidden;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
border: 0.02rem solid #e9ecef;
box-shadow: 0 0.02rem 0.06rem rgba(0, 0, 0, 0.04);
}
.search .search-box:focus-within {
transform: translateY(-0.01rem);
}
.search .search-btn {
font-size: 0.2rem;
display: flex;
justify-content: center;
align-items: center;
width: 18%;
color: #fff;
padding: 0.18rem 0;
background: linear-gradient(90deg, #1f70ff, #3a8cff);
border-bottom-right-radius: 0.3rem;
border-top-right-radius: 0.3rem;
font-size: 0.28rem;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.search .search-btn::after {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.2) 50%, rgba(255, 255, 255, 0) 100%);
transition: left 0.5s ease;
}
.search .search-btn:hover {
background: linear-gradient(90deg, #0d5aff, #2a7aff);
width: 20%;
}
.search .search-btn:hover::after {
left: 100%;
}
.search .search-btn:active {
background: linear-gradient(90deg, #0a50e6, #2575e6);
transform: scale(0.98);
}
.search .input {
flex: 1;
padding: 0.16rem 0;
padding-left: 0.25rem;
display: flex;
align-items: center;
}
.search .input input {
border: none;
outline: none;
background: none;
padding: 0;
margin: 0;
width: 100%;
font-size: 0.26rem;
color: #333;
line-height: 1.4;
}
.search .input input::placeholder {
color: #adb5bd;
font-size: 0.24rem;
transition: color 0.3s ease;
}
.search .input input:focus::placeholder {
color: #868e96;
}
/* 为供应商容器和产品列表添加搜索状态样式 */
.supplier-container {
transition: opacity 0.3s ease;
}
.box {
transition: transform 0.3s ease;
}
/* 当有搜索关键词时,调整一些元素的样式 */
:global body.search-active .supplier-container {
opacity: 0.8;
}
:global body.search-active .box {
animation: searchResultAppear 0.4s ease;
}
@keyframes searchResultAppear {
0% {
opacity: 0;
transform: translateY(0.1rem);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
/* 响应式调整 */
@media (max-width: 480px) {
.search {
padding: 0 0.2rem;
margin: 0.25rem 0;
}
.search .search-box {
border-radius: 0.25rem;
}
.search .search-btn {
font-size: 0.26rem;
padding: 0.16rem 0;
}
.search .input {
padding: 0.14rem 0;
padding-left: 0.2rem;
}
.search .input input {
font-size: 0.24rem;
}
}

View File

@ -5,20 +5,24 @@
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
font-size: .39rem; /* 增大30%: .3rem * 1.3 = .39rem */
font-size: .39rem;
/* 增大30%: .3rem * 1.3 = .39rem */
font-weight: bold;
margin: .3rem 0;
}
.supplier-container {
display: flex;
flex-wrap: wrap; /* 允许换行 */
flex-wrap: wrap;
/* 允许换行 */
padding: .2rem .22rem;
gap: .15rem; /* 使用gap控制间距 */
gap: .15rem;
/* 使用gap控制间距 */
}
.supplier {
flex-shrink: 0; /* 防止收缩 */
flex-shrink: 0;
/* 防止收缩 */
.supplier-title {
font-size: .28rem;
@ -29,7 +33,8 @@
cursor: pointer;
transition: all 0.3s ease;
white-space: nowrap; /* 防止文字换行 */
white-space: nowrap;
/* 防止文字换行 */
&:hover {
background-color: #e0e0e0;
@ -52,6 +57,7 @@
flex-wrap: wrap;
justify-content: space-between;
padding: 0 .3rem;
.box-item {
display: flex;
width: 48%;
@ -69,19 +75,21 @@
border-color: #1f70ff;
}
.item-tit{
.item-tit {
font-size: .26rem;
color: #000;
font-weight: bold;
margin-bottom: .1rem;
}
.item-detail{
.item-detail {
color: #666;
font-size: .22rem;
margin: .15rem 0;
line-height: 1.4;
}
.item-desc{
.item-desc {
color: #666;
background-color: #f8f9fa;
font-size: .2rem;
@ -90,11 +98,13 @@
margin-bottom: .15rem;
border: .01rem solid #e9ecef;
}
.item-btn{
.item-btn {
width: 100%;
display: flex;
justify-content: flex-end;
.btn{
.btn {
background: linear-gradient(90deg, #1f70ff, #3a8cff);
color: #fff;
padding: .08rem .2rem;
@ -113,11 +123,170 @@
}
}
}
.search{
.search {
width: 100%;
margin: .2rem 0;
display: flex;
.search-btn{
font-size: .2rem;
margin: .3rem 0;
padding: 0 .3rem;
.search-box {
display: flex;
justify-content: space-between;
background-color: #f8f9fa;
border-radius: .3rem;
overflow: hidden;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
border: .02rem solid #e9ecef;
box-shadow: 0 .02rem .06rem rgba(0, 0, 0, 0.04);
// &:hover {
// border-color: #ced4da;
// background-color: #fff;
// box-shadow: 0 .04rem .12rem rgba(0, 0, 0, 0.08);
// }
&:focus-within {
// border-color: #1f70ff;
// background-color: #fff;
// box-shadow: 0 .04rem .16rem rgba(31, 112, 255, 0.15);
transform: translateY(-0.01rem);
}
}
.search-btn {
display: flex;
justify-content: center;
align-items: center;
width: 18%;
color: #fff;
padding: .18rem 0;
background: linear-gradient(90deg, #1f70ff, #3a8cff);
border-bottom-right-radius: .3rem;
border-top-right-radius: .3rem;
font-size: .28rem;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
&::after {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg,
rgba(255, 255, 255, 0) 0%,
rgba(255, 255, 255, 0.2) 50%,
rgba(255, 255, 255, 0) 100%);
transition: left 0.5s ease;
}
&:hover {
background: linear-gradient(90deg, #0d5aff, #2a7aff);
width: 20%;
&::after {
left: 100%;
}
}
&:active {
background: linear-gradient(90deg, #0a50e6, #2575e6);
transform: scale(0.98);
}
}
.input {
flex: 1;
padding: .16rem 0;
padding-left: .25rem;
display: flex;
align-items: center;
input {
border: none;
outline: none;
background: none;
padding: 0;
margin: 0;
width: 100%;
font-size: .26rem;
color: #333;
line-height: 1.4;
&::placeholder {
color: #adb5bd;
font-size: .24rem;
transition: color 0.3s ease;
}
&:focus {
&::placeholder {
color: #868e96;
}
}
}
}
}
/* 为供应商容器和产品列表添加搜索状态样式 */
.supplier-container {
transition: opacity 0.3s ease;
}
.box {
transition: transform 0.3s ease;
}
/* 当有搜索关键词时,调整一些元素的样式 */
:global {
body.search-active {
.supplier-container {
opacity: 0.8;
}
.box {
animation: searchResultAppear 0.4s ease;
}
}
}
@keyframes searchResultAppear {
0% {
opacity: 0;
transform: translateY(.1rem);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
/* 响应式调整 */
@media (max-width: 480px) {
.search {
padding: 0 .2rem;
margin: .25rem 0;
.search-box {
border-radius: .25rem;
}
.search-btn {
font-size: .26rem;
padding: .16rem 0;
}
.input {
padding: .14rem 0;
padding-left: .2rem;
input {
font-size: .24rem;
}
}
}
}

View File

@ -117,3 +117,130 @@
transform: translateY(-0.02rem);
box-shadow: 0 0.04rem 0.1rem rgba(31, 112, 255, 0.3);
}
.search {
width: 100%;
margin: 0.3rem 0;
padding: 0 0.3rem;
}
.search .search-box {
display: flex;
justify-content: space-between;
background-color: #f8f9fa;
border-radius: 0.3rem;
overflow: hidden;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
border: 0.02rem solid #e9ecef;
box-shadow: 0 0.02rem 0.06rem rgba(0, 0, 0, 0.04);
}
.search .search-box:focus-within {
transform: translateY(-0.01rem);
}
.search .search-btn {
display: flex;
justify-content: center;
align-items: center;
width: 18%;
color: #fff;
padding: 0.18rem 0;
background: linear-gradient(90deg, #1f70ff, #3a8cff);
border-bottom-right-radius: 0.3rem;
border-top-right-radius: 0.3rem;
font-size: 0.28rem;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.search .search-btn::after {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.2) 50%, rgba(255, 255, 255, 0) 100%);
transition: left 0.5s ease;
}
.search .search-btn:hover {
background: linear-gradient(90deg, #0d5aff, #2a7aff);
width: 20%;
}
.search .search-btn:hover::after {
left: 100%;
}
.search .search-btn:active {
background: linear-gradient(90deg, #0a50e6, #2575e6);
transform: scale(0.98);
}
.search .input {
flex: 1;
padding: 0.16rem 0;
padding-left: 0.25rem;
display: flex;
align-items: center;
}
.search .input input {
border: none;
outline: none;
background: none;
padding: 0;
margin: 0;
width: 100%;
font-size: 0.26rem;
color: #333;
line-height: 1.4;
}
.search .input input::placeholder {
color: #adb5bd;
font-size: 0.24rem;
transition: color 0.3s ease;
}
.search .input input:focus::placeholder {
color: #868e96;
}
/* 为供应商容器和产品列表添加搜索状态样式 */
.supplier-container {
transition: opacity 0.3s ease;
}
.box {
transition: transform 0.3s ease;
}
/* 当有搜索关键词时,调整一些元素的样式 */
:global body.search-active .supplier-container {
opacity: 0.8;
}
:global body.search-active .box {
animation: searchResultAppear 0.4s ease;
}
@keyframes searchResultAppear {
0% {
opacity: 0;
transform: translateY(0.1rem);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
/* 响应式调整 */
@media (max-width: 480px) {
.search {
padding: 0 0.2rem;
margin: 0.25rem 0;
}
.search .search-box {
border-radius: 0.25rem;
}
.search .search-btn {
font-size: 0.26rem;
padding: 0.16rem 0;
}
.search .input {
padding: 0.14rem 0;
padding-left: 0.2rem;
}
.search .input input {
font-size: 0.24rem;
}
}

View File

@ -134,3 +134,169 @@
}
}
}
.search {
width: 100%;
margin: .3rem 0;
padding: 0 .3rem;
.search-box {
display: flex;
justify-content: space-between;
background-color: #f8f9fa;
border-radius: .3rem;
overflow: hidden;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
border: .02rem solid #e9ecef;
box-shadow: 0 .02rem .06rem rgba(0, 0, 0, 0.04);
// &:hover {
// border-color: #ced4da;
// background-color: #fff;
// box-shadow: 0 .04rem .12rem rgba(0, 0, 0, 0.08);
// }
&:focus-within {
// border-color: #1f70ff;
// background-color: #fff;
// box-shadow: 0 .04rem .16rem rgba(31, 112, 255, 0.15);
transform: translateY(-0.01rem);
}
}
.search-btn {
display: flex;
justify-content: center;
align-items: center;
width: 18%;
color: #fff;
padding: .18rem 0;
background: linear-gradient(90deg, #1f70ff, #3a8cff);
border-bottom-right-radius: .3rem;
border-top-right-radius: .3rem;
font-size: .28rem;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
&::after {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg,
rgba(255, 255, 255, 0) 0%,
rgba(255, 255, 255, 0.2) 50%,
rgba(255, 255, 255, 0) 100%);
transition: left 0.5s ease;
}
&:hover {
background: linear-gradient(90deg, #0d5aff, #2a7aff);
width: 20%;
&::after {
left: 100%;
}
}
&:active {
background: linear-gradient(90deg, #0a50e6, #2575e6);
transform: scale(0.98);
}
}
.input {
flex: 1;
padding: .16rem 0;
padding-left: .25rem;
display: flex;
align-items: center;
input {
border: none;
outline: none;
background: none;
padding: 0;
margin: 0;
width: 100%;
font-size: .26rem;
color: #333;
line-height: 1.4;
&::placeholder {
color: #adb5bd;
font-size: .24rem;
transition: color 0.3s ease;
}
&:focus {
&::placeholder {
color: #868e96;
}
}
}
}
}
/* 为供应商容器和产品列表添加搜索状态样式 */
.supplier-container {
transition: opacity 0.3s ease;
}
.box {
transition: transform 0.3s ease;
}
/* 当有搜索关键词时,调整一些元素的样式 */
:global {
body.search-active {
.supplier-container {
opacity: 0.8;
}
.box {
animation: searchResultAppear 0.4s ease;
}
}
}
@keyframes searchResultAppear {
0% {
opacity: 0;
transform: translateY(.1rem);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
/* 响应式调整 */
@media (max-width: 480px) {
.search {
padding: 0 .2rem;
margin: .25rem 0;
.search-box {
border-radius: .25rem;
}
.search-btn {
font-size: .26rem;
padding: .16rem 0;
}
.input {
padding: .14rem 0;
padding-left: .2rem;
input {
font-size: .24rem;
}
}
}
}

View File

@ -95,7 +95,7 @@
width: var(--dialog-width, 6rem) !important;
max-width: 90%;
border-radius: 0.08rem;
z-index: 99999;
z-index: 9999;
}
::v-deep .product-consult-dialog.el-dialog .el-dialog__header {
padding: 0.2rem 0.3rem 0.1rem;

View File

@ -108,7 +108,7 @@
width: var(--dialog-width, 6rem) !important;
max-width: 90%;
border-radius: .08rem;
z-index: 99999;
z-index: 9999;
.el-dialog__header {
padding: .2rem .3rem .1rem;

View File

@ -0,0 +1,365 @@
.h5-container {
display: flex;
flex-direction: column;
height: 100vh;
overflow: hidden;
position: relative;
}
.main {
flex: 1;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
/* 为iOS添加平滑滚动 */
}
/* 页面切换动画 */
.fade-enter-active,
.fade-leave-active {
transition: all 0.3s ease;
}
.fade-enter-from {
opacity: 0;
transform: translateY(0.2rem);
}
.fade-leave-to {
opacity: 0;
transform: translateY(-0.2rem);
}
/* 返回顶部按钮样式 */
.back-to-top {
position: fixed;
right: 0.4rem;
bottom: 1.5rem;
/* 在底部导航栏上方 */
z-index: 999;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 1.1rem;
height: 1.1rem;
background: linear-gradient(90deg, #275AFF 0%, #2EBDFA 100%);
border-radius: 50%;
box-shadow: 0 0.08rem 0.24rem rgba(102, 126, 234, 0.4);
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
user-select: none;
-webkit-tap-highlight-color: transparent;
/* 悬停效果 */
/* 激活效果 */
/* 点击动画 */
}
.back-to-top:hover {
transform: translateY(-0.1rem);
box-shadow: 0 0.12rem 0.36rem rgba(102, 126, 234, 0.6);
background: linear-gradient(90deg, #275AFF 0%, #2EBDFA 100%);
}
.back-to-top:active {
transform: scale(0.95);
}
.back-to-top.clicked {
animation: pulse 0.3s ease;
}
.back-to-top .back-to-top-icon {
width: 0.45rem;
height: 0.45rem;
color: white;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 0.04rem;
}
.back-to-top .back-to-top-icon svg {
width: 100%;
height: 100%;
stroke: currentColor;
transition: transform 0.3s ease;
}
.back-to-top .back-to-top-text {
color: white;
font-size: 0.24rem;
font-weight: 500;
line-height: 1;
letter-spacing: 0.02rem;
text-shadow: 0 0.02rem 0.04rem rgba(0, 0, 0, 0.2);
}
/* 脉冲动画 */
@keyframes pulse {
0% {
transform: scale(1);
}
50% {
transform: scale(0.9);
}
100% {
transform: scale(1);
}
}
/* 返回顶部按钮动画 */
.fade-scale-enter-active,
.fade-scale-leave-active {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.fade-scale-enter-from,
.fade-scale-leave-to {
opacity: 0;
transform: scale(0.8) translateY(0.2rem);
}
/* TabBar 样式 */
.tabBar {
padding: 0.2rem 0;
background-color: rgba(255, 255, 255, 0.95);
width: 100%;
display: flex;
justify-content: space-around;
align-items: center;
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 1000;
box-shadow: 0 -0.02rem 0.2rem rgba(0, 0, 0, 0.08);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border-top: 1px solid rgba(0, 0, 0, 0.05);
}
.tabBar .tabBar-item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
padding: 0.1rem 0.15rem;
border-radius: 0.3rem;
position: relative;
overflow: hidden;
user-select: none;
/* 悬停效果 */
/* 激活状态 */
/* 点击动画 */
/* 激活指示器 */
}
.tabBar .tabBar-item:hover {
background-color: rgba(24, 144, 255, 0.08);
transform: translateY(-0.05rem);
}
.tabBar .tabBar-item.active .item-text {
color: #1890ff;
font-weight: 600;
}
.tabBar .tabBar-item.click-animation {
animation: tabClick 0.3s ease;
}
.tabBar .tabBar-item .active-indicator {
position: absolute;
bottom: 0.05rem;
left: 50%;
transform: translateX(-50%);
width: 0.3rem;
height: 0.04rem;
border-radius: 0.02rem;
animation: indicatorAppear 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
.tabBar .item-img {
margin-bottom: 0.08rem;
position: relative;
width: 0.5rem;
height: 0.5rem;
display: flex;
align-items: center;
justify-content: center;
}
.tabBar .item-img img {
width: 100%;
height: 100%;
display: block;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.tabBar .item-text {
font-size: 0.24rem;
color: #666;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
height: 0.3rem;
display: flex;
align-items: center;
justify-content: center;
}
/* 图标动画 */
.icon-bounce-enter-active {
animation: iconBounceIn 0.4s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
.icon-bounce-leave-active {
animation: iconBounceOut 0.3s ease;
}
@keyframes iconBounceIn {
0% {
opacity: 0;
transform: scale(0.3) rotate(-30deg);
}
50% {
transform: scale(1.2) rotate(10deg);
}
70% {
transform: scale(0.9) rotate(-5deg);
}
100% {
opacity: 1;
transform: scale(1) rotate(0deg);
}
}
@keyframes iconBounceOut {
0% {
opacity: 1;
transform: scale(1) rotate(0deg);
}
100% {
opacity: 0;
transform: scale(0.5) rotate(30deg);
}
}
/* 文字动画 */
.text-slide-enter-active {
animation: textSlideIn 0.3s ease-out;
}
.text-slide-leave-active {
animation: textSlideOut 0.2s ease-in;
}
@keyframes textSlideIn {
0% {
opacity: 0;
transform: translateY(0.1rem);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
@keyframes textSlideOut {
0% {
opacity: 1;
transform: translateY(0);
}
100% {
opacity: 0;
transform: translateY(-0.1rem);
}
}
/* Tab点击动画 */
@keyframes tabClick {
0% {
transform: scale(1);
}
50% {
transform: scale(0.95);
}
100% {
transform: scale(1);
}
}
/* 指示器出现动画 */
@keyframes indicatorAppear {
0% {
opacity: 0;
transform: translateX(-50%) scaleX(0);
}
100% {
opacity: 1;
transform: translateX(-50%) scaleX(1);
}
}
/* 响应式调整 */
@media (max-width: 480px) {
.back-to-top {
right: 0.3rem;
bottom: 1.6rem;
width: 1rem;
height: 1rem;
}
.back-to-top .back-to-top-icon {
width: 0.4rem;
height: 0.4rem;
margin-bottom: 0.03rem;
}
.back-to-top .back-to-top-text {
font-size: 0.22rem;
}
.tabBar {
padding: 0.15rem 0;
}
.tabBar .tabBar-item {
padding: 0.08rem 0.12rem;
}
.tabBar .item-img {
width: 0.45rem;
height: 0.45rem;
}
.tabBar .item-text {
font-size: 0.22rem;
}
}
@media (min-width: 768px) {
.back-to-top {
right: 0.5rem;
bottom: 2rem;
width: 1.2rem;
height: 1.2rem;
}
.back-to-top .back-to-top-icon {
width: 0.5rem;
height: 0.5rem;
margin-bottom: 0.05rem;
}
.back-to-top .back-to-top-text {
font-size: 0.26rem;
}
}
/* 深色模式支持 */
@media (prefers-color-scheme: dark) {
.back-to-top {
background: linear-gradient(90deg, #275AFF 0%, #2EBDFA 100%);
box-shadow: 0 0.08rem 0.24rem rgba(138, 43, 226, 0.4);
}
.back-to-top:hover {
background: linear-gradient(90deg, #275AFF 0%, #2EBDFA 100%);
box-shadow: 0 0.12rem 0.36rem rgba(138, 43, 226, 0.6);
}
.tabBar {
background-color: rgba(30, 30, 30, 0.95);
border-top: 1px solid rgba(255, 255, 255, 0.05);
}
.tabBar .tabBar-item .item-text {
color: #b0b0b0;
}
.tabBar .tabBar-item:hover {
background-color: rgba(100, 181, 246, 0.08);
}
.tabBar .tabBar-item.active .item-text {
color: #64b5f6;
}
.tabBar .tabBar-item.active .active-indicator {
background: linear-gradient(90deg, #64b5f6, #81c784);
}
}
/* 安全区域适配iPhone X及以上机型 */
@supports (padding: max(0px)) {
.back-to-top {
bottom: calc(1.5rem + env(safe-area-inset-bottom, 0));
}
.tabBar {
padding-bottom: calc(0.2rem + env(safe-area-inset-bottom, 0));
}
@media (max-width: 480px) {
.back-to-top {
bottom: calc(1.6rem + env(safe-area-inset-bottom, 0));
}
.tabBar {
padding-bottom: calc(0.15rem + env(safe-area-inset-bottom, 0));
}
}
@media (min-width: 768px) {
.back-to-top {
bottom: calc(2rem + env(safe-area-inset-bottom, 0));
}
}
}

View File

@ -0,0 +1,438 @@
.h5-container {
display: flex;
flex-direction: column;
height: 100vh;
overflow: hidden;
position: relative;
}
.main {
flex: 1;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
/* 为iOS添加平滑滚动 */
}
/* 页面切换动画 */
.fade-enter-active,
.fade-leave-active {
transition: all 0.3s ease;
}
.fade-enter-from {
opacity: 0;
transform: translateY(0.2rem);
}
.fade-leave-to {
opacity: 0;
transform: translateY(-0.2rem);
}
/* 返回顶部按钮样式 */
.back-to-top {
position: fixed;
right: 0.4rem;
bottom: 1.5rem;
/* 在底部导航栏上方 */
z-index: 999;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 1.1rem;
height: 1.1rem;
background: linear-gradient(90deg, #275AFF 0%, #2EBDFA 100%);
border-radius: 50%;
box-shadow: 0 0.08rem 0.24rem rgba(102, 126, 234, 0.4);
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
user-select: none;
-webkit-tap-highlight-color: transparent;
/* 悬停效果 */
&:hover {
transform: translateY(-0.1rem);
box-shadow: 0 0.12rem 0.36rem rgba(102, 126, 234, 0.6);
background: linear-gradient(90deg, #275AFF 0%, #2EBDFA 100%);
}
/* 激活效果 */
&:active {
transform: scale(0.95);
}
/* 点击动画 */
&.clicked {
animation: pulse 0.3s ease;
}
.back-to-top-icon {
width: 0.45rem;
height: 0.45rem;
color: white;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 0.04rem;
svg {
width: 100%;
height: 100%;
stroke: currentColor;
transition: transform 0.3s ease;
}
}
.back-to-top-text {
color: white;
font-size: 0.24rem;
font-weight: 500;
line-height: 1;
letter-spacing: 0.02rem;
text-shadow: 0 0.02rem 0.04rem rgba(0, 0, 0, 0.2);
}
}
/* 脉冲动画 */
@keyframes pulse {
0% {
transform: scale(1);
}
50% {
transform: scale(0.9);
}
100% {
transform: scale(1);
}
}
/* 返回顶部按钮动画 */
.fade-scale-enter-active,
.fade-scale-leave-active {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.fade-scale-enter-from,
.fade-scale-leave-to {
opacity: 0;
transform: scale(0.8) translateY(0.2rem);
}
/* TabBar 样式 */
.tabBar {
padding: 0.2rem 0;
background-color: rgba(255, 255, 255, 0.95);
width: 100%;
display: flex;
justify-content: space-around;
align-items: center;
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 1000;
box-shadow: 0 -0.02rem 0.2rem rgba(0, 0, 0, 0.08);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border-top: 1px solid rgba(0, 0, 0, 0.05);
.tabBar-item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
padding: 0.1rem 0.15rem;
border-radius: 0.3rem;
position: relative;
overflow: hidden;
user-select: none;
/* 悬停效果 */
&:hover {
background-color: rgba(24, 144, 255, 0.08);
transform: translateY(-0.05rem);
}
/* 激活状态 */
&.active {
.item-text {
color: #1890ff;
font-weight: 600;
}
}
/* 点击动画 */
&.click-animation {
animation: tabClick 0.3s ease;
}
/* 激活指示器 */
.active-indicator {
position: absolute;
bottom: 0.05rem;
left: 50%;
transform: translateX(-50%);
width: 0.3rem;
height: 0.04rem;
// background: linear-gradient(90deg, #1890ff);
border-radius: 0.02rem;
animation: indicatorAppear 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
}
.item-img {
margin-bottom: 0.08rem;
position: relative;
width: 0.5rem;
height: 0.5rem;
display: flex;
align-items: center;
justify-content: center;
img {
width: 100%;
height: 100%;
display: block;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
}
.item-text {
font-size: 0.24rem;
color: #666;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
height: 0.3rem;
display: flex;
align-items: center;
justify-content: center;
}
}
/* 图标动画 */
.icon-bounce-enter-active {
animation: iconBounceIn 0.4s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
.icon-bounce-leave-active {
animation: iconBounceOut 0.3s ease;
}
@keyframes iconBounceIn {
0% {
opacity: 0;
transform: scale(0.3) rotate(-30deg);
}
50% {
transform: scale(1.2) rotate(10deg);
}
70% {
transform: scale(0.9) rotate(-5deg);
}
100% {
opacity: 1;
transform: scale(1) rotate(0deg);
}
}
@keyframes iconBounceOut {
0% {
opacity: 1;
transform: scale(1) rotate(0deg);
}
100% {
opacity: 0;
transform: scale(0.5) rotate(30deg);
}
}
/* 文字动画 */
.text-slide-enter-active {
animation: textSlideIn 0.3s ease-out;
}
.text-slide-leave-active {
animation: textSlideOut 0.2s ease-in;
}
@keyframes textSlideIn {
0% {
opacity: 0;
transform: translateY(0.1rem);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
@keyframes textSlideOut {
0% {
opacity: 1;
transform: translateY(0);
}
100% {
opacity: 0;
transform: translateY(-0.1rem);
}
}
/* Tab点击动画 */
@keyframes tabClick {
0% {
transform: scale(1);
}
50% {
transform: scale(0.95);
}
100% {
transform: scale(1);
}
}
/* 指示器出现动画 */
@keyframes indicatorAppear {
0% {
opacity: 0;
transform: translateX(-50%) scaleX(0);
}
100% {
opacity: 1;
transform: translateX(-50%) scaleX(1);
}
}
/* 响应式调整 */
@media (max-width: 480px) {
.back-to-top {
right: 0.3rem;
bottom: 1.6rem;
width: 1rem;
height: 1rem;
.back-to-top-icon {
width: 0.4rem;
height: 0.4rem;
margin-bottom: 0.03rem;
}
.back-to-top-text {
font-size: 0.22rem;
}
}
.tabBar {
padding: 0.15rem 0;
.tabBar-item {
padding: 0.08rem 0.12rem;
}
.item-img {
width: 0.45rem;
height: 0.45rem;
}
.item-text {
font-size: 0.22rem;
}
}
}
@media (min-width: 768px) {
.back-to-top {
right: 0.5rem;
bottom: 2rem;
width: 1.2rem;
height: 1.2rem;
.back-to-top-icon {
width: 0.5rem;
height: 0.5rem;
margin-bottom: 0.05rem;
}
.back-to-top-text {
font-size: 0.26rem;
}
}
}
/* 深色模式支持 */
@media (prefers-color-scheme: dark) {
.back-to-top {
background: linear-gradient(90deg, #275AFF 0%, #2EBDFA 100%);
box-shadow: 0 0.08rem 0.24rem rgba(138, 43, 226, 0.4);
&:hover {
background: linear-gradient(90deg, #275AFF 0%, #2EBDFA 100%);
box-shadow: 0 0.12rem 0.36rem rgba(138, 43, 226, 0.6);
}
}
.tabBar {
background-color: rgba(30, 30, 30, 0.95);
border-top: 1px solid rgba(255, 255, 255, 0.05);
.tabBar-item {
.item-text {
color: #b0b0b0;
}
&:hover {
background-color: rgba(100, 181, 246, 0.08);
}
&.active {
.item-text {
color: #64b5f6;
}
.active-indicator {
background: linear-gradient(90deg, #64b5f6, #81c784);
}
}
}
}
}
/* 安全区域适配iPhone X及以上机型 */
@supports (padding: max(0px)) {
.back-to-top {
bottom: calc(1.5rem + env(safe-area-inset-bottom, 0));
}
.tabBar {
padding-bottom: calc(0.2rem + env(safe-area-inset-bottom, 0));
}
@media (max-width: 480px) {
.back-to-top {
bottom: calc(1.6rem + env(safe-area-inset-bottom, 0));
}
.tabBar {
padding-bottom: calc(0.15rem + env(safe-area-inset-bottom, 0));
}
}
@media (min-width: 768px) {
.back-to-top {
bottom: calc(2rem + env(safe-area-inset-bottom, 0));
}
}
}

View File

@ -26,7 +26,7 @@
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
font-size: 0.7rem;
font-size: 0.68rem;
}
.title .title-top {
font-size: 0.6rem;
@ -72,13 +72,23 @@
.journey-box .content .item-box,
.latitude-box .content .item-box {
width: 48%;
background-color: #fff;
border-radius: 0.1rem;
padding: 0.2rem;
box-shadow: 0 0.02rem 0.08rem rgba(0, 0, 0, 0.05);
box-shadow: 0 0.02rem 0.08rem rgba(39, 90, 255, 0.08);
margin-bottom: 0.2rem;
display: flex;
flex-direction: column;
background: linear-gradient(135deg, #f0f7ff 0%, #ffffff 100%);
border: 1px solid rgba(39, 90, 255, 0.1);
transition: all 0.3s ease;
}
.base-box .content .item-box:hover,
.journey-box .content .item-box:hover,
.latitude-box .content .item-box:hover {
box-shadow: 0 0.04rem 0.16rem rgba(39, 90, 255, 0.12);
transform: translateY(-2px);
border-color: rgba(39, 90, 255, 0.2);
background: linear-gradient(135deg, #e8f2ff 0%, #ffffff 100%);
}
.base-box .content .item-box .item-title,
.journey-box .content .item-box .item-title,
@ -99,7 +109,7 @@
.base-box .content .item-box .advantage-list,
.journey-box .content .item-box .advantage-list,
.latitude-box .content .item-box .advantage-list {
margin: 0.1rem 0;
display: block;
}
.base-box .content .item-box .advantage-list .advantage-item,
.journey-box .content .item-box .advantage-list .advantage-item,
@ -128,7 +138,6 @@
.base-box .content .item-box .advantage-list .advantage-item .advantage-content,
.journey-box .content .item-box .advantage-list .advantage-item .advantage-content,
.latitude-box .content .item-box .advantage-list .advantage-item .advantage-content {
flex: 1;
font-size: 0.18rem;
}
.base-box .content .item-box .item-price,
@ -245,7 +254,6 @@
background: #f5f7fa;
color: #fff;
padding: 0.4rem 0.2rem;
margin-top: 0.8rem;
}
.footer-content {
max-width: 12rem;
@ -256,7 +264,6 @@
background: #f6f8fd;
color: #333;
padding: 0.6rem 0.2rem 0.4rem;
margin-top: 1rem;
position: relative;
overflow: hidden;
border-top: 1px solid #e8edf5;
@ -279,8 +286,6 @@
display: flex;
flex-direction: column;
align-items: flex-start;
padding-bottom: 0.4rem;
margin-bottom: 0.4rem;
}
.logo-footer {
width: 2.4rem;
@ -292,38 +297,29 @@
width: 100%;
height: 100%;
}
.contact-info {
flex: 1;
.footer-center {
font-size: 0.24rem;
display: grid;
grid-template-columns: 1fr;
gap: 0.24rem;
padding: 0.3rem 0.2rem;
background: #fff;
border-radius: 0.16rem;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
margin-top: 0.4rem;
border: 1px solid #eef2f9;
width: 100%;
}
@media (min-width: 768px) {
.contact-info {
.footer-center {
grid-template-columns: 1fr 1fr;
gap: 0.3rem 0.6rem;
}
}
.contact-info .contact-item {
.footer-center .contact-item {
display: flex;
align-items: flex-start;
padding: 0.16rem 0.2rem;
background: #fff;
border-radius: 0.12rem;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
cursor: pointer;
border: 1px solid #eef2f9;
}
.contact-info .contact-item:hover {
background: #fff;
border-color: #2ebdfa;
transform: translateY(-2px);
box-shadow: 0 4px 16px rgba(39, 90, 255, 0.12);
}
.contact-info .contact-item .iconfont {
.footer-center .contact-item .iconfont {
width: 0.2rem;
height: 0.2rem;
margin-right: 0.12rem;
@ -332,31 +328,31 @@
flex-shrink: 0;
font-size: 0.26rem;
}
.contact-info .contact-item .label {
.footer-center .contact-item .label {
color: #666;
flex-shrink: 0;
font-weight: 500;
margin-right: 0.08rem;
font-size: 0.24rem;
}
.contact-info .contact-item .value {
.footer-center .contact-item .value {
color: #444;
flex: 1;
line-height: 1.5;
}
.contact-info .contact-item .phone-numbers {
.footer-center .contact-item .phone-numbers {
display: flex;
flex-direction: column;
gap: 0.08rem;
}
@media (min-width: 768px) {
.contact-info .contact-item .phone-numbers {
.footer-center .contact-item .phone-numbers {
flex-direction: row;
align-items: center;
gap: 0.16rem;
}
}
.contact-info .contact-item .phone-link {
.footer-center .contact-item .phone-link {
color: #333;
text-decoration: none;
transition: all 0.3s;
@ -364,20 +360,20 @@
font-size: 0.208rem;
/* 增大30%: 0.16rem * 1.3 = 0.208rem */
}
.contact-info .contact-item .phone-link:hover {
.footer-center .contact-item .phone-link:hover {
color: #275AFF;
text-decoration: underline;
}
.contact-info .contact-item .phone-separator {
.footer-center .contact-item .phone-separator {
color: #999;
font-weight: 300;
}
@media (max-width: 768px) {
.contact-info .contact-item .phone-separator {
.footer-center .contact-item .phone-separator {
display: none;
}
}
.contact-info .contact-item .email-link {
.footer-center .contact-item .email-link {
color: #275AFF;
text-decoration: none;
word-break: break-all;
@ -385,7 +381,7 @@
font-size: 0.208rem;
/* 增大30%: 0.16rem * 1.3 = 0.208rem */
}
.contact-info .contact-item .email-link:hover {
.footer-center .contact-item .email-link:hover {
color: #2ebdfa;
text-decoration: underline;
}

View File

@ -28,7 +28,7 @@
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
font-size: .7rem;
font-size: .68rem;
}
.title-top {
@ -78,13 +78,22 @@
.item-box {
width: 48%;
background-color: #fff;
border-radius: 0.1rem;
padding: 0.2rem;
box-shadow: 0 .02rem .08rem rgba(0, 0, 0, 0.05);
box-shadow: 0 .02rem .08rem rgba(39, 90, 255, 0.08);
margin-bottom: 0.2rem;
display: flex;
flex-direction: column;
background: linear-gradient(135deg, #f0f7ff 0%, #ffffff 100%);
border: 1px solid rgba(39, 90, 255, 0.1);
transition: all 0.3s ease;
&:hover {
box-shadow: 0 .04rem .16rem rgba(39, 90, 255, 0.12);
transform: translateY(-2px);
border-color: rgba(39, 90, 255, 0.2);
background: linear-gradient(135deg, #e8f2ff 0%, #ffffff 100%);
}
.item-title {
font-size: 0.26rem;
@ -101,14 +110,12 @@
}
.advantage-list {
margin: 0.1rem 0;
display: block;
.advantage-item {
display: block;
font-size: 0.156rem;
color: #666;
// margin-bottom: 0.08rem;
// line-height: 1.4;
.advantage-icon {
width: 0.18rem;
@ -126,7 +133,7 @@
}
.advantage-content {
flex: 1;
// flex: 1;
font-size: .18rem;
}
}
@ -249,7 +256,7 @@
background: #f5f7fa;
color: #fff;
padding: 0.4rem 0.2rem;
margin-top: 0.8rem;
// margin-top: 0.8rem;
}
.footer-content {
@ -262,7 +269,7 @@
background: #f6f8fd;
color: #333;
padding: 0.6rem 0.2rem 0.4rem;
margin-top: 1rem;
// margin-top: 1rem;
position: relative;
overflow: hidden;
border-top: 1px solid #e8edf5;
@ -289,8 +296,8 @@
display: flex;
flex-direction: column;
align-items: flex-start;
padding-bottom: 0.4rem;
margin-bottom: 0.4rem;
// padding-bottom: 0.4rem;
// margin-bottom: 0.4rem;
}
@ -306,12 +313,14 @@
}
}
.contact-info {
flex: 1;
.footer-center {
font-size: 0.24rem;
display: grid;
grid-template-columns: 1fr;
gap: 0.24rem;
padding: 0.3rem 0.2rem;
background: #fff;
border-radius: 0.16rem;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
margin-top: 0.4rem;
border: 1px solid #eef2f9;
width: 100%;
@media (min-width: 768px) {
@ -323,19 +332,7 @@
display: flex;
align-items: flex-start;
padding: 0.16rem 0.2rem;
background: #fff;
border-radius: 0.12rem;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
cursor: pointer;
border: 1px solid #eef2f9;
&:hover {
background: #fff;
border-color: #2ebdfa;
transform: translateY(-2px);
box-shadow: 0 4px 16px rgba(39, 90, 255, 0.12);
}
.iconfont {
width: 0.2rem;
@ -372,7 +369,9 @@
gap: 0.16rem;
}
}
.center{
// display: flex;
}
.phone-link {
color: #333;
text-decoration: none;
@ -434,6 +433,7 @@
&:hover {
background: #fff;
border-color: #2ebdfa;
transform: translateY(-4px);
box-shadow: 0 8px 24px rgba(39, 90, 255, 0.15);

View File

@ -4,7 +4,22 @@
<div class="top-tit">
开元云
</div>
<!-- 搜索 -->
<div class="search">
<div class="search-box">
<div class="input">
<input
type="text"
placeholder="请输入产品名称"
v-model="searchValue"
@keyup.enter="handleSearch"
/>
</div>
<div class="search-btn" @click="handleSearch">
搜索
</div>
</div>
</div>
<!-- 供应商 -->
<div v-if="cloudData.secMenu && cloudData.secMenu.length > 0" class="supplier-container">
<div
@ -32,6 +47,7 @@
v-for="product in thrMenu.value"
:key="product.id"
class="box-item"
v-show="shouldShowProduct(product)"
>
<!-- 标题 -->
<div class="item-tit">
@ -76,13 +92,14 @@ import { reqProductConsult } from '@/api/H5/index'
export default {
components: {
ProductConsultDialog,
},
data() {
return {
cloudData: {},
activeSupplierIndex: 0, //
searchValue: '', //
isSearching: false, //
//
showConsultDialog: false,
@ -116,6 +133,25 @@ export default {
}
},
//
handleSearch() {
this.isSearching = !!this.searchValue.trim()
console.log('搜索关键词:', this.searchValue)
},
//
shouldShowProduct(product) {
if (!this.isSearching) {
return true
}
//
const keyword = this.searchValue.toLowerCase().trim()
return (
(product.name && product.name.toLowerCase().includes(keyword)) ||
(product.description && product.description.toLowerCase().includes(keyword))
)
},
//
selectSupplier(index) {
this.activeSupplierIndex = index

View File

@ -21,17 +21,18 @@
<!-- 内容 -->
<div class="content">
<div class="item-box" v-for="(item, key) in baseData" :key="key">
<div class="item-title">{{ item.title }}</div>
<div class="item-description">{{ item.description }}</div>
<!-- 优势列表 -->
<div class="advantage-list" v-if="item.list && item.list.length">
<div class="advantage-item" v-for="listItem in item.list" :key="listItem.id">
<p>
<img v-if="listItem.icon" :src="getIconPath(listItem.icon)" alt="" class="advantage-icon" />
<div>
<img v-if="listItem.icon" :src="getIconPath(listItem.icon)" alt="" class="advantage-icon" />
<span v-if="listItem.name" class="advantage-name">{{ listItem.name }} : </span>
<span class="advantage-content">{{ listItem.content }}</span>
</p>
</div>
</div>
</div>
@ -61,11 +62,11 @@
<!-- 优势列表 -->
<div class="advantage-list" v-if="item.list && item.list.length">
<div class="advantage-item" v-for="listItem in item.list" :key="listItem.id">
<p>
<img v-if="listItem.icon" :src="getIconPath(listItem.icon)" alt="" class="advantage-icon" />
<div>
<img v-if="listItem.icon" :src="getIconPath(listItem.icon)" alt="" class="advantage-icon" />
<span v-if="listItem.name" class="advantage-name">{{ listItem.name }} : </span>
<span class="advantage-content">{{ listItem.content }}</span>
</p>
</div>
</div>
</div>
@ -95,11 +96,11 @@
<!-- 优势列表 -->
<div class="advantage-list" v-if="item.advantageList && item.advantageList.length">
<div class="advantage-item" v-for="advantage in item.advantageList" :key="advantage.id">
<p>
<img v-if="advantage.icon" :src="getIconPath(advantage.icon)" alt="" class="advantage-icon" />
<span class="advantage-name">{{ advantage.name }}</span>
<span class="advantage-content">{{ advantage.content }}</span>
</p>
<div>
<img v-if="advantage.icon" :src="getIconPath(advantage.icon)" alt="" class="advantage-icon" />
<span class="advantage-name">{{ advantage.name }}</span>
<span class="advantage-content">{{ advantage.content }}</span>
</div>
</div>
</div>
@ -135,7 +136,7 @@
</div>
</div>
<!-- 修改footer部分 -->
<!-- footer部分 -->
<div class="footer">
<div class="footer-content">
<!-- 顶部信息 -->
@ -144,12 +145,15 @@
<img :src="logoImg" alt="公司logo" v-if="logoImg">
<!-- <img src="@/assets/kyy/LOGO.png" alt="公司logo" class="img"> -->
</div>
<div class="contact-info">
</div>
<div class="footer-center">
<div class="center">
<div class="contact-item">
<i class="iconfont icon-dizhi"></i>
<span class="label">地址</span>
<span class="value">{{ address }}</span>
</div>
<div class="contact-item">
<i class="iconfont icon-dianhua"></i>
<span class="label">电话</span>
@ -168,8 +172,25 @@
</div>
</div>
</div>
<div class="mobile-qr">
<div class="qr-item">
<div class="qr-code">
<img src="@/assets/kyy/kyy公众号.jpg" alt="微信客服二维码">
</div>
<span class="qr-desc">扫描关注二维码</span>
</div>
<div class="qr-item">
<div class="qr-code">
<img src="@/assets/kyy/客服wechat.png" alt="微信客服二维码">
</div>
<span class="qr-desc">微信客服</span>
</div>
</div>
</div>
<!-- 备案信息 -->
<div class="footer-bottom">
<div class="icp-info">
@ -182,6 +203,7 @@
</div>
</div>
<div class="record-info">
<div class="police-record">
<img src="@/image/login/policeInsignia/policeInsignia.png" alt="公安备案图标" class="police-icon">
@ -197,33 +219,11 @@
</div>
</div>
<!-- 移动端显示的二维码 -->
<div class="mobile-qr">
<div class="qr-item">
<div class="qr-code">
<img src="@/assets/kyy/kyy公众号.jpg" alt="微信客服二维码">
</div>
<span class="qr-desc">扫描关注二维码</span>
</div>
<div class="qr-item">
<div class="qr-code">
<img src="@/assets/kyy/客服wechat.png" alt="微信客服二维码">
</div>
<span class="qr-desc">微信客服</span>
</div>
</div>
</div>
</div>
<!-- PC端显示的二维码移动端隐藏 -->
<div class="pc-qr">
<div class="qr-box">
<div class="qr-code">
<img src="@/assets/kyy/客服wechat.png" alt="微信客服二维码">
</div>
<span class="qr-content">微信客服</span>
</div>
</div>
</div>
<!-- 产品咨询弹窗 -->
<ProductConsultDialog :visible.sync="showConsultDialog" :platform-name="platformName" :qr-code="qrCode"

View File

@ -6,12 +6,19 @@
</div>
<!-- 搜索 -->
<div class="search">
<div class="search-box">
<div class="input">
<input type="text" placeholder="请输入产品名称" v-model="searchValue"></input>
<input
type="text"
placeholder="请输入产品名称"
v-model="searchValue"
@keyup.enter="handleSearch"
/>
</div>
<div class="search-btn">
搜索
<div class="search-btn" @click="handleSearch">
搜索
</div>
</div>
</div>
<!-- 供应商 -->
<div v-if="cloudData.secMenu && cloudData.secMenu.length > 0" class="supplier-container">
@ -28,7 +35,7 @@
<template v-if="cloudData.secMenu && cloudData.secMenu.length > 0 && activeSupplierIndex >= 0">
<template v-for="thrMenu in cloudData.secMenu[activeSupplierIndex].thrMenu">
<!-- 循环每个分类下的产品 -->
<div v-for="product in thrMenu.value" :key="product.id" class="box-item">
<div v-for="product in thrMenu.value" :key="product.id" class="box-item" v-show="shouldShowProduct(product)">
<!-- 标题 -->
<div class="item-tit">
{{ product.name }}
@ -73,6 +80,8 @@ export default {
return {
cloudData: {},
activeSupplierIndex: 0, //
searchValue: '', //
isSearching: false, //
//
showConsultDialog: false,
@ -106,6 +115,25 @@ export default {
}
},
//
handleSearch() {
this.isSearching = !!this.searchValue.trim()
console.log('搜索关键词:', this.searchValue)
},
//
shouldShowProduct(product) {
if (!this.isSearching) {
return true
}
//
const keyword = this.searchValue.toLowerCase().trim()
return (
(product.name && product.name.toLowerCase().includes(keyword)) ||
(this.currentCategory && this.currentCategory.thrTitle && this.currentCategory.thrTitle.toLowerCase().includes(keyword))
)
},
//
selectSupplier(index) {
this.activeSupplierIndex = index

View File

@ -13,13 +13,11 @@
</el-table-column>
<el-table-column prop="content" label="内容" min-width="180">
</el-table-column>
<el-table-column prop="create_time" label="咨询时间" min-width="180">
<el-table-column prop="update_time" label="咨询时间" min-width="180">
</el-table-column>
<el-table-column prop="update_time" label="联系时间" min-width="180">
</el-table-column>
<el-table-column prop="update_time" label="操作" min-width="180">
<el-table-column prop="update_time" label="反馈状态" min-width="180">
<template slot-scope="scope">
<el-button type="text" @click="handleEdit(scope.row)">已回复</el-button>
<el-button type="text" >{{ scope.row.feedback === '1' ? '已回复' : '未回复' }}</el-button>
</template>
</el-table-column>
</el-table>