Compare commits
No commits in common. "fc29e9705c6fb3ce90b03949a8078a4b5719f30c" and "0fecf5102d6a76f8e8a236cab594f1372359701b" have entirely different histories.
fc29e9705c
...
0fecf5102d
@ -645,8 +645,8 @@ async def baidu_users_get_post_pay(ns={}):
|
|||||||
userid = baidu_user['user_id']
|
userid = baidu_user['user_id']
|
||||||
baidu_id = baidu_user['baidu_id']
|
baidu_id = baidu_user['baidu_id']
|
||||||
|
|
||||||
if baidu_id != 'a6f0dbc20f074ea18b4d3ac3ec77d537':
|
# if baidu_id != 'dcf0fa1519d24de893b186e52d733bd2':
|
||||||
continue
|
# continue
|
||||||
try:
|
try:
|
||||||
user_orgid = (await sor.R('users', {'id': userid}))[0]['orgid']
|
user_orgid = (await sor.R('users', {'id': userid}))[0]['orgid']
|
||||||
user_parentid = (await sor.R('organization', {'id': user_orgid}))[0]['parentid']
|
user_parentid = (await sor.R('organization', {'id': user_orgid}))[0]['parentid']
|
||||||
|
|||||||
@ -1,53 +0,0 @@
|
|||||||
async def update_user_orders_interval(ns={}):
|
|
||||||
"""
|
|
||||||
更新用户订单列表
|
|
||||||
"""
|
|
||||||
domain_name = ns.get('domain_name')
|
|
||||||
db = DBPools()
|
|
||||||
async with db.sqlorContext('kboss') as sor:
|
|
||||||
sql = """select bo.orderid, bs.user_id from baidu_orders as bo inner join baidu_users as bs on bo.accountid = bs.baidu_id inner join users as u on bs.user_id = u.id inner join organization as o on o.id = u.orgid where o.parentid = '%s' and bo.ordertype = 'RENEW' and bo.status = 'NEED_CONFIRM' and bo.del_flg = '0';""" % ns.get('orgid')
|
|
||||||
order_list = await sor.sqlExe(sql, {})
|
|
||||||
try:
|
|
||||||
for order in order_list:
|
|
||||||
orderid = order['orderid']
|
|
||||||
user_id = order['user_id']
|
|
||||||
url = 'https://%s/baiducloud/get_baidu_orderlist.dspy' % domain_name
|
|
||||||
params = {
|
|
||||||
'order_id': orderid,
|
|
||||||
'userid': user_id
|
|
||||||
}
|
|
||||||
method = 'POST'
|
|
||||||
async with aiohttp_client.request(
|
|
||||||
method=method,
|
|
||||||
url=url,
|
|
||||||
json=params) as res:
|
|
||||||
order_result = await res.text()
|
|
||||||
with open('update_baidu_renew.log', 'a+') as f:
|
|
||||||
# 行首添加时间
|
|
||||||
f.write(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + ' ' + orderid + ':' + order_result + '\n')
|
|
||||||
|
|
||||||
url_update = 'https://%s/baiduc/update_baidu_order_list.dspy' % domain_name
|
|
||||||
params_update = {
|
|
||||||
'orgid': ns.get('orgid')
|
|
||||||
}
|
|
||||||
method = 'POST'
|
|
||||||
async with aiohttp_client.request(
|
|
||||||
method=method,
|
|
||||||
url=url_update,
|
|
||||||
json=params_update) as res:
|
|
||||||
data_text = await res.text()
|
|
||||||
with open('update_baidu_renew.log', 'a+') as f:
|
|
||||||
# 行首添加时间
|
|
||||||
f.write(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + ' ' + data_text + '\n')
|
|
||||||
return {
|
|
||||||
'status': True,
|
|
||||||
'msg': '更新成功'
|
|
||||||
}
|
|
||||||
except Exception as e:
|
|
||||||
import traceback
|
|
||||||
with open('update_baidu_renew.log', 'a+') as f:
|
|
||||||
f.write(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + ' ' + str(e) + traceback.format_exc() + '\n')
|
|
||||||
traceback.print_exc()
|
|
||||||
|
|
||||||
ret = await update_user_orders_interval(params_kw)
|
|
||||||
return ret
|
|
||||||
@ -24,57 +24,44 @@ async def get_user_role(ns={}):
|
|||||||
return role
|
return role
|
||||||
|
|
||||||
async def user_browse_history_add(ns={}):
|
async def user_browse_history_add(ns={}):
|
||||||
|
# ns = {
|
||||||
|
# 'userid': '9KVhsVCJsW_29q3hRhMAr', # 用户ID
|
||||||
|
# 'product_id': 'p2s2YPPU7uquza3gGw9k2', # 产品ID
|
||||||
|
# 'ip_address': '192.168.1.1', # IP地址
|
||||||
|
# 'user_agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/98.0.4758.102' # 用户代理
|
||||||
|
# }
|
||||||
# 必要参数校验
|
# 必要参数校验
|
||||||
if not ns.get('userid') or not ns.get('productid'):
|
if not ns.get('userid') or not ns.get('product_id'):
|
||||||
return {
|
return {
|
||||||
'status': False,
|
'status': False,
|
||||||
'msg': 'userid and productid are required'
|
'msg': 'userid and product_id are required'
|
||||||
}
|
}
|
||||||
|
|
||||||
db = DBPools()
|
db = DBPools()
|
||||||
async with db.sqlorContext('kboss') as sor:
|
async with db.sqlorContext('kboss') as sor:
|
||||||
try:
|
try:
|
||||||
# 根据timestamp时间字段:browse_time去重 查找10个小时内是否存在
|
# 根据timestamp时间字段:browse_time去重 查找10个小时内是否存在
|
||||||
# browse_time = datetime.datetime.now() - datetime.timedelta(hours=10)
|
browse_time = datetime.datetime.now() - datetime.timedelta(hours=10)
|
||||||
|
|
||||||
# 检查产品的publish_type
|
|
||||||
product_sql = """
|
|
||||||
SELECT publish_type FROM user_publish_product
|
|
||||||
WHERE id = '%s' AND del_flg = '0';
|
|
||||||
""" % ns.get('productid')
|
|
||||||
product_result = await sor.sqlExe(product_sql, {})
|
|
||||||
if product_result:
|
|
||||||
publish_type = product_result[0]['publish_type']
|
|
||||||
else:
|
|
||||||
publish_type = 99
|
|
||||||
|
|
||||||
check_sql = """
|
check_sql = """
|
||||||
SELECT * FROM user_browse_history
|
SELECT * FROM user_browse_history
|
||||||
WHERE userid = '%s' AND productid = '%s' AND del_flg = '0';
|
WHERE userid = '%s' AND product_id = '%s' AND del_flg = '0' AND browse_time >= '%s';
|
||||||
""" % (ns.get('userid'), ns.get('productid'))
|
""" % (ns.get('userid'), ns.get('product_id'), browse_time)
|
||||||
check_result = await sor.sqlExe(check_sql, {})
|
check_result = await sor.sqlExe(check_sql, {})
|
||||||
if check_result:
|
if check_result:
|
||||||
# 数据库更新browse_time字段
|
|
||||||
update_sql = """
|
|
||||||
UPDATE user_browse_history
|
|
||||||
SET browse_time = '%s'
|
|
||||||
WHERE id = '%s';
|
|
||||||
""" % (datetime.datetime.now(), check_result[0]['id'])
|
|
||||||
await sor.sqlExe(update_sql, {})
|
|
||||||
return {
|
return {
|
||||||
'status': True,
|
'status': False,
|
||||||
'msg': 'Browse history recorded successfully',
|
'msg': 'The user has browsed this product within the last 10 hours'
|
||||||
'data': {'record_id': check_result[0]['id']}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# 生成记录ID
|
# 生成记录ID
|
||||||
record_id = uuid()
|
record_id = uuid()
|
||||||
|
# 插入浏览记录
|
||||||
insert_sql = """
|
insert_sql = """
|
||||||
INSERT INTO user_browse_history (
|
INSERT INTO user_browse_history (
|
||||||
id, userid, productid, ip_address, user_agent, del_flg, tag, publish_type
|
id, userid, product_id, ip_address, user_agent, del_flg
|
||||||
) VALUES ('%s', '%s', '%s', '%s', '%s', '0', '%s', '%s');
|
) VALUES ('%s', '%s', '%s', '%s', '%s', '0');
|
||||||
""" % (record_id, ns.get('userid'), ns.get('productid'),
|
""" % (record_id, ns.get('userid'), ns.get('product_id'),
|
||||||
ns.get('ip_address', ''), ns.get('user_agent', ''), ns.get('tag', ''), publish_type)
|
ns.get('ip_address', ''), ns.get('user_agent', ''))
|
||||||
await sor.sqlExe(insert_sql, {})
|
await sor.sqlExe(insert_sql, {})
|
||||||
return {
|
return {
|
||||||
'status': True,
|
'status': True,
|
||||||
@ -128,7 +115,7 @@ async def publish_product_search_detail(ns={}):
|
|||||||
|
|
||||||
# 保存浏览记录
|
# 保存浏览记录
|
||||||
if userid:
|
if userid:
|
||||||
res = await user_browse_history_add({'userid': userid, 'productid': ns.get('id'), 'tag': 'upp', 'publish_type': product_list[0]['publish_type']})
|
await user_browse_history_add({'userid': userid, 'product_id': ns.get('id')})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'status': True,
|
'status': True,
|
||||||
|
|||||||
@ -1,43 +1,3 @@
|
|||||||
async def favorite_check(ns={}):
|
|
||||||
"""
|
|
||||||
检查用户是否已收藏某个商品/需求
|
|
||||||
:param ns: 包含userid, productid, favorite_type参数
|
|
||||||
:return: 检查结果
|
|
||||||
"""
|
|
||||||
db = DBPools()
|
|
||||||
async with db.sqlorContext('kboss') as sor:
|
|
||||||
try:
|
|
||||||
if not ns.get('userid') or not ns.get('productid'):
|
|
||||||
return {
|
|
||||||
'status': False,
|
|
||||||
'msg': '缺少必要参数'
|
|
||||||
}
|
|
||||||
|
|
||||||
check_sql = """
|
|
||||||
SELECT id FROM user_favorite
|
|
||||||
WHERE userid = '%s' AND productid = '%s' AND del_flg = '0'
|
|
||||||
""" % (ns.get('userid'), ns.get('productid'))
|
|
||||||
|
|
||||||
check_result = await sor.sqlExe(check_sql, {})
|
|
||||||
if check_result:
|
|
||||||
return {
|
|
||||||
'status': True,
|
|
||||||
'msg': '查询成功',
|
|
||||||
'data': {
|
|
||||||
'is_favorite': True,
|
|
||||||
'id': check_result[0]['id']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
return {
|
|
||||||
'status': False
|
|
||||||
}
|
|
||||||
except Exception as e:
|
|
||||||
return {
|
|
||||||
'status': False,
|
|
||||||
'msg': '查询失败, %s' % str(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
async def publish_product_search_first_page(ns={}):
|
async def publish_product_search_first_page(ns={}):
|
||||||
"""
|
"""
|
||||||
普通客户查看
|
普通客户查看
|
||||||
@ -46,13 +6,6 @@ async def publish_product_search_first_page(ns={}):
|
|||||||
:param ns:
|
:param ns:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
# 处理userid
|
|
||||||
if ns.get('userid'):
|
|
||||||
userid = ns.get('userid')
|
|
||||||
else:
|
|
||||||
userid = await get_user()
|
|
||||||
|
|
||||||
ns['userid'] = userid
|
|
||||||
publish_type = ns.get('publish_type')
|
publish_type = ns.get('publish_type')
|
||||||
page_size = int(ns['page_size']) if ns.get('page_size') else 8
|
page_size = int(ns['page_size']) if ns.get('page_size') else 8
|
||||||
current_page_param = int(ns['current_page']) if ns.get('current_page') else 1
|
current_page_param = int(ns['current_page']) if ns.get('current_page') else 1
|
||||||
@ -100,13 +53,6 @@ async def publish_product_search_first_page(ns={}):
|
|||||||
else:
|
else:
|
||||||
res['img'] = None
|
res['img'] = None
|
||||||
|
|
||||||
# 是否收藏关注
|
|
||||||
check_status_li = await favorite_check({'userid': ns.get('userid'), 'productid': res.get('id')})
|
|
||||||
if check_status_li['status']:
|
|
||||||
res['favorite'] = '1'
|
|
||||||
else:
|
|
||||||
res['favorite'] = '0'
|
|
||||||
|
|
||||||
# 电话和邮箱模糊化处理
|
# 电话和邮箱模糊化处理
|
||||||
if res.get('phone_number'):
|
if res.get('phone_number'):
|
||||||
res['phone_number'] = res['phone_number'][:3] + '****' + res['phone_number'][7:]
|
res['phone_number'] = res['phone_number'][:3] + '****' + res['phone_number'][7:]
|
||||||
|
|||||||
@ -46,7 +46,7 @@ async def get_ipc_logo(ns={}):
|
|||||||
if '?domain_name=' in url_link:
|
if '?domain_name=' in url_link:
|
||||||
domain_url = url_link.split('?domain_name=')[1]
|
domain_url = url_link.split('?domain_name=')[1]
|
||||||
# 如果是业主机构
|
# 如果是业主机构
|
||||||
if ('ncmatch' in domain_url or '9527' in domain_url or '8889' in domain_url or '8891' in domain_url or domain_url in ['xterm.kaiyuancloud.cn','www.kaiyuancloud.cn', 'dev.kaiyuancloud.cn', 'dev.opencomputing.cn', 'test.kaiyuancloud.cn', 'localhost', 'www.opencomputing.cn', 'opencomputing.cn']) and '/domain/' not in url_link:
|
if ('ncmatch' in domain_url or '9527' in domain_url or '8889' in domain_url or '8891' in domain_url or domain_url in ['xterm.kaiyuancloud.cn','www.kaiyuancloud.cn', 'dev.kaiyuancloud.cn', 'dev.opencomputing.cn', 'test.kaiyuancloud.cn', 'localhost']) and '/domain/' not in url_link:
|
||||||
yezhu_info = (await sor.R('organization', {'org_type': '0'}))[0]
|
yezhu_info = (await sor.R('organization', {'org_type': '0'}))[0]
|
||||||
domain_res = (await sor.R('params', {'pname': '业主机构域名'}))[0]['pvalue']
|
domain_res = (await sor.R('params', {'pname': '业主机构域名'}))[0]['pvalue']
|
||||||
# yezhu = {
|
# yezhu = {
|
||||||
|
|||||||
@ -1,59 +0,0 @@
|
|||||||
async def favorite_add(ns={}):
|
|
||||||
"""
|
|
||||||
添加用户收藏
|
|
||||||
:param ns: 包含userid, productid, favorite_type等参数
|
|
||||||
:return: 操作结果
|
|
||||||
"""
|
|
||||||
ns_dic = {
|
|
||||||
'id': uuid(), # 生成32位ID
|
|
||||||
'userid': ns.get('userid'),
|
|
||||||
'productid': ns.get('productid'),
|
|
||||||
'favorite_type': ns.get('favorite_type', '1'), # 默认为商品收藏
|
|
||||||
'tag': ns.get('tag') # 标签
|
|
||||||
}
|
|
||||||
|
|
||||||
# 处理userid
|
|
||||||
if ns.get('userid'):
|
|
||||||
ns_dic['userid'] = ns.get('userid')
|
|
||||||
else:
|
|
||||||
ns_dic['userid'] = await get_user()
|
|
||||||
|
|
||||||
if not ns_dic.get('userid'):
|
|
||||||
server_error(401)
|
|
||||||
|
|
||||||
db = DBPools()
|
|
||||||
async with db.sqlorContext('kboss') as sor:
|
|
||||||
try:
|
|
||||||
# 检查是否已收藏 处理tag是NULL的情况
|
|
||||||
conditions = [
|
|
||||||
"userid = '%s'" % ns_dic['userid'],
|
|
||||||
"productid = '%s'" % ns_dic['productid'],
|
|
||||||
"favorite_type = '%s'" % ns_dic['favorite_type'] if ns_dic['favorite_type'] is not None else "favorite_type IS NULL",
|
|
||||||
"del_flg = '0'",
|
|
||||||
"tag = '%s'" % ns_dic['tag'] if ns_dic['tag'] is not None else "tag IS NULL"
|
|
||||||
]
|
|
||||||
check_sql = "SELECT id FROM user_favorite WHERE " + " AND ".join(conditions)
|
|
||||||
|
|
||||||
check_result = await sor.sqlExe(check_sql, {})
|
|
||||||
|
|
||||||
if check_result:
|
|
||||||
return {
|
|
||||||
'status': False,
|
|
||||||
'msg': '已收藏关注'
|
|
||||||
}
|
|
||||||
|
|
||||||
# 执行收藏操作
|
|
||||||
await sor.C('user_favorite', ns_dic)
|
|
||||||
return {
|
|
||||||
'status': True,
|
|
||||||
'msg': '关注收藏成功'
|
|
||||||
}
|
|
||||||
except Exception as e:
|
|
||||||
await sor.rollback()
|
|
||||||
return {
|
|
||||||
'status': False,
|
|
||||||
'msg': '关注收藏失败, %s' % str(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = await favorite_add(params_kw)
|
|
||||||
return ret
|
|
||||||
@ -1,43 +0,0 @@
|
|||||||
async def favorite_delete(ns={}):
|
|
||||||
"""
|
|
||||||
删除用户收藏(软删除)
|
|
||||||
:param ns: 包含id或userid+productid+favorite_type参数
|
|
||||||
:return: 操作结果
|
|
||||||
"""
|
|
||||||
# 处理userid
|
|
||||||
if ns.get('userid'):
|
|
||||||
ns['userid'] = ns.get('userid')
|
|
||||||
else:
|
|
||||||
ns['userid'] = await get_user()
|
|
||||||
if not ns.get('userid'):
|
|
||||||
server_error(401)
|
|
||||||
db = DBPools()
|
|
||||||
async with db.sqlorContext('kboss') as sor:
|
|
||||||
try:
|
|
||||||
if ns.get('id'):
|
|
||||||
# 根据收藏ID删除
|
|
||||||
update_sql = """
|
|
||||||
UPDATE user_favorite
|
|
||||||
SET del_flg = '1'
|
|
||||||
WHERE userid = '%s' AND productid = '%s'
|
|
||||||
""" % (ns.get('userid'), ns.get('id'))
|
|
||||||
await sor.sqlExe(update_sql, {})
|
|
||||||
else:
|
|
||||||
return {
|
|
||||||
'status': False,
|
|
||||||
'msg': '缺少必要参数'
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
'status': True,
|
|
||||||
'msg': '取消关注收藏成功'
|
|
||||||
}
|
|
||||||
except Exception as e:
|
|
||||||
await sor.rollback()
|
|
||||||
return {
|
|
||||||
'status': False,
|
|
||||||
'msg': '取消关注收藏失败, %s' % str(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = await favorite_delete(params_kw)
|
|
||||||
return ret
|
|
||||||
@ -1,108 +0,0 @@
|
|||||||
async def favorite_search(ns={}):
|
|
||||||
"""
|
|
||||||
查询用户收藏列表
|
|
||||||
:param ns: 包含userid, favorite_type等查询参数
|
|
||||||
:return: 查询结果
|
|
||||||
"""
|
|
||||||
# 处理userid
|
|
||||||
if ns.get('userid'):
|
|
||||||
ns['userid'] = ns.get('userid')
|
|
||||||
else:
|
|
||||||
ns['userid'] = await get_user()
|
|
||||||
if not ns.get('userid'):
|
|
||||||
server_error(401)
|
|
||||||
|
|
||||||
db = DBPools()
|
|
||||||
async with db.sqlorContext('kboss') as sor:
|
|
||||||
try:
|
|
||||||
# 分页参数
|
|
||||||
current_page = int(ns.get('current_page', 1))
|
|
||||||
page_size = int(ns.get('page_size', 1000))
|
|
||||||
offset = (current_page - 1) * page_size
|
|
||||||
|
|
||||||
# 构建查询条件
|
|
||||||
where_conditions = ["f.del_flg = '0'"]
|
|
||||||
if ns.get('userid'):
|
|
||||||
where_conditions.append("f.userid = '%s'" % ns.get('userid'))
|
|
||||||
if ns.get('publish_type'):
|
|
||||||
where_conditions.append("f.favorite_type = '%s'" % ns.get('publish_type'))
|
|
||||||
|
|
||||||
where_clause = " AND ".join(where_conditions)
|
|
||||||
|
|
||||||
# 查询总数
|
|
||||||
count_sql = """
|
|
||||||
SELECT COUNT(*) AS total_count
|
|
||||||
FROM user_favorite f
|
|
||||||
WHERE %s
|
|
||||||
""" % where_clause
|
|
||||||
|
|
||||||
count_result = await sor.sqlExe(count_sql, {})
|
|
||||||
total_count = count_result[0]['total_count'] if count_result else 0
|
|
||||||
|
|
||||||
# 查询数据
|
|
||||||
query_sql = """
|
|
||||||
SELECT *
|
|
||||||
FROM user_favorite f
|
|
||||||
WHERE %s
|
|
||||||
ORDER BY f.create_at DESC
|
|
||||||
LIMIT %s OFFSET %s
|
|
||||||
""" % (where_clause, page_size, offset)
|
|
||||||
result = await sor.sqlExe(query_sql, {})
|
|
||||||
|
|
||||||
# 通过查询数据中的productid, 查询product表, 增加product_info
|
|
||||||
for product in result:
|
|
||||||
product_sql = f"""
|
|
||||||
SELECT * FROM user_publish_product
|
|
||||||
WHERE id = '{product['productid']}' AND del_flg = '0' AND listing_status = 'listing';
|
|
||||||
"""
|
|
||||||
product_info_li = await sor.sqlExe(product_sql, {})
|
|
||||||
if product_info_li:
|
|
||||||
product['product_info'] = product_info_li[0]
|
|
||||||
# 增加收藏状态
|
|
||||||
product['product_info']['favorite'] = '1'
|
|
||||||
# 手机号加*
|
|
||||||
if product['product_info'].get('phone_number'):
|
|
||||||
product['product_info']['phone_number'] = '**************'
|
|
||||||
if product['product_info'].get('img'):
|
|
||||||
product['product_info']['img'] = 'https://' + product['product_info']['domain_name'] + '/idfile?path=' + product['product_info']['img']
|
|
||||||
|
|
||||||
else:
|
|
||||||
product['product_info'] = None
|
|
||||||
|
|
||||||
date_groups = {}
|
|
||||||
for item in result:
|
|
||||||
# 提取日期部分(如"2025-08-22 15:58:52" → "2025-08-22")
|
|
||||||
browse_date = datetime.datetime.strptime(item["create_at"], "%Y-%m-%d %H:%M:%S").strftime("%Y-%m-%d")
|
|
||||||
if browse_date not in date_groups:
|
|
||||||
date_groups[browse_date] = []
|
|
||||||
|
|
||||||
date_groups[browse_date].append(item)
|
|
||||||
|
|
||||||
# 按日期升序排序并添加序号
|
|
||||||
sorted_dates = sorted(date_groups.keys(), reverse=True) # 按日期升序排列
|
|
||||||
result = []
|
|
||||||
for idx, date in enumerate(sorted_dates, start=1):
|
|
||||||
result.append({
|
|
||||||
"id": str(idx), # 序号从1开始
|
|
||||||
"browse_date": date,
|
|
||||||
"products": date_groups[date] # 该日期下的所有浏览记录
|
|
||||||
})
|
|
||||||
|
|
||||||
return {
|
|
||||||
'status': True,
|
|
||||||
'msg': '查询成功',
|
|
||||||
'data': {
|
|
||||||
'total_count': total_count,
|
|
||||||
'current_page': current_page,
|
|
||||||
'page_size': page_size,
|
|
||||||
'favorites': result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
except Exception as e:
|
|
||||||
return {
|
|
||||||
'status': False,
|
|
||||||
'msg': '查询失败, %s' % str(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = await favorite_search(params_kw)
|
|
||||||
return ret
|
|
||||||
@ -1,43 +1,42 @@
|
|||||||
async def user_browse_history_add(ns={}):
|
async def user_browse_history_add(ns={}):
|
||||||
|
# ns = {
|
||||||
|
# 'userid': '9KVhsVCJsW_29q3hRhMAr', # 用户ID
|
||||||
|
# 'product_id': 'p2s2YPPU7uquza3gGw9k2', # 产品ID
|
||||||
|
# 'ip_address': '192.168.1.1', # IP地址
|
||||||
|
# 'user_agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/98.0.4758.102' # 用户代理
|
||||||
|
# }
|
||||||
# 必要参数校验
|
# 必要参数校验
|
||||||
if not ns.get('userid') or not ns.get('productid'):
|
if not ns.get('userid') or not ns.get('product_id'):
|
||||||
return {
|
return {
|
||||||
'status': False,
|
'status': False,
|
||||||
'msg': 'userid and productid are required'
|
'msg': 'userid and product_id are required'
|
||||||
}
|
}
|
||||||
|
|
||||||
db = DBPools()
|
db = DBPools()
|
||||||
async with db.sqlorContext('kboss') as sor:
|
async with db.sqlorContext('kboss') as sor:
|
||||||
try:
|
try:
|
||||||
# 根据timestamp时间字段:browse_time去重 查找10个小时内是否存在
|
# 根据timestamp时间字段:browse_time去重 查找10个小时内是否存在
|
||||||
# browse_time = datetime.datetime.now() - datetime.timedelta(hours=10)
|
browse_time = datetime.datetime.now() - datetime.timedelta(hours=10)
|
||||||
check_sql = """
|
check_sql = """
|
||||||
SELECT * FROM user_browse_history
|
SELECT * FROM user_browse_history
|
||||||
WHERE userid = '%s' AND productid = '%s' AND del_flg = '0';
|
WHERE userid = '%s' AND product_id = '%s' AND del_flg = '0' AND browse_time >= '%s';
|
||||||
""" % (ns.get('userid'), ns.get('productid'))
|
""" % (ns.get('userid'), ns.get('product_id'), browse_time)
|
||||||
check_result = await sor.sqlExe(check_sql, {})
|
check_result = await sor.sqlExe(check_sql, {})
|
||||||
if check_result:
|
if check_result:
|
||||||
# 数据库更新browse_time字段
|
|
||||||
update_sql = """
|
|
||||||
UPDATE user_browse_history
|
|
||||||
SET browse_time = '%s'
|
|
||||||
WHERE id = '%s';
|
|
||||||
""" % (datetime.datetime.now(), check_result[0]['id'])
|
|
||||||
await sor.sqlExe(update_sql, {})
|
|
||||||
return {
|
return {
|
||||||
'status': True,
|
'status': False,
|
||||||
'msg': 'Browse history recorded successfully',
|
'msg': 'The user has browsed this product within the last 10 hours'
|
||||||
'data': {'record_id': check_result[0]['id']}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# 生成记录ID
|
# 生成记录ID
|
||||||
record_id = uuid()
|
record_id = uuid()
|
||||||
|
# 插入浏览记录
|
||||||
insert_sql = """
|
insert_sql = """
|
||||||
INSERT INTO user_browse_history (
|
INSERT INTO user_browse_history (
|
||||||
id, userid, productid, ip_address, user_agent, del_flg, tag
|
id, userid, product_id, ip_address, user_agent, del_flg
|
||||||
) VALUES ('%s', '%s', '%s', '%s', '%s', '0', '%s');
|
) VALUES ('%s', '%s', '%s', '%s', '%s', '0');
|
||||||
""" % (record_id, ns.get('userid'), ns.get('productid'),
|
""" % (record_id, ns.get('userid'), ns.get('product_id'),
|
||||||
ns.get('ip_address', ''), ns.get('user_agent', ''), ns.get('tag', ''))
|
ns.get('ip_address', ''), ns.get('user_agent', ''))
|
||||||
await sor.sqlExe(insert_sql, {})
|
await sor.sqlExe(insert_sql, {})
|
||||||
return {
|
return {
|
||||||
'status': True,
|
'status': True,
|
||||||
|
|||||||
@ -1,24 +1,20 @@
|
|||||||
async def user_browse_history_search(ns={}):
|
async def user_browse_history_search(ns={}):
|
||||||
# 处理url_link转换成domain_name
|
|
||||||
if ns.get('url_link'):
|
|
||||||
domain_name = ns.get('url_link').split("//")[1].split("/")[0]
|
|
||||||
else:
|
|
||||||
domain_name = None
|
|
||||||
|
|
||||||
# 处理userid
|
# 处理userid
|
||||||
if ns.get('userid'):
|
if ns.get('userid'):
|
||||||
userid = ns.get('userid')
|
userid = ns.get('userid')
|
||||||
else:
|
else:
|
||||||
userid = await get_user()
|
userid = await get_user()
|
||||||
if not userid:
|
if not userid:
|
||||||
server_error(401)
|
return {
|
||||||
|
'status': False,
|
||||||
|
'msg': 'no match user'
|
||||||
|
}
|
||||||
|
|
||||||
# 参数处理
|
# 参数处理
|
||||||
productid = ns.get('productid')
|
product_id = ns.get('product_id')
|
||||||
publish_type = ns.get('publish_type')
|
|
||||||
start_time = ns.get('start_time')
|
start_time = ns.get('start_time')
|
||||||
end_time = ns.get('end_time')
|
end_time = ns.get('end_time')
|
||||||
page_size = int(ns.get('page_size', 10000))
|
page_size = int(ns.get('page_size', 10))
|
||||||
current_page = int(ns.get('current_page', 1))
|
current_page = int(ns.get('current_page', 1))
|
||||||
offset = (current_page - 1) * page_size
|
offset = (current_page - 1) * page_size
|
||||||
|
|
||||||
@ -29,10 +25,8 @@ async def user_browse_history_search(ns={}):
|
|||||||
base_conditions = ["del_flg = '0'"]
|
base_conditions = ["del_flg = '0'"]
|
||||||
if userid:
|
if userid:
|
||||||
base_conditions.append(f"userid = '{userid}'")
|
base_conditions.append(f"userid = '{userid}'")
|
||||||
if productid:
|
if product_id:
|
||||||
base_conditions.append(f"productid = '{productid}'")
|
base_conditions.append(f"product_id = '{product_id}'")
|
||||||
if publish_type:
|
|
||||||
base_conditions.append(f"publish_type = '{publish_type}'")
|
|
||||||
if start_time and end_time:
|
if start_time and end_time:
|
||||||
end_time += ' 23:59:59'
|
end_time += ' 23:59:59'
|
||||||
base_conditions.append(f"browse_time BETWEEN '{start_time}' AND '{end_time}'")
|
base_conditions.append(f"browse_time BETWEEN '{start_time}' AND '{end_time}'")
|
||||||
@ -40,6 +34,8 @@ async def user_browse_history_search(ns={}):
|
|||||||
# 构建查询SQL
|
# 构建查询SQL
|
||||||
where_clause = " AND ".join(base_conditions)
|
where_clause = " AND ".join(base_conditions)
|
||||||
|
|
||||||
|
# 根据product_id查询product_info
|
||||||
|
|
||||||
find_sql = f"""
|
find_sql = f"""
|
||||||
SELECT * FROM user_browse_history
|
SELECT * FROM user_browse_history
|
||||||
WHERE {where_clause}
|
WHERE {where_clause}
|
||||||
@ -56,54 +52,6 @@ async def user_browse_history_search(ns={}):
|
|||||||
result = await sor.sqlExe(find_sql, {})
|
result = await sor.sqlExe(find_sql, {})
|
||||||
total_count = (await sor.sqlExe(count_sql, {}))[0]['total_count']
|
total_count = (await sor.sqlExe(count_sql, {}))[0]['total_count']
|
||||||
|
|
||||||
# 根据result中productid查询product_info
|
|
||||||
for product in result:
|
|
||||||
# 查询product_info
|
|
||||||
product_sql = f"""
|
|
||||||
SELECT * FROM user_publish_product
|
|
||||||
WHERE id = '{product['productid']}' AND del_flg = '0' AND listing_status = 'listing';
|
|
||||||
"""
|
|
||||||
favorite_sql = f"""
|
|
||||||
SELECT * FROM user_favorite
|
|
||||||
WHERE productid = '{product['productid']}' AND userid = '{userid}' AND del_flg = '0';
|
|
||||||
"""
|
|
||||||
favorite_status = await sor.sqlExe(favorite_sql, {})
|
|
||||||
product_info_li = await sor.sqlExe(product_sql, {})
|
|
||||||
if product_info_li:
|
|
||||||
product['product_info'] = product_info_li[0]
|
|
||||||
|
|
||||||
if favorite_status:
|
|
||||||
product['product_info']['favorite'] = '1'
|
|
||||||
else:
|
|
||||||
product['product_info']['favorite'] = '0'
|
|
||||||
|
|
||||||
if product['product_info'].get('phone_number'):
|
|
||||||
product['product_info']['phone_number'] = '***************'
|
|
||||||
if product['product_info'].get('img'):
|
|
||||||
product['product_info']['img'] = 'https://' + product['product_info']['domain_name'] + '/idfile?path=' + product['product_info']['img']
|
|
||||||
else:
|
|
||||||
product['product_info'] = None
|
|
||||||
|
|
||||||
date_groups = {}
|
|
||||||
for item in result:
|
|
||||||
# 提取日期部分(如"2025-08-22 15:58:52" → "2025-08-22")
|
|
||||||
browse_date = datetime.datetime.strptime(item["browse_time"], "%Y-%m-%d %H:%M:%S").strftime("%Y-%m-%d")
|
|
||||||
if browse_date not in date_groups:
|
|
||||||
date_groups[browse_date] = []
|
|
||||||
|
|
||||||
date_groups[browse_date].append(item)
|
|
||||||
|
|
||||||
# 按日期升序排序并添加序号
|
|
||||||
sorted_dates = sorted(date_groups.keys(), reverse=True) # 按日期升序排列
|
|
||||||
result = []
|
|
||||||
for idx, date in enumerate(sorted_dates, start=1):
|
|
||||||
result.append({
|
|
||||||
"id": str(idx), # 序号从1开始
|
|
||||||
"browse_date": date,
|
|
||||||
"products": date_groups[date] # 该日期下的所有浏览记录
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'status': True,
|
'status': True,
|
||||||
'msg': 'Browse history retrieved successfully',
|
'msg': 'Browse history retrieved successfully',
|
||||||
|
|||||||
@ -220,59 +220,3 @@ export function reqSupplyAndDemandSecondCategory(data){
|
|||||||
data
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//收藏 /product/publish_product_collect.dspy
|
|
||||||
export function reqPublishProductCollect(data){
|
|
||||||
return request({
|
|
||||||
url: '/user/favorite_add.dspy',
|
|
||||||
method: 'post',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
//取消收藏 /user/favorite_delete.dspy
|
|
||||||
export function reqFavoriteDelete(data){
|
|
||||||
return request({
|
|
||||||
url: '/user/favorite_delete.dspy',
|
|
||||||
method: 'post',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
//浏览记录 /user/user_browse_history_search.dspy
|
|
||||||
export function reqUserBrowseHistorySearch(data){
|
|
||||||
return request({
|
|
||||||
url: '/user/user_browse_history_search.dspy',
|
|
||||||
method: 'post',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
//删除浏览记录 /user/user_browse_history_delete.dspy
|
|
||||||
export function reqUserBrowseHistoryDeleteById(data){
|
|
||||||
return request({
|
|
||||||
url: '/user/user_browse_history_delete.dspy',
|
|
||||||
method: 'post',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
//删除关注记录 /user/favorite_delete.dspy
|
|
||||||
export function reqFavoriteDeleteById(data){
|
|
||||||
return request({
|
|
||||||
url: '/user/favorite_delete.dspy',
|
|
||||||
method: 'post',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
//全部收藏列表 /user/favorite_search.dspy
|
|
||||||
export function reqFavoriteSearch(data){
|
|
||||||
return request({
|
|
||||||
url: '/user/favorite_search.dspy',
|
|
||||||
method: 'post',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@ -106,7 +106,7 @@ router.beforeEach(async (to, from, next) => {
|
|||||||
// NProgress.done();
|
// NProgress.done();
|
||||||
// return
|
// return
|
||||||
// }
|
// }
|
||||||
if (to.path.includes("/demoDify")||to.path.includes("/ncmatchHome")||to.path.includes("/kyyForm") || to.path.includes("/screen") || to.path.includes("/beforeLogin") || to.path.includes("/wxDetailPage") || to.path.includes("/wxPage") || to.path.includes("/login") || to.path.includes("/homePage") || to.path.includes("/registrationPage") || to.path.includes("/payPage") || to.path.includes("/paySuccess") || to.path.includes("/homePageImage")) {
|
if (to.path.includes("/ncmatchHome")||to.path.includes("/kyyForm") || to.path.includes("/screen") || to.path.includes("/beforeLogin") || to.path.includes("/wxDetailPage") || to.path.includes("/wxPage") || to.path.includes("/login") || to.path.includes("/homePage") || to.path.includes("/registrationPage") || to.path.includes("/payPage") || to.path.includes("/paySuccess") || to.path.includes("/homePageImage")) {
|
||||||
console.log("to", to)
|
console.log("to", to)
|
||||||
try {
|
try {
|
||||||
if (to.path.includes("/beforeLogin") || to.path.includes("/registrationPage")) {
|
if (to.path.includes("/beforeLogin") || to.path.includes("/registrationPage")) {
|
||||||
|
|||||||
@ -65,12 +65,6 @@ export const constantRoutes = [
|
|||||||
component: () => import('@/views/beforeLogin/index.vue'),
|
component: () => import('@/views/beforeLogin/index.vue'),
|
||||||
hidden: true
|
hidden: true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/demoDify',
|
|
||||||
name: 'DemoDify',
|
|
||||||
title: 'DemoDify',
|
|
||||||
component: () => import('@/views/demoDify/index.vue'),
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
{
|
||||||
path: '/wxPage',
|
path: '/wxPage',
|
||||||
@ -198,20 +192,6 @@ export const constantRoutes = [
|
|||||||
hidden: true,
|
hidden: true,
|
||||||
meta: { title: "产品查询", fullPath: "/ncmatch/searchBox" },
|
meta: { title: "产品查询", fullPath: "/ncmatch/searchBox" },
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: "historyBox",
|
|
||||||
component: () => import("@/views/homePage/ncmatch/historyBox/index.vue"),
|
|
||||||
name: "historyBox",
|
|
||||||
hidden: true,
|
|
||||||
meta: { title: "浏览记录", fullPath: "/ncmatch/historyBox" },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "favoriteBox",
|
|
||||||
component: () => import("@/views/homePage/ncmatch/favoriteBox/index.vue"),
|
|
||||||
name: "favoriteBox",
|
|
||||||
hidden: true,
|
|
||||||
meta: { title: "我的关注", fullPath: "/ncmatch/favoriteBox" },
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,17 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
|
|
||||||
<iframe
|
|
||||||
src="http://aigc.smartcrec.com/chatbot/HKghmPZLD4JczCXc"
|
|
||||||
style="width: 100%; height: 100%; min-height: 700px"
|
|
||||||
frameborder="0"
|
|
||||||
allow="microphone">
|
|
||||||
</iframe>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'DemoDify',
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@ -1,304 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="followBox">
|
|
||||||
<div class="followBox-title">
|
|
||||||
<span>我的</span>
|
|
||||||
<span class="hightText">关注</span>
|
|
||||||
</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">
|
|
||||||
<span class="radio-text">企业商品</span>
|
|
||||||
</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 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>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import { reqFavoriteSearch } from '@/api/ncmatch';
|
|
||||||
import productCard from '../mainPage/productCard/index.vue';
|
|
||||||
import { formatBrowseDate, getRelativeTime } from './tool.js';
|
|
||||||
export default {
|
|
||||||
name: 'followBox',
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
loadingBox:false,
|
|
||||||
productList: [],
|
|
||||||
value1: null,
|
|
||||||
publish_type: '1', // 默认选择企业商品
|
|
||||||
|
|
||||||
myProductList: [
|
|
||||||
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.reqFavoriteSearch();
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
productCard
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
formatBrowseDate,
|
|
||||||
getRelativeTime,
|
|
||||||
handleTypeChange() {
|
|
||||||
// 当类型改变时重新获取数据
|
|
||||||
this.reqFavoriteSearch();
|
|
||||||
},
|
|
||||||
reqFavoriteSearch() {
|
|
||||||
this.loadingBox = true;
|
|
||||||
reqFavoriteSearch({
|
|
||||||
url_list: window.location.href,
|
|
||||||
publish_type: this.publish_type // 传递发布类型参数
|
|
||||||
}).then(res => {
|
|
||||||
this.loadingBox = false;
|
|
||||||
if (res.status) {
|
|
||||||
// 处理数据结构,将product_info的子项提升到上一级
|
|
||||||
this.productList = this.flattenProductInfo(res.data.favorites);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
this.$message.error(res.msg);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* 将product_info的所有子项提升到products中每个产品的上一级,去掉product_info字段
|
|
||||||
* @param {Array} historyList - 原始的历史记录列表
|
|
||||||
* @returns {Array} 处理后的历史记录列表
|
|
||||||
*/
|
|
||||||
flattenProductInfo(historyList) {
|
|
||||||
if (!Array.isArray(historyList)) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return historyList.map(historyItem => {
|
|
||||||
if (historyItem.products && Array.isArray(historyItem.products)) {
|
|
||||||
// 处理每个历史记录中的products数组
|
|
||||||
const flattenedProducts = historyItem.products.map(product => {
|
|
||||||
if (product.product_info) {
|
|
||||||
// 将product_info的所有属性合并到product的上一级
|
|
||||||
const flattenedProduct = { ...product };
|
|
||||||
|
|
||||||
// 遍历product_info的所有属性
|
|
||||||
Object.keys(product.product_info).forEach(key => {
|
|
||||||
if(key == 'id'){
|
|
||||||
flattenedProduct.productid = product.product_info.id;
|
|
||||||
}
|
|
||||||
// 如果上一级已经有同名属性,则跳过(避免覆盖)
|
|
||||||
if (!(key in flattenedProduct)) {
|
|
||||||
flattenedProduct[key] = product.product_info[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 删除product_info字段
|
|
||||||
delete flattenedProduct.product_info;
|
|
||||||
|
|
||||||
return flattenedProduct;
|
|
||||||
}
|
|
||||||
return product;
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
...historyItem,
|
|
||||||
products: flattenedProducts
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return historyItem;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* 处理删除事件,从列表中移除被删除的项目
|
|
||||||
* @param {string} deletedId - 被删除项目的ID
|
|
||||||
*/
|
|
||||||
handleDeleteItem(deletedId) {
|
|
||||||
// 遍历productList,找到包含被删除产品的历史记录
|
|
||||||
for (let i = 0; i < this.productList.length; i++) {
|
|
||||||
const historyItem = this.productList[i];
|
|
||||||
if (historyItem.products && Array.isArray(historyItem.products)) {
|
|
||||||
// 在products数组中查找并删除指定ID的产品
|
|
||||||
const productIndex = historyItem.products.findIndex(product => product.id === deletedId);
|
|
||||||
if (productIndex !== -1) {
|
|
||||||
// 删除该产品
|
|
||||||
historyItem.products.splice(productIndex, 1);
|
|
||||||
|
|
||||||
// 如果该历史记录下没有产品了,删除整个历史记录
|
|
||||||
if (historyItem.products.length === 0) {
|
|
||||||
this.productList.splice(i, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新视图
|
|
||||||
this.$forceUpdate();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style>
|
|
||||||
.followBox-title {
|
|
||||||
font-size: 32px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #363a46;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
|
|
||||||
.hightText {
|
|
||||||
background: linear-gradient(90deg, #275aff, #2ebdfa);
|
|
||||||
-webkit-background-clip: text;
|
|
||||||
background-clip: text;
|
|
||||||
color: transparent;
|
|
||||||
display: inline-block;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.radio-group-container {
|
|
||||||
width: 100% !important;
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-start;
|
|
||||||
align-items: center;
|
|
||||||
max-width: 1400px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.radio-group {
|
|
||||||
display: flex;
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 8px;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.radio-item {
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 8px 16px;
|
|
||||||
border-radius: 6px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
background: #fff;
|
|
||||||
border: 1px solid #e8e8e8;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 关注记录列表样式 */
|
|
||||||
.history-list {
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.history-item {
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 12px;
|
|
||||||
padding: 20px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
|
||||||
border: 1px solid #f0f0f0;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.history-item:hover {
|
|
||||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
|
|
||||||
/* transform: translateY(-2px); */
|
|
||||||
}
|
|
||||||
|
|
||||||
.history-date {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
padding-bottom: 12px;
|
|
||||||
border-bottom: 1px solid #f5f5f5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.date-text {
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #275AFF;
|
|
||||||
margin-right: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.relative-time {
|
|
||||||
font-size: 14px;
|
|
||||||
color: #999;
|
|
||||||
background: #f8f9fa;
|
|
||||||
padding: 4px 8px;
|
|
||||||
border-radius: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.history-content {
|
|
||||||
margin-top: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 空状态样式 */
|
|
||||||
.empty-state {
|
|
||||||
text-align: center;
|
|
||||||
padding: 60px 20px;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.empty-icon {
|
|
||||||
font-size: 48px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
opacity: 0.6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.empty-text {
|
|
||||||
font-size: 16px;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,75 +0,0 @@
|
|||||||
// 日期格式化工具函数
|
|
||||||
/**
|
|
||||||
* 如果是今年之展示xx月xxx日
|
|
||||||
* 如果是去年之展示xx年xx月xx日
|
|
||||||
* 如果是今年之前之展示xx年xx月xx日
|
|
||||||
* 如果是今年之后之展示xx月xx日
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 格式化浏览日期
|
|
||||||
* @param {string|Date} date - 日期字符串或Date对象
|
|
||||||
* @returns {string} 格式化后的日期字符串
|
|
||||||
*/
|
|
||||||
export function formatBrowseDate(date) {
|
|
||||||
if (!date) return '';
|
|
||||||
|
|
||||||
const targetDate = new Date(date);
|
|
||||||
const currentDate = new Date();
|
|
||||||
const currentYear = currentDate.getFullYear();
|
|
||||||
const targetYear = targetDate.getFullYear();
|
|
||||||
|
|
||||||
// 获取月份和日期
|
|
||||||
const month = targetDate.getMonth() + 1;
|
|
||||||
const day = targetDate.getDate();
|
|
||||||
|
|
||||||
// 如果是今年
|
|
||||||
if (targetYear === currentYear) {
|
|
||||||
return `${month}月${day}日`;
|
|
||||||
}
|
|
||||||
// 如果是去年
|
|
||||||
else if (targetYear === currentYear - 1) {
|
|
||||||
return `${targetYear}年${month}月${day}日`;
|
|
||||||
}
|
|
||||||
// 如果是今年之前
|
|
||||||
else if (targetYear < currentYear) {
|
|
||||||
return `${targetYear}年${month}月${day}日`;
|
|
||||||
}
|
|
||||||
// 如果是今年之后(未来日期)
|
|
||||||
else {
|
|
||||||
return `${month}月${day}日`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取相对时间描述
|
|
||||||
* @param {string|Date} date - 日期字符串或Date对象
|
|
||||||
* @returns {string} 相对时间描述
|
|
||||||
*/
|
|
||||||
export function getRelativeTime(date) {
|
|
||||||
if (!date) return '';
|
|
||||||
|
|
||||||
const targetDate = new Date(date);
|
|
||||||
const currentDate = new Date();
|
|
||||||
const diffTime = currentDate - targetDate;
|
|
||||||
const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24));
|
|
||||||
|
|
||||||
if (diffDays === 0) {
|
|
||||||
return '今天';
|
|
||||||
} else if (diffDays === 1) {
|
|
||||||
return '昨天';
|
|
||||||
} else if (diffDays === 2) {
|
|
||||||
return '前天';
|
|
||||||
} else if (diffDays < 7) {
|
|
||||||
return `${diffDays}天前`;
|
|
||||||
} else if (diffDays < 30) {
|
|
||||||
const weeks = Math.floor(diffDays / 7);
|
|
||||||
return `${weeks}周前`;
|
|
||||||
} else if (diffDays < 365) {
|
|
||||||
const months = Math.floor(diffDays / 30);
|
|
||||||
return `${months}个月前`;
|
|
||||||
} else {
|
|
||||||
const years = Math.floor(diffDays / 365);
|
|
||||||
return `${years}年前`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,304 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="historyBox">
|
|
||||||
<div class="historyBox-title">
|
|
||||||
<span>浏览</span>
|
|
||||||
<span class="hightText">记录</span>
|
|
||||||
</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">
|
|
||||||
<span class="radio-text">企业商品</span>
|
|
||||||
</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 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>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import { reqUserBrowseHistorySearch } from '@/api/ncmatch';
|
|
||||||
import productCard from '../mainPage/productCard/index.vue';
|
|
||||||
import { formatBrowseDate, getRelativeTime } from './tool.js';
|
|
||||||
export default {
|
|
||||||
name: 'historyBox',
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
loadingBox:false,
|
|
||||||
productList: [],
|
|
||||||
value1: null,
|
|
||||||
publish_type: '1', // 默认选择企业商品
|
|
||||||
|
|
||||||
myProductList: [
|
|
||||||
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.reqUserBrowseHistorySearch();
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
productCard
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
formatBrowseDate,
|
|
||||||
getRelativeTime,
|
|
||||||
handleTypeChange() {
|
|
||||||
// 当类型改变时重新获取数据
|
|
||||||
this.reqUserBrowseHistorySearch();
|
|
||||||
},
|
|
||||||
reqUserBrowseHistorySearch() {
|
|
||||||
this.loadingBox = true;
|
|
||||||
reqUserBrowseHistorySearch({
|
|
||||||
url_list: window.location.href,
|
|
||||||
publish_type: this.publish_type // 传递发布类型参数
|
|
||||||
}).then(res => {
|
|
||||||
this.loadingBox = false;
|
|
||||||
if (res.status) {
|
|
||||||
// 处理数据结构,将product_info的子项提升到上一级
|
|
||||||
this.productList = this.flattenProductInfo(res.data.history_list);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
this.$message.error(res.msg);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* 将product_info的所有子项提升到products中每个产品的上一级,去掉product_info字段
|
|
||||||
* @param {Array} historyList - 原始的历史记录列表
|
|
||||||
* @returns {Array} 处理后的历史记录列表
|
|
||||||
*/
|
|
||||||
flattenProductInfo(historyList) {
|
|
||||||
if (!Array.isArray(historyList)) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return historyList.map(historyItem => {
|
|
||||||
if (historyItem.products && Array.isArray(historyItem.products)) {
|
|
||||||
// 处理每个历史记录中的products数组
|
|
||||||
const flattenedProducts = historyItem.products.map(product => {
|
|
||||||
if (product.product_info) {
|
|
||||||
// 将product_info的所有属性合并到product的上一级
|
|
||||||
const flattenedProduct = { ...product };
|
|
||||||
|
|
||||||
// 遍历product_info的所有属性
|
|
||||||
Object.keys(product.product_info).forEach(key => {
|
|
||||||
if(key == 'id'){
|
|
||||||
flattenedProduct.productid = product.product_info.id;
|
|
||||||
}
|
|
||||||
// 如果上一级已经有同名属性,则跳过(避免覆盖)
|
|
||||||
if (!(key in flattenedProduct)) {
|
|
||||||
flattenedProduct[key] = product.product_info[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 删除product_info字段
|
|
||||||
delete flattenedProduct.product_info;
|
|
||||||
|
|
||||||
return flattenedProduct;
|
|
||||||
}
|
|
||||||
return product;
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
...historyItem,
|
|
||||||
products: flattenedProducts
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return historyItem;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* 处理删除事件,从列表中移除被删除的项目
|
|
||||||
* @param {string} deletedId - 被删除项目的ID
|
|
||||||
*/
|
|
||||||
handleDeleteItem(deletedId) {
|
|
||||||
// 遍历productList,找到包含被删除产品的历史记录
|
|
||||||
for (let i = 0; i < this.productList.length; i++) {
|
|
||||||
const historyItem = this.productList[i];
|
|
||||||
if (historyItem.products && Array.isArray(historyItem.products)) {
|
|
||||||
// 在products数组中查找并删除指定ID的产品
|
|
||||||
const productIndex = historyItem.products.findIndex(product => product.id === deletedId);
|
|
||||||
if (productIndex !== -1) {
|
|
||||||
// 删除该产品
|
|
||||||
historyItem.products.splice(productIndex, 1);
|
|
||||||
|
|
||||||
// 如果该历史记录下没有产品了,删除整个历史记录
|
|
||||||
if (historyItem.products.length === 0) {
|
|
||||||
this.productList.splice(i, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新视图
|
|
||||||
this.$forceUpdate();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style>
|
|
||||||
.historyBox-title {
|
|
||||||
font-size: 32px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #363a46;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
|
|
||||||
.hightText {
|
|
||||||
background: linear-gradient(90deg, #275aff, #2ebdfa);
|
|
||||||
-webkit-background-clip: text;
|
|
||||||
background-clip: text;
|
|
||||||
color: transparent;
|
|
||||||
display: inline-block;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.radio-group-container {
|
|
||||||
width: 100% !important;
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-start;
|
|
||||||
align-items: center;
|
|
||||||
max-width: 1400px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.radio-group {
|
|
||||||
display: flex;
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 8px;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.radio-item {
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 8px 16px;
|
|
||||||
border-radius: 6px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
background: #fff;
|
|
||||||
border: 1px solid #e8e8e8;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 历史记录列表样式 */
|
|
||||||
.history-list {
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.history-item {
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 12px;
|
|
||||||
padding: 20px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
|
||||||
border: 1px solid #f0f0f0;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.history-item:hover {
|
|
||||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
|
|
||||||
/* transform: translateY(-2px); */
|
|
||||||
}
|
|
||||||
|
|
||||||
.history-date {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
padding-bottom: 12px;
|
|
||||||
border-bottom: 1px solid #f5f5f5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.date-text {
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #275AFF;
|
|
||||||
margin-right: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.relative-time {
|
|
||||||
font-size: 14px;
|
|
||||||
color: #999;
|
|
||||||
background: #f8f9fa;
|
|
||||||
padding: 4px 8px;
|
|
||||||
border-radius: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.history-content {
|
|
||||||
margin-top: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 空状态样式 */
|
|
||||||
.empty-state {
|
|
||||||
text-align: center;
|
|
||||||
padding: 60px 20px;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.empty-icon {
|
|
||||||
font-size: 48px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
opacity: 0.6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.empty-text {
|
|
||||||
font-size: 16px;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,75 +0,0 @@
|
|||||||
// 日期格式化工具函数
|
|
||||||
/**
|
|
||||||
* 如果是今年之展示xx月xxx日
|
|
||||||
* 如果是去年之展示xx年xx月xx日
|
|
||||||
* 如果是今年之前之展示xx年xx月xx日
|
|
||||||
* 如果是今年之后之展示xx月xx日
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 格式化浏览日期
|
|
||||||
* @param {string|Date} date - 日期字符串或Date对象
|
|
||||||
* @returns {string} 格式化后的日期字符串
|
|
||||||
*/
|
|
||||||
export function formatBrowseDate(date) {
|
|
||||||
if (!date) return '';
|
|
||||||
|
|
||||||
const targetDate = new Date(date);
|
|
||||||
const currentDate = new Date();
|
|
||||||
const currentYear = currentDate.getFullYear();
|
|
||||||
const targetYear = targetDate.getFullYear();
|
|
||||||
|
|
||||||
// 获取月份和日期
|
|
||||||
const month = targetDate.getMonth() + 1;
|
|
||||||
const day = targetDate.getDate();
|
|
||||||
|
|
||||||
// 如果是今年
|
|
||||||
if (targetYear === currentYear) {
|
|
||||||
return `${month}月${day}日`;
|
|
||||||
}
|
|
||||||
// 如果是去年
|
|
||||||
else if (targetYear === currentYear - 1) {
|
|
||||||
return `${targetYear}年${month}月${day}日`;
|
|
||||||
}
|
|
||||||
// 如果是今年之前
|
|
||||||
else if (targetYear < currentYear) {
|
|
||||||
return `${targetYear}年${month}月${day}日`;
|
|
||||||
}
|
|
||||||
// 如果是今年之后(未来日期)
|
|
||||||
else {
|
|
||||||
return `${month}月${day}日`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取相对时间描述
|
|
||||||
* @param {string|Date} date - 日期字符串或Date对象
|
|
||||||
* @returns {string} 相对时间描述
|
|
||||||
*/
|
|
||||||
export function getRelativeTime(date) {
|
|
||||||
if (!date) return '';
|
|
||||||
|
|
||||||
const targetDate = new Date(date);
|
|
||||||
const currentDate = new Date();
|
|
||||||
const diffTime = currentDate - targetDate;
|
|
||||||
const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24));
|
|
||||||
|
|
||||||
if (diffDays === 0) {
|
|
||||||
return '今天';
|
|
||||||
} else if (diffDays === 1) {
|
|
||||||
return '昨天';
|
|
||||||
} else if (diffDays === 2) {
|
|
||||||
return '前天';
|
|
||||||
} else if (diffDays < 7) {
|
|
||||||
return `${diffDays}天前`;
|
|
||||||
} else if (diffDays < 30) {
|
|
||||||
const weeks = Math.floor(diffDays / 7);
|
|
||||||
return `${weeks}周前`;
|
|
||||||
} else if (diffDays < 365) {
|
|
||||||
const months = Math.floor(diffDays / 30);
|
|
||||||
return `${months}个月前`;
|
|
||||||
} else {
|
|
||||||
const years = Math.floor(diffDays / 365);
|
|
||||||
return `${years}年前`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -16,7 +16,7 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
boxLoading: false,
|
boxLoading:false,
|
||||||
selectedCategory: "",
|
selectedCategory: "",
|
||||||
showTip: false,
|
showTip: false,
|
||||||
total: 0,
|
total: 0,
|
||||||
@ -258,20 +258,6 @@ export default Vue.extend({
|
|||||||
handleSearch() {
|
handleSearch() {
|
||||||
console.log('搜索:1', this.searchKeyword)
|
console.log('搜索:1', this.searchKeyword)
|
||||||
|
|
||||||
},
|
|
||||||
goFavorite() {
|
|
||||||
if (this.loginState) {
|
|
||||||
this.$router.push('/ncmatchHome/favoriteBox')
|
|
||||||
} else {
|
|
||||||
this.$router.push('/login')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
goHistory() {
|
|
||||||
if (this.loginState) {
|
|
||||||
this.$router.push('/ncmatchHome/historyBox')
|
|
||||||
} else {
|
|
||||||
this.$router.push('/login')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -316,11 +302,11 @@ export default Vue.extend({
|
|||||||
<span class="publish-goods" @click="sendInfo('2')">发布需求</span>
|
<span class="publish-goods" @click="sendInfo('2')">发布需求</span>
|
||||||
<span class="publish-goods" @click="sendInfo('1')">发布商品</span>
|
<span class="publish-goods" @click="sendInfo('1')">发布商品</span>
|
||||||
|
|
||||||
<ul class="userBtn">
|
<!-- <ul class="userBtn">
|
||||||
<li @click="goHistory"><img style="width: 26px;height: 26px;" src="./img/eye.png" alt="">浏览记录</li>
|
<li><img 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/collect.png" alt="">收藏商品</li>
|
||||||
<!-- <li><img src="./img/like.png" alt="">关注需求</li> -->
|
<li><img src="./img/like.png" alt="">关注需求</li>
|
||||||
</ul>
|
</ul> -->
|
||||||
</aside>
|
</aside>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
@ -369,20 +355,12 @@ export default Vue.extend({
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
|
|
||||||
* {
|
|
||||||
img {
|
|
||||||
width: 20px !important;
|
|
||||||
height: 20px !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: #2c96fc;
|
color: #2c96fc;
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
|
|
||||||
path {
|
path {
|
||||||
fill: #2c96fc !important;
|
fill: #2c96fc !important;
|
||||||
}
|
}
|
||||||
@ -504,7 +482,7 @@ export default Vue.extend({
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-top: 50px;
|
|
||||||
.activeMenu {
|
.activeMenu {
|
||||||
background: linear-gradient(90deg, #275AFF 0%, #2EBDFA 100%);
|
background: linear-gradient(90deg, #275AFF 0%, #2EBDFA 100%);
|
||||||
color: white;
|
color: white;
|
||||||
@ -719,9 +697,8 @@ export default Vue.extend({
|
|||||||
|
|
||||||
.user-sidebar {
|
.user-sidebar {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
*{
|
||||||
* {
|
font-size: 20px!important;
|
||||||
font-size: 20px !important;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -52,34 +52,13 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="product-price">
|
<div class="product-price">
|
||||||
<span class="price">¥{{ item.discount_price }}</span>
|
<span class="price">¥{{ item.discount_price }}</span>
|
||||||
<span class="price-unit">{{ item.unit }} {{ item.short_term === '1' ? '(可短租)' : '' }} </span> <el-tag size="mini" style="margin-left: 10px;" v-if="item.favorite=='1'" type="success">已收藏</el-tag>
|
<span class="price-unit">{{ item.unit }} {{ item.short_term === '1' ? '(可短租)' : '' }} </span>
|
||||||
</div>
|
|
||||||
<div class="action-buttons">
|
|
||||||
<el-button :disabled="loadingStates[item.id]" class="consult-btn" @click="openTalk">立即咨询</el-button>
|
|
||||||
<span @click="openDetail(item)" class="detail-btn">
|
|
||||||
详情 <i v-if="loadingStates[item.id]" class="el-icon-loading"></i> <span v-else>>></span>
|
|
||||||
</span>
|
|
||||||
<span
|
|
||||||
:style="{ color: item.favorite === '1' ? 'red' : 'green' }"
|
|
||||||
@click="collect(item)"
|
|
||||||
class="detail-btn"
|
|
||||||
style="cursor: pointer;"
|
|
||||||
>
|
|
||||||
{{ item.favorite === '1' ? '取消收藏' : '收藏' }}
|
|
||||||
<i v-if="collectLoadingStates[item.id]" class="el-icon-loading"></i>
|
|
||||||
<i
|
|
||||||
v-else
|
|
||||||
:class="item.favorite === '1' ? 'el-icon-star-off' : 'el-icon-star-on'"
|
|
||||||
style="width: 14px;height: 14px;margin-left: 2px;"
|
|
||||||
></i>
|
|
||||||
</span>
|
|
||||||
<span v-if="contentType === 'history'||contentType === 'favorite'" @click="deleteProduct(item)" class="delete-btn" :class="{ 'loading': deleteLoadingStates[item.id] }">
|
|
||||||
删除
|
|
||||||
<i v-if="deleteLoadingStates[item.id]" class="el-icon-loading"></i>
|
|
||||||
<i v-else style="color: red;" class="el-icon-delete"></i>
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div style="display: flex;justify-content: space-between;align-items: center;">
|
||||||
|
|
||||||
|
<el-button :disabled="loadingStates[item.id]" class="consult-btn" @click="openTalk">立即咨询</el-button> <span @click="openDetail(item)"
|
||||||
|
class="detail-btn">详情 <i v-if="loadingStates[item.id]" class="el-icon-loading"></i> <span v-else>>></span> </span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -115,30 +94,10 @@
|
|||||||
<span class="price">¥{{ item.discount_price }}</span>
|
<span class="price">¥{{ item.discount_price }}</span>
|
||||||
<span class="price-unit">{{ item.unit }} {{ item.short_term === '1' ? '(可短租)' : '' }} </span>
|
<span class="price-unit">{{ item.unit }} {{ item.short_term === '1' ? '(可短租)' : '' }} </span>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div style="display: flex;justify-content: space-between;align-items: center;">
|
||||||
<el-button :disabled="loadingStates[item.id]" class="consult-btn" @click="openTalk">立即咨询</el-button>
|
|
||||||
<span @click="openDetail(item)" class="detail-btn">
|
<el-button :disabled="loadingStates[item.id]" class="consult-btn" @click="openTalk">立即咨询</el-button> <span @click="openDetail(item)"
|
||||||
详情 <i v-if="loadingStates[item.id]" class="el-icon-loading"></i> <span v-else>>></span>
|
class="detail-btn">详情 <i v-if="loadingStates[item.id]" class="el-icon-loading"></i> <span v-else>>></span> </span>
|
||||||
</span>
|
|
||||||
<span
|
|
||||||
:style="{ color: item.favorite === '1' ? 'red' : 'green' }"
|
|
||||||
@click="collect(item)"
|
|
||||||
class="detail-btn"
|
|
||||||
style="cursor: pointer;"
|
|
||||||
>
|
|
||||||
{{ item.favorite === '1' ? '取消收藏' : '收藏' }}
|
|
||||||
<i v-if="collectLoadingStates[item.id]" class="el-icon-loading"></i>
|
|
||||||
<i
|
|
||||||
v-else
|
|
||||||
:class="item.favorite === '1' ? 'el-icon-star-off' : 'el-icon-star-on'"
|
|
||||||
style="width: 14px;height: 14px;margin-left: 2px;"
|
|
||||||
></i>
|
|
||||||
</span>
|
|
||||||
<span v-if="contentType === 'history'||contentType === 'favorite'" @click="deleteProduct(item)" class="delete-btn" :class="{ 'loading': deleteLoadingStates[item.id] }">
|
|
||||||
删除
|
|
||||||
<i v-if="deleteLoadingStates[item.id]" class="el-icon-loading"></i>
|
|
||||||
<i v-else style="color: red;" class="el-icon-delete"></i>
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
@ -148,17 +107,13 @@
|
|||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import Talk from '@/views/homePage/dialog/talk/index.vue'
|
import Talk from '@/views/homePage/dialog/talk/index.vue'
|
||||||
import { reqGetProductDetail,reqPublishProductCollect,reqFavoriteDelete,reqUserBrowseHistoryDeleteById,reqFavoriteDeleteById } from '@/api/ncmatch'
|
import { reqGetProductDetail } from '@/api/ncmatch'
|
||||||
export default {
|
export default {
|
||||||
name: 'productCard',
|
name: 'productCard',
|
||||||
components: {
|
components: {
|
||||||
Talk
|
Talk
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
contentType: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
productList: {
|
productList: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => []
|
default: () => []
|
||||||
@ -174,102 +129,17 @@ export default {
|
|||||||
},
|
},
|
||||||
data(){
|
data(){
|
||||||
return{
|
return{
|
||||||
loadingStates: {},
|
loadingStates: {}
|
||||||
collectLoadingStates: {},
|
|
||||||
deleteLoadingStates: {}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
//删除历史记录
|
|
||||||
deleteHistory(item){
|
|
||||||
this.$set(this.deleteLoadingStates, item.id, true);
|
|
||||||
reqUserBrowseHistoryDeleteById({id:item.id}).then(res=>{
|
|
||||||
if(res.status){
|
|
||||||
this.$emit('delete-item', item.id);
|
|
||||||
}else{
|
|
||||||
this.$message.error(res.msg);
|
|
||||||
}
|
|
||||||
this.$set(this.deleteLoadingStates, item.id, false);
|
|
||||||
}).catch(err => {
|
|
||||||
console.error('删除失败:', err);
|
|
||||||
this.$message.error('删除失败,请重试');
|
|
||||||
this.$set(this.deleteLoadingStates, item.id, false);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
//删除关注记录
|
|
||||||
deleteFavorite(item){
|
|
||||||
console.log("删除",item);
|
|
||||||
this.$set(this.deleteLoadingStates, item.id, true);
|
|
||||||
reqFavoriteDeleteById({id:item.id}).then(res=>{
|
|
||||||
if(res.status){
|
|
||||||
this.$message.success("删除成功");
|
|
||||||
this.$emit('delete-item', item.id);
|
|
||||||
}else{
|
|
||||||
this.$message.error(res.msg);
|
|
||||||
}
|
|
||||||
this.$set(this.deleteLoadingStates, item.id, false);
|
|
||||||
}).catch(err => {
|
|
||||||
console.error('删除失败:', err);
|
|
||||||
this.$message.error('删除失败,请重试');
|
|
||||||
this.$set(this.deleteLoadingStates, item.id, false);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
deleteProduct(item){
|
|
||||||
console.log("删除",item);
|
|
||||||
if(this.contentType === 'history'){
|
|
||||||
this.deleteHistory(item);
|
|
||||||
}else if(this.contentType === 'favorite'){
|
|
||||||
this.deleteFavorite(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
// reqPublishProductDelete({
|
|
||||||
// id:item.id,
|
|
||||||
// }).then(res=>{
|
|
||||||
// console.log("删除",res);
|
|
||||||
// })
|
|
||||||
},
|
|
||||||
collect(item){
|
|
||||||
this.$set(this.collectLoadingStates, item.id, true);
|
|
||||||
// 这里添加收藏/取消收藏的逻辑
|
|
||||||
if(item.favorite=='1'){
|
|
||||||
|
|
||||||
reqFavoriteDelete({
|
|
||||||
id:item.productid?item.productid:item.id,
|
|
||||||
}).then(res=>{
|
|
||||||
item.favorite='0'
|
|
||||||
if(res.status){
|
|
||||||
this.$message.success(res.msg);
|
|
||||||
this.$set(this.collectLoadingStates, item.id, false);
|
|
||||||
}else{
|
|
||||||
this.$message.error(res.msg);
|
|
||||||
this.$set(this.collectLoadingStates, item.id, false);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}else if(item.favorite=='0'){
|
|
||||||
|
|
||||||
reqPublishProductCollect({
|
|
||||||
productid:item.productid?item.productid:item.id,
|
|
||||||
favorite_type:item.publish_type
|
|
||||||
}).then(res=>{
|
|
||||||
item.favorite='1'
|
|
||||||
if(res.status){
|
|
||||||
this.$message.success(res.msg);
|
|
||||||
this.$set(this.collectLoadingStates, item.id, false);
|
|
||||||
}else{
|
|
||||||
this.$message.error(res.msg);
|
|
||||||
this.$set(this.collectLoadingStates, item.id, false);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
openTalk() {
|
openTalk() {
|
||||||
this.$store.commit('setShowTalk', true);
|
this.$store.commit('setShowTalk', true);
|
||||||
},
|
},
|
||||||
async openDetail(item) {
|
async openDetail(item) {
|
||||||
this.$set(this.loadingStates, item.id, true);
|
this.$set(this.loadingStates, item.id, true);
|
||||||
reqGetProductDetail({
|
reqGetProductDetail({
|
||||||
id:item.productid?item.productid:item.id,
|
id: item.id,
|
||||||
from:'f'
|
from:'f'
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
|
|
||||||
@ -406,34 +276,22 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.consult-btn {
|
.consult-btn {
|
||||||
|
width: 100%;
|
||||||
background: linear-gradient(90deg, #275AFF 0%, #2EBDFA 100%);
|
background: linear-gradient(90deg, #275AFF 0%, #2EBDFA 100%);
|
||||||
color: white;
|
color: white;
|
||||||
border: none;
|
border: none;
|
||||||
padding: 12px 32px;
|
padding: 12px 24px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
white-space: nowrap;
|
|
||||||
flex: 1;
|
|
||||||
min-width: 120px;
|
|
||||||
max-width: 200px;
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
box-shadow: 0 4px 12px rgba(39, 90, 255, 0.3);
|
box-shadow: 0 4px 12px rgba(39, 90, 255, 0.3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-buttons {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-start;
|
|
||||||
align-items: center;
|
|
||||||
gap: 16px;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
margin-top: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail-btn {
|
.detail-btn {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -441,24 +299,8 @@ export default {
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #275AFF;
|
color: #275AFF;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: fit-content;
|
min-width: 50px;
|
||||||
white-space: nowrap;
|
margin-left: 25px;
|
||||||
}
|
|
||||||
|
|
||||||
.delete-btn {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-start;
|
|
||||||
font-size: 14px;
|
|
||||||
color: #e74c3c;
|
|
||||||
cursor: pointer;
|
|
||||||
width: fit-content;
|
|
||||||
white-space: nowrap;
|
|
||||||
|
|
||||||
&.loading {
|
|
||||||
cursor: not-allowed;
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,15 +13,11 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="content" label="内容" min-width="180">
|
<el-table-column prop="content" label="内容" min-width="180">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="create_time" label="咨询时间" min-width="180">
|
<el-table-column prop="create_time" label="创建时间" min-width="180">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="update_time" label="联系时间" min-width="180">
|
<el-table-column prop="update_time" label="更新时间" min-width="180">
|
||||||
</el-table-column>
|
|
||||||
<el-table-column prop="update_time" label="操作" min-width="180">
|
|
||||||
<template slot-scope="scope">
|
|
||||||
<el-button type="text" @click="handleEdit(scope.row)">已回复</el-button>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
</el-table>
|
</el-table>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user