From b632da39e8f7a41ce62a38c3444ed72c886c26ce Mon Sep 17 00:00:00 2001 From: ping <1017253325@qq.com> Date: Tue, 19 Aug 2025 15:27:26 +0800 Subject: [PATCH] update --- b/product/homepage_category_tree_delete.dspy | 16 +++ b/product/publish_product_search.dspy | 124 +++++++++++++++++++ b/product/publish_product_search_detail.dspy | 56 +++++++++ b/product/search_user_inquiry.dspy | 36 ++++++ b/user/enterprise_audit_info_search.dspy | 45 ++++++- b/user/user_browse_history_add.dspy | 53 ++++++++ b/user/user_browse_history_delete.dspy | 29 +++++ b/user/user_browse_history_search.dspy | 72 +++++++++++ 8 files changed, 428 insertions(+), 3 deletions(-) create mode 100644 b/product/homepage_category_tree_delete.dspy create mode 100644 b/user/user_browse_history_add.dspy create mode 100644 b/user/user_browse_history_delete.dspy create mode 100644 b/user/user_browse_history_search.dspy diff --git a/b/product/homepage_category_tree_delete.dspy b/b/product/homepage_category_tree_delete.dspy new file mode 100644 index 0000000..8b16a94 --- /dev/null +++ b/b/product/homepage_category_tree_delete.dspy @@ -0,0 +1,16 @@ +async def homepage_category_tree_delete(ns={}): + if not ns.get('id'): + return { + 'status': False, + 'msg': '请传递分类ID' + } + db = DBPools() + async with db.sqlorContext('kboss') as sor: + await sor.U('homepage_category_tree', {'id': ns.get('id'), 'del_flg': '1'}) + return { + 'status': True, + 'msg': 'product category deleted successfully' + } + +ret = await homepage_category_tree_delete(params_kw) +return ret \ No newline at end of file diff --git a/b/product/publish_product_search.dspy b/b/product/publish_product_search.dspy index a2cbf13..2deb96d 100644 --- a/b/product/publish_product_search.dspy +++ b/b/product/publish_product_search.dspy @@ -1,3 +1,121 @@ +async def publish_product_to_excel(ns={}): + if not ns.get('ids') and (not ns.get('result_from_search')): + return { + 'status': False, + 'msg': '请传递产品ID' + } + result = [] + if ns.get('ids'): + db = DBPools() + async with db.sqlorContext('kboss') as sor: + ids = json.loads(ns.get('ids')) if isinstance(ns.get('ids'), str) else ns.get('ids') + # 根据ids查询user_publish_product表 + find_sql = """SELECT * FROM user_publish_product WHERE id IN (%s) AND del_flg = '0';""" % ','.join(["'%s'" % id for id in ids]) + result = await sor.sqlExe(find_sql, {}) + if not result: + return { + 'status': False, + 'msg': '没有找到匹配的产品' + } + if ns.get('result_from_search'): + result = ns.get('result_from_search') + + # 结果转换成 中文名称:值 的字典列表 + field_mapping = { + # 'id': 'id', + # 'publish_type': '类型', + 'img': '图片链接', + # 'cart_flag': '是否支持显卡', + # 'domain_name': '所属域名', + # 'orgid': '所属机构', + 'product_name': '商品名称', + # 'product_category': '所属类别', + 'company_name': '企业名称', + # 'company_type': '公司类别', + 'contact_person': '联系人', + 'job_title': '职务', + 'phone_number': '手机号码', + 'email': '邮箱', + 'cpu': 'cpu', + 'memory': '内存', + 'gpu': 'gpu', + 'sys_disk': '系统盘', + 'data_disk': '数据盘', + 'net_card': '网卡', + 'price': '价格', + 'unit': '价格单位', + 'discount': '价格折扣', + 'discount_price': '折扣后价格', + 'service_charge': '服务费', + 'short_term': '是否短租', + # 'priority': '排序优先级', + 'status': '上架状态', + # 'title': '主题', + # 'label': '标签', + # 'first_page': '是否推送到首页', + # 'admin_push': '是否是运营人员提交', + 'requirement_summary': '需求概述', + 'related_parameters': '相关参数', + 'application_scenario': '应用场景', + 'audit_status': '审核状态', + 'listing_status': '上架状态', + 'reject_reason': '驳回原因', + 'update_time': '更新时间', + 'create_at': '创建时间', + # 'publish_time': '发布日期', + # 'del_flg': '删除标志' + } + # 转换字典键为中文 + for data_dic in result: + # 如果有图片路径 则转换为完整的图片链接 + if data_dic.get('img') and data_dic['img'] != 'null': + data_dic['img'] = 'https://' + data_dic['domain_name'] + '/idfile?path=' + data_dic['img'] + else: + data_dic['img'] = None + # 转换字典键为中文 对应的值要有映射 + # 拆分后:显式循环结构(便于后续处理) + new_data_dic = {} + for key, value in data_dic.items(): + if key == 'publish_type': + # 显示类型映射 + if value == '1': + value = '产品' + elif value == '2': + value = '需求' + if key == 'audit_status': + # 显示审核状态映射 + if value == 'pending': + value = '待审' + elif value == 'approved': + value = '通过' + elif value == 'rejected': + value = '拒绝' + if key == 'listing_status': + # 显示上架状态映射 + if value == 'listing': + value = '上架' + elif value == 'delisting': + value = '下架' + if key == 'short_term': + # 显示短租状态映射 + if value == '1': + value = '是' + elif value == '0': + value = '否' + # 获取中文映射键 + chinese_key = field_mapping.get(key) + # 仅保留有映射关系的字段 + if chinese_key is not None: + new_data_dic[chinese_key] = value + data_dic.clear() + data_dic.update(new_data_dic) + + return { + 'status': True, + 'msg': 'export to excel success', + 'data': result + } + async def get_user_role(ns={}): sor = ns['sor'] # get role @@ -48,6 +166,12 @@ async def publish_product_search(ns={}): 'status': False, 'msg': 'url_link is required' } + if not ns.get('publish_type'): + return { + 'status': False, + 'msg': 'publish_type is required' + } + domain_name = ns.get('url_link').split("//")[1].split("/")[0] if 'localhost' in domain_name: diff --git a/b/product/publish_product_search_detail.dspy b/b/product/publish_product_search_detail.dspy index f4938e4..9db7072 100644 --- a/b/product/publish_product_search_detail.dspy +++ b/b/product/publish_product_search_detail.dspy @@ -23,6 +23,57 @@ async def get_user_role(ns={}): return role +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('product_id'): + return { + 'status': False, + 'msg': 'userid and product_id are required' + } + + db = DBPools() + async with db.sqlorContext('kboss') as sor: + try: + # 根据timestamp时间字段:browse_time去重 查找10个小时内是否存在 + browse_time = datetime.datetime.now() - datetime.timedelta(hours=10) + check_sql = """ + SELECT * FROM user_browse_history + WHERE userid = '%s' AND product_id = '%s' AND del_flg = '0' AND browse_time >= '%s'; + """ % (ns.get('userid'), ns.get('product_id'), browse_time) + check_result = await sor.sqlExe(check_sql, {}) + if check_result: + return { + 'status': False, + 'msg': 'The user has browsed this product within the last 10 hours' + } + + # 生成记录ID + record_id = uuid() + # 插入浏览记录 + insert_sql = """ + INSERT INTO user_browse_history ( + id, userid, product_id, ip_address, user_agent, del_flg + ) VALUES ('%s', '%s', '%s', '%s', '%s', '0'); + """ % (record_id, ns.get('userid'), ns.get('product_id'), + ns.get('ip_address', ''), ns.get('user_agent', '')) + await sor.sqlExe(insert_sql, {}) + return { + 'status': True, + 'msg': 'Browse history recorded successfully', + 'data': {'record_id': record_id} + } + except Exception as e: + return { + 'status': False, + 'msg': 'Failed to record browse history, %s' % str(e) + } + async def publish_product_search_detail(ns={}): """ :param ns: @@ -36,6 +87,7 @@ async def publish_product_search_detail(ns={}): db = DBPools() async with db.sqlorContext('kboss') as sor: user_role = None + orgid = None # 区分运营和普通客户 if userid: user_list = await sor.R('users', {'id': userid}) @@ -61,6 +113,10 @@ async def publish_product_search_detail(ns={}): else: product['email'] = 'kawa@****.com' + # 保存浏览记录 + if userid: + await user_browse_history_add({'userid': userid, 'product_id': ns.get('id')}) + return { 'status': True, 'msg': 'Product retrieved successfully', diff --git a/b/product/search_user_inquiry.dspy b/b/product/search_user_inquiry.dspy index 1dae62e..906e50e 100644 --- a/b/product/search_user_inquiry.dspy +++ b/b/product/search_user_inquiry.dspy @@ -12,6 +12,42 @@ async def search_user_inquiry(ns={}): async with db.sqlorContext('kboss') as sor: search_sql = """select * from product_inquiry where domain_name = '%s' and del_flg = '0' order by update_time desc;""" % domain_name result = await sor.sqlExe(search_sql, {}) + if ns.get('to_excel') == '1': + # 创建映射字段 导出execl + # 结果转换成 中文名称:值 的字典列表 + field_mapping = { + 'name': '联系人姓名', + 'custom_type': '客户类型', + 'phone': '联系人电话', + 'email': '邮箱', + 'company': '公司名称', + 'content': '咨询内容', + 'feedback': '反馈状态', + } + # 新增值映射字典,集中管理各字段的数值转换规则 + value_mapping = { + 'custom_type': {'0': '个人', '1': '企业'}, + 'feedback': {'0': '未反馈', '1': '已反馈'} # 根据表结构补充反馈状态映射 + } + # 转换字典键为中文 + for data_dic in result: + # 拆分后:显式循环结构(便于后续处理) + new_data_dic = {} + # 按field_mapping定义的顺序处理字段,确保输出顺序一致 + for key in field_mapping.keys(): + # 跳过数据中不存在的字段 + if key not in data_dic: + continue + value = data_dic[key] + chinese_key = field_mapping[key] + if key in value_mapping: + mapped_value = value_mapping[key].get(str(value), value) # 若未找到对应映射,保留原始值 + new_data_dic[chinese_key] = mapped_value + else: + new_data_dic[chinese_key] = value + data_dic.clear() + data_dic.update(new_data_dic) + return { 'status': True, 'msg': 'search success', diff --git a/b/user/enterprise_audit_info_search.dspy b/b/user/enterprise_audit_info_search.dspy index 3bc5eb1..6294bb7 100644 --- a/b/user/enterprise_audit_info_search.dspy +++ b/b/user/enterprise_audit_info_search.dspy @@ -29,6 +29,14 @@ async def enterprise_audit_info_search(ns={}): 'status': False, 'msg': '请传递url_link' } + + # 分页 + current_page = int(ns['current_page']) if ns.get('current_page') else 1 + page_size = int(ns['page_size']) if ns.get('page_size') else 10 + offset = (current_page - 1) * page_size + + audit_status = ns.get('audit_status') + domain_name = ns.get('url_link').split("//")[1].split("/")[0] if 'localhost' in domain_name: domain_name = 'dev.opencomputing.cn' @@ -50,10 +58,36 @@ async def enterprise_audit_info_search(ns={}): user_role = await get_user_role({'userid': userid, 'sor': sor}) try: if user_role == '客户': # 客户查询 + count_sql = """SELECT COUNT(*) AS total_count FROM enterprise_audit_info WHERE orgid = '%s' AND del_flg = '0';""" % orgid find_sql = """SELECT * FROM enterprise_audit_info WHERE orgid = '%s' AND del_flg = '0';""" % orgid else: # 运营查询 enterprise_audit_info和organization表关联查询 enterprise_audit_info中的orgid和organization表中的id关联查询 - find_sql = """SELECT eai.* FROM enterprise_audit_info AS eai LEFT JOIN organization as org ON eai.orgid = org.id WHERE org.parentid = '%s' AND eai.del_flg = '0' ORDER BY eai.update_time DESC;""" % orgid - # 执行查询 + count_sql = """SELECT COUNT(*) AS total_count FROM enterprise_audit_info AS eai LEFT JOIN organization as org ON eai.orgid = org.id WHERE org.parentid = '%s' AND eai.del_flg = '0';""" % orgid + find_sql = """SELECT eai.* FROM enterprise_audit_info AS eai LEFT JOIN organization as org ON eai.orgid = org.id WHERE org.parentid = '%s' AND eai.del_flg = '0' ORDER BY eai.update_time DESC LIMIT %s OFFSET %s;""" % (orgid, page_size, offset) + # 拆分find_sql 增加audit_status条件筛选 + if audit_status: + # Split the audit_status string into individual statuses + statuses = [status.strip() for status in audit_status.split(',') if status.strip()] + if statuses: + # Create a properly escaped list of statuses for SQL + escaped_statuses = [] + for status in statuses: + # Escape single quotes by doubling them (SQL standard) + escaped_status = status.replace("'", "''") + escaped_statuses.append(f"'{escaped_status}'") + + # Join the escaped statuses for the IN clause + statuses_str = ','.join(escaped_statuses) + + if statuses_str: + count_sql = count_sql.split("WHERE")[0] + f"WHERE eai.audit_status IN ({statuses_str}) AND " + count_sql.split("WHERE")[1] + find_sql = find_sql.split("WHERE")[0] + f"WHERE eai.audit_status IN ({statuses_str}) AND " + find_sql.split("WHERE")[1] + # 非pending + else: + count_sql = count_sql.split("WHERE")[0] + "WHERE eai.audit_status != 'pending' AND " + count_sql.split("WHERE")[1] + find_sql = find_sql.split("WHERE")[0] + "WHERE eai.audit_status != 'pending' AND " + find_sql.split("WHERE")[1] + + # 执行查询 + total_count = (await sor.sqlExe(count_sql, {}))[0]['total_count'] res = await sor.sqlExe(find_sql, {}) # 处理结果中的图片路径 增加前缀 @@ -66,7 +100,12 @@ async def enterprise_audit_info_search(ns={}): return { 'status': True, 'msg': 'enterprise audit info search successfully', - 'data': res + 'data': { + 'total_count': total_count, + 'current_page': current_page, + 'page_size': page_size, + 'data': res + } } except Exception as e: return { diff --git a/b/user/user_browse_history_add.dspy b/b/user/user_browse_history_add.dspy new file mode 100644 index 0000000..bbdd7b0 --- /dev/null +++ b/b/user/user_browse_history_add.dspy @@ -0,0 +1,53 @@ +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('product_id'): + return { + 'status': False, + 'msg': 'userid and product_id are required' + } + + db = DBPools() + async with db.sqlorContext('kboss') as sor: + try: + # 根据timestamp时间字段:browse_time去重 查找10个小时内是否存在 + browse_time = datetime.datetime.now() - datetime.timedelta(hours=10) + check_sql = """ + SELECT * FROM user_browse_history + WHERE userid = '%s' AND product_id = '%s' AND del_flg = '0' AND browse_time >= '%s'; + """ % (ns.get('userid'), ns.get('product_id'), browse_time) + check_result = await sor.sqlExe(check_sql, {}) + if check_result: + return { + 'status': False, + 'msg': 'The user has browsed this product within the last 10 hours' + } + + # 生成记录ID + record_id = uuid() + # 插入浏览记录 + insert_sql = """ + INSERT INTO user_browse_history ( + id, userid, product_id, ip_address, user_agent, del_flg + ) VALUES ('%s', '%s', '%s', '%s', '%s', '0'); + """ % (record_id, ns.get('userid'), ns.get('product_id'), + ns.get('ip_address', ''), ns.get('user_agent', '')) + await sor.sqlExe(insert_sql, {}) + return { + 'status': True, + 'msg': 'Browse history recorded successfully', + 'data': {'record_id': record_id} + } + except Exception as e: + return { + 'status': False, + 'msg': 'Failed to record browse history, %s' % str(e) + } + +ret = await user_browse_history_add(params_kw) +return ret \ No newline at end of file diff --git a/b/user/user_browse_history_delete.dspy b/b/user/user_browse_history_delete.dspy new file mode 100644 index 0000000..7439659 --- /dev/null +++ b/b/user/user_browse_history_delete.dspy @@ -0,0 +1,29 @@ +async def user_browse_history_delete(ns={}): + if not ns.get('id'): + return { + 'status': False, + 'msg': 'record id is required' + } + + db = DBPools() + async with db.sqlorContext('kboss') as sor: + try: + # 逻辑删除(更新删除标志) + update_sql = """ + UPDATE user_browse_history + SET del_flg = '1' + WHERE id = '%s'; + """ % ns.get('id') + await sor.sqlExe(update_sql, {}) + return { + 'status': True, + 'msg': 'Browse history deleted successfully' + } + except Exception as e: + return { + 'status': False, + 'msg': 'Failed to delete browse history, %s' % str(e) + } + +ret = await user_browse_history_delete(params_kw) +return ret \ No newline at end of file diff --git a/b/user/user_browse_history_search.dspy b/b/user/user_browse_history_search.dspy new file mode 100644 index 0000000..9df8083 --- /dev/null +++ b/b/user/user_browse_history_search.dspy @@ -0,0 +1,72 @@ +async def user_browse_history_search(ns={}): + # 处理userid + if ns.get('userid'): + userid = ns.get('userid') + else: + userid = await get_user() + if not userid: + return { + 'status': False, + 'msg': 'no match user' + } + + # 参数处理 + product_id = ns.get('product_id') + start_time = ns.get('start_time') + end_time = ns.get('end_time') + page_size = int(ns.get('page_size', 10)) + current_page = int(ns.get('current_page', 1)) + offset = (current_page - 1) * page_size + + db = DBPools() + async with db.sqlorContext('kboss') as sor: + try: + # 基础查询条件 + base_conditions = ["del_flg = '0'"] + if userid: + base_conditions.append(f"userid = '{userid}'") + if product_id: + base_conditions.append(f"product_id = '{product_id}'") + if start_time and end_time: + end_time += ' 23:59:59' + base_conditions.append(f"browse_time BETWEEN '{start_time}' AND '{end_time}'") + + # 构建查询SQL + where_clause = " AND ".join(base_conditions) + + # 根据product_id查询product_info + + find_sql = f""" + SELECT * FROM user_browse_history + WHERE {where_clause} + ORDER BY browse_time DESC + LIMIT {page_size} OFFSET {offset}; + """ + # 总数查询SQL + count_sql = f""" + SELECT COUNT(*) AS total_count FROM user_browse_history + WHERE {where_clause}; + """ + + # 执行查询 + result = await sor.sqlExe(find_sql, {}) + total_count = (await sor.sqlExe(count_sql, {}))[0]['total_count'] + + return { + 'status': True, + 'msg': 'Browse history retrieved successfully', + 'data': { + 'total_count': total_count, + 'page_size': page_size, + 'current_page': current_page, + 'history_list': result + } + } + except Exception as e: + return { + 'status': False, + 'msg': 'Failed to retrieve browse history, %s' % str(e) + } + +ret = await user_browse_history_search(params_kw) +return ret \ No newline at end of file