main #50
45
b/product/home_page_product_add.dspy
Normal file
45
b/product/home_page_product_add.dspy
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
async def home_page_product_add(ns={}):
|
||||||
|
"""
|
||||||
|
添加产品信息
|
||||||
|
:param ns: 包含产品信息的字典
|
||||||
|
"""
|
||||||
|
ns_dic = {
|
||||||
|
'id': uuid(), # 固定写法
|
||||||
|
'menu_id': ns.get('menu_id'),
|
||||||
|
'name': ns.get('name'),
|
||||||
|
'description': ns.get('description'),
|
||||||
|
'label': ns.get('label'),
|
||||||
|
'product_group': ns.get('product_group'),
|
||||||
|
'url': ns.get('url'),
|
||||||
|
'list_url': ns.get('list_url'),
|
||||||
|
'icon_url': ns.get('icon_url'),
|
||||||
|
'source': ns.get('source'),
|
||||||
|
'sort_order': ns.get('sort_order', 0),
|
||||||
|
'del_flg': '0'
|
||||||
|
}
|
||||||
|
|
||||||
|
# 验证必填字段
|
||||||
|
if not ns_dic.get('menu_id') or not ns_dic.get('name'):
|
||||||
|
return {
|
||||||
|
'status': False,
|
||||||
|
'msg': 'menu_id and name are required'
|
||||||
|
}
|
||||||
|
|
||||||
|
db = DBPools()
|
||||||
|
async with db.sqlorContext('kboss') as sor:
|
||||||
|
try:
|
||||||
|
await sor.C('home_page_product_info', ns_dic)
|
||||||
|
return {
|
||||||
|
'status': True,
|
||||||
|
'msg': 'create product success',
|
||||||
|
'data': {'id': ns_dic['id']}
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
await sor.rollback()
|
||||||
|
return {
|
||||||
|
'status': False,
|
||||||
|
'msg': 'create product failed, %s' % str(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = await home_page_product_add(params_kw)
|
||||||
|
return ret
|
||||||
33
b/product/home_page_product_delete.dspy
Normal file
33
b/product/home_page_product_delete.dspy
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
async def home_page_product_delete(ns={}):
|
||||||
|
"""
|
||||||
|
软删除产品信息 id值必传 并且把del_flg值修改为1
|
||||||
|
:param ns:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if not ns.get('id'):
|
||||||
|
return {
|
||||||
|
'status': False,
|
||||||
|
'msg': 'product id is required'
|
||||||
|
}
|
||||||
|
|
||||||
|
ns_dic = {
|
||||||
|
'id': ns.get('id'),
|
||||||
|
'del_flg': '1'
|
||||||
|
}
|
||||||
|
db = DBPools()
|
||||||
|
async with db.sqlorContext('kboss') as sor:
|
||||||
|
try:
|
||||||
|
await sor.U('home_page_product_info', ns_dic)
|
||||||
|
return {
|
||||||
|
'status': True,
|
||||||
|
'msg': 'delete product success'
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
await sor.rollback()
|
||||||
|
return {
|
||||||
|
'status': False,
|
||||||
|
'msg': 'delete product failed, %s' % str(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = await home_page_product_delete(params_kw)
|
||||||
|
return ret
|
||||||
45
b/product/home_page_product_menu_add.dspy
Normal file
45
b/product/home_page_product_menu_add.dspy
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
async def home_page_product_menu_add(ns={}):
|
||||||
|
"""
|
||||||
|
添加首页产品菜单
|
||||||
|
:param ns: 包含菜单信息的字典
|
||||||
|
"""
|
||||||
|
ns_dic = {
|
||||||
|
'id': uuid(), # 固定写法
|
||||||
|
'parent_id': ns.get('parent_id'), # NULL表示一级菜单
|
||||||
|
'menu_level': ns.get('menu_level'), # 1-一级, 2-二级, 3-三级
|
||||||
|
'title': ns.get('title'),
|
||||||
|
'sort_order': ns.get('sort_order', 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# 验证必填字段
|
||||||
|
if not ns_dic.get('menu_level') or not ns_dic.get('title'):
|
||||||
|
return {
|
||||||
|
'status': False,
|
||||||
|
'msg': 'menu_level and title are required'
|
||||||
|
}
|
||||||
|
|
||||||
|
if ns.get('menu_level') > 1 and not ns.get('parent_id'):
|
||||||
|
return {
|
||||||
|
'status': False,
|
||||||
|
'msg': 'parent_id is required for menu_level > 1'
|
||||||
|
}
|
||||||
|
|
||||||
|
db = DBPools()
|
||||||
|
async with db.sqlorContext('kboss') as sor:
|
||||||
|
try:
|
||||||
|
await sor.C('home_page_product_menu', ns_dic)
|
||||||
|
return {
|
||||||
|
'status': True,
|
||||||
|
'msg': 'create menu success',
|
||||||
|
'data': {'id': ns_dic['id']}
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
await sor.rollback()
|
||||||
|
return {
|
||||||
|
'status': False,
|
||||||
|
'msg': 'create menu failed, %s' % str(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = await home_page_product_menu_add(params_kw)
|
||||||
|
return ret
|
||||||
33
b/product/home_page_product_menu_delete.dspy
Normal file
33
b/product/home_page_product_menu_delete.dspy
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
async def home_page_product_menu_delete(ns={}):
|
||||||
|
"""
|
||||||
|
软删除菜单 id值必传 并且把del_flg值修改为1
|
||||||
|
:param ns:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if not ns.get('id'):
|
||||||
|
return {
|
||||||
|
'status': False,
|
||||||
|
'msg': 'menu id is required'
|
||||||
|
}
|
||||||
|
|
||||||
|
ns_dic = {
|
||||||
|
'id': ns.get('id'),
|
||||||
|
'del_flg': '1'
|
||||||
|
}
|
||||||
|
db = DBPools()
|
||||||
|
async with db.sqlorContext('kboss') as sor:
|
||||||
|
try:
|
||||||
|
await sor.U('home_page_product_menu', ns_dic)
|
||||||
|
return {
|
||||||
|
'status': True,
|
||||||
|
'msg': 'delete menu success'
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
await sor.rollback()
|
||||||
|
return {
|
||||||
|
'status': False,
|
||||||
|
'msg': 'delete menu failed, %s' % str(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = await home_page_product_menu_delete(params_kw)
|
||||||
|
return ret
|
||||||
229
b/product/home_page_product_menu_search.dspy
Normal file
229
b/product/home_page_product_menu_search.dspy
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
async def home_page_product_menu_search(ns={}):
|
||||||
|
"""
|
||||||
|
查找菜单,支持按层级和父级ID筛选
|
||||||
|
规则:
|
||||||
|
1. 无参数时,返回所有数据并有嵌套层级
|
||||||
|
2. 有参数时,menu_level和title必传,返回当前层级以及向下的嵌套层级数据
|
||||||
|
:param ns:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
db = DBPools()
|
||||||
|
async with db.sqlorContext('kboss') as sor:
|
||||||
|
try:
|
||||||
|
# 无参数时,返回所有数据
|
||||||
|
if not ns:
|
||||||
|
conditions = {"del_flg": "0"}
|
||||||
|
result = await sor.R('home_page_product_menu', conditions)
|
||||||
|
menu_tree = await build_menu_tree(result)
|
||||||
|
return {
|
||||||
|
'status': True,
|
||||||
|
'msg': 'search all menu success',
|
||||||
|
'data': menu_tree
|
||||||
|
}
|
||||||
|
|
||||||
|
# 有参数时,验证必填参数
|
||||||
|
# if not ns.get('menu_level') or not ns.get('title'):
|
||||||
|
# return {
|
||||||
|
# 'status': False,
|
||||||
|
# 'msg': 'menu_level and title are required when parameters are provided'
|
||||||
|
# }
|
||||||
|
|
||||||
|
# 获取指定层级及向下层级的数据
|
||||||
|
menu_level = int(ns.get('menu_level'))
|
||||||
|
title = ns.get('title')
|
||||||
|
|
||||||
|
# 构建查询条件,获取当前层级及向下层级的数据
|
||||||
|
conditions = {"del_flg": "0"}
|
||||||
|
|
||||||
|
# 根据层级获取相应的数据
|
||||||
|
if menu_level == 1:
|
||||||
|
# 获取所有层级的数据,用于构建完整的树形结构
|
||||||
|
all_conditions = {"del_flg": "0"}
|
||||||
|
if title:
|
||||||
|
# 如果指定了标题,获取所有层级中标题匹配的数据
|
||||||
|
all_result = await sor.R('home_page_product_menu', all_conditions)
|
||||||
|
filtered_result = [item for item in all_result if title in item.get('title', '')]
|
||||||
|
|
||||||
|
# 获取匹配项的所有子级数据
|
||||||
|
result = []
|
||||||
|
parent_ids = set()
|
||||||
|
|
||||||
|
# 收集一级菜单的ID
|
||||||
|
for item in filtered_result:
|
||||||
|
if item['menu_level'] == 1:
|
||||||
|
parent_ids.add(item['id'])
|
||||||
|
result.append(item)
|
||||||
|
|
||||||
|
# 获取所有子级数据
|
||||||
|
if parent_ids:
|
||||||
|
all_data = await sor.R('home_page_product_menu', {"del_flg": "0"})
|
||||||
|
for item in all_data:
|
||||||
|
if item['parent_id'] in parent_ids:
|
||||||
|
result.append(item)
|
||||||
|
|
||||||
|
menu_tree = await build_menu_tree(result)
|
||||||
|
else:
|
||||||
|
# 获取所有数据
|
||||||
|
result = await sor.R('home_page_product_menu', all_conditions)
|
||||||
|
menu_tree = await build_menu_tree(result)
|
||||||
|
|
||||||
|
elif menu_level == 2:
|
||||||
|
# 获取二级菜单及其子级(三级)
|
||||||
|
all_conditions = {"del_flg": "0"}
|
||||||
|
all_result = await sor.R('home_page_product_menu', all_conditions)
|
||||||
|
|
||||||
|
# 筛选匹配的二级菜单
|
||||||
|
level2_items = [item for item in all_result if item['menu_level'] == 2 and title in item.get('title', '')]
|
||||||
|
|
||||||
|
if level2_items:
|
||||||
|
parent_ids = set(item['id'] for item in level2_items)
|
||||||
|
|
||||||
|
# 获取对应的一级菜单
|
||||||
|
result = []
|
||||||
|
for item in all_result:
|
||||||
|
if item['menu_level'] == 1 and any(level2['parent_id'] == item['id'] for level2 in level2_items):
|
||||||
|
result.append(item)
|
||||||
|
|
||||||
|
# 添加匹配的二级菜单
|
||||||
|
result.extend(level2_items)
|
||||||
|
|
||||||
|
# 获取三级子菜单
|
||||||
|
for item in all_result:
|
||||||
|
if item['menu_level'] == 3 and item['parent_id'] in parent_ids:
|
||||||
|
result.append(item)
|
||||||
|
|
||||||
|
menu_tree = await build_menu_tree(result)
|
||||||
|
else:
|
||||||
|
menu_tree = []
|
||||||
|
|
||||||
|
elif menu_level == 3:
|
||||||
|
# 获取三级菜单
|
||||||
|
all_conditions = {"del_flg": "0"}
|
||||||
|
all_result = await sor.R('home_page_product_menu', all_conditions)
|
||||||
|
|
||||||
|
# 筛选匹配的三级菜单
|
||||||
|
level3_items = [item for item in all_result if item['menu_level'] == 3 and title in item.get('title', '')]
|
||||||
|
|
||||||
|
if level3_items:
|
||||||
|
result = []
|
||||||
|
|
||||||
|
# 获取对应的二级和一级菜单
|
||||||
|
level2_ids = set()
|
||||||
|
level1_ids = set()
|
||||||
|
|
||||||
|
for item in level3_items:
|
||||||
|
level2_ids.add(item['parent_id'])
|
||||||
|
|
||||||
|
for item in all_result:
|
||||||
|
if item['menu_level'] == 2 and item['id'] in level2_ids:
|
||||||
|
result.append(item)
|
||||||
|
level1_ids.add(item['parent_id'])
|
||||||
|
|
||||||
|
for item in all_result:
|
||||||
|
if item['menu_level'] == 1 and item['id'] in level1_ids:
|
||||||
|
result.append(item)
|
||||||
|
|
||||||
|
# 添加匹配的三级菜单
|
||||||
|
result.extend(level3_items)
|
||||||
|
|
||||||
|
menu_tree = await build_menu_tree(result)
|
||||||
|
else:
|
||||||
|
menu_tree = []
|
||||||
|
else:
|
||||||
|
return {
|
||||||
|
'status': False,
|
||||||
|
'msg': 'Invalid menu_level, must be 1, 2, or 3'
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
'status': True,
|
||||||
|
'msg': 'search menu success',
|
||||||
|
'data': menu_tree
|
||||||
|
}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return {
|
||||||
|
'status': False,
|
||||||
|
'msg': 'search menu failed, %s' % str(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
async def get_home_page_product(ns={}):
|
||||||
|
db = DBPools()
|
||||||
|
async with db.sqlorContext('kboss') as sor:
|
||||||
|
find_sql = """select * from home_page_product_info where menu_id = '%s' and del_flg = '0' order by sort_order asc;""" % ns.get("menu_id")
|
||||||
|
result = await sor.sqlExe(find_sql, {})
|
||||||
|
return result
|
||||||
|
|
||||||
|
# 构建菜单树形结构
|
||||||
|
async def build_menu_tree(menu_list, target_level=None, target_title=None):
|
||||||
|
"""
|
||||||
|
将扁平的菜单列表转换为树形结构
|
||||||
|
:param menu_list: 菜单列表
|
||||||
|
:param target_level: 目标层级(可选)
|
||||||
|
:param target_title: 目标标题(可选)
|
||||||
|
:return: 树形结构的菜单
|
||||||
|
"""
|
||||||
|
|
||||||
|
# 通过sort_order对菜单进行排序
|
||||||
|
menu_list.sort(key=lambda x: x['sort_order'], reverse=True)
|
||||||
|
|
||||||
|
menu_dict = {}
|
||||||
|
result = []
|
||||||
|
|
||||||
|
# 先创建所有菜单的字典
|
||||||
|
for menu in menu_list:
|
||||||
|
# 创建菜单节点的基本结构
|
||||||
|
menu_node = {
|
||||||
|
'id': menu['id'],
|
||||||
|
'title': menu['title'],
|
||||||
|
'menu_level': menu['menu_level'],
|
||||||
|
'parent_id': menu['parent_id'],
|
||||||
|
'children': [] # 动态子菜单数组
|
||||||
|
}
|
||||||
|
menu_dict[menu['id']] = menu_node
|
||||||
|
|
||||||
|
# 构建父子关系
|
||||||
|
for menu in menu_list:
|
||||||
|
menu_node = menu_dict[menu['id']]
|
||||||
|
parent_id = menu['parent_id']
|
||||||
|
|
||||||
|
# 如果有父级且父级存在
|
||||||
|
if parent_id and parent_id in menu_dict:
|
||||||
|
parent_node = menu_dict[parent_id]
|
||||||
|
parent_node['children'].append(menu_node)
|
||||||
|
else:
|
||||||
|
# 没有父级的菜单(根节点)
|
||||||
|
result.append(menu_node)
|
||||||
|
|
||||||
|
# 递归构建层级结构
|
||||||
|
async def build_hierarchy(node, level=1):
|
||||||
|
"""递归构建层级结构"""
|
||||||
|
if level == 1:
|
||||||
|
return {
|
||||||
|
'id': node['id'],
|
||||||
|
'firTitle': node['title'],
|
||||||
|
'secMenu': [await build_hierarchy(child, 2) for child in node['children']]
|
||||||
|
}
|
||||||
|
elif level == 2:
|
||||||
|
return {
|
||||||
|
'id': node['id'],
|
||||||
|
'secTitle': node['title'],
|
||||||
|
'thrMenu': [await build_hierarchy(child, 3) for child in node['children']]
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
# 三级及以上
|
||||||
|
return {
|
||||||
|
'id': node['id'],
|
||||||
|
'thrTitle': node['title'],
|
||||||
|
'value': await get_home_page_product({'menu_id': node['id']}) # 三级菜单没有子菜单,value为空列表
|
||||||
|
}
|
||||||
|
|
||||||
|
# 构建最终的树形结构
|
||||||
|
final_result = []
|
||||||
|
for root_node in result:
|
||||||
|
final_result.append(await build_hierarchy(root_node))
|
||||||
|
|
||||||
|
return final_result
|
||||||
|
|
||||||
|
ret = await home_page_product_menu_search(params_kw)
|
||||||
|
return ret
|
||||||
40
b/product/home_page_product_menu_update.dspy
Normal file
40
b/product/home_page_product_menu_update.dspy
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
async def home_page_product_menu_update(ns={}):
|
||||||
|
"""
|
||||||
|
更新菜单信息
|
||||||
|
:param ns:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if not ns.get('id'):
|
||||||
|
return {
|
||||||
|
'status': False,
|
||||||
|
'msg': 'menu id is required'
|
||||||
|
}
|
||||||
|
|
||||||
|
# 构建更新字段,只更新传入的字段
|
||||||
|
ns_dic = {'id': ns.get('id')}
|
||||||
|
if ns.get('title'):
|
||||||
|
ns_dic['title'] = ns.get('title')
|
||||||
|
if ns.get('parent_id') is not None:
|
||||||
|
ns_dic['parent_id'] = ns.get('parent_id')
|
||||||
|
if ns.get('menu_level'):
|
||||||
|
ns_dic['menu_level'] = ns.get('menu_level')
|
||||||
|
if ns.get('sort_order') is not None:
|
||||||
|
ns_dic['sort_order'] = ns.get('sort_order')
|
||||||
|
|
||||||
|
db = DBPools()
|
||||||
|
async with db.sqlorContext('kboss') as sor:
|
||||||
|
try:
|
||||||
|
await sor.U('home_page_product_menu', ns_dic)
|
||||||
|
return {
|
||||||
|
'status': True,
|
||||||
|
'msg': 'update menu success'
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
await sor.rollback()
|
||||||
|
return {
|
||||||
|
'status': False,
|
||||||
|
'msg': 'update menu failed, %s' % str(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = await home_page_product_menu_update(params_kw)
|
||||||
|
return ret
|
||||||
86
b/product/home_page_product_search.dspy
Normal file
86
b/product/home_page_product_search.dspy
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
async def home_page_product_search(ns={}):
|
||||||
|
"""
|
||||||
|
查找产品信息,支持按菜单ID、产品名称等筛选
|
||||||
|
:param ns:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
# 分页参数
|
||||||
|
current_page = int(ns.get('current_page', 1))
|
||||||
|
page_size = int(ns.get('page_size', 10))
|
||||||
|
offset = (current_page - 1) * page_size
|
||||||
|
|
||||||
|
# 构建查询条件
|
||||||
|
conditions = ["hp.del_flg = '0'"]
|
||||||
|
|
||||||
|
if ns.get('menu_id'):
|
||||||
|
conditions.append(f"hp.menu_id = '{ns.get('menu_id')}'")
|
||||||
|
if ns.get('name'):
|
||||||
|
conditions.append(f"hp.name LIKE '%{ns.get('name')}%'")
|
||||||
|
if ns.get('product_group'):
|
||||||
|
conditions.append(f"hp.product_group = '{ns.get('product_group')}'")
|
||||||
|
if ns.get('source'):
|
||||||
|
conditions.append(f"hp.source = '{ns.get('source')}'")
|
||||||
|
|
||||||
|
where_clause = " AND ".join(conditions)
|
||||||
|
|
||||||
|
db = DBPools()
|
||||||
|
async with db.sqlorContext('kboss') as sor:
|
||||||
|
try:
|
||||||
|
# 查询总数
|
||||||
|
count_sql = f"""
|
||||||
|
SELECT COUNT(*) AS total_count
|
||||||
|
FROM home_page_product_info hp
|
||||||
|
WHERE {where_clause}
|
||||||
|
"""
|
||||||
|
total_count = (await sor.sqlExe(count_sql, {}))[0]['total_count']
|
||||||
|
|
||||||
|
# 查询产品列表
|
||||||
|
find_sql = f"""
|
||||||
|
SELECT hp.*, hm.title as menu_title, hm.menu_level
|
||||||
|
FROM home_page_product_info hp
|
||||||
|
LEFT JOIN home_page_product_menu hm ON hp.menu_id = hm.id
|
||||||
|
WHERE {where_clause}
|
||||||
|
ORDER BY hp.sort_order ASC, hp.create_at DESC
|
||||||
|
LIMIT {page_size} OFFSET {offset}
|
||||||
|
"""
|
||||||
|
result = await sor.sqlExe(find_sql, {})
|
||||||
|
|
||||||
|
# 格式化返回数据,匹配home_page_menu.json的数据格式
|
||||||
|
product_list = []
|
||||||
|
for product in result:
|
||||||
|
product_data = {
|
||||||
|
'id': product['id'],
|
||||||
|
'name': product['name'],
|
||||||
|
'description': product['description'],
|
||||||
|
'label': product['label'],
|
||||||
|
'product_group': product['product_group'], # 注意字段名映射
|
||||||
|
'url': product['url'],
|
||||||
|
'list_url': product['list_url'], # 注意字段名映射
|
||||||
|
'iconUrl': product['icon_url'], # 注意字段名映射
|
||||||
|
'icon_url': product['source'],
|
||||||
|
'menu_id': product['menu_id'],
|
||||||
|
'menu_title': product['menu_title'],
|
||||||
|
'menu_level': product['menu_level']
|
||||||
|
}
|
||||||
|
product_list.append(product_data)
|
||||||
|
|
||||||
|
return {
|
||||||
|
'status': True,
|
||||||
|
'msg': 'search product success',
|
||||||
|
'data': {
|
||||||
|
'product_list': product_list
|
||||||
|
},
|
||||||
|
'pagination': {
|
||||||
|
'total': total_count,
|
||||||
|
'page_size': page_size,
|
||||||
|
'current_page': current_page,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
return {
|
||||||
|
'status': False,
|
||||||
|
'msg': 'search product failed, %s' % str(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = await home_page_product_search(params_kw)
|
||||||
|
return ret
|
||||||
52
b/product/home_page_product_update.dspy
Normal file
52
b/product/home_page_product_update.dspy
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
async def home_page_product_update(ns={}):
|
||||||
|
"""
|
||||||
|
更新产品信息
|
||||||
|
:param ns:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if not ns.get('id'):
|
||||||
|
return {
|
||||||
|
'status': False,
|
||||||
|
'msg': 'product id is required'
|
||||||
|
}
|
||||||
|
|
||||||
|
# 构建更新字段,只更新传入的字段
|
||||||
|
ns_dic = {'id': ns.get('id')}
|
||||||
|
if ns.get('name'):
|
||||||
|
ns_dic['name'] = ns.get('name')
|
||||||
|
if ns.get('description') is not None:
|
||||||
|
ns_dic['description'] = ns.get('description')
|
||||||
|
if ns.get('label') is not None:
|
||||||
|
ns_dic['label'] = ns.get('label')
|
||||||
|
if ns.get('product_group') is not None:
|
||||||
|
ns_dic['product_group'] = ns.get('product_group')
|
||||||
|
if ns.get('url') is not None:
|
||||||
|
ns_dic['url'] = ns.get('url')
|
||||||
|
if ns.get('list_url') is not None:
|
||||||
|
ns_dic['list_url'] = ns.get('list_url')
|
||||||
|
if ns.get('icon_url') is not None:
|
||||||
|
ns_dic['icon_url'] = ns.get('icon_url')
|
||||||
|
if ns.get('source') is not None:
|
||||||
|
ns_dic['source'] = ns.get('source')
|
||||||
|
if ns.get('sort_order') is not None:
|
||||||
|
ns_dic['sort_order'] = ns.get('sort_order')
|
||||||
|
if ns.get('menu_id'):
|
||||||
|
ns_dic['menu_id'] = ns.get('menu_id')
|
||||||
|
|
||||||
|
db = DBPools()
|
||||||
|
async with db.sqlorContext('kboss') as sor:
|
||||||
|
try:
|
||||||
|
await sor.U('home_page_product_info', ns_dic)
|
||||||
|
return {
|
||||||
|
'status': True,
|
||||||
|
'msg': 'update product success'
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
await sor.rollback()
|
||||||
|
return {
|
||||||
|
'status': False,
|
||||||
|
'msg': 'update product failed, %s' % str(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = await home_page_product_update(params_kw)
|
||||||
|
return ret
|
||||||
BIN
f/web-kboss/src - 快捷方式.lnk
Normal file
BIN
f/web-kboss/src - 快捷方式.lnk
Normal file
Binary file not shown.
@ -4,15 +4,15 @@
|
|||||||
<div id="topContainer" class="container">
|
<div id="topContainer" class="container">
|
||||||
<!-- 统一显示logo和导航 -->
|
<!-- 统一显示logo和导航 -->
|
||||||
<div class="logo">
|
<div class="logo">
|
||||||
<!-- Logo图片,点击跳转首页 -->
|
<!-- Logo图片,点击跳转首页 - 使用与goHome相同的逻辑 -->
|
||||||
<img v-if="JSON.stringify(logoInfoNew) !== '{}'" @click="$router.push(homePath)" style="cursor:pointer;"
|
<img v-if="JSON.stringify(logoInfoNew) !== '{}'" @click="goHome" style="cursor:pointer;"
|
||||||
class="logoImg" :src="logoInfoNew.home.logoImg || ''" alt="">
|
class="logoImg" :src="logoInfoNew.home.logoImg || ''" alt="">
|
||||||
|
|
||||||
<!-- 主导航菜单 -->
|
<!-- 主导航菜单 -->
|
||||||
<nav class="main-nav">
|
<nav class="main-nav">
|
||||||
<div class="nav-list">
|
<div class="nav-list">
|
||||||
<!-- 首页 -->
|
<!-- 首页 -->
|
||||||
<p :class="{ active: $route.path.includes('/index') }">
|
<p :class="{ active: isActiveHome }">
|
||||||
<!-- 动态判断域名跳转首页 -->
|
<!-- 动态判断域名跳转首页 -->
|
||||||
<a @click="goHome">{{ translations[language].home }}</a>
|
<a @click="goHome">{{ translations[language].home }}</a>
|
||||||
</p>
|
</p>
|
||||||
@ -488,6 +488,14 @@ export default Vue.extend({
|
|||||||
// 判断当前是否为ncmatch.cn域名
|
// 判断当前是否为ncmatch.cn域名
|
||||||
isNcmatchDomain() {
|
isNcmatchDomain() {
|
||||||
return window.location.hostname.includes('ncmatch.cn');
|
return window.location.hostname.includes('ncmatch.cn');
|
||||||
|
},
|
||||||
|
// 首页激活状态计算
|
||||||
|
isActiveHome() {
|
||||||
|
if (this.isNcmatchDomain) {
|
||||||
|
return this.$route.path.includes('/ncmatchHome/index');
|
||||||
|
} else {
|
||||||
|
return this.$route.path.includes('/homePage/index');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -904,7 +912,7 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 首页跳转方法
|
// 首页跳转方法 - 根据域名判断跳转到不同的首页
|
||||||
goHome() {
|
goHome() {
|
||||||
if (this.isNcmatchDomain) {
|
if (this.isNcmatchDomain) {
|
||||||
this.$router.push('/ncmatchHome/index');
|
this.$router.push('/ncmatchHome/index');
|
||||||
@ -949,6 +957,12 @@ export default Vue.extend({
|
|||||||
|
|
||||||
.logoImg {
|
.logoImg {
|
||||||
width: 148px;
|
width: 148px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -972,6 +986,7 @@ export default Vue.extend({
|
|||||||
font-size: 18px !important;
|
font-size: 18px !important;
|
||||||
padding: 5px 0;
|
padding: 5px 0;
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: #1E6FFF;
|
color: #1E6FFF;
|
||||||
@ -1032,6 +1047,7 @@ export default Vue.extend({
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-btn {
|
.login-btn {
|
||||||
|
|||||||
@ -1,57 +1,87 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="followBox">
|
<div class="followBox">
|
||||||
<div class="followBox-title">
|
<!-- 页面标题区域 -->
|
||||||
<span>我的</span>
|
<div class="follow-header">
|
||||||
<span class="hightText">关注</span>
|
<div class="followBox-title">
|
||||||
|
<span>我的</span>
|
||||||
|
<span class="hightText">关注</span>
|
||||||
|
</div>
|
||||||
|
<div class="follow-subtitle">管理您关注的企业商品和需求</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="radio-group">
|
|
||||||
<label class="radio-item" style="margin-right: 25px;" :class="{ active: publish_type === '1' }">
|
<!-- 筛选区域 -->
|
||||||
<input type="radio" v-model="publish_type" value="1" @change="handleTypeChange">
|
<div class="filter-section">
|
||||||
<span class="radio-text">企业商品</span>
|
<div class="radio-group">
|
||||||
</label>
|
<label class="radio-item" :class="{ active: publish_type === '1' }">
|
||||||
<label class="radio-item" :class="{ active: publish_type === '2' }">
|
<input type="radio" v-model="publish_type" value="1" @change="handleTypeChange">
|
||||||
<input type="radio" v-model="publish_type" value="2" @change="handleTypeChange">
|
<span class="radio-text">企业商品</span>
|
||||||
<span class="radio-text">企业需求</span>
|
</label>
|
||||||
</label>
|
<label class="radio-item" :class="{ active: publish_type === '2' }">
|
||||||
|
<input type="radio" v-model="publish_type" value="2" @change="handleTypeChange">
|
||||||
|
<span class="radio-text">企业需求</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 统计信息 -->
|
||||||
|
<div class="stats-info" v-if="productList.length > 0">
|
||||||
|
共 {{ getTotalItems() }} 个关注
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 关注列表 -->
|
||||||
|
<div v-loading="loadingBox" class="follow-list" v-if="productList.length > 0">
|
||||||
|
<div class="follow-item" v-for="item in productList" :key="item.id">
|
||||||
|
<div class="follow-header-info">
|
||||||
|
<div class="follow-date">
|
||||||
|
<span class="date-text">{{ formatBrowseDate(item.browse_date) }}</span>
|
||||||
|
<span class="relative-time">{{ getRelativeTime(item.browse_date) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="follow-count" v-if="item.products && item.products.length > 0">
|
||||||
|
关注了 {{ item.products.length }} 个项目
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="follow-content">
|
||||||
|
<productCard
|
||||||
|
contentType="favorite"
|
||||||
|
:productList="item.products"
|
||||||
|
:type="publish_type == '1' ? 'homePage' : 'supplyAndDemandSquare'"
|
||||||
|
@delete-item="handleDeleteItem">
|
||||||
|
</productCard>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 空状态 -->
|
||||||
|
<div class="empty-state" v-else>
|
||||||
|
<div class="empty-content">
|
||||||
|
<div class="empty-icon">⭐</div>
|
||||||
|
<div class="empty-text">暂无关注记录</div>
|
||||||
|
<div class="empty-desc">您还没有关注任何{{ publish_type === '1' ? '商品' : '需求' }},快去发现精彩内容吧</div>
|
||||||
|
<div class="empty-action">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
@click="$router.push('/ncmatchHome')"
|
||||||
|
class="explore-btn">
|
||||||
|
去首页探索
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-loading="loadingBox" class="history-list" v-if="productList.length > 0">
|
|
||||||
<div class="history-item" v-for="item in productList" :key="item.id">
|
|
||||||
<div class="history-date">
|
|
||||||
<span class="date-text">{{ formatBrowseDate(item.browse_date) }}</span>
|
|
||||||
<span class="relative-time">{{ getRelativeTime(item.browse_date) }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="history-content">
|
|
||||||
<productCard
|
|
||||||
contentType="favorite"
|
|
||||||
:productList="item.products"
|
|
||||||
:type="publish_type == '1' ? 'homePage' : 'supplyAndDemandSquare'"
|
|
||||||
@delete-item="handleDeleteItem">
|
|
||||||
</productCard>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="empty-state" v-else>
|
|
||||||
<div class="empty-icon">📋</div>
|
|
||||||
<div class="empty-text">暂无关注记录</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { reqFavoriteSearch } from '@/api/ncmatch';
|
import { reqFavoriteSearch } from '@/api/ncmatch';
|
||||||
import productCard from '../mainPage/productCard/index.vue';
|
import productCard from '../mainPage/productCard/index.vue';
|
||||||
import { formatBrowseDate, getRelativeTime } from './tool.js';
|
import { formatBrowseDate, getRelativeTime } from './tool.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'followBox',
|
name: 'followBox',
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
loadingBox:false,
|
loadingBox: false,
|
||||||
productList: [],
|
productList: [],
|
||||||
value1: null,
|
|
||||||
publish_type: '1', // 默认选择企业商品
|
publish_type: '1', // 默认选择企业商品
|
||||||
|
|
||||||
myProductList: [
|
|
||||||
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
@ -71,55 +101,49 @@ export default {
|
|||||||
this.loadingBox = true;
|
this.loadingBox = true;
|
||||||
reqFavoriteSearch({
|
reqFavoriteSearch({
|
||||||
url_list: window.location.href,
|
url_list: window.location.href,
|
||||||
publish_type: this.publish_type // 传递发布类型参数
|
publish_type: this.publish_type
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
this.loadingBox = false;
|
this.loadingBox = false;
|
||||||
if (res.status) {
|
if (res.status) {
|
||||||
// 处理数据结构,将product_info的子项提升到上一级
|
|
||||||
this.productList = this.flattenProductInfo(res.data.favorites);
|
this.productList = this.flattenProductInfo(res.data.favorites);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
this.$message.error(res.msg);
|
this.$message.error(res.msg || '获取关注记录失败');
|
||||||
}
|
}
|
||||||
})
|
}).catch(error => {
|
||||||
|
this.loadingBox = false;
|
||||||
|
this.$message.error('网络错误,请稍后重试');
|
||||||
|
console.error('获取关注记录失败:', error);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 将product_info的所有子项提升到products中每个产品的上一级,去掉product_info字段
|
* 将product_info的所有子项提升到products中每个产品的上一级,去掉product_info字段
|
||||||
* @param {Array} historyList - 原始的历史记录列表
|
|
||||||
* @returns {Array} 处理后的历史记录列表
|
|
||||||
*/
|
*/
|
||||||
flattenProductInfo(historyList) {
|
flattenProductInfo(historyList) {
|
||||||
if (!Array.isArray(historyList)) {
|
if (!Array.isArray(historyList)) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return historyList.map(historyItem => {
|
return historyList.map(historyItem => {
|
||||||
if (historyItem.products && Array.isArray(historyItem.products)) {
|
if (historyItem.products && Array.isArray(historyItem.products)) {
|
||||||
// 处理每个历史记录中的products数组
|
|
||||||
const flattenedProducts = historyItem.products.map(product => {
|
const flattenedProducts = historyItem.products.map(product => {
|
||||||
if (product.product_info) {
|
if (product.product_info) {
|
||||||
// 将product_info的所有属性合并到product的上一级
|
|
||||||
const flattenedProduct = { ...product };
|
const flattenedProduct = { ...product };
|
||||||
|
|
||||||
// 遍历product_info的所有属性
|
|
||||||
Object.keys(product.product_info).forEach(key => {
|
Object.keys(product.product_info).forEach(key => {
|
||||||
if(key == 'id'){
|
if (key == 'id') {
|
||||||
flattenedProduct.productid = product.product_info.id;
|
flattenedProduct.productid = product.product_info.id;
|
||||||
}
|
}
|
||||||
// 如果上一级已经有同名属性,则跳过(避免覆盖)
|
|
||||||
if (!(key in flattenedProduct)) {
|
if (!(key in flattenedProduct)) {
|
||||||
flattenedProduct[key] = product.product_info[key];
|
flattenedProduct[key] = product.product_info[key];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 删除product_info字段
|
|
||||||
delete flattenedProduct.product_info;
|
delete flattenedProduct.product_info;
|
||||||
|
|
||||||
return flattenedProduct;
|
return flattenedProduct;
|
||||||
}
|
}
|
||||||
return product;
|
return product;
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...historyItem,
|
...historyItem,
|
||||||
products: flattenedProducts
|
products: flattenedProducts
|
||||||
@ -130,64 +154,93 @@ export default {
|
|||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 处理删除事件,从列表中移除被删除的项目
|
* 处理删除事件,从列表中移除被删除的项目
|
||||||
* @param {string} deletedId - 被删除项目的ID
|
|
||||||
*/
|
*/
|
||||||
handleDeleteItem(deletedId) {
|
handleDeleteItem(deletedId) {
|
||||||
// 遍历productList,找到包含被删除产品的历史记录
|
|
||||||
for (let i = 0; i < this.productList.length; i++) {
|
for (let i = 0; i < this.productList.length; i++) {
|
||||||
const historyItem = this.productList[i];
|
const historyItem = this.productList[i];
|
||||||
if (historyItem.products && Array.isArray(historyItem.products)) {
|
if (historyItem.products && Array.isArray(historyItem.products)) {
|
||||||
// 在products数组中查找并删除指定ID的产品
|
|
||||||
const productIndex = historyItem.products.findIndex(product => product.id === deletedId);
|
const productIndex = historyItem.products.findIndex(product => product.id === deletedId);
|
||||||
if (productIndex !== -1) {
|
if (productIndex !== -1) {
|
||||||
// 删除该产品
|
|
||||||
historyItem.products.splice(productIndex, 1);
|
historyItem.products.splice(productIndex, 1);
|
||||||
|
|
||||||
// 如果该历史记录下没有产品了,删除整个历史记录
|
|
||||||
if (historyItem.products.length === 0) {
|
if (historyItem.products.length === 0) {
|
||||||
this.productList.splice(i, 1);
|
this.productList.splice(i, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新视图
|
|
||||||
this.$forceUpdate();
|
this.$forceUpdate();
|
||||||
|
this.$message.success('取消关注成功');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 获取总关注数
|
||||||
|
*/
|
||||||
|
getTotalItems() {
|
||||||
|
return this.productList.reduce((total, item) => {
|
||||||
|
return total + (item.products ? item.products.length : 0);
|
||||||
|
}, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
|
||||||
.followBox-title {
|
|
||||||
font-size: 32px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #363a46;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
|
|
||||||
.hightText {
|
<style scoped>
|
||||||
background: linear-gradient(90deg, #275aff, #2ebdfa);
|
.followBox {
|
||||||
-webkit-background-clip: text;
|
max-width: 1400px;
|
||||||
background-clip: text;
|
margin: 0 auto;
|
||||||
color: transparent;
|
padding: 30px 20px;
|
||||||
display: inline-block;
|
min-height: calc(100vh - 100px);
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.radio-group-container {
|
/* 页面标题区域 */
|
||||||
width: 100% !important;
|
.follow-header {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.followBox-title {
|
||||||
|
font-size: 36px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #363a46;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.followBox-title .hightText {
|
||||||
|
background: linear-gradient(135deg, #275aff, #2ebdfa);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
background-clip: text;
|
||||||
|
color: transparent;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.follow-subtitle {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #666;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 筛选区域 */
|
||||||
|
.filter-section {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-start;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
max-width: 1400px;
|
margin-bottom: 30px;
|
||||||
|
padding: 0 20px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.radio-group {
|
.radio-group {
|
||||||
display: flex;
|
display: flex;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 8px;
|
border-radius: 12px;
|
||||||
margin-bottom: 15px;
|
padding: 4px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||||
|
border: 1px solid #f0f0f0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.radio-item {
|
.radio-item {
|
||||||
@ -195,110 +248,317 @@ export default {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 8px 16px;
|
padding: 12px 24px;
|
||||||
border-radius: 6px;
|
border-radius: 8px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
background: #fff;
|
background: transparent;
|
||||||
border: 1px solid #e8e8e8;
|
font-size: 14px;
|
||||||
margin-right: 4px;
|
|
||||||
font-size: 16px !important;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="radio"] {
|
|
||||||
position: absolute;
|
|
||||||
opacity: 0;
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.radio-text {
|
|
||||||
font-size: 16px;
|
|
||||||
color: #275AFF;
|
|
||||||
font-weight: 500;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
border-color: #275AFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
background: linear-gradient(to right, #275AFF, #2EBDFA);
|
|
||||||
border-color: #275AFF;
|
|
||||||
box-shadow: 0 2px 8px rgba(39, 90, 255, 0.3);
|
|
||||||
|
|
||||||
.radio-text {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 关注记录列表样式 */
|
.radio-item:last-child {
|
||||||
.history-list {
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-item input[type="radio"] {
|
||||||
|
position: absolute;
|
||||||
|
opacity: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-text {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-item:hover {
|
||||||
|
background: rgba(255, 107, 107, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-item.active {
|
||||||
|
background: linear-gradient(135deg, #275aff, #2ebdfa);
|
||||||
|
box-shadow: 0 4px 12px rgba(255, 107, 107, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-item.active .radio-text {
|
||||||
|
color: #fff;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-info {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
background: #f8f9fa;
|
||||||
|
padding: 8px 16px;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 关注列表样式 */
|
||||||
|
.follow-list {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.history-item {
|
.follow-item {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 12px;
|
border-radius: 16px;
|
||||||
padding: 20px;
|
padding: 24px;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 20px;
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
|
||||||
border: 1px solid #f0f0f0;
|
border: 1px solid #f0f0f0;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.history-item:hover {
|
.follow-item::before {
|
||||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
|
content: '';
|
||||||
/* transform: translateY(-2px); */
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 4px;
|
||||||
|
background: linear-gradient(135deg, #275aff, #2ebdfa);
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.history-date {
|
.follow-item:hover {
|
||||||
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.follow-item:hover::before {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.follow-header-info {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding-bottom: 16px;
|
||||||
|
border-bottom: 1px solid #f5f5f5;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.follow-date {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 16px;
|
gap: 12px;
|
||||||
padding-bottom: 12px;
|
}
|
||||||
border-bottom: 1px solid #f5f5f5;
|
|
||||||
|
.date-icon {
|
||||||
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.date-text {
|
.date-text {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #275AFF;
|
color: #ff6b6b;
|
||||||
margin-right: 12px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.relative-time {
|
.relative-time {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #999;
|
color: #999;
|
||||||
background: #f8f9fa;
|
background: #f8f9fa;
|
||||||
padding: 4px 8px;
|
padding: 6px 12px;
|
||||||
border-radius: 12px;
|
border-radius: 16px;
|
||||||
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.history-content {
|
.follow-count {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
background: linear-gradient(135deg, #275aff, #2ebdfa);
|
||||||
|
color: white;
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-radius: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.follow-content {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 空状态样式 */
|
/* 空状态样式 */
|
||||||
.empty-state {
|
.empty-state {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 60px 20px;
|
padding: 80px 20px;
|
||||||
color: #999;
|
margin-top: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-content {
|
||||||
|
max-width: 400px;
|
||||||
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty-icon {
|
.empty-icon {
|
||||||
font-size: 48px;
|
font-size: 80px;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 24px;
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty-text {
|
.empty-text {
|
||||||
font-size: 16px;
|
font-size: 20px;
|
||||||
color: #999;
|
color: #333;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
</style>
|
|
||||||
|
.empty-desc {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #999;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.explore-btn {
|
||||||
|
padding: 12px 32px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-weight: 500;
|
||||||
|
background: linear-gradient(135deg, #275aff, #2ebdfa);
|
||||||
|
border: none;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.explore-btn:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 6px 20px rgba(255, 107, 107, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式设计 */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.followBox {
|
||||||
|
padding: 20px 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.follow-header {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.followBox-title {
|
||||||
|
font-size: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-section {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-group {
|
||||||
|
width: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-item {
|
||||||
|
flex: 1;
|
||||||
|
padding: 10px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-info {
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.follow-item {
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.follow-header-info {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.follow-date {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-state {
|
||||||
|
padding: 60px 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-icon {
|
||||||
|
font-size: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-text {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.followBox {
|
||||||
|
padding: 15px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.followBox-title {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.follow-item {
|
||||||
|
padding: 16px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-text {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-item {
|
||||||
|
padding: 8px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-icon {
|
||||||
|
font-size: 50px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 加载状态优化 */
|
||||||
|
::v-deep .el-loading-mask {
|
||||||
|
border-radius: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-loading-spinner .circular {
|
||||||
|
width: 42px;
|
||||||
|
height: 42px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-loading-spinner .path {
|
||||||
|
stroke: #ff6b6b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 特殊样式 - 关注页面的独特视觉效果 */
|
||||||
|
.follow-item .heart-pulse {
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
right: 20px;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23ff6b6b'%3E%3Cpath d='M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z'/%3E%3C/svg%3E");
|
||||||
|
animation: pulse 2s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
0% {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: scale(1.1);
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,57 +1,84 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="historyBox">
|
<div class="historyBox">
|
||||||
<div class="historyBox-title">
|
<!-- 页面标题 -->
|
||||||
<span>浏览</span>
|
<div class="history-header">
|
||||||
<span class="hightText">记录</span>
|
<div class="historyBox-title">
|
||||||
|
<span>浏览</span>
|
||||||
|
<span class="hightText">记录</span>
|
||||||
|
</div>
|
||||||
|
<div class="history-subtitle">查看您的商品和需求浏览历史</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="radio-group">
|
|
||||||
<label class="radio-item" style="margin-right: 25px;" :class="{ active: publish_type === '1' }">
|
<!-- 筛选标签 -->
|
||||||
<input type="radio" v-model="publish_type" value="1" @change="handleTypeChange">
|
<div class="filter-section">
|
||||||
<span class="radio-text">企业商品</span>
|
<div class="radio-group">
|
||||||
</label>
|
<label class="radio-item" :class="{ active: publish_type === '1' }">
|
||||||
<label class="radio-item" :class="{ active: publish_type === '2' }">
|
<input type="radio" v-model="publish_type" value="1" @change="handleTypeChange">
|
||||||
<input type="radio" v-model="publish_type" value="2" @change="handleTypeChange">
|
<span class="radio-text">企业商品</span>
|
||||||
<span class="radio-text">企业需求</span>
|
</label>
|
||||||
</label>
|
<label class="radio-item" :class="{ active: publish_type === '2' }">
|
||||||
|
<input type="radio" v-model="publish_type" value="2" @change="handleTypeChange">
|
||||||
|
<span class="radio-text">企业需求</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 统计信息 -->
|
||||||
|
<div class="stats-info" v-if="productList.length > 0">
|
||||||
|
共 {{ getTotalItems() }} 条记录
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 历史记录列表 -->
|
||||||
|
<div v-loading="loadingBox" class="history-list" v-if="productList.length > 0">
|
||||||
|
<div class="history-item" v-for="item in productList" :key="item.id">
|
||||||
|
<div class="history-date">
|
||||||
|
<div class="date-content">
|
||||||
|
<span class="date-text">{{ formatBrowseDate(item.browse_date) }}</span>
|
||||||
|
<span class="relative-time">{{ getRelativeTime(item.browse_date) }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="history-content">
|
||||||
|
<productCard
|
||||||
|
contentType="history"
|
||||||
|
:productList="item.products"
|
||||||
|
:type="publish_type == '1' ? 'homePage' : 'supplyAndDemandSquare'"
|
||||||
|
@delete-item="handleDeleteItem">
|
||||||
|
</productCard>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 空状态 -->
|
||||||
|
<div class="empty-state" v-else>
|
||||||
|
<div class="empty-content">
|
||||||
|
<div class="empty-icon">📋</div>
|
||||||
|
<div class="empty-text">暂无浏览记录</div>
|
||||||
|
<div class="empty-desc">您还没有浏览过任何{{ publish_type === '1' ? '商品' : '需求' }},快去探索吧</div>
|
||||||
|
<div class="empty-action">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
@click="$router.push('/ncmatchHome')"
|
||||||
|
class="explore-btn">
|
||||||
|
去首页逛逛
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-loading="loadingBox" class="history-list" v-if="productList.length > 0">
|
|
||||||
<div class="history-item" v-for="item in productList" :key="item.id">
|
|
||||||
<div class="history-date">
|
|
||||||
<span class="date-text">{{ formatBrowseDate(item.browse_date) }}</span>
|
|
||||||
<span class="relative-time">{{ getRelativeTime(item.browse_date) }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="history-content">
|
|
||||||
<productCard
|
|
||||||
contentType="history"
|
|
||||||
:productList="item.products"
|
|
||||||
:type="publish_type == '1' ? 'homePage' : 'supplyAndDemandSquare'"
|
|
||||||
@delete-item="handleDeleteItem">
|
|
||||||
</productCard>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="empty-state" v-else>
|
|
||||||
<div class="empty-icon">📋</div>
|
|
||||||
<div class="empty-text">暂无浏览记录</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { reqUserBrowseHistorySearch } from '@/api/ncmatch';
|
import { reqUserBrowseHistorySearch } from '@/api/ncmatch';
|
||||||
import productCard from '../mainPage/productCard/index.vue';
|
import productCard from '../mainPage/productCard/index.vue';
|
||||||
import { formatBrowseDate, getRelativeTime } from './tool.js';
|
import { formatBrowseDate, getRelativeTime } from './tool.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'historyBox',
|
name: 'historyBox',
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
loadingBox:false,
|
loadingBox: false,
|
||||||
productList: [],
|
productList: [],
|
||||||
value1: null,
|
|
||||||
publish_type: '1', // 默认选择企业商品
|
publish_type: '1', // 默认选择企业商品
|
||||||
|
|
||||||
myProductList: [
|
|
||||||
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
@ -71,55 +98,49 @@ export default {
|
|||||||
this.loadingBox = true;
|
this.loadingBox = true;
|
||||||
reqUserBrowseHistorySearch({
|
reqUserBrowseHistorySearch({
|
||||||
url_list: window.location.href,
|
url_list: window.location.href,
|
||||||
publish_type: this.publish_type // 传递发布类型参数
|
publish_type: this.publish_type
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
this.loadingBox = false;
|
this.loadingBox = false;
|
||||||
if (res.status) {
|
if (res.status) {
|
||||||
// 处理数据结构,将product_info的子项提升到上一级
|
|
||||||
this.productList = this.flattenProductInfo(res.data.history_list);
|
this.productList = this.flattenProductInfo(res.data.history_list);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
this.$message.error(res.msg);
|
this.$message.error(res.msg || '获取浏览记录失败');
|
||||||
}
|
}
|
||||||
})
|
}).catch(error => {
|
||||||
|
this.loadingBox = false;
|
||||||
|
this.$message.error('网络错误,请稍后重试');
|
||||||
|
console.error('获取浏览记录失败:', error);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 将product_info的所有子项提升到products中每个产品的上一级,去掉product_info字段
|
* 将product_info的所有子项提升到products中每个产品的上一级,去掉product_info字段
|
||||||
* @param {Array} historyList - 原始的历史记录列表
|
|
||||||
* @returns {Array} 处理后的历史记录列表
|
|
||||||
*/
|
*/
|
||||||
flattenProductInfo(historyList) {
|
flattenProductInfo(historyList) {
|
||||||
if (!Array.isArray(historyList)) {
|
if (!Array.isArray(historyList)) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return historyList.map(historyItem => {
|
return historyList.map(historyItem => {
|
||||||
if (historyItem.products && Array.isArray(historyItem.products)) {
|
if (historyItem.products && Array.isArray(historyItem.products)) {
|
||||||
// 处理每个历史记录中的products数组
|
|
||||||
const flattenedProducts = historyItem.products.map(product => {
|
const flattenedProducts = historyItem.products.map(product => {
|
||||||
if (product.product_info) {
|
if (product.product_info) {
|
||||||
// 将product_info的所有属性合并到product的上一级
|
|
||||||
const flattenedProduct = { ...product };
|
const flattenedProduct = { ...product };
|
||||||
|
|
||||||
// 遍历product_info的所有属性
|
|
||||||
Object.keys(product.product_info).forEach(key => {
|
Object.keys(product.product_info).forEach(key => {
|
||||||
if(key == 'id'){
|
if (key == 'id') {
|
||||||
flattenedProduct.productid = product.product_info.id;
|
flattenedProduct.productid = product.product_info.id;
|
||||||
}
|
}
|
||||||
// 如果上一级已经有同名属性,则跳过(避免覆盖)
|
|
||||||
if (!(key in flattenedProduct)) {
|
if (!(key in flattenedProduct)) {
|
||||||
flattenedProduct[key] = product.product_info[key];
|
flattenedProduct[key] = product.product_info[key];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 删除product_info字段
|
|
||||||
delete flattenedProduct.product_info;
|
delete flattenedProduct.product_info;
|
||||||
|
|
||||||
return flattenedProduct;
|
return flattenedProduct;
|
||||||
}
|
}
|
||||||
return product;
|
return product;
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...historyItem,
|
...historyItem,
|
||||||
products: flattenedProducts
|
products: flattenedProducts
|
||||||
@ -130,64 +151,93 @@ export default {
|
|||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 处理删除事件,从列表中移除被删除的项目
|
* 处理删除事件,从列表中移除被删除的项目
|
||||||
* @param {string} deletedId - 被删除项目的ID
|
|
||||||
*/
|
*/
|
||||||
handleDeleteItem(deletedId) {
|
handleDeleteItem(deletedId) {
|
||||||
// 遍历productList,找到包含被删除产品的历史记录
|
|
||||||
for (let i = 0; i < this.productList.length; i++) {
|
for (let i = 0; i < this.productList.length; i++) {
|
||||||
const historyItem = this.productList[i];
|
const historyItem = this.productList[i];
|
||||||
if (historyItem.products && Array.isArray(historyItem.products)) {
|
if (historyItem.products && Array.isArray(historyItem.products)) {
|
||||||
// 在products数组中查找并删除指定ID的产品
|
|
||||||
const productIndex = historyItem.products.findIndex(product => product.id === deletedId);
|
const productIndex = historyItem.products.findIndex(product => product.id === deletedId);
|
||||||
if (productIndex !== -1) {
|
if (productIndex !== -1) {
|
||||||
// 删除该产品
|
|
||||||
historyItem.products.splice(productIndex, 1);
|
historyItem.products.splice(productIndex, 1);
|
||||||
|
|
||||||
// 如果该历史记录下没有产品了,删除整个历史记录
|
|
||||||
if (historyItem.products.length === 0) {
|
if (historyItem.products.length === 0) {
|
||||||
this.productList.splice(i, 1);
|
this.productList.splice(i, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新视图
|
|
||||||
this.$forceUpdate();
|
this.$forceUpdate();
|
||||||
|
this.$message.success('删除成功');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 获取总记录数
|
||||||
|
*/
|
||||||
|
getTotalItems() {
|
||||||
|
return this.productList.reduce((total, item) => {
|
||||||
|
return total + (item.products ? item.products.length : 0);
|
||||||
|
}, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
|
||||||
.historyBox-title {
|
|
||||||
font-size: 32px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #363a46;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
|
|
||||||
.hightText {
|
<style scoped>
|
||||||
background: linear-gradient(90deg, #275aff, #2ebdfa);
|
.historyBox {
|
||||||
-webkit-background-clip: text;
|
max-width: 1400px;
|
||||||
background-clip: text;
|
margin: 0 auto;
|
||||||
color: transparent;
|
padding: 30px 20px;
|
||||||
display: inline-block;
|
min-height: calc(100vh - 100px);
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.radio-group-container {
|
/* 页面标题区域 */
|
||||||
width: 100% !important;
|
.history-header {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.historyBox-title {
|
||||||
|
font-size: 36px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #363a46;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.historyBox-title .hightText {
|
||||||
|
background: linear-gradient(135deg, #275aff, #2ebdfa);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
background-clip: text;
|
||||||
|
color: transparent;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-subtitle {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #666;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 筛选区域 */
|
||||||
|
.filter-section {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-start;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
max-width: 1400px;
|
margin-bottom: 30px;
|
||||||
|
padding: 0 20px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.radio-group {
|
.radio-group {
|
||||||
display: flex;
|
display: flex;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 8px;
|
border-radius: 12px;
|
||||||
margin-bottom: 15px;
|
padding: 4px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||||
|
border: 1px solid #f0f0f0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.radio-item {
|
.radio-item {
|
||||||
@ -195,46 +245,53 @@ export default {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 8px 16px;
|
padding: 12px 24px;
|
||||||
border-radius: 6px;
|
border-radius: 8px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
background: #fff;
|
background: transparent;
|
||||||
border: 1px solid #e8e8e8;
|
font-size: 14px;
|
||||||
margin-right: 4px;
|
}
|
||||||
font-size: 16px !important;
|
|
||||||
|
|
||||||
&:last-child {
|
.radio-item:last-child {
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="radio"] {
|
.radio-item input[type="radio"] {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
width: 0;
|
width: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.radio-text {
|
.radio-text {
|
||||||
font-size: 16px;
|
font-size: 14px;
|
||||||
color: #275AFF;
|
color: #666;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
.radio-item:hover {
|
||||||
border-color: #275AFF;
|
background: rgba(39, 90, 255, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.active {
|
.radio-item.active {
|
||||||
background: linear-gradient(to right, #275AFF, #2EBDFA);
|
background: linear-gradient(135deg, #275AFF, #2EBDFA);
|
||||||
border-color: #275AFF;
|
box-shadow: 0 4px 12px rgba(39, 90, 255, 0.3);
|
||||||
box-shadow: 0 2px 8px rgba(39, 90, 255, 0.3);
|
}
|
||||||
|
|
||||||
.radio-text {
|
.radio-item.active .radio-text {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.stats-info {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
background: #f8f9fa;
|
||||||
|
padding: 8px 16px;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 历史记录列表样式 */
|
/* 历史记录列表样式 */
|
||||||
@ -244,40 +301,66 @@ export default {
|
|||||||
|
|
||||||
.history-item {
|
.history-item {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 12px;
|
border-radius: 16px;
|
||||||
padding: 20px;
|
padding: 24px;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 20px;
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
|
||||||
border: 1px solid #f0f0f0;
|
border: 1px solid #f0f0f0;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-item::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 4px;
|
||||||
|
background: linear-gradient(to bottom, #275AFF, #2EBDFA);
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.history-item:hover {
|
.history-item:hover {
|
||||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
|
||||||
/* transform: translateY(-2px); */
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-item:hover::before {
|
||||||
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.history-date {
|
.history-date {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding-bottom: 16px;
|
||||||
|
border-bottom: 1px solid #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 16px;
|
gap: 12px;
|
||||||
padding-bottom: 12px;
|
}
|
||||||
border-bottom: 1px solid #f5f5f5;
|
|
||||||
|
.date-icon {
|
||||||
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.date-text {
|
.date-text {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #275AFF;
|
color: #275AFF;
|
||||||
margin-right: 12px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.relative-time {
|
.relative-time {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #999;
|
color: #999;
|
||||||
background: #f8f9fa;
|
background: #f8f9fa;
|
||||||
padding: 4px 8px;
|
padding: 6px 12px;
|
||||||
border-radius: 12px;
|
border-radius: 16px;
|
||||||
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.history-content {
|
.history-content {
|
||||||
@ -287,18 +370,145 @@ export default {
|
|||||||
/* 空状态样式 */
|
/* 空状态样式 */
|
||||||
.empty-state {
|
.empty-state {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 60px 20px;
|
padding: 80px 20px;
|
||||||
color: #999;
|
margin-top: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-content {
|
||||||
|
max-width: 400px;
|
||||||
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty-icon {
|
.empty-icon {
|
||||||
font-size: 48px;
|
font-size: 80px;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 24px;
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty-text {
|
.empty-text {
|
||||||
font-size: 16px;
|
font-size: 20px;
|
||||||
color: #999;
|
color: #333;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
</style>
|
|
||||||
|
.empty-desc {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #999;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.explore-btn {
|
||||||
|
padding: 12px 32px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-weight: 500;
|
||||||
|
background: linear-gradient(135deg, #275AFF, #2EBDFA);
|
||||||
|
border: none;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.explore-btn:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 6px 20px rgba(39, 90, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式设计 */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.historyBox {
|
||||||
|
padding: 20px 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-header {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.historyBox-title {
|
||||||
|
font-size: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-section {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-group {
|
||||||
|
width: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-item {
|
||||||
|
flex: 1;
|
||||||
|
padding: 10px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-info {
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-item {
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-content {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-state {
|
||||||
|
padding: 60px 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-icon {
|
||||||
|
font-size: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-text {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.historyBox {
|
||||||
|
padding: 15px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.historyBox-title {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-item {
|
||||||
|
padding: 16px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-text {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-item {
|
||||||
|
padding: 8px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-icon {
|
||||||
|
font-size: 50px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 加载状态优化 */
|
||||||
|
::v-deep .el-loading-mask {
|
||||||
|
border-radius: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-loading-spinner .circular {
|
||||||
|
width: 42px;
|
||||||
|
height: 42px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-loading-spinner .path {
|
||||||
|
stroke: #275AFF;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,24 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="homeOut" class="homeOut">
|
<div id="homeOut" class="homeOut">
|
||||||
<TopBox id="topBox"></TopBox>
|
<TopBox id="topBox"></TopBox>
|
||||||
<div class="banner-box">
|
|
||||||
<div class="conter">
|
|
||||||
<div class="title">
|
|
||||||
供需广场
|
|
||||||
</div>
|
|
||||||
<div class="banner-title">
|
|
||||||
开元云供需对接广场,是企业级云服务合作核心阵地。围绕云资源、算力、网络服务、模型及应用,企业可灵活发布资源供给或业务需求,通过精准匹配打破信息壁垒。这里既能盘活企业闲置算力与云资源,又能快速对接所需技术服务与合作机会,助力企业降本增效,加速数字化与智能化转型。
|
|
||||||
</div>
|
|
||||||
<div class="btn">
|
|
||||||
<div class="btn-box" @click="sendInfo('2')">发布需求</div>
|
|
||||||
<div class="btn-box" @click="sendInfo('1')">发布商品</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- <div class="search-box">
|
<!-- <div class="search-box">
|
||||||
<search></search>
|
<search></search>
|
||||||
</div> -->
|
</div> -->
|
||||||
<div style="width: 90%;max-width: 1600px;">
|
<div style="width: 100%;">
|
||||||
<router-view></router-view>
|
<router-view></router-view>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -92,7 +79,6 @@ import { mapGetters, mapState } from "vuex";
|
|||||||
import search from "./search/index.vue";
|
import search from "./search/index.vue";
|
||||||
import { reqEnterpriseAuditInfoSearch } from '@/api/ncmatch'
|
import { reqEnterpriseAuditInfoSearch } from '@/api/ncmatch'
|
||||||
import productDetail from "./proDetail/index.vue";
|
import productDetail from "./proDetail/index.vue";
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
name: "indexLast",
|
name: "indexLast",
|
||||||
components: {
|
components: {
|
||||||
@ -228,54 +214,7 @@ export default Vue.extend({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
/deep/.banner-box {
|
|
||||||
height: 700px!important;
|
|
||||||
background: url('./img/tt-banner.png') no-repeat ;
|
|
||||||
width: 100%;
|
|
||||||
padding-bottom: 200px;
|
|
||||||
|
|
||||||
.conter {
|
|
||||||
width: 700px;
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: flex-start;
|
|
||||||
margin: 140px 240px 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
font-size: 30px;
|
|
||||||
font-weight: 600;
|
|
||||||
margin-bottom: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.banner-title {
|
|
||||||
width: 700px;
|
|
||||||
font-size: 16px;
|
|
||||||
color: #8890ab;
|
|
||||||
line-height: 2 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn{
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-box{
|
|
||||||
padding: 10px 20px;
|
|
||||||
background: linear-gradient(90deg, rgb(39, 90, 255), rgb(46, 189, 250));
|
|
||||||
border-radius: 14px;
|
|
||||||
color: #fff;
|
|
||||||
margin-right: 20px;
|
|
||||||
margin-top: 20px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
transform: translateY(-2px);
|
|
||||||
box-shadow: 0 4px 12px rgba(39, 90, 255, 0.3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-box {
|
.search-box {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@ -1,7 +1,97 @@
|
|||||||
|
<template>
|
||||||
|
<div class="jd-homepage">
|
||||||
|
<!-- 搜索区域 -->
|
||||||
|
<div class="search-box">
|
||||||
|
<search></search>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 主内容区域 -->
|
||||||
|
<main class="main-content">
|
||||||
|
<div class="content-wrapper">
|
||||||
|
<!-- 左侧菜单 -->
|
||||||
|
<menuAside></menuAside>
|
||||||
|
|
||||||
|
<!-- 中间主内容 -->
|
||||||
|
<section class="main-section">
|
||||||
|
<!-- 顶部促销横幅 -->
|
||||||
|
<div id="banner" class="banner">
|
||||||
|
<div class="centerBox">
|
||||||
|
<div class="title">
|
||||||
|
<span class="leftText">NCMatch</span>
|
||||||
|
<span class="rightText">算力供需对接平台</span>
|
||||||
|
</div>
|
||||||
|
<ul class="tagUl">
|
||||||
|
<li>匠造臻品 <span class="separator"></span> 精奢惠选</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- 右侧用户信息栏 -->
|
||||||
|
<aside class="user-sidebar">
|
||||||
|
<div class="sidebar-content">
|
||||||
|
<span class="publish-goods" @click="$router.push('/ncmatchHome/supplyAndDemandSquare')">
|
||||||
|
算力供需广场
|
||||||
|
</span>
|
||||||
|
<span class="publish-goods" @click="sendInfo('2')">发布需求</span>
|
||||||
|
<span class="publish-goods" @click="sendInfo('1')">发布商品</span>
|
||||||
|
|
||||||
|
<ul class="userBtn">
|
||||||
|
<li @click="goHistory">
|
||||||
|
<img src="./img/eye.png" alt="浏览记录">
|
||||||
|
浏览记录
|
||||||
|
</li>
|
||||||
|
<li @click="goFavorite">
|
||||||
|
<img src="./img/collect.png" alt="我的收藏">
|
||||||
|
我的收藏
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<!-- 产品列表区域 -->
|
||||||
|
<div class="productList">
|
||||||
|
<ul class="myTab">
|
||||||
|
<li v-for="menu in product" :class="currentHotMenu === menu.id ? 'activeMenu' : ''" @click="clickNetMenu(menu)"
|
||||||
|
:key="menu.name">
|
||||||
|
<span class="tab-text">{{ menu.product_category }}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<productCard v-loading="boxLoading" :productList="hotProductList"></productCard>
|
||||||
|
|
||||||
|
<el-pagination @current-change="handleCurrentChange" :page-size="page_size" layout="total, prev, pager, next"
|
||||||
|
:total="total">
|
||||||
|
</el-pagination>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 发布商品/需求对话框 -->
|
||||||
|
<el-dialog :title="publish_type === '2' ? '发布需求' : '发布商品'" width="60vw" top="5vh"
|
||||||
|
:visible.sync="sendProductVisible">
|
||||||
|
<sendProduct :isEdit="false" v-if="publish_type" @success="sendProductSuccess" :publish_type="publish_type">
|
||||||
|
</sendProduct>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 提示对话框 -->
|
||||||
|
<el-dialog title="温馨提示" :visible.sync="showTip" width="30%">
|
||||||
|
<span>您还没有完善企业信息,完善企业信息审核通过后您可以发布需求与商品。</span>
|
||||||
|
<span slot="footer" class="dialog-footer">
|
||||||
|
<span>
|
||||||
|
<span style="margin-right: 10px;">跳转到</span>
|
||||||
|
<el-button size="small" type="primary" @click="goInfo">信息完善</el-button>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import { reqPublishProductSearchFirstPage, reqEnterpriseAuditInfoSearch, reqHomepageProductCategory, reqGetSupplyAndDemandSquareList } from '@/api/ncmatch'
|
import { reqPublishProductSearchFirstPage, reqEnterpriseAuditInfoSearch, reqHomepageProductCategory, reqGetSupplyAndDemandSquareList } from '@/api/ncmatch'
|
||||||
import { mapGetters, mapState } from "vuex";
|
import { mapGetters, mapState } from "vuex";
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
name: "mainPage",
|
name: "mainPage",
|
||||||
components: {
|
components: {
|
||||||
@ -12,7 +102,6 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.getHomepageProductCategory()
|
this.getHomepageProductCategory()
|
||||||
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -24,110 +113,12 @@ export default Vue.extend({
|
|||||||
sendProductVisible: false,
|
sendProductVisible: false,
|
||||||
currentHotMenu: "",
|
currentHotMenu: "",
|
||||||
product: [],
|
product: [],
|
||||||
hotProductList: [
|
hotProductList: [],
|
||||||
// {
|
|
||||||
// id: 1,
|
|
||||||
// name: 'NVIDIA-4090',
|
|
||||||
// image: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjE1MCIgdmlld0JveD0iMCAwIDIwMCAxNTAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIyMDAiIGhlaWdodD0iMTUwIiBmaWxsPSIjMjIyMjIyIi8+Cjx0ZXh0IHg9IjEwMCIgeT0iNzUiIGZvbnQtZmFtaWx5PSJBcmlhbCIgZm9udC1zaXplPSIxNCIgZmlsbD0id2hpdGUiIHRleHQtYW5jaG9yPSJtaWRkbGUiPk5WSUQpQSBSVFggNDA5MDwvdGV4dD4KPC9zdmc+Cg==',
|
|
||||||
// price: 6000,
|
|
||||||
// cpu: 'AMD EPYC 7542 32 C * 2',
|
|
||||||
// memory: '64G DDR4-3200 * 8',
|
|
||||||
// gpu: 'NVIDIA-4090-24GB * 8',
|
|
||||||
// sys_disk: '960G SATA SSD * 2 (Raid)',
|
|
||||||
// data_disk: '3.84T U.2 NVMe SSD * 1',
|
|
||||||
// net_card: 'Mellanox Connect4 25G SFP28 2-port * 1'
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// id: 2,
|
|
||||||
// name: 'NVIDIA-4090',
|
|
||||||
// image: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjE1MCIgdmlld0JveD0iMCAwIDIwMCAxNTAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIyMDAiIGhlaWdodD0iMTUwIiBmaWxsPSIjMjIyMjIyIi8+Cjx0ZXh0IHg9IjEwMCIgeT0iNzUiIGZvbnQtZmFtaWx5PSJBcmlhbCIgZm9udC1zaXplPSIxNCIgZmlsbD0id2hpdGUiIHRleHQtYW5jaG9yPSJtaWRkbGUiPk5WSUQpQSBSVFggNDA5MDwvdGV4dD4KPC9zdmc+Cg==',
|
|
||||||
// price: 6000,
|
|
||||||
// cpu: 'AMD EPYC 7542 32 C * 2',
|
|
||||||
// memory: '64G DDR4-3200 * 8',
|
|
||||||
// gpu: 'NVIDIA-4090-24GB * 8',
|
|
||||||
// sys_disk: '960G SATA SSD * 2 (Raid)',
|
|
||||||
// data_disk: '3.84T U.2 NVMe SSD * 1',
|
|
||||||
// net_card: 'Mellanox Connect4 25G SFP28 2-port * 1'
|
|
||||||
// }
|
|
||||||
],
|
|
||||||
hotMenuList: [
|
|
||||||
{
|
|
||||||
id: "hot",
|
|
||||||
name: "热门推荐",
|
|
||||||
icon: require("../../newImg/niu.png"),
|
|
||||||
activeIcon: require("../../newImg/niuActive.png")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "hlzx",
|
|
||||||
name: "互联网专线",
|
|
||||||
icon: require("../../newImg/niu.png"),
|
|
||||||
activeIcon: require("../../newImg/niuActive.png"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "SDWAN",
|
|
||||||
name: "SDWAN",
|
|
||||||
icon: require("../../newImg/niu.png"),
|
|
||||||
activeIcon: require("../../newImg/niuActive.png"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "DCI",
|
|
||||||
name: "DCI",
|
|
||||||
icon: require("../../newImg/niu.png"),
|
|
||||||
activeIcon: require("../../newImg/niuActive.png"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "AI",
|
|
||||||
name: "AI专线",
|
|
||||||
icon: require("../../newImg/niu.png"),
|
|
||||||
activeIcon: require("../../newImg/niuActive.png"),
|
|
||||||
}
|
|
||||||
],
|
|
||||||
searchKeyword: '',
|
|
||||||
hotSearchKeywords: [
|
|
||||||
'昆仑芯-P800',
|
|
||||||
'天垓-150',
|
|
||||||
'4090',
|
|
||||||
'云服务器-GPU',
|
|
||||||
'人脸识别',
|
|
||||||
'SDWAN',
|
|
||||||
'互联网专线',
|
|
||||||
'DCI',
|
|
||||||
'AI专线',
|
|
||||||
'对象存储',
|
|
||||||
'智慧医疗',
|
|
||||||
'智慧客服',
|
|
||||||
'A800',
|
|
||||||
'A100',
|
|
||||||
'910B'
|
|
||||||
],
|
|
||||||
topNavItems: [
|
|
||||||
{ name: '早十好价', icon: '10', color: 'red' },
|
|
||||||
{ name: '司法拍卖', icon: '⚖️', color: 'red' },
|
|
||||||
{ name: '企业购', icon: '🏢', color: 'blue' },
|
|
||||||
{ name: '京东新品', icon: '🎁', color: 'blue' },
|
|
||||||
{ name: '男装馆', icon: '👔', color: 'blue' },
|
|
||||||
{ name: '黑色星期五', icon: '🍃', color: 'green' },
|
|
||||||
{ name: '服饰美妆', icon: '👗', color: 'purple' },
|
|
||||||
{ name: '清洁馆', icon: '💧', color: 'blue' },
|
|
||||||
{ name: '五金城', icon: '⚙️', color: 'red' },
|
|
||||||
{ name: '全部频道', icon: '📱', color: 'rainbow' }
|
|
||||||
],
|
|
||||||
categories: [
|
|
||||||
{ name: '云', icon: require('./img/cloud.png'), product_list: ['百度云'] },
|
|
||||||
{ name: '国产算力', icon: require('./img/computing.png'), product_list: ['昇腾910B', 'P800', '其他'] },
|
|
||||||
{ name: 'NVIDIA', icon: require('./img/nvidia.png'), product_list: ['3090', '4090', '5080', '5090'] },
|
|
||||||
{ name: '网', icon: require('./img/net.png'), product_list: ['AI专线', 'SDWAN', '互联网专线', 'DCI'] },
|
|
||||||
{ name: '一体机', icon: require('./img/computer.png'), product_list: ['昆仑芯', '天数智芯'] },
|
|
||||||
{ name: '硬件', icon: require('./img/ying.png'), product_list: ['机器人', 'AR眼镜'] },
|
|
||||||
{ name: 'AI应用', icon: require('./img/aiApp.png'), product_list: ['数字人', '智慧医疗', '智能客服'] },
|
|
||||||
],
|
|
||||||
current_page: 1,
|
current_page: 1,
|
||||||
page_size: 8,
|
page_size: 8,
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
||||||
...mapGetters(["sidebar", "avatar", "device"]),
|
...mapGetters(["sidebar", "avatar", "device"]),
|
||||||
...mapState({
|
...mapState({
|
||||||
isShowPanel: (state) => state.product.showHomeNav,
|
isShowPanel: (state) => state.product.showHomeNav,
|
||||||
@ -161,12 +152,10 @@ export default Vue.extend({
|
|||||||
goInfo() {
|
goInfo() {
|
||||||
this.showTip = false
|
this.showTip = false
|
||||||
this.$router.push('/customer/approve')
|
this.$router.push('/customer/approve')
|
||||||
|
|
||||||
},
|
},
|
||||||
handleCurrentChange(val) {
|
handleCurrentChange(val) {
|
||||||
this.current_page = val
|
this.current_page = val
|
||||||
this.initData()
|
this.initData()
|
||||||
// this.init_product_list()
|
|
||||||
},
|
},
|
||||||
sendInfo(type) {
|
sendInfo(type) {
|
||||||
if (this.loginState) {
|
if (this.loginState) {
|
||||||
@ -200,8 +189,6 @@ export default Vue.extend({
|
|||||||
this.showTip = true
|
this.showTip = true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
this.$router.push('/login')
|
this.$router.push('/login')
|
||||||
}
|
}
|
||||||
@ -226,13 +213,18 @@ export default Vue.extend({
|
|||||||
this.hotProductList = res.data[0].product_list
|
this.hotProductList = res.data[0].product_list
|
||||||
this.total = res.data[0].total_count
|
this.total = res.data[0].total_count
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
},
|
},
|
||||||
init_product_list() {
|
init_product_list() {
|
||||||
reqPublishProductSearchFirstPage({ publish_type: "1", url_link: window.location.href, to_page: 'first_page', page_size: this.page_size, current_page: this.current_page, product_type: this.currentHotMenu }).then(res => {
|
reqPublishProductSearchFirstPage({
|
||||||
|
publish_type: "1",
|
||||||
|
url_link: window.location.href,
|
||||||
|
to_page: 'first_page',
|
||||||
|
page_size: this.page_size,
|
||||||
|
current_page: this.current_page,
|
||||||
|
product_type: this.currentHotMenu
|
||||||
|
}).then(res => {
|
||||||
if (res.status) {
|
if (res.status) {
|
||||||
if (res.data.length > 0) {
|
if (res.data.length > 0) {
|
||||||
this.currentHotMenu = res.data[0].id
|
this.currentHotMenu = res.data[0].id
|
||||||
@ -240,7 +232,6 @@ export default Vue.extend({
|
|||||||
this.product = res.data
|
this.product = res.data
|
||||||
this.total = res.data[0].total_count
|
this.total = res.data[0].total_count
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@ -253,11 +244,6 @@ export default Vue.extend({
|
|||||||
this.currentHotMenu = menu.id;
|
this.currentHotMenu = menu.id;
|
||||||
this.selectedCategory = menu.id
|
this.selectedCategory = menu.id
|
||||||
this.initData()
|
this.initData()
|
||||||
// this.hotProductList = menu.product_list || [];
|
|
||||||
},
|
|
||||||
handleSearch() {
|
|
||||||
console.log('搜索:1', this.searchKeyword)
|
|
||||||
|
|
||||||
},
|
},
|
||||||
goFavorite() {
|
goFavorite() {
|
||||||
if (this.loginState) {
|
if (this.loginState) {
|
||||||
@ -277,155 +263,55 @@ export default Vue.extend({
|
|||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="jd-homepage">
|
|
||||||
<!-- 顶部Header -->
|
|
||||||
<!-- <header class="header">
|
|
||||||
<div class="header-content">
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</header> -->
|
|
||||||
<!-- 主内容区域 -->
|
|
||||||
<main class="main-content">
|
|
||||||
<div class="content-wrapper">
|
|
||||||
|
|
||||||
<menuAside></menuAside>
|
|
||||||
<!-- 中间主内容 -->
|
|
||||||
<section class="main-section">
|
|
||||||
<!-- 顶部促销横幅 -->
|
|
||||||
<div id="banner" class="banner">
|
|
||||||
<div class="centerBox">
|
|
||||||
<span style="margin-top: 100px" class="title">
|
|
||||||
<span class="leftText">
|
|
||||||
NCMatch
|
|
||||||
</span>
|
|
||||||
<span class="rightText" style="margin-left: 10px;"> 算力供需对接平台</span>
|
|
||||||
</span>
|
|
||||||
<!-- <span class="description">支持模型训练、推理和数据处理,灵活配置,助您高效释放AI潜能</span>-->
|
|
||||||
<ul style="margin-top: 50px" class="tagUl">
|
|
||||||
<li>匠造臻品 <span style="display: inline-block;margin: 0 15px;"></span> 精奢惠选</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<!-- 右侧用户信息栏 -->
|
|
||||||
<aside class="user-sidebar" style="background-color: #f8fbfe;padding: 10px;padding-top: 20px;">
|
|
||||||
<span class="publish-goods" @click="$router.push('/ncmatchHome/supplyAndDemandSquare')"> 算力供需广场</span>
|
|
||||||
<span class="publish-goods" @click="sendInfo('2')">发布需求</span>
|
|
||||||
<span class="publish-goods" @click="sendInfo('1')">发布商品</span>
|
|
||||||
|
|
||||||
<ul class="userBtn">
|
|
||||||
<li @click="goHistory"><img style="width: 26px;height: 26px;" src="./img/eye.png" alt="">浏览记录</li>
|
|
||||||
<li @click="goFavorite"><img style="width: 26px;height: 26px;" src="./img/collect.png" alt="">我的收藏</li>
|
|
||||||
<!-- <li><img src="./img/like.png" alt="">关注需求</li> -->
|
|
||||||
</ul>
|
|
||||||
</aside>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
<div class="productList">
|
|
||||||
<ul class="myTab">
|
|
||||||
<li v-for="menu in product" :class="currentHotMenu === menu.id ? 'activeMenu' : ''" @click="clickNetMenu(menu)"
|
|
||||||
:key="menu.name">
|
|
||||||
<!-- <img :src="currentHotMenu === menu.id ? menu.activeIcon : menu.icon" alt="" /> -->
|
|
||||||
<span class="tab-text">{{ menu.product_category }}</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
|
|
||||||
<productCard v-loading="boxLoading" :productList="hotProductList"></productCard>
|
|
||||||
<el-pagination style="background-color: white;" @current-change="handleCurrentChange" :page-size="page_size"
|
|
||||||
layout="total, prev, pager, next" :total="total">
|
|
||||||
</el-pagination>
|
|
||||||
<el-dialog :title="publish_type === '2' ? '发布需求' : '发布商品'" width="60vw" top="5vh"
|
|
||||||
:visible.sync="sendProductVisible">
|
|
||||||
<sendProduct :isEdit="false" v-if="publish_type" @success="sendProductSuccess" :publish_type="publish_type">
|
|
||||||
</sendProduct>
|
|
||||||
</el-dialog>
|
|
||||||
<el-dialog title="温馨提示" :visible.sync="showTip" width="30%">
|
|
||||||
<span>您还没有完善企业信息,完善企业信息审核通过后您可以发布需求与商品。</span>
|
|
||||||
<span slot="footer" class="dialog-footer">
|
|
||||||
|
|
||||||
<span> <span style="margin-right: 10px;"> 跳转到</span> <el-button size="small" type="primary"
|
|
||||||
@click="goInfo">信息完善</el-button></span>
|
|
||||||
</span>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.userBtn {
|
.jd-homepage {
|
||||||
margin-top: 40px !important;
|
margin: 30px;
|
||||||
display: flex;
|
margin-top: 100px;
|
||||||
justify-content: space-around;
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
li {
|
|
||||||
font-size: 12px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
transition: all 0.3s;
|
|
||||||
|
|
||||||
* {
|
|
||||||
img {
|
|
||||||
width: 20px !important;
|
|
||||||
height: 20px !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
transition: all 0.3s;
|
|
||||||
cursor: pointer;
|
|
||||||
color: #2c96fc;
|
|
||||||
|
|
||||||
svg {
|
|
||||||
|
|
||||||
path {
|
|
||||||
fill: #2c96fc !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search-box {
|
||||||
|
margin-bottom: 20px;
|
||||||
.productList {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 1600px;
|
|
||||||
margin: 0 auto;
|
|
||||||
// padding-bottom: 45px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.publish-goods {
|
/* 主内容区域 */
|
||||||
margin-bottom: 25px;
|
.main-content {
|
||||||
display: flex;
|
padding: 40px;
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 60px;
|
margin-top: 50px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
background: url('./img//btnBg.png');
|
|
||||||
background-size: cover;
|
|
||||||
background-position: top;
|
|
||||||
color: #222F60 !important;
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: 900;
|
|
||||||
|
|
||||||
&:hover {
|
.content-wrapper {
|
||||||
cursor: pointer;
|
box-sizing: border-box;
|
||||||
// background: #2EBDFA;
|
display: grid;
|
||||||
|
grid-template-columns: 300px 1fr 300px;
|
||||||
|
gap: 20px;
|
||||||
|
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
grid-template-columns: 250px 1fr 250px;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 992px) {
|
||||||
|
grid-template-columns: 200px 1fr;
|
||||||
|
|
||||||
|
.user-sidebar {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
|
||||||
|
.user-sidebar {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 横幅样式 */
|
||||||
.banner {
|
.banner {
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
background: url("../../newImg/banner.png");
|
background: url("../../newImg/banner.png");
|
||||||
@ -433,7 +319,11 @@ export default Vue.extend({
|
|||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 100%;
|
height: 500px;
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
.centerBox {
|
.centerBox {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -441,7 +331,7 @@ export default Vue.extend({
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 35%;
|
top: 50%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
@ -450,27 +340,35 @@ export default Vue.extend({
|
|||||||
color: #222F60;
|
color: #222F60;
|
||||||
font-size: 42px;
|
font-size: 42px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
@media (max-width: 992px) {
|
||||||
|
font-size: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
font-size: 28px;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
.leftText {
|
.leftText {
|
||||||
background: linear-gradient(to right, #275AFF, #2EBDFA);
|
background: linear-gradient(to right, #275AFF, #2EBDFA);
|
||||||
/* 渐变方向颜色 */
|
|
||||||
-webkit-background-clip: text;
|
-webkit-background-clip: text;
|
||||||
/* 关键属性:裁剪背景到文字 */
|
|
||||||
background-clip: text;
|
background-clip: text;
|
||||||
color: transparent;
|
color: transparent;
|
||||||
/* 文字颜色透明 */
|
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
/* 确保渐变生效 */
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
.rightText {
|
||||||
|
margin-left: 10px;
|
||||||
|
|
||||||
.description {
|
@media (max-width: 768px) {
|
||||||
margin: 15px 0;
|
margin-left: 0;
|
||||||
color: #7A82A0;
|
margin-top: 5px;
|
||||||
font-size: 24px;
|
}
|
||||||
height: 75px;
|
}
|
||||||
line-height: 1.6;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tagUl {
|
.tagUl {
|
||||||
@ -479,22 +377,112 @@ export default Vue.extend({
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
|
margin-top: 30px;
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
font-size: 18px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
li {
|
li {
|
||||||
padding: 0 30px;
|
padding: 0 30px;
|
||||||
margin-top: 25px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
&:not(:last-child) {
|
.separator {
|
||||||
border-right: 2px solid #D2D7E6;
|
display: inline-block;
|
||||||
}
|
margin: 0 15px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 用户侧边栏 */
|
||||||
|
.user-sidebar {
|
||||||
|
background-color: #f8fbfe;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 20px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||||
|
|
||||||
|
.sidebar-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.publish-goods {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 60px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: url('./img/btnBg.png');
|
||||||
|
background-size: cover;
|
||||||
|
background-position: top;
|
||||||
|
color: #222F60 !important;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 900;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 992px) {
|
||||||
|
height: 50px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.userBtn {
|
||||||
|
margin-top: 40px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 15px;
|
||||||
|
|
||||||
|
li {
|
||||||
|
font-size: 14px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 12px 15px;
|
||||||
|
border-radius: 8px;
|
||||||
|
transition: all 0.3s;
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: white;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #e6f7ff;
|
||||||
|
color: #2c96fc;
|
||||||
|
transform: translateX(5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 产品列表区域 */
|
||||||
|
.productList {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 1600px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0 20px 40px;
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
padding: 0 10px 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.myTab {
|
.myTab {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
@ -505,6 +493,13 @@ export default Vue.extend({
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-top: 50px;
|
margin-top: 50px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
margin-top: 30px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
.activeMenu {
|
.activeMenu {
|
||||||
background: linear-gradient(90deg, #275AFF 0%, #2EBDFA 100%);
|
background: linear-gradient(90deg, #275AFF 0%, #2EBDFA 100%);
|
||||||
color: white;
|
color: white;
|
||||||
@ -513,243 +508,69 @@ export default Vue.extend({
|
|||||||
li {
|
li {
|
||||||
transition: all .2s ease-in-out;
|
transition: all .2s ease-in-out;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
padding: 10px 20px;
|
padding: 10px 100px;
|
||||||
margin-right: 45px;
|
margin: 5px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
&:hover {
|
@media (max-width: 768px) {
|
||||||
cursor: pointer !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.jd-homepage {
|
|
||||||
min-height: 100vh;
|
|
||||||
background-color: #f8fbfe;
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Header样式
|
|
||||||
.header {
|
|
||||||
padding: 10px 0;
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-start;
|
|
||||||
align-items: center;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.header-content {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 950px;
|
|
||||||
// margin: 0 auto;
|
|
||||||
margin-top: 15px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
// gap: 20px;
|
|
||||||
position: absolute;
|
|
||||||
left: 420px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo-section {
|
|
||||||
|
|
||||||
margin: 0 50px;
|
|
||||||
|
|
||||||
img {
|
|
||||||
height: 70px;
|
|
||||||
width: 70px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
.logo-text {
|
|
||||||
font-size: 24px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #e1251b;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo-mascot {
|
|
||||||
font-size: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.signin-section {
|
|
||||||
.signin-btn {
|
|
||||||
background: linear-gradient(45deg, #ffd700, #ff6b35);
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
padding: 8px 15px;
|
padding: 8px 15px;
|
||||||
border-radius: 4px;
|
margin: 3px;
|
||||||
cursor: pointer;
|
|
||||||
font-size: 12px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 5px;
|
|
||||||
|
|
||||||
.signin-icon {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 分页样式 */
|
||||||
|
.el-pagination {
|
||||||
|
padding: 20px 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
// 主内容区域
|
@media (max-width: 768px) {
|
||||||
.main-content {
|
|
||||||
// padding: 16px;
|
|
||||||
|
|
||||||
width: 100%;
|
::v-deep .el-pagination__total,
|
||||||
max-width: 1600px;
|
::v-deep .el-pagination__jump {
|
||||||
margin: 20px auto;
|
display: none;
|
||||||
margin-top: 10px;
|
}
|
||||||
margin-bottom: 0;
|
|
||||||
border-radius: 10px;
|
|
||||||
overflow: visible;
|
|
||||||
background-color: white;
|
|
||||||
height: 320px;
|
|
||||||
|
|
||||||
.content-wrapper {
|
|
||||||
box-sizing: border-box;
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 300px 1fr 250px;
|
|
||||||
gap: 20px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 响应式设计 */
|
||||||
|
@media (max-width: 576px) {
|
||||||
|
.jd-homepage {
|
||||||
|
margin: 15px;
|
||||||
|
margin-top: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
// 中间主内容区域
|
.main-content {
|
||||||
.main-section {
|
|
||||||
.promo-banner {
|
|
||||||
background: linear-gradient(45deg, #52c41a, #73d13d);
|
|
||||||
border-radius: 8px;
|
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
margin-bottom: 20px;
|
margin-top: 30px;
|
||||||
position: relative;
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
.banner-content {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.banner-text {
|
|
||||||
color: white;
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
margin: 0 0 10px 0;
|
|
||||||
font-size: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin: 5px 0;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.banner-image {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.fridge-img {
|
|
||||||
width: 120px;
|
|
||||||
height: 90px;
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flower-decoration {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
font-size: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.subsidy-section,
|
.banner {
|
||||||
.live-section,
|
height: 150px;
|
||||||
.seckill-section {
|
|
||||||
background: white;
|
|
||||||
border-radius: 8px;
|
|
||||||
padding: 20px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
|
|
||||||
.section-header {
|
.centerBox .title {
|
||||||
display: flex;
|
font-size: 22px;
|
||||||
justify-content: space-between;
|
}
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
|
|
||||||
h3 {
|
.centerBox .tagUl {
|
||||||
margin: 0;
|
font-size: 16px;
|
||||||
font-size: 18px;
|
margin-top: 15px;
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.official-tag,
|
|
||||||
.live-tag,
|
|
||||||
.seckill-tag {
|
|
||||||
background: #e1251b;
|
|
||||||
color: white;
|
|
||||||
padding: 4px 8px;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.user-sidebar .publish-goods {
|
||||||
|
height: 45px;
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-sidebar {
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
* {
|
|
||||||
font-size: 20px !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 响应式设计
|
|
||||||
@media (max-width: 1200px) {
|
|
||||||
.main-content .content-wrapper {
|
|
||||||
grid-template-columns: 180px 1fr 220px;
|
|
||||||
gap: 15px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.main-content .content-wrapper {
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.category-sidebar,
|
.myTab {
|
||||||
.user-sidebar {
|
font-size: 14px;
|
||||||
display: none;
|
margin-top: 20px;
|
||||||
}
|
|
||||||
|
|
||||||
.header .header-content {
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-section {
|
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
|
Before Width: | Height: | Size: 873 KiB After Width: | Height: | Size: 873 KiB |
File diff suppressed because it is too large
Load Diff
BIN
f/web-kboss/src/views/login/img/banner.png
Normal file
BIN
f/web-kboss/src/views/login/img/banner.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.5 MiB |
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div @keyup.enter.native="handleLogin('loginForm')" class="main-box" style="position: relative">
|
<div @keyup.enter.native="handleLogin('loginForm')" class="main-box" style="position: relative ">
|
||||||
<!-- 广告弹窗(当前未启用) -->
|
<!-- 广告弹窗(当前未启用) -->
|
||||||
<div class="ad-dialog" v-if="adShow">
|
<div class="ad-dialog" v-if="adShow">
|
||||||
<div class="showAdImg" style=""></div>
|
<div class="showAdImg" style=""></div>
|
||||||
@ -1022,7 +1022,7 @@ $light_gray: #eee;
|
|||||||
$dark_gray: #889aa4;
|
$dark_gray: #889aa4;
|
||||||
|
|
||||||
.main-box {
|
.main-box {
|
||||||
background: url('/static/img/banner.png') no-repeat center center;
|
background: url('/static/img/banner.0798e703.png') no-repeat center center;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
|||||||
@ -30,7 +30,8 @@ class BaiduSMS:
|
|||||||
self.sms_client = self.create_client(self.access_key, self.access_key_secret, self.host)
|
self.sms_client = self.create_client(self.access_key, self.access_key_secret, self.host)
|
||||||
# 替换为您的百度短信签名名称
|
# 替换为您的百度短信签名名称
|
||||||
# self.signature_id = 'sms-sign-qQHYeC17077' # 开元云科技
|
# self.signature_id = 'sms-sign-qQHYeC17077' # 开元云科技
|
||||||
self.signature_id = 'sms-sign-BqOhYB33019' # 开元云
|
# self.signature_id = 'sms-sign-BqOhYB33019' # 开元云
|
||||||
|
self.signature_id = 'sms-sign-LOShPq75464' # 开元云北京
|
||||||
# 短信模板类型映射(键为业务类型,值为对应模板ID)
|
# 短信模板类型映射(键为业务类型,值为对应模板ID)
|
||||||
self.sms_types = {
|
self.sms_types = {
|
||||||
"注册登录验证": "sms-tpl-123", # 示例模板ID
|
"注册登录验证": "sms-tpl-123", # 示例模板ID
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user