main #34

Merged
charles merged 191 commits from main into prod 2025-11-19 16:18:39 +08:00
154 changed files with 34099 additions and 8791 deletions

View File

@ -4,7 +4,7 @@ async def jiajie_get_token_redirect(ns={}):
:return: :return:
""" """
# target_host = 'https://testing.vstecscloud.shop' # target_host = 'https://testing.vstecscloud.shop'
target_host = 'https://aliyun.kaiyuancloud.cn' target_host = 'https://aliyun.opencomputing.cn'
if ns.get('userid'): if ns.get('userid'):
userid = ns.get('userid') userid = ns.get('userid')
@ -39,7 +39,7 @@ async def jiajie_get_token_redirect(ns={}):
# 发送HTTP请求 # 发送HTTP请求
url = "%s/api/blade-auth/oauth/token" % target_host url = "%s/api/blade-auth/oauth/token" % target_host
if 'kaiyuancloud' in target_host: if 'opencomputing' in target_host:
tenantid = '502332' tenantid = '502332'
else: else:
tenantid = '024060' tenantid = '024060'

View File

@ -15,7 +15,7 @@ async def jiajie_sync_user(ns={}):
'msg': '用户还未登录' 'msg': '用户还未登录'
} }
# target_host = 'https://testing.vstecscloud.shop' # target_host = 'https://testing.vstecscloud.shop'
target_host = 'https://aliyun.kaiyuancloud.cn' target_host = 'https://aliyun.opencomputing.cn'
db = DBPools() db = DBPools()
async with db.sqlorContext('kboss') as sor: async with db.sqlorContext('kboss') as sor:
exits_user = await sor.R('weishijiajie_users', {'user_id': userid}) exits_user = await sor.R('weishijiajie_users', {'user_id': userid})
@ -71,7 +71,7 @@ async def jiajie_sync_user(ns={}):
else: else:
return { return {
'status': False, 'status': False,
'msg': f"请求失败,状态码: {result.get('code')},响应内容: {result.get('msg')}" 'msg': f"用户手机号:{phone}, 请求失败,状态码: {result.get('code')},响应内容: {result.get('msg')}"
} }
ret = await jiajie_sync_user(params_kw) ret = await jiajie_sync_user(params_kw)

View File

@ -198,6 +198,63 @@ async def baidu_order_cancel(ns={}):
'msg': 'order cancel success' 'msg': 'order cancel success'
} }
async def get_time_diff(time_old=None, time_new=None):
# # 定义两个时间字符串
# time_old = '2023-12-01 09:40:00'
# time_new = '2023-12-01 23:15:00'
# 将时间字符串解析为datetime对象
time_dt1 = datetime.datetime.strptime(time_old, '%Y-%m-%d %H:%M:%S')
time_dt2 = datetime.datetime.strptime(time_new, '%Y-%m-%d %H:%M:%S')
# 计算时间差
time_difference = time_dt2 - time_dt1
# 提取时间差中的分钟数
minutes_difference = time_difference.total_seconds() / 60
# day = time_difference.days
# hour = time_difference.total_seconds() / 3600
return minutes_difference
async def diff_sms_send_save(sor=None, productname=None, time_interval=24*60, send_type='用户欠费通知', user_orgid=None, sms_send_dict=None):
sms_should_send = False
send_type = send_type
# 记录到欠费表中
# 首先查询欠费表中时间是否再范围内
db = DBPools()
async with db.sqlorContext('kboss') as sor:
try:
print('引用发送短信...')
customer_phone = (await sor.R('organization', {'id': user_orgid}))[0]['contactor_phone']
# customer_name = (await sor.R('organization', {'id': user_orgid}))[0]['orgname']
sms_exist_li = await sor.R('sms_record', {'mobile': customer_phone, 'send_type': send_type, 'send_status': '1',
'sort': ['send_time desc']})
if sms_exist_li:
# 如果原来发送成功 时间范围大于24小时 再次发送
if sms_exist_li[0]['send_status']:
sms_exist_time = sms_exist_li[0]['send_time']
time_diff = await get_time_diff(sms_exist_time, time.strftime('%Y-%m-%d %H:%M:%S'))
# 如果发送过的短信在一天范围内 不再发送短信
if time_diff >= time_interval:
sms_should_send = True
else:
print('%s %s短信已经发送过, 但是没有超过阈值时间, 不再发送...' % (send_type, customer_phone))
else:
print('%s %s短信没有发送过, 发送...' % (send_type, customer_phone))
sms_should_send = True
if sms_should_send or not sms_exist_li:
# 给个人发送短信
await send_vcode(customer_phone, send_type, sms_send_dict)
except Exception as e:
print('发送短信失败: %s' % e)
return {
'status': False,
'msg': '发送短信失败',
'data': e
}
async def get_baidu_orderlist(ns={}): async def get_baidu_orderlist(ns={}):
""" """
百度支付 百度支付
@ -579,20 +636,21 @@ async def get_baidu_orderlist(ns={}):
else: else:
#取消订单 #取消订单
await sor.rollback() await sor.rollback()
paydata = {'queryAccountId':baidu_users[0]['baidu_id'],'orderIds':[ns.get('order_id')]} # 余额不足不cancle订单
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()]) # paydata = {'queryAccountId':baidu_users[0]['baidu_id'],'orderIds':[ns.get('order_id')]}
url = 'https://billing.baidubce.com/v1/order/cancel?%s' % ns_format # ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
method = 'POST' # url = 'https://billing.baidubce.com/v1/order/cancel?%s' % ns_format
header = { # method = 'POST'
"Host": "billing.baidubce.com" # header = {
} # "Host": "billing.baidubce.com"
header = await get_auth_header(method=method, url=url, header=header) # }
async with aiohttp_client.request( # header = await get_auth_header(method=method, url=url, header=header)
method=method, # async with aiohttp_client.request(
url=url, # method=method,
headers=header, # url=url,
json=paydata) as res: # headers=header,
await res.json() # json=paydata) as res:
# await res.json()
ns_record = { ns_record = {
'orderid': ns.get('order_id'), 'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'], 'ordertype': orders[0]['type'],
@ -600,6 +658,14 @@ async def get_baidu_orderlist(ns={}):
'reason': '该账号余额不足,无法完成购买' 'reason': '该账号余额不足,无法完成购买'
} }
await user_action_record(ns_record) await user_action_record(ns_record)
# 发送短信
sms_send_dict = {
'time': time.strftime('%Y-%m-%d %H:') + '00:00',
'productname': None
}
await diff_sms_send_save(sor=sor, time_interval=24*60, send_type='用户欠费通知', user_orgid=orgid, sms_send_dict=sms_send_dict)
return {'status': False,'msg': '该账号余额不足,无法完成购买'} return {'status': False,'msg': '该账号余额不足,无法完成购买'}
except Exception as e: except Exception as e:
await baidu_order_cancel({'baidu_id': baidu_users[0]['baidu_id'], 'order_id': ns.get('order_id')}) await baidu_order_cancel({'baidu_id': baidu_users[0]['baidu_id'], 'order_id': ns.get('order_id')})
@ -720,11 +786,11 @@ async def baidu_confirm_auto_renew_order(ns={}):
# 读取baidu_orders表格 确定状态是renew的订单ID # 读取baidu_orders表格 确定状态是renew的订单ID
renew_results = [] renew_results = []
return {'1': 2} # return {'1': 2}
db = DBPools() db = DBPools()
async with db.sqlorContext('kboss') as sor: async with db.sqlorContext('kboss') as sor:
renew_sql = """"SELECT bo.*, bs.user_id FROM baidu_orders AS bo LEFT JOIN baidu_users AS bs ON bo.accountid = bs.baidu_id WHERE bo.ordertype = 'RENEW' AND bo.status = 'NEED_CONFIRM' AND bo.del_flg = '0';""" renew_sql = """ SELECT bo.*, bs.user_id FROM baidu_orders AS bo LEFT JOIN baidu_users AS bs ON bo.accountid = bs.baidu_id WHERE bo.ordertype = 'RENEW' AND bo.status = 'NEED_CONFIRM' AND bo.del_flg = '0'; """
return {'1': renew_sql} # return {'1': renew_sql}
renew_results = await sor.sqlExe(renew_sql, {}) renew_results = await sor.sqlExe(renew_sql, {})
renew_status_count = 0 renew_status_count = 0

View File

@ -1,6 +1,7 @@
async def user_action_record(ns={}): async def user_action_record(ns={}):
ns_dic_id = uuid() if not ns.get('id') else ns.get('id')
ns_dic = { ns_dic = {
'id': uuid(), 'id': ns_dic_id,
'source': '百度智能云', 'source': '百度智能云',
'orderid': ns.get('orderid'), 'orderid': ns.get('orderid'),
'ordertype': ns.get('ordertype'), 'ordertype': ns.get('ordertype'),
@ -42,8 +43,8 @@ async def affirmbz_order(ns={}):
servicename = orgid[0]['servicename'] servicename = orgid[0]['servicename']
product_url = None product_url = None
if ('BCC' in servicename) or ('GPU' in servicename): # if ('BCC' in servicename) or ('GPU' in servicename):
product_url = 'https://console.vcp.baidu.com/bcc/#/bcc/instance/list' # product_url = 'https://console.vcp.baidu.com/bcc/#/bcc/instance/list'
date = await get_business_date(sor=None) date = await get_business_date(sor=None)
# await sor.U('bz_order',{'id':ns['orderid'],'order_date': date}) # await sor.U('bz_order',{'id':ns['orderid'],'order_date': date})
@ -68,10 +69,18 @@ async def affirmbz_order(ns={}):
# 处理退订逻辑 # 处理退订逻辑
if order_type == 'REFUND': if order_type == 'REFUND':
# 找到资源并更新时间 # 找到资源并更新时间
resource_find_sql = """select id from customer_goods where resourceid = '%s';""" % j['resourceids'] resource_find_sql = """select id, resourceid, expire_resourceid from customer_goods where FIND_IN_SET('%s', resourceid) and del_flg = '0';""" % j['resourceids']
resource_find_li = await sor.sqlExe(resource_find_sql, {}) resource_find_li = await sor.sqlExe(resource_find_sql, {})
resource_find_id = resource_find_li[0]['id'] resource_find_id = resource_find_li[0]['id']
await sor.U('customer_goods', {'id': resource_find_id, 'del_flg': '1'}) expire_resourceid = resource_find_li[0]['expire_resourceid']
expire_resourceid += expire_resourceid + ',' + j['resourceids'] if expire_resourceid else j['resourceids']
items_refund = resource_find_li[0]['resourceid'].split(',') if resource_find_li[0]['resourceid'] else []
filtered_items = [item for item in items_refund if item != j['resourceids']]
result = ','.join(filtered_items)
if not result:
await sor.U('customer_goods', {'id': resource_find_id, 'del_flg': '1'})
else:
await sor.U('customer_goods', {'id': resource_find_id, 'resourceid': result, 'expire_resourceid': expire_resourceid})
# 处理续费逻辑 # 处理续费逻辑
elif order_type == 'RENEW': elif order_type == 'RENEW':
@ -109,15 +118,14 @@ async def affirmbz_order(ns={}):
return {'status': True, 'msg': '支付成功'} return {'status': True, 'msg': '支付成功'}
except Exception as error: except Exception as error:
await sor.rollback() await sor.rollback()
raise error return {'status': False, 'msg': str(error)}
async def baidu_new_update_resouce(ns={}):
# 增加延迟
import asyncio
await asyncio.sleep(12)
async def get_baidu_orderlist(ns={}):
"""
百度支付
1、获取订单
2、算出购买的产品折扣
3、比对账号余额
"""
db = DBPools() db = DBPools()
async with db.sqlorContext('kboss') as sor: async with db.sqlorContext('kboss') as sor:
baidu_users = await sor.R('baidu_users', {'user_id': ns.get('userid'),'del_flg':'0'}) baidu_users = await sor.R('baidu_users', {'user_id': ns.get('userid'),'del_flg':'0'})
@ -138,15 +146,107 @@ async def get_baidu_orderlist(ns={}):
headers=header, headers=header,
json=nss) as res: json=nss) as res:
data_ = await res.json() data_ = await res.json()
with open('baidu_new_order_after_confirm.txt', 'a+') as f:
f.write(json.dumps(data_) + '\n')
orders = data_['orders']
for item in orders:
order_items = item['orderItems']
for order_info in order_items:
resourceids = ','.join(order_info['shortIds']) if order_info.get('shortIds') else ''
if not resourceids:
continue
resourcestarttime = await time_convert(order_info.get('resourceStartTime')) if order_info.get(
'resourceStartTime') else None
resourceendtime = await time_convert(order_info.get('resourceEndTime')) if order_info.get(
'resourceEndTime') else None
order_key = order_info['key']
update_order_goods_sql = """ UPDATE order_goods og
JOIN bz_order o ON og.orderid = o.id
SET
og.resourceids = '%s',
og.resourcestarttime = '%s',
og.resourceendtime = '%s'
WHERE
og.orderkey = '%s'
AND o.provider_orderid = '%s'; """ \
% (resourceids, resourcestarttime, resourceendtime, order_key, ns.get('order_id'))
await sor.sqlExe(update_order_goods_sql, {})
update_customer_goods_sql = """ UPDATE customer_goods og
JOIN bz_order o ON og.orderid = o.id
SET
og.resourceid = '%s',
og.start_date = '%s',
og.expire_date = '%s'
WHERE
og.orderkey = '%s'
AND o.provider_orderid = '%s'; """ \
% (resourceids, resourcestarttime, resourceendtime, order_key, ns.get('order_id'))
await sor.sqlExe(update_customer_goods_sql, {})
async def baidu_order_cancel(ns={}):
baidu_id = ns['baidu_id']
order_id = ns['order_id']
paydata = {'queryAccountId': baidu_id, 'orderIds': [order_id]}
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://billing.baidubce.com/v1/order/cancel?%s' % ns_format
method = 'POST'
header = {
"Host": "billing.baidubce.com"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=paydata) as res:
await res.json()
return {
'status': True,
'msg': 'order cancel success'
}
async def get_baidu_orderlist(ns={}):
"""
百度支付
1、获取订单
2、算出购买的产品折扣
3、比对账号余额
"""
# 增加延迟
import asyncio
await asyncio.sleep(1)
db = DBPools()
async with db.sqlorContext('kboss') as sor:
baidu_users = await sor.R('baidu_users', {'user_id': ns.get('userid'),'del_flg':'0'})
user = await sor.R('users', {'id': ns.get('userid')})
orgid = await sor.R('organization', {'id': user[0]['orgid']})
nss = {'uuids': [ns.get('order_id')], 'queryAccountId': baidu_users[0]['baidu_id']}
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://billing.baidubce.com/v1/order/getByUuid?%s' % ns_format
method = 'POST'
header = {
"Host": "billing.baidubce.com",
"ContentType": "application/json;charset=UTF-8"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=nss) as res:
data_ = await res.json()
with open('baidu_new_order.txt', 'a+') as f:
f.write(json.dumps(data_) + '\n')
orders = data_['orders'] orders = data_['orders']
serviceType = orders[0]['orderItems'] serviceType = orders[0]['orderItems']
# 可能获取得到的是延迟订单 # 可能获取得到的是延迟订单
if orders[0]['type'] == 'REFUND' and orders[0]['status'] != 'CREATED': # if orders[0]['type'] == 'REFUND' and orders[0]['status'] != 'CREATED':
return { # await update_baidu_order_list({'userid': ns.get('userid')})
'status': False, # res_refund = await baidu_confirm_refund_order({'order_id': ns.get('order_id'), 'baidu_id': baidu_users[0]['baidu_id'], 'user_id': ns.get('userid')})
'msg': 'delay_order' # return res_refund
}
# 避免重复退订 # 避免重复退订
if orders[0]['type'] == 'REFUND' and orders[0]['status'] == 'CREATED': if orders[0]['type'] == 'REFUND' and orders[0]['status'] == 'CREATED':
@ -165,19 +265,52 @@ async def get_baidu_orderlist(ns={}):
(float(orders[0]['price']), orders[0]['status'], updatetime, ns.get('order_id')) (float(orders[0]['price']), orders[0]['status'], updatetime, ns.get('order_id'))
await sor.sqlExe(update_refund_sql, {}) await sor.sqlExe(update_refund_sql, {})
productType = 'prepay'
# 判断订单item中productType是否有后付费的产品 # 判断订单item中productType是否有后付费的产品
for item in orders: for item in orders:
order_items = item['orderItems'] order_items = item['orderItems']
for order_info in order_items: for order_info in order_items:
postpay_price = order_info['itemFee']['price'] if order_info.get('itemFee') else order_info['catalogPrice'] postpay_price = order_info['itemFee']['price'] if order_info.get('itemFee') else order_info['catalogPrice']
if not postpay_price:
# cpt1Price: 固定配置,按分钟计费
postpay_price = order_info['pricingDetail'].get('cpt1Price') if order_info.get('pricingDetail') else 0
# 确定是否是后付费订单
if order_info['productType'] == 'postpay' and postpay_price != 0: if order_info['productType'] == 'postpay' and postpay_price != 0:
return { productType = 'postpay'
'status': False, # 获取余额
'msg': '暂不支持后付费按量购买, 请联系后台开通' user_balance = await getCustomerBalance(sor, orgid[0]['id'])
} # 判断余额是否大于50
if user_balance < 50:
await sor.rollback()
paydata = {'queryAccountId': baidu_users[0]['baidu_id'], 'orderIds': [ns.get('order_id')]}
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://billing.baidubce.com/v1/order/cancel?%s' % ns_format
method = 'POST'
header = {
"Host": "billing.baidubce.com"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=paydata) as res:
await res.json()
ns_record = {
'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'],
'userid': ns.get('userid'),
'reason': '后付费 该账号余额不足50无法完成购买'
}
await user_action_record(ns_record)
return {
'status': False,
'msg': '您的余额小于该产品的起购金额50元, 目前无法购买立即充值'
}
# 实付价格 # 实付价格
total_price = 0 total_price = 0
productType = '' # productType = ''
# 买/续/退 字段映射 # 买/续/退 字段映射
order_type = orders[0]['type'] order_type = orders[0]['type']
@ -210,7 +343,8 @@ async def get_baidu_orderlist(ns={}):
bz_ns['order_date'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") bz_ns['order_date'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
bz_ns['thirdparty_order'] = ns.get('order_id') bz_ns['thirdparty_order'] = ns.get('order_id')
bz_ns['source'] = '百度智能云' bz_ns['source'] = '百度智能云'
bz_ns['originalprice'] = orders[0]['price'] # bz_ns['originalprice'] = orders[0]['price']
bz_ns['originalprice'] = sum(i['catalogPrice'] for i in serviceType)
bz_ns['provider_orderid'] = ns.get('order_id') bz_ns['provider_orderid'] = ns.get('order_id')
bz_ns['ordertype'] = orders[0]['productType'] bz_ns['ordertype'] = orders[0]['productType']
bz_ns['servicename'] = orders[0]['serviceType'] bz_ns['servicename'] = orders[0]['serviceType']
@ -219,23 +353,45 @@ async def get_baidu_orderlist(ns={}):
bz_ns['specdataid'] = ns['specdataid'] bz_ns['specdataid'] = ns['specdataid']
await sor.C('bz_order', bz_ns) await sor.C('bz_order', bz_ns)
for i in serviceType: for i in serviceType:
if i['productType'] == 'prepay': # if i['productType'] == 'prepay':
# 预付费 # # 预付费
productType = 'prepay' # productType = 'prepay'
# financePrice = 0 # financePrice = 0
# 获取产品id # 获取产品id
product = await sor.R('product', {'providerpid': 'baidu_' + i['serviceType'], 'del_flg': '0'}) product = await sor.R('product', {'providerpid': 'baidu_' + i['serviceType'], 'del_flg': '0'})
if not product:
return {
'status': False,
'msg': '未配置该产品, 请联系售后处理'
}
# 获取协议 # 获取协议
saleprotocol = await sor.R('saleprotocol', saleprotocol_to_person = await sor.R('saleprotocol',
{'bid_orgid': orgid[0]['id'], 'offer_orgid': orgid[0]['parentid'], {'bid_orgid': orgid[0]['id'], 'offer_orgid': orgid[0]['parentid'],
'del_flg': '0'}) 'del_flg': '0'})
if saleprotocol == []: # 等于空就代表这个客户没有特殊折扣,就要找到买方为*的协议
# 等于空就代表这个客户没有特殊折扣,就要找到买方为*的协议 saleprotocol_to_all = await sor.R('saleprotocol', {'bid_orgid': '*', 'offer_orgid': orgid[0]['parentid'],
saleprotocol = await sor.R('saleprotocol', {'bid_orgid': '*', 'offer_orgid': orgid[0]['parentid'], 'del_flg': '0', 'salemode': '0'})
'del_flg': '0', 'salemode': '0'})
product_salemode = await sor.R('product_salemode', if saleprotocol_to_person:
{'protocolid': saleprotocol[0]['id'], 'productid': product[0]['id'], product_salemode = await sor.R('product_salemode',
'del_flg': '0'}) {'protocolid': saleprotocol_to_person[0]['id'],
'productid': product[0]['id'],
'del_flg': '0'})
if not product_salemode:
product_salemode = await sor.R('product_salemode',
{'protocolid': saleprotocol_to_all[0]['id'],
'productid': product[0]['id'],
'del_flg': '0'})
else:
product_salemode = await sor.R('product_salemode',
{'protocolid': saleprotocol_to_all[0]['id'],
'productid': product[0]['id'],
'del_flg': '0'})
if not product_salemode:
return {
'status': False,
'msg': '还未上线这个产品的协议配置'
}
supply_price = i['itemFee']['price'] if i.get('itemFee') else i['catalogPrice'] supply_price = i['itemFee']['price'] if i.get('itemFee') else i['catalogPrice']
financePrice = abs(supply_price * product_salemode[0]['discount']) financePrice = abs(supply_price * product_salemode[0]['discount'])
total_price += financePrice total_price += financePrice
@ -261,10 +417,27 @@ async def get_baidu_orderlist(ns={}):
nss['chargeduration'] = i.get('time') nss['chargeduration'] = i.get('time')
nss['unit'] = i.get('timeUnit') nss['unit'] = i.get('timeUnit')
nss['resourceids'] = ','.join(i['shortIds']) if i.get('shortIds') else '' nss['resourceids'] = ','.join(i['shortIds']) if i.get('shortIds') else ''
nss['orderkey'] = i.get('key')
try:
# 保存配置configurations 存入specdata表中
if i.get('configurations'):
specdata = json.dumps(i['configurations'], ensure_ascii=False)
ns_specificdata = {
'id': uuid(),
'productid': product[0]['id'],
'spec_data': specdata,
}
nss['spec_id'] = ns_specificdata['id']
await sor.C('specificdata', ns_specificdata)
except Exception as e:
print('保存配置configurations失败', str(e))
with open('baidu_error.log', 'a') as f:
f.write('保存配置configurations失败' + str(e) + '\n')
# 如果是续费订单 由于没有返回日期, 重新计算日期 # 如果是续费订单 由于没有返回日期, 重新计算日期
if order_type == 'RENEW': if order_type == 'RENEW':
history_time_sql = "select resourcestarttime, resourceendtime from order_goods where resourceids = '%s' order by resourceendtime desc;" % \ history_time_sql = "select resourcestarttime, resourceendtime from order_goods where FIND_IN_SET('%s', resourceids) order by resourceendtime desc;" % \
nss['resourceids'] nss['resourceids']
history_time = await sor.sqlExe(history_time_sql, {}) history_time = await sor.sqlExe(history_time_sql, {})
new_end_time = await cal_expire_time(history_time=history_time[0]['resourceendtime'], new_end_time = await cal_expire_time(history_time=history_time[0]['resourceendtime'],
@ -273,27 +446,45 @@ async def get_baidu_orderlist(ns={}):
nss['resourcestarttime'] = history_time[0]['resourcestarttime'] nss['resourcestarttime'] = history_time[0]['resourcestarttime']
nss['resourceendtime'] = new_end_time nss['resourceendtime'] = new_end_time
else: else:
nss['resourcestarttime'] = await time_convert(i.get('resourceStartTime')) if i.get( if i.get('resourceStartTime'):
'resourceStartTime') else None nss['resourcestarttime'] = await time_convert(i.get('resourceStartTime'))
nss['resourceendtime'] = await time_convert(i.get('resourceEndTime')) if i.get( else:
'resourceEndTime') else None nss['resourcestarttime'] = await time_convert(orders[0]['updateTime'])
if i.get('resourceEndTime'):
nss['resourceendtime'] = await time_convert(i.get('resourceEndTime'))
# 后付费没有资源结束时间
if i.get('productType') == 'prepay':
end_time = await time_convert(orders[0]['updateTime'])
nss['resourceendtime'] = await cal_expire_time(history_time=end_time,
chargeduration=nss['chargeduration'],
unit=nss['unit'])
else:
nss['resourceendtime'] = None
await sor.C('order_goods', nss) await sor.C('order_goods', nss)
# 循环后更新订单中总价 # 循环后更新订单中总价
await sor.U('bz_order', {'id': bz_ns['id'], 'amount': round(total_price, 2)}) await sor.U('bz_order', {'id': bz_ns['id'], 'amount': round(total_price, 2)})
except Exception as e: except Exception as e:
await baidu_order_cancel({'baidu_id': baidu_users[0]['baidu_id'], 'order_id': ns.get('order_id')})
import traceback
ns_record = { ns_record = {
'orderid': ns.get('order_id'), 'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'], 'ordertype': orders[0]['type'],
'userid': ns.get('userid'), 'userid': ns.get('userid'),
'reason': '发生错误, %s' % str(e)[:100] 'reason': '发生错误, %s' % str(traceback.format_exc())
} }
await user_action_record(ns_record) await user_action_record(ns_record)
import traceback
with open('baiducloud_err.txt', 'w') as f: with open('baiducloud_err.txt', 'w') as f:
f.write(str(e)+ traceback.format_exc()) f.write(str(e) + str(traceback.format_exc()))
traceback.print_exc() traceback.print_exc()
await sor.rollback()
return {
'status': False,
'msg': '产品错误, 请联系售后'
}
# 判断用户账户余额是否足够支付 # 判断用户账户余额是否足够支付
try: try:
@ -303,7 +494,7 @@ async def get_baidu_orderlist(ns={}):
if round(total_price,2) <= count: if round(total_price,2) <= count:
#判断预付费或者后付费 #判断预付费或者后付费
if productType == 'prepay': if productType == 'prepay' or productType == 'postpay':
# 调用扣费接口 # 调用扣费接口
affirmbz_order_ns = { affirmbz_order_ns = {
'sor': sor, 'sor': sor,
@ -318,7 +509,7 @@ async def get_baidu_orderlist(ns={}):
'orderid': ns.get('order_id'), 'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'], 'ordertype': orders[0]['type'],
'userid': ns.get('userid'), 'userid': ns.get('userid'),
'reason': '支付错误, 请联系售后' 'reason': '支付错误, 请联系售后, %s' % affirmbz_order_res.get('msg')
} }
await user_action_record(ns_record) await user_action_record(ns_record)
return { return {
@ -334,22 +525,21 @@ async def get_baidu_orderlist(ns={}):
} }
else: else:
# 调用支付订单接口 # 调用支付订单接口
# paydata = {'queryAccountId':baidu_users[0]['baidu_id'],'orderId':ns.get('order_id')} paydata = {'queryAccountId':baidu_users[0]['baidu_id'],'orderId':ns.get('order_id')}
# ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()]) ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
# url = 'https://billing.baidubce.com/v1/order/pay?%s' % ns_format url = 'https://billing.baidubce.com/v1/order/pay?%s' % ns_format
# method = 'POST' method = 'POST'
# header = { header = {
# "Host": "billing.baidubce.com" "Host": "billing.baidubce.com"
# } }
# header = await get_auth_header(method=method, url=url, header=header) header = await get_auth_header(method=method, url=url, header=header)
# async with aiohttp_client.request( async with aiohttp_client.request(
# method=method, method=method,
# url=url, url=url,
# headers=header, headers=header,
# json=paydata) as res: json=paydata) as res:
# data_ = await res.json() data_ = await res.json()
# if data_ == {'success': True}: if data_ == {'success': True}:
if True:
ns_record = { ns_record = {
'orderid': ns.get('order_id'), 'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'], 'ordertype': orders[0]['type'],
@ -357,12 +547,23 @@ async def get_baidu_orderlist(ns={}):
'reason': '购买成功' 'reason': '购买成功'
} }
await user_action_record(ns_record) await user_action_record(ns_record)
return { ns_cron_job = {
'status': True, 'id': uuid(),
'orderid': bz_ns['id'] 'source': 'baidu',
'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'],
'userid': ns.get('userid'),
'reason': 'buy success'
} }
await sor.C('baidu_cron_job', ns_cron_job)
# return {
# 'status': True,
# 'orderid': bz_ns['id']
# }
else: else:
await sor.rollback() await sor.rollback()
await baidu_order_cancel(
{'baidu_id': baidu_users[0]['baidu_id'], 'order_id': ns.get('order_id')})
ns_record = { ns_record = {
'orderid': ns.get('order_id'), 'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'], 'ordertype': orders[0]['type'],
@ -425,92 +626,240 @@ async def get_baidu_orderlist(ns={}):
await user_action_record(ns_record) await user_action_record(ns_record)
return {'status': False,'msg': '该账号余额不足,无法完成购买'} return {'status': False,'msg': '该账号余额不足,无法完成购买'}
except Exception as e: except Exception as e:
await baidu_order_cancel({'baidu_id': baidu_users[0]['baidu_id'], 'order_id': ns.get('order_id')})
import traceback import traceback
with open('baiducloud_err.txt', 'w') as f: with open('baiducloud_err.txt', 'w') as f:
f.write(str(e)+ traceback.format_exc()) f.write(str(e)+ traceback.format_exc())
traceback.print_exc() traceback.print_exc()
await sor.rollback()
return {
'status': False,
'msg': '产品错误, 请联系售后'
}
# 更新资源时间 资源id
# if order_type == 'NEW':
# await baidu_new_update_resouce(ns)
return {
'status': True,
'orderid': bz_ns.get('id'),
'originalprice': bz_ns.get('originalprice'),
'servicename': bz_ns.get('servicename'),
'amount': total_price
}
async def baidu_confirm_refund_order(ns={}): async def get_order_list_base_page(baidu_id, pageNo=1, pageSize=500):
ns = {'queryAccountId': baidu_id, 'pageNo': pageNo, 'pageSize': pageSize}
method = 'POST'
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://billing.baidubce.com/v1/order/list?%s' % ns_format
header = {
"Host": "billing.baidubce.com",
"ContentType": "application/json;charset=UTF-8"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=ns) as res:
data_orders = await res.json()
return data_orders
async def update_baidu_order_list(ns={}):
"""
ns = {'queryAccountId': '139fc7a23b314596ad78b6bb8e7c1503', 'orderType': 'REFUND'}
:return:
"""
db = DBPools() db = DBPools()
async with db.sqlorContext('kboss') as sor: async with db.sqlorContext('kboss') as sor:
refund_status_li = await sor.R('baidu_orders', {'orderid': ns.get('order_id')}) username = None
refundstatus = refund_status_li[0]['refundstatus'] # 更新机构下全部用户订单信息
refund_id = refund_status_li[0]['id'] if ns.get('orgid'):
users_find_sql = """SELECT DISTINCT b.baidu_id FROM organization o INNER JOIN users u ON o.id = u.orgid INNER JOIN baidu_users b ON u.id = b.user_id WHERE o.parentid = '%s' AND b.del_flg = '0';""" % ns.get('orgid')
users = await sor.sqlExe(users_find_sql, {})
if not refundstatus: # 更新个人订单信息
# data_ = {} elif ns.get('userid'):
# 调用支付订单接口 users = await sor.R('baidu_users', {'user_id': ns['userid']})
paydata = {'queryAccountId': ns.get('baidu_id'), 'orderId':ns.get('order_id')} username_li = await sor.R('users', {'id': ns['userid']})
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()]) username = username_li[0]['username'] if username_li else None
url = 'https://billing.baidubce.com/v1/order/pay?%s' % ns_format
method = 'POST'
header = {
"Host": "billing.baidubce.com"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=paydata) as res:
data_ = await res.json()
if data_ == {'success': True}:
# if True:
ns_record = {
'orderid': ns.get('order_id'),
'ordertype': 'REFUND',
'userid': ns.get('userid'),
'reason': '远程退款成功'
}
await user_action_record(ns_record)
db = DBPools()
async with db.sqlorContext('kboss') as sor:
await sor.U('baidu_orders', {'id': refund_id, 'refundstatus': '1'})
# 增加延迟
import asyncio
await asyncio.sleep(10)
else: else:
ns_record = { users = []
'orderid': ns.get('order_id'),
'ordertype': 'REFUND', update_count = 0
'userid': ns.get('userid'), add_count = 0
'reason': '产品退费失败, %s' % str(data_)[:400] for baidu_id in users:
} data_orders = await get_order_list_base_page(baidu_id['baidu_id'], pageNo=1, pageSize=1000)
await user_action_record(ns_record) page_num_count = int(data_orders['totalCount'] / data_orders['pageSize']) + 1
return { for page_num in range(1, page_num_count + 1):
'status': False, data_orders = await get_order_list_base_page(baidu_id['baidu_id'], pageNo=page_num, pageSize=1000)
'msg': '产品退款出错!%s' % str(data_)[:400] orders = data_orders['orders']
} for item in orders:
updatetime = await time_convert(item.get('updateTime')) if item.get('updateTime') else None
ns_dic = {
"id": uuid(),
"orderid": item.get("uuid"),
"ordertype": item.get("type"),
"accountid": item.get("accountId"),
"servicetype": item.get("serviceType"),
"producttype": item.get("productType"),
"shortids": ','.join(item['shortIds']) if item.get('shortIds') else '',
"price": item.get("price"),
"status": item.get("status"),
"autoreneworder": '1' if item.get("autoRenewOrder") else '0',
"createtime": await time_convert(item.get('createTime')) if item.get(
'createTime') else None,
"updatetime": updatetime
}
ns_exist_order = {
'orderid': item.get("uuid")
}
exist_order = await sor.R('baidu_orders', ns_exist_order)
if exist_order and exist_order[0]['updatetime'] != updatetime:
update_refund_sql = """UPDATE baidu_orders SET price = '%s', status = '%s', updatetime = '%s' WHERE orderid = '%s';""" % \
(item.get("price"), item.get("status"), updatetime,
item.get("uuid"))
await sor.sqlExe(update_refund_sql, {})
update_count += 1
if not exist_order:
await sor.C('baidu_orders', ns_dic)
add_count += 1
if refundstatus == '2':
return { return {
'status': True, 'status': True,
'msg': '已退款成功' 'msg': '同步数据成功, 新增 %s 条, 更新 %s 条' % (add_count, update_count),
'data': {
'username': username
}
} }
# 获取created状态后再去退款 async def baidu_confirm_refund_order(ns={}):
local_refund_status = await get_baidu_orderlist({'order_id': ns.get('order_id'), 'userid': ns.get('user_id')}) # ns = {
print('local_refund_status', local_refund_status) # 'order_id': ["13f3518648054796abf7f3d00ed611bf"],
if local_refund_status.get('status'): # 'userid': 'KsKhCUPizQyGiw3L1WVRy'
# }
import asyncio
# 把 NEED_CONFIRM的订单同步到本地库用于后续状态更新
await update_baidu_order_list({'userid': ns.get('userid')})
db = DBPools()
async with db.sqlorContext('kboss') as sor:
users = await sor.R('baidu_users', {'user_id': ns['userid']})
ns['baidu_id'] = users[0]['baidu_id'] if users else None
if not ns['baidu_id']:
return {
'status': False,
'msg': '用户 %s 未绑定百度智能云账号' % ns.get('userid')
}
orders = json.loads(ns.get('order_id')) if isinstance(ns.get('order_id'), str) else ns.get('order_id')
for order_id in orders:
db = DBPools() db = DBPools()
async with db.sqlorContext('kboss') as sor: async with db.sqlorContext('kboss') as sor:
await sor.U('baidu_orders', {'id': refund_id, 'refundstatus': '2'}) refund_status_li = await sor.R('baidu_orders', {'orderid': order_id})
refundstatus = refund_status_li[0]['refundstatus']
refund_id = refund_status_li[0]['id']
return { ns_record_li = await sor.R('user_action', {'orderid': order_id})
'status': True, ns_record_id = ns_record_li[0]['id'] if ns_record_li else None
'msg': '百度云给平台退款成功,平台给客户退款成功' ns_record = {'id': ns_record_id} if ns_record_id else None
}
else: if not refundstatus:
if local_refund_status.get('msg') == 'delay_order': # data_ = {}
# 调用支付订单接口
paydata = {'queryAccountId': ns.get('baidu_id'), 'orderId': order_id}
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://billing.baidubce.com/v1/order/pay?%s' % ns_format
method = 'POST'
header = {
"Host": "billing.baidubce.com"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=paydata) as res:
data_ = await res.json()
if data_ == {'success': True}:
# if True:
ns_record = {
'id': uuid(),
'orderid': order_id,
'ordertype': 'REFUND',
'userid': ns.get('userid'),
'reason': '远程退款成功'
}
await user_action_record(ns_record)
db = DBPools()
async with db.sqlorContext('kboss') as sor:
await sor.U('baidu_orders', {'id': refund_id, 'refundstatus': '1'})
# 增加延迟
await asyncio.sleep(4)
# 延迟2-3秒还是获取到 ready状态的订单那就重复请求一次目的是尽快刷新状态
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=paydata) as res:
await res.json()
# 把 NEED_CONFIRM的本地库改为CREATED
await update_baidu_order_list({'userid': ns.get('userid')})
else:
ns_record = {
'orderid': order_id,
'ordertype': 'REFUND',
'userid': ns.get('userid'),
'reason': '产品退费失败, %s' % str(data_)[:400]
}
await user_action_record(ns_record)
return {
'status': False,
'msg': '产品退款出错!%s' % str(data_)[:400]
}
if refundstatus == '2':
"""
退款状态为2, 说明退款成功, 无需继续处理
"""
continue
# 获取created状态后再去退款
local_refund_status = await get_baidu_orderlist({'order_id': order_id, 'userid': ns.get('userid')})
print('local_refund_status', local_refund_status)
if local_refund_status.get('status'):
db = DBPools()
async with db.sqlorContext('kboss') as sor:
baidu_orders_status_update = """update baidu_orders set refundstatus='2' where id='%s';""" % refund_id
await sor.sqlExe(baidu_orders_status_update, {})
await sor.U('user_action', {'id': ns_record.get('id'), 'ordertype': 'REFUND', 'reason': '远程退款成功, 本地客户退款成功'})
continue
# return {
# 'status': True,
# 'msg': '百度云给平台退款成功,平台给客户退款成功'
# }
else:
if local_refund_status.get('msg') == 'delay_order':
return {
'status': False,
'msg': '百度远程订单还未生成, 请十秒后重试, %s' % str(local_refund_status)
}
return { return {
'status': False, 'status': False,
'msg': '百度远程订单还未生成, 请十秒后重试' 'msg': '百度云退款成功,本机构给客户退款出错!, %s' % str(local_refund_status)
} }
return {
'status': False, return {
'msg': '百度云退款成功,本机构给客户退款出错!' 'status': True,
} 'msg': '退款处理完成'
}
ret = await baidu_confirm_refund_order(params_kw) ret = await baidu_confirm_refund_order(params_kw)
return ret return ret

View File

@ -0,0 +1,29 @@
async def baidu_order_cancel(ns={}):
baidu_id = ns['baidu_id']
order_id = ns['order_id']
paydata = {'queryAccountId': baidu_id, 'orderIds': [order_id]}
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://billing.baidubce.com/v1/order/cancel?%s' % ns_format
method = 'POST'
header = {
"Host": "billing.baidubce.com"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=paydata) as res:
res = await res.json()
db = DBPools()
async with db.sqlorContext('kboss') as sor:
if res.get('success'):
sql_update = "update baidu_orders set status='CANCELLED' where order_id='%s'" % order_id
await sor.sqlExe(sql_update, {})
return {
'status': True,
'msg': 'order cancel success, %s' % str(res)
}
ret = await baidu_order_cancel(params_kw)
return ret

View File

@ -1,7 +1,68 @@
async def create_baiduuser(ns):
"""
ns = {
"name": "用户名",
"email": "邮箱",
"mobilePhone": "手机号",
"accountType": "0"为个人|“1”为企业
}
:param ns:
:return:
"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
user = await sor.R('users',{'id':ns.get('userid')})
data = {'name':user[0]['username'],'mobilePhone':user[0]['mobile'],'accountType':'0'}
method = "POST"
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://iam.bj.baidubce.com/v1/vs/account?%s' % ns_format
header = {
"Host": "iam.bj.baidubce.com",
"Content-Type": "application/json"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=data) as res:
data_ = await res.json()
if not data_.get('userId'):
return {
'status': False,
'msg': '创建用户失败',
'data': data_
}
else:
#用户创建成功
userdata = {
'id' : uuid(),
# 'id' : UUID(),
'user_id' : ns.get('userid'),
'baidu_id' : data_.get('userId'),
'baidu_username' : data_.get('name'),
}
await sor.C('baidu_users',userdata)
return {
'status': True,
'msg': '创建用户成功',
'data': data_
}
async def get_baiduQualifyInfo(ns): async def get_baiduQualifyInfo(ns):
""" """
获取百度实名认证接口 获取百度实名认证接口
""" """
db_baidu = DBPools()
async with db_baidu.sqlorContext('kboss') as sor:
user = await sor.R('baidu_users', {'user_id': ns.get('user_id'), 'del_flg': '0'})
if not user:
res = await create_baiduuser({'userid': ns.get('user_id')})
if not res.get('status'):
return res
db = DBPools() db = DBPools()
async with db.sqlorContext('kboss') as sor: async with db.sqlorContext('kboss') as sor:
user = await sor.R('baidu_users',{'user_id':ns.get('user_id')}) user = await sor.R('baidu_users',{'user_id':ns.get('user_id')})
@ -23,11 +84,11 @@ async def get_baiduQualifyInfo(ns):
json=ns) as res: json=ns) as res:
data_ = await res.json() data_ = await res.json()
if data_['qualifyType'] != None and data_['status'] == 'PASS': if data_['qualifyType'] != None and data_['status'] == 'PASS':
return {'status': True, 'msg': '实名认证通过'} return {'status': True, 'msg': '实名认证通过', 'data': data_}
else: else:
return {'status': False, 'msg': '实名认证未通过'} return {'status': False, 'msg': '实名认证未通过', 'data': data_}
else: else:
return {'status': False, 'msg': '百度用户创建失败'} return {'status': False, 'msg': 'user not exist, please create baidu user first'}
ret = await get_baiduQualifyInfo(params_kw) ret = await get_baiduQualifyInfo(params_kw)
return ret return ret

View File

@ -1,6 +1,7 @@
async def user_action_record(ns={}): async def user_action_record(ns={}):
ns_dic_id = uuid() if not ns.get('id') else ns.get('id')
ns_dic = { ns_dic = {
'id': uuid(), 'id': ns_dic_id,
'source': '百度智能云', 'source': '百度智能云',
'orderid': ns.get('orderid'), 'orderid': ns.get('orderid'),
'ordertype': ns.get('ordertype'), 'ordertype': ns.get('ordertype'),
@ -198,6 +199,178 @@ async def baidu_order_cancel(ns={}):
'msg': 'order cancel success' 'msg': 'order cancel success'
} }
async def baidu_confirm_refund_order(ns={}):
db = DBPools()
async with db.sqlorContext('kboss') as sor:
refund_status_li = await sor.R('baidu_orders', {'orderid': ns.get('order_id')})
refundstatus = refund_status_li[0]['refundstatus']
refund_id = refund_status_li[0]['id']
if not refundstatus:
# data_ = {}
# 调用支付订单接口
paydata = {'queryAccountId': ns.get('baidu_id'), 'orderId':ns.get('order_id')}
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://billing.baidubce.com/v1/order/pay?%s' % ns_format
method = 'POST'
header = {
"Host": "billing.baidubce.com"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=paydata) as res:
data_ = await res.json()
if data_ == {'success': True}:
# if True:
ns_record = {
'id': uuid(),
'orderid': order_id,
'ordertype': 'REFUND',
'userid': ns.get('userid'),
'reason': '远程退款成功'
}
await user_action_record(ns_record)
db = DBPools()
async with db.sqlorContext('kboss') as sor:
await sor.U('baidu_orders', {'id': refund_id, 'refundstatus': '1'})
# 增加延迟
import asyncio
await asyncio.sleep(1)
else:
ns_record = {
'orderid': ns.get('order_id'),
'ordertype': 'REFUND',
'userid': ns.get('userid'),
'reason': '产品退费失败, %s' % str(data_)[:400]
}
await user_action_record(ns_record)
return {
'status': False,
'msg': '产品退款出错!%s' % str(data_)[:400]
}
if refundstatus == '2':
return {
'status': True,
'msg': '已退款成功'
}
# 获取created状态后再去退款
local_refund_status = await get_baidu_orderlist({'order_id': ns.get('order_id'), 'userid': ns.get('user_id')})
print('local_refund_status', local_refund_status)
if local_refund_status.get('status'):
db = DBPools()
async with db.sqlorContext('kboss') as sor:
await sor.U('baidu_orders', {'id': refund_id, 'refundstatus': '2'})
await sor.U('user_action', {'id': ns_record.get('id'), 'ordertype': 'REFUND', 'reason': '远程退款成功, 本地客户退款成功'})
return {
'status': True,
'msg': '百度云给平台退款成功,平台给客户退款成功'
}
else:
if local_refund_status.get('msg') == 'delay_order':
return {
'status': False,
'msg': '百度远程订单还未生成, 请十秒后重试'
}
return {
'status': False,
'msg': '百度云退款成功,本机构给客户退款出错!, %s' % str(local_refund_status)
}
async def get_order_list_base_page(baidu_id, pageNo=1, pageSize=500):
ns = {'queryAccountId': baidu_id, 'pageNo': pageNo, 'pageSize': pageSize}
method = 'POST'
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://billing.baidubce.com/v1/order/list?%s' % ns_format
header = {
"Host": "billing.baidubce.com",
"ContentType": "application/json;charset=UTF-8"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=ns) as res:
data_orders = await res.json()
return data_orders
async def update_baidu_order_list(ns={}):
"""
ns = {'queryAccountId': '139fc7a23b314596ad78b6bb8e7c1503', 'orderType': 'REFUND'}
:return:
"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
username = None
# 更新机构下全部用户订单信息
if ns.get('orgid'):
users_find_sql = """SELECT DISTINCT b.baidu_id FROM organization o INNER JOIN users u ON o.id = u.orgid INNER JOIN baidu_users b ON u.id = b.user_id WHERE o.parentid = '%s' AND b.del_flg = '0';""" % ns.get('orgid')
users = await sor.sqlExe(users_find_sql, {})
# 更新个人订单信息
elif ns.get('userid'):
users = await sor.R('baidu_users', {'user_id': ns['userid']})
username_li = await sor.R('users', {'id': ns['userid']})
username = username_li[0]['username'] if username_li else None
else:
users = []
update_count = 0
add_count = 0
for baidu_id in users:
data_orders = await get_order_list_base_page(baidu_id['baidu_id'], pageNo=1, pageSize=1000)
page_num_count = int(data_orders['totalCount'] / data_orders['pageSize']) + 1
for page_num in range(1, page_num_count + 1):
data_orders = await get_order_list_base_page(baidu_id['baidu_id'], pageNo=page_num, pageSize=1000)
orders = data_orders['orders']
for item in orders:
updatetime = await time_convert(item.get('updateTime')) if item.get('updateTime') else None
ns_dic = {
"id": uuid(),
"orderid": item.get("uuid"),
"ordertype": item.get("type"),
"accountid": item.get("accountId"),
"servicetype": item.get("serviceType"),
"producttype": item.get("productType"),
"shortids": ','.join(item['shortIds']) if item.get('shortIds') else '',
"price": item.get("price"),
"status": item.get("status"),
"autoreneworder": '1' if item.get("autoRenewOrder") else '0',
"createtime": await time_convert(item.get('createTime')) if item.get(
'createTime') else None,
"updatetime": updatetime
}
ns_exist_order = {
'orderid': item.get("uuid")
}
exist_order = await sor.R('baidu_orders', ns_exist_order)
if exist_order and exist_order[0]['updatetime'] != updatetime:
update_refund_sql = """UPDATE baidu_orders SET price = '%s', status = '%s', updatetime = '%s' WHERE orderid = '%s';""" % \
(item.get("price"), item.get("status"), updatetime,
item.get("uuid"))
await sor.sqlExe(update_refund_sql, {})
update_count += 1
if not exist_order:
await sor.C('baidu_orders', ns_dic)
add_count += 1
return {
'status': True,
'msg': '同步数据成功, 新增 %s 条, 更新 %s 条' % (add_count, update_count),
'data': {
'username': username
}
}
async def get_baidu_orderlist(ns={}): async def get_baidu_orderlist(ns={}):
""" """
百度支付 百度支付
@ -207,7 +380,7 @@ async def get_baidu_orderlist(ns={}):
""" """
# 增加延迟 # 增加延迟
import asyncio import asyncio
await asyncio.sleep(2) await asyncio.sleep(1)
db = DBPools() db = DBPools()
async with db.sqlorContext('kboss') as sor: async with db.sqlorContext('kboss') as sor:
baidu_users = await sor.R('baidu_users', {'user_id': ns.get('userid'),'del_flg':'0'}) baidu_users = await sor.R('baidu_users', {'user_id': ns.get('userid'),'del_flg':'0'})
@ -235,10 +408,9 @@ async def get_baidu_orderlist(ns={}):
# 可能获取得到的是延迟订单 # 可能获取得到的是延迟订单
if orders[0]['type'] == 'REFUND' and orders[0]['status'] != 'CREATED': if orders[0]['type'] == 'REFUND' and orders[0]['status'] != 'CREATED':
return { await update_baidu_order_list({'userid': ns.get('userid')})
'status': False, res_refund = await baidu_confirm_refund_order({'order_id': ns.get('order_id'), 'baidu_id': baidu_users[0]['baidu_id'], 'user_id': ns.get('userid')})
'msg': 'delay_order' return res_refund
}
# 避免重复退订 # 避免重复退订
if orders[0]['type'] == 'REFUND' and orders[0]['status'] == 'CREATED': if orders[0]['type'] == 'REFUND' and orders[0]['status'] == 'CREATED':
@ -273,7 +445,7 @@ async def get_baidu_orderlist(ns={}):
# 获取余额 # 获取余额
user_balance = await getCustomerBalance(sor, orgid[0]['id']) user_balance = await getCustomerBalance(sor, orgid[0]['id'])
# 判断余额是否大于50 # 判断余额是否大于50
if user_balance < 50: if user_balance < 5000000:
await sor.rollback() await sor.rollback()
paydata = {'queryAccountId': baidu_users[0]['baidu_id'], 'orderIds': [ns.get('order_id')]} paydata = {'queryAccountId': baidu_users[0]['baidu_id'], 'orderIds': [ns.get('order_id')]}
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()]) ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
@ -293,12 +465,14 @@ async def get_baidu_orderlist(ns={}):
'orderid': ns.get('order_id'), 'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'], 'ordertype': orders[0]['type'],
'userid': ns.get('userid'), 'userid': ns.get('userid'),
'reason': '后付费 该账号余额不足50无法完成购买' # 'reason': '后付费 该账号余额不足50无法完成购买'
'reason': '后付费 功能暂未开放,请您联系售后人员协助购买'
} }
await user_action_record(ns_record) await user_action_record(ns_record)
return { return {
'status': False, 'status': False,
'msg': '您的余额小于该产品的起购金额50元, 目前无法购买立即充值' 'msg': '后付费 功能暂未开放,请您联系售后人员协助购买'
# 'msg': '您的余额小于该产品的起购金额50元, 目前无法购买立即充值'
} }
# 实付价格 # 实付价格
total_price = 0 total_price = 0
@ -411,6 +585,22 @@ async def get_baidu_orderlist(ns={}):
nss['resourceids'] = ','.join(i['shortIds']) if i.get('shortIds') else '' nss['resourceids'] = ','.join(i['shortIds']) if i.get('shortIds') else ''
nss['orderkey'] = i.get('key') nss['orderkey'] = i.get('key')
try:
# 保存配置configurations 存入specdata表中
if i.get('configurations'):
specdata = json.dumps(i['configurations'], ensure_ascii=False)
ns_specificdata = {
'id': uuid(),
'productid': product[0]['id'],
'spec_data': specdata,
}
nss['spec_id'] = ns_specificdata['id']
await sor.C('specificdata', ns_specificdata)
except Exception as e:
print('保存配置configurations失败', str(e))
with open('baidu_error.log', 'a') as f:
f.write('保存配置configurations失败' + str(e) + '\n')
# 如果是续费订单 由于没有返回日期, 重新计算日期 # 如果是续费订单 由于没有返回日期, 重新计算日期
if order_type == 'RENEW': if order_type == 'RENEW':
history_time_sql = "select resourcestarttime, resourceendtime from order_goods where FIND_IN_SET('%s', resourceids) order by resourceendtime desc;" % \ history_time_sql = "select resourcestarttime, resourceendtime from order_goods where FIND_IN_SET('%s', resourceids) order by resourceendtime desc;" % \
@ -445,16 +635,16 @@ async def get_baidu_orderlist(ns={}):
await sor.U('bz_order', {'id': bz_ns['id'], 'amount': round(total_price, 2)}) await sor.U('bz_order', {'id': bz_ns['id'], 'amount': round(total_price, 2)})
except Exception as e: except Exception as e:
await baidu_order_cancel({'baidu_id': baidu_users[0]['baidu_id'], 'order_id': ns.get('order_id')}) await baidu_order_cancel({'baidu_id': baidu_users[0]['baidu_id'], 'order_id': ns.get('order_id')})
import traceback
ns_record = { ns_record = {
'orderid': ns.get('order_id'), 'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'], 'ordertype': orders[0]['type'],
'userid': ns.get('userid'), 'userid': ns.get('userid'),
'reason': '发生错误, %s' % str(e)[:100] 'reason': '发生错误, %s' % str(traceback.format_exc())
} }
await user_action_record(ns_record) await user_action_record(ns_record)
import traceback
with open('baiducloud_err.txt', 'w') as f: with open('baiducloud_err.txt', 'w') as f:
f.write(str(e)+ traceback.format_exc()) f.write(str(e) + str(traceback.format_exc()))
traceback.print_exc() traceback.print_exc()
await sor.rollback() await sor.rollback()
return { return {

View File

@ -0,0 +1,54 @@
async def cumulative_order(ns={}):
"""查询订单商品详情,带分页功能"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
try:
users_id = await get_user()
if not users_id:
server_error(401)
user = await sor.R('users', {'id': users_id, 'del_flg': '0'})
orgid = await sor.R('organization', {'id': user[0]['orgid'], 'del_flg': '0'})
customerid = orgid[0]['id']
# 统计全部 累计支付金额和累计优惠金额 不包含各种筛选条件
# 累计支付金额=BUY+RENEW-BUY_REVERSE并且对应order_status=1是实际支付金额 累计优惠金额=BUY+RENEW-BUY_REVERSE并且对应order_status=1是优惠金额
total_amount_sql = """
SELECT
COALESCE(SUM(
CASE
WHEN bo.order_status = 1 AND bo.business_op IN ('BUY', 'RENEW') THEN og.amount
WHEN bo.order_status = 1 AND bo.business_op = 'BUY_REVERSE' THEN -og.amount
ELSE 0
END
), 0) AS total_paid_amount,
COALESCE(SUM(
CASE
WHEN bo.order_status = 1 AND bo.business_op IN ('BUY', 'RENEW') THEN (og.list_price * og.quantity - og.amount)
WHEN bo.order_status = 1 AND bo.business_op = 'BUY_REVERSE' THEN -(og.list_price * og.quantity - og.amount)
ELSE 0
END
), 0) AS total_discount_amount
FROM order_goods og
JOIN bz_order bo ON og.orderid = bo.id
WHERE og.del_flg = '0'
AND bo.del_flg = '0'
AND bo.customerid = ${customerid}$
"""
total_amount_result = await sor.sqlExe(total_amount_sql, {'customerid': customerid})
total_paid_amount = float(total_amount_result[0]['total_paid_amount']) if total_amount_result else 0.0
total_discount_amount = float(total_amount_result[0]['total_discount_amount']) if total_amount_result else 0.0
# 将累计支付金额和累计优惠金额添加到返回结果中
ns['total_paid_amount'] = total_paid_amount
ns['total_discount_amount'] = total_discount_amount
return {
'status': True,
'data': ns
}
except Exception as e:
import traceback
traceback.print_exc()
return {'status': False, 'msg': '信息错误: %s' % str(e) + traceback.format_exc()}
ret = await cumulative_order(params_kw)
return ret

View File

@ -1,110 +1,198 @@
async def getbz_order(ns={}): async def getbz_order(ns={}):
"""查询订单详情/我的所有订单""" """查询订单商品详情,带分页功能"""
db = DBPools() db = DBPools()
async with db.sqlorContext('kboss') as sor: async with db.sqlorContext('kboss') as sor:
try: try:
users_id = await get_user() users_id = await get_user()
ns['del_flg'] = '0' if not users_id:
ns['sort'] = 'create_at desc' server_error(401)
if ns.get('id') and not ns.get('type'):
# 查询订单详情
reacs = await sor.R('bz_order', ns)
# 兼容第三范式产品展示 这段代码可注释 # 分页参数
if reacs and reacs[0].get('specdataid'): page = int(ns.get('page', 1))
specdata = await sor.R('specificdata', {'id': reacs[0].get('specdataid'), 'del_flg': '0'}) size = int(ns.get('size', 10))
if specdata: offset = (page - 1) * size
specdata_dumps = json.dumps(specdata[0]) if isinstance(specdata[0], dict) else specdata[0]
if 'internalip' in specdata_dumps and 'externalip' in specdata_dumps:
reacs[0]['spec_data'] = json.loads(json.loads(specdata_dumps)['spec_data'])
reacsgoods = await sor.R('order_goods', {'orderid': ns['id'], 'del_flg': '0'}) user = await sor.R('users', {'id': users_id, 'del_flg': '0'})
for i in reacsgoods: orgid = await sor.R('organization', {'id': user[0]['orgid'], 'del_flg': '0'})
if i['discount'] == None or i['discount'] == 1.0: customerid = orgid[0]['id']
del i['discount']
i['discount'] = i['discount'] * 10 if i.get('discount') else None
goods = await sor.R('product', {'id': i['productid'], 'del_flg': '0'})
if len(goods) >= 1:
i['productid'] = goods[0]['name']
i['ptype'] = goods[0]['ptype']
reacs[0]['order_goods'] = reacsgoods
return {'status': True, 'data': reacs}
elif ns.get('type') == '200':
#筛选支付类型
user = await sor.R('users', {'id': users_id, 'del_flg': '0'})
orgid = await sor.R('organization', {'id': user[0]['orgid'], 'del_flg': '0'})
ns['customerid'] = orgid[0]['id']
if ns.get('id'):
#根据订单号搜索
reacs = await sor.R('bz_order', {'id': ns['id']})
elif ns.get('start_time'):
sql = """select * from bz_order where del_flg = 0 AND customerid = ${customerid}$ AND order_date >= ${start_time}$ AND order_date <= ${end_time}$ ORDER BY order_date DESC """
start_time = ns.get('start_time') + ' 00:00:00'
end_time = ns.get('end_time') + ' 23:59:59'
reacs = await sor.sqlExe(sql, {'start_time': start_time,'end_time': end_time,'customerid' :ns['customerid']})
params = {'customerid': customerid, 'del_flg': '0'}
# 构建查询SQL主要查询order_goods并关联bz_order的部分字段
sql = """
SELECT
og.*,
bo.customerid,
bo.order_date,
bo.source,
bo.order_status,
bo.business_op,
bo.ordertype,
bo.originalprice,
bo.autoreneworder
FROM order_goods og
JOIN bz_order bo ON og.orderid = bo.id
WHERE og.del_flg = '0'
AND bo.del_flg = '0'
AND bo.customerid = ${customerid}$
"""
# 构建计数SQL
count_sql = """
SELECT COUNT(*) as total_count
FROM order_goods og
JOIN bz_order bo ON og.orderid = bo.id
WHERE og.del_flg = '0'
AND bo.del_flg = '0'
AND bo.customerid = ${customerid}$
"""
# # 统计全部 累计支付金额和累计优惠金额 不包含各种筛选条件
# # 累计支付金额=BUY+RENEW-BUY_REVERSE实际支付金额 累计优惠金额=BUY+RENEW-BUY_REVERSE优惠金额
# total_amount_sql = """
# SELECT
# COALESCE(SUM(
# CASE
# WHEN bo.business_op IN ('BUY', 'RENEW') THEN og.amount
# WHEN bo.business_op = 'BUY_REVERSE' THEN -og.amount
# ELSE 0
# END
# ), 0) AS total_paid_amount,
# COALESCE(SUM(
# CASE
# WHEN bo.business_op IN ('BUY', 'RENEW') THEN (og.list_price * og.quantity - og.amount)
# WHEN bo.business_op = 'BUY_REVERSE' THEN -(og.list_price * og.quantity - og.amount)
# ELSE 0
# END
# ), 0) AS total_discount_amount
# FROM order_goods og
# JOIN bz_order bo ON og.orderid = bo.id
# WHERE og.del_flg = '0'
# AND bo.del_flg = '0'
# AND bo.customerid = ${customerid}$
# """
# total_amount_result = await sor.sqlExe(total_amount_sql, {'customerid': customerid})
# total_paid_amount = float(total_amount_result[0]['total_paid_amount']) if total_amount_result else 0.0
# total_discount_amount = float(total_amount_result[0]['total_discount_amount']) if total_amount_result else 0.0
# # 将累计支付金额和累计优惠金额添加到返回结果中
# ns['total_paid_amount'] = total_paid_amount
# ns['total_discount_amount'] = total_discount_amount
# ns['total_count'] = total_count[0]['total_count'] if total_count else 0
# 根据订单号搜索
if ns.get('id'):
sql += " AND bo.id LIKE ${order_id}$"
count_sql += " AND bo.id LIKE ${order_id}$"
params['order_id'] = f"%{ns.get('id')}%"
# 时间范围查询
if ns.get('start_time'):
sql += " AND bo.order_date >= ${start_time}$"
count_sql += " AND bo.order_date >= ${start_time}$"
params['start_time'] = ns.get('start_time') + ' 00:00:00'
if ns.get('end_time'):
sql += " AND bo.order_date <= ${end_time}$"
count_sql += " AND bo.order_date <= ${end_time}$"
params['end_time'] = ns.get('end_time') + ' 23:59:59'
# 订单状态查询
if ns.get('order_status'):
sql += " AND bo.order_status = ${order_status}$"
count_sql += " AND bo.order_status = ${order_status}$"
params['order_status'] = ns.get('order_status')
# 业务操作筛选business_op BUY, RENEW, BUY_REVERSE
if ns.get('business_op'):
sql += " AND bo.business_op = ${business_op}$"
count_sql += " AND bo.business_op = ${business_op}$"
params['business_op'] = ns.get('business_op')
# 添加排序
sql += " ORDER BY bo.order_date DESC"
# 获取总记录数
total_result = await sor.sqlExe(count_sql, params)
total_count = total_result[0]['total_count'] if total_result else 0
# 添加分页
sql += " LIMIT ${size}$ OFFSET ${offset}$"
params['size'] = size
params['offset'] = offset
# 执行查询
order_goods_list = await sor.sqlExe(sql, params)
if not order_goods_list:
return {
'status': True,
'data': [],
'pagination': {'page': page, 'size': size, 'total': 0}
}
# 处理数据
for item in order_goods_list:
# 清理折扣数据
if item['discount'] is None or item['discount'] == 1.0:
del item['discount']
else: else:
reacs = await sor.R('bz_order', {'customerid':ns['customerid'],'sort':'order_date desc','order_status':ns.get('order_status'),'del_flg':'0'}) item['discount'] = item['discount'] * 10 # 转换为百分比显示
all_price = 0
if len(reacs) >= 1: # 处理结果中原价list_price和数量quantity 计算总价
for j in reacs: if item['list_price'] is None:
reacsgoods = await sor.R('order_goods', {'orderid': j['id'], 'del_flg': '0'}) item['list_price'] = 0
countlist_price = 0 if item['quantity'] is None:
for i in reacsgoods: item['quantity'] = 0
if i['discount'] == None or i['discount'] == 1.0: item['origin_amout'] = float(item['list_price']) * float(item['quantity'])
del i['discount']
goods = await sor.R('product', {'id': i['productid'], 'del_flg': '0'})
if len(goods) >= 1: # 获取产品名称
i['productid'] = goods[0]['name'] goods = await sor.R('product', {'id': item['productid'], 'del_flg': '0'})
j['order_goods'] = reacsgoods if len(goods) >= 1:
countlist_price += i['list_price'] item['product_name'] = goods[0]['name']
countlist_price *= i['quantity'] item['product_type'] = goods[0]['ptype']
if j['order_status'] == '1':
all_price += countlist_price # 获取产品配置详情
j['countprice'] = round(countlist_price,2) item['spec_data'] = None
if j['countprice'] == 0: if item.get('spec_id'):
j['countprice'] = j['originalprice'] specdata_list = await sor.R('specificdata', {'id': item['spec_id'], 'del_flg': '0'})
return {'status': True, 'data': reacs, 'all_price': round(all_price, 2)} if specdata_list and specdata_list[0]['spec_data']:
else: item['spec_data'] = json.loads(specdata_list[0]['spec_data'])
# 我的所有订单
ns['del_flg'] = '0' # 格式化订单状态
ns['sort'] = 'create_at desc' status_mapping = {
user = await sor.R('users', {'id': users_id, 'del_flg': '0'}) '0': '未支付',
orgid = await sor.R('organization', {'id': user[0]['orgid'], 'del_flg': '0'}) '1': '已支付',
ns['customerid'] = orgid[0]['id'] '2': '已关闭',
reacs = await sor.R('bz_order', {'customerid':ns['customerid'],'sort':'create_at desc','del_flg':'0'}) '3': '已取消',
actual_all_price = 0 '4': '后付费'
for j in reacs: }
reacsgoods = await sor.R('order_goods', {'orderid': j['id'], 'del_flg': '0'}) item['order_status_text'] = status_mapping.get(item['order_status'], '未知状态')
all_price = 0
countlist_price = 0 # 格式化业务操作
business_op = j['business_op'] business_op_mapping = {
for i in reacsgoods: 'BUY': '购买',
if i['discount'] == None or i['discount'] == 1.0: 'RENEW': '续费',
del i['discount'] 'BUY_REVERSE': '退款',
i['discount'] = i['discount'] * 10 if i.get('discount') else None # 'UPGRADE': '升级'
goods = await sor.R('product', {'id': i['productid'], 'del_flg': '0'}) }
if len(goods) < 1: item['business_op_text'] = business_op_mapping.get(item['business_op'], item['business_op'])
continue
i['ptype'] = goods[0]['ptype'] return {
if len(goods) >= 1: 'status': True,
i['productid'] = goods[0]['name'] 'data': order_goods_list,
j['order_goods'] = reacsgoods 'pagination': {
countlist_price = i['list_price'] * i['quantity'] 'page': page,
actual_price = i['price'] * i['quantity'] 'size': size,
# countlist_price += i['list_price'] 'total': total_count
# countlist_price *= i['quantity'] }
if j['order_status'] == '1': }
all_price += countlist_price
if business_op != 'BUY_REVERSE':
actual_all_price += actual_price
j['countprice'] = round(all_price,2)
if j['countprice'] == 0:
j['countprice'] = j['originalprice']
return {'status': True, 'data': reacs,'all_price': round(actual_all_price,2)}
except Exception as e: except Exception as e:
raise e import traceback
return {'status': False, 'msg': '信息错误'} traceback.print_exc()
return {'status': False, 'msg': '信息错误: %s' % str(e) + traceback.format_exc()}
ret = await getbz_order(params_kw) ret = await getbz_order(params_kw)
return ret return ret

View File

@ -0,0 +1,110 @@
async def getbz_order(ns={}):
"""查询订单详情/我的所有订单"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
try:
users_id = await get_user()
ns['del_flg'] = '0'
ns['sort'] = 'create_at desc'
if ns.get('id') and not ns.get('type'):
# 查询订单详情
reacs = await sor.R('bz_order', ns)
# 兼容第三范式产品展示 这段代码可注释
if reacs and reacs[0].get('specdataid'):
specdata = await sor.R('specificdata', {'id': reacs[0].get('specdataid'), 'del_flg': '0'})
if specdata:
specdata_dumps = json.dumps(specdata[0]) if isinstance(specdata[0], dict) else specdata[0]
if 'internalip' in specdata_dumps and 'externalip' in specdata_dumps:
reacs[0]['spec_data'] = json.loads(json.loads(specdata_dumps)['spec_data'])
reacsgoods = await sor.R('order_goods', {'orderid': ns['id'], 'del_flg': '0'})
for i in reacsgoods:
if i['discount'] == None or i['discount'] == 1.0:
del i['discount']
i['discount'] = i['discount'] * 10 if i.get('discount') else None
goods = await sor.R('product', {'id': i['productid'], 'del_flg': '0'})
if len(goods) >= 1:
i['productid'] = goods[0]['name']
i['ptype'] = goods[0]['ptype']
reacs[0]['order_goods'] = reacsgoods
return {'status': True, 'data': reacs}
elif ns.get('type') == '200':
#筛选支付类型
user = await sor.R('users', {'id': users_id, 'del_flg': '0'})
orgid = await sor.R('organization', {'id': user[0]['orgid'], 'del_flg': '0'})
ns['customerid'] = orgid[0]['id']
if ns.get('id'):
#根据订单号搜索
reacs = await sor.R('bz_order', {'id': ns['id']})
elif ns.get('start_time'):
sql = """select * from bz_order where del_flg = 0 AND customerid = ${customerid}$ AND order_date >= ${start_time}$ AND order_date <= ${end_time}$ ORDER BY order_date DESC """
start_time = ns.get('start_time') + ' 00:00:00'
end_time = ns.get('end_time') + ' 23:59:59'
reacs = await sor.sqlExe(sql, {'start_time': start_time,'end_time': end_time,'customerid' :ns['customerid']})
else:
reacs = await sor.R('bz_order', {'customerid':ns['customerid'],'sort':'order_date desc','order_status':ns.get('order_status'),'del_flg':'0'})
all_price = 0
if len(reacs) >= 1:
for j in reacs:
reacsgoods = await sor.R('order_goods', {'orderid': j['id'], 'del_flg': '0'})
countlist_price = 0
for i in reacsgoods:
if i['discount'] == None or i['discount'] == 1.0:
del i['discount']
goods = await sor.R('product', {'id': i['productid'], 'del_flg': '0'})
if len(goods) >= 1:
i['productid'] = goods[0]['name']
j['order_goods'] = reacsgoods
countlist_price += i['list_price']
countlist_price *= i['quantity']
if j['order_status'] == '1':
all_price += countlist_price
j['countprice'] = round(countlist_price,2)
if j['countprice'] == 0:
j['countprice'] = j['originalprice']
return {'status': True, 'data': reacs, 'all_price': round(all_price, 2)}
else:
# 我的所有订单
ns['del_flg'] = '0'
ns['sort'] = 'create_at desc'
user = await sor.R('users', {'id': users_id, 'del_flg': '0'})
orgid = await sor.R('organization', {'id': user[0]['orgid'], 'del_flg': '0'})
ns['customerid'] = orgid[0]['id']
reacs = await sor.R('bz_order', {'customerid':ns['customerid'],'sort':'create_at desc','del_flg':'0'})
actual_all_price = 0
for j in reacs:
reacsgoods = await sor.R('order_goods', {'orderid': j['id'], 'del_flg': '0'})
all_price = 0
countlist_price = 0
business_op = j['business_op']
for i in reacsgoods:
if i['discount'] == None or i['discount'] == 1.0:
del i['discount']
i['discount'] = i['discount'] * 10 if i.get('discount') else None
goods = await sor.R('product', {'id': i['productid'], 'del_flg': '0'})
if len(goods) < 1:
continue
i['ptype'] = goods[0]['ptype']
if len(goods) >= 1:
i['productid'] = goods[0]['name']
j['order_goods'] = reacsgoods
countlist_price = i['list_price'] * i['quantity']
actual_price = i['price'] * i['quantity']
# countlist_price += i['list_price']
# countlist_price *= i['quantity']
if j['order_status'] == '1':
all_price += countlist_price
if business_op != 'BUY_REVERSE':
actual_all_price += actual_price
j['countprice'] = round(all_price,2)
if j['countprice'] == 0:
j['countprice'] = j['originalprice']
return {'status': True, 'data': reacs,'all_price': round(actual_all_price,2)}
except Exception as e:
raise e
return {'status': False, 'msg': '信息错误'}
ret = await getbz_order(params_kw)
return ret

39
b/bz_order/todo_info.dspy Normal file
View File

@ -0,0 +1,39 @@
async def todo_info(ns={}):
"""查询订单待支付,待续费,处理中的信息"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
try:
users_id = await get_user()
if not users_id:
server_error(401)
user = await sor.R('users', {'id': users_id, 'del_flg': '0'})
orgid = await sor.R('organization', {'id': user[0]['orgid'], 'del_flg': '0'})
customerid = orgid[0]['id']
print(customerid)
# 查询订单待支付,待续费,处理中的信息
pending_payment_orders = await sor.sqlExe(
"SELECT COUNT(*) AS count FROM bz_order WHERE customerid = '%s' AND order_status = '0' AND del_flg = '0';" % customerid, {}
)
ns['pending_payment_orders'] = pending_payment_orders[0]['count'] if pending_payment_orders else 0
pending_renew_orders = await sor.sqlExe(
"SELECT COUNT(*) AS count FROM bz_order WHERE customerid = '%s' AND order_status = '0' AND del_flg = '0';" % customerid, {}
)
ns['pending_renew_orders'] = pending_renew_orders[0]['count'] if pending_renew_orders else 0
processing_orders = await sor.sqlExe(
"SELECT COUNT(*) AS count FROM bz_order WHERE customerid = '%s' AND order_status = '1000' AND del_flg = '0';" % customerid, {}
)
ns['processing_orders'] = processing_orders[0]['count'] if processing_orders else 0
return {
'status': True,
'data': ns
}
except Exception as e:
import traceback
traceback.print_exc()
return {'status': False, 'msg': '信息错误: %s' % str(e) + traceback.format_exc()}
ret = await todo_info(params_kw)
return ret

View File

@ -1,21 +1,111 @@
async def getNoinvitationcode(ns): async def getNoinvitationcode(ns={}):
"""展示所有没有销售的客户""" """展示所有没有销售的客户"""
db = DBPools() try:
async with db.sqlorContext('kboss') as sor: db = DBPools()
orgs = await sor.R('organization', {"org_type": '0'}) async with db.sqlorContext('kboss') as sor:
ns['del_flg'] = '0' # 获取组织信息
ns['sort'] = 'create_at desc' orgs = await sor.R('organization', {"org_type": '0'})
ns['parentid'] = orgs[0]['id'] if not orgs:
datalist = [] return {'status': False, 'message': '未找到组织信息'}
prc = await sor.R('customer', {'del_flg': '0'})
for i in prc: # 获取目标组织ID优先使用ns中的orgid否则使用第一个组织的ID
if not i['salemanid']: target_org_id = ns.get('orgid') or orgs[0]['id']
customer_id_parentid_li = await sor.R('organization', {'id': i['customerid']})
customer_id_parentid = customer_id_parentid_li[0]['parentid'] # 获取分页参数
if customer_id_parentid == ns.get('orgid'): page = int(ns.get('page', 1)) # 当前页码默认为1
datalist.append(customer_id_parentid_li[0]) page_size = int(ns.get('size', 10)) # 每页数量默认为10
data = {'rows':datalist} offset = (page - 1) * page_size # 计算偏移量
return {'status': True, 'data': data}
# 获取筛选条件
orgname = ns.get('orgname', '').strip() # 组织名称
contactor_phone = ns.get('contactor_phone', '').strip() # 联系人电话
# 构建WHERE条件
where_conditions = [
"(c.salemanid IS NULL OR c.salemanid = '')",
"o.parentid = '%s'",
"c.del_flg = '0'",
"o.del_flg = '0'"
]
params = [target_org_id]
# 添加组织名称模糊查询条件
if orgname:
where_conditions.append("o.orgname LIKE '%s'")
params.append(f"%%{orgname}%%")
# 添加联系人电话条件
if contactor_phone:
where_conditions.append("o.contactor_phone LIKE '%s'")
params.append(f"%%{contactor_phone}%%")
where_clause = " AND ".join(where_conditions)
# 构建查询总数的SQL
count_sql = f"""
SELECT COUNT(*) as total
FROM customer c
JOIN organization o ON c.customerid = o.id
WHERE {where_clause}
"""
count_sql = count_sql % tuple(params)
# 执行总数查询
count_result = await sor.sqlExe(count_sql,{})
total = count_result[0]['total'] if count_result else 0
# 构建查询数据的SQL添加分页
data_sql = f"""
SELECT o.*
FROM customer c
JOIN organization o ON c.customerid = o.id
WHERE {where_clause}
ORDER BY o.create_at DESC
LIMIT %s OFFSET %s
"""
# 添加分页参数
params.extend([page_size, offset])
data_sql = data_sql % tuple(params)
# 执行数据查询
result = await sor.sqlExe(data_sql, {})
# 返回结果,包含分页信息
return {
'status': True,
'data': {
'rows': result
},
'pagination': {
'page': page,
'size': page_size,
'total': total
}
}
except Exception as e:
# 记录错误日志(可根据实际情况添加日志记录)
return {'status': False, 'message': f'查询失败: {str(e)}'}
# async def getNoinvitationcode(ns):
# """展示所有没有销售的客户"""
# db = DBPools()
# async with db.sqlorContext('kboss') as sor:
# orgs = await sor.R('organization', {"org_type": '0'})
# ns['del_flg'] = '0'
# ns['sort'] = 'create_at desc'
# ns['parentid'] = orgs[0]['id']
# datalist = []
# prc = await sor.R('customer', {'del_flg': '0'})
# for i in prc:
# if not i['salemanid']:
# customer_id_parentid_li = await sor.R('organization', {'id': i['customerid']})
# customer_id_parentid = customer_id_parentid_li[0]['parentid']
# if customer_id_parentid == ns.get('orgid'):
# datalist.append(customer_id_parentid_li[0])
# data = {'rows':datalist}
# return {'status': True, 'data': data}
ret = await getNoinvitationcode(params_kw) ret = await getNoinvitationcode(params_kw)
return ret return ret

View File

@ -1,54 +1,155 @@
async def getcustomer_goods(ns={}): async def getcustomer_goods(ns={}):
"""
获取客户产品列表,支持产品名称筛选、日期范围筛选和分页功能
参数:
ns: 参数字典,包含:
- userid: 用户ID (可选)
- productname: 产品名称筛选关键字 (可选)
- start_date: 开始日期 (格式: YYYY-MM-DD, 可选)
- end_date: 结束日期 (格式: YYYY-MM-DD, 可选)
- page: 页码 (默认1)
- page_size: 每页条数 (默认20)
返回:
dict: 包含状态、数据列表、总条数、当前页、总页数的信息
"""
db = DBPools() db = DBPools()
async with db.sqlorContext('kboss') as sor: async with db.sqlorContext('kboss') as sor:
try: try:
# 获取用户ID
if ns.get('userid'): if ns.get('userid'):
users_id = ns.get('userid') users_id = ns.get('userid')
else: else:
users_id = await get_user() users_id = await get_user()
user = await sor.R('users', {'id': users_id}) user = await sor.R('users', {'id': users_id})
date = datetime.datetime.now().date() if not user:
return {'status': False, 'msg': '用户不存在'}
customerid = user[0]['orgid']
current_date = datetime.datetime.now().date()
# 更新过期产品的删除标志
sql = """update customer_goods SET del_flg = '1' where expire_date < ${date}$ and customerid = ${customerid}$""" sql = """update customer_goods SET del_flg = '1' where expire_date < ${date}$ and customerid = ${customerid}$"""
await sor.sqlExe(sql, {'date': date, 'customerid': user[0]['orgid']}) await sor.sqlExe(sql, {'date': current_date, 'customerid': customerid})
customer_goods = await sor.R('customer_goods', {'customerid': user[0]['orgid'],'sort':'create_at desc','del_flg':'0'})
for i in customer_goods: # 获取筛选参数
ordergoods = await sor.R('order_goods', {'orderid':i['orderid']}) product_name_filter = ns.get('productname', '').strip()
# jnorg = await sor.R('organization', {'id': i['providerrid'], 'orgname': '济南超算'}) start_date = ns.get('start_date')
# if len(jnorg) >= 1: end_date = ns.get('end_date')
# i['org'] = 'jinan' page = max(1, int(ns.get('page', 1)))
for j in ordergoods: page_size = max(1, min(100, int(ns.get('page_size', 20)))) # 限制每页最多100条
if j['end_date']:
await sor.U('customer_goods',{'id':i['id'],'expire_date':j['end_date']}) # 构建基础查询条件
await sor.sqlExe(sql, {'date': date, 'customerid': user[0]['orgid']}) base_conditions = {
customer = await sor.R('customer_goods', 'customerid': customerid,
{'customerid': user[0]['orgid'], 'sort': 'create_at desc', 'del_flg': '0'}) 'del_flg': '0',
for cu in customer: 'sort': 'create_at desc'
}
# 先获取所有有效的产品数据
all_customer_goods = await sor.R('customer_goods', base_conditions)
# 处理订单商品数据并更新过期日期
for item in all_customer_goods:
ordergoods = await sor.R('order_goods', {'orderid': item['orderid']})
for order_item in ordergoods:
if order_item['end_date']:
await sor.U('customer_goods', {'id': item['id'], 'expire_date': order_item['end_date']})
# 重新获取更新后的数据
all_customer_goods = await sor.R('customer_goods', base_conditions)
# 处理产品数据并应用筛选
processed_goods = []
for cu in all_customer_goods:
provider_id_li = await sor.R('product', {'id': cu['productid'], 'del_flg': '0'}) provider_id_li = await sor.R('product', {'id': cu['productid'], 'del_flg': '0'})
if provider_id_li: if not provider_id_li:
cu['classify'] = provider_id_li[0]['classify'] continue
# 处理k8s资源 cu['classify'] = provider_id_li[0]['classify']
if cu.get('classify') and 'CPCC' in cu['classify']:
cu['classify'] = 'CPCC' # 处理k8s资源
prd_name = cu['productname'].split('.')[0] if cu.get('classify') and 'CPCC' in cu['classify']:
if '-' == prd_name or 'STANDARD' == prd_name: cu['classify'] = 'CPCC'
cu['productname'] = 'CPU计算型' prd_name = cu['productname'].split('.')[0]
else: if '-' == prd_name or 'STANDARD' == prd_name:
cu['productname'] = prd_name cu['productname'] = 'CPU计算型'
spec_note_li = await sor.R('specificdata', {'id': cu['specdataid']}) else:
cu['productname'] = prd_name
spec_note_li = await sor.R('specificdata', {'id': cu['specdataid']})
if spec_note_li:
cu['instance_info'] = json.loads(spec_note_li[0]['spec_data']) cu['instance_info'] = json.loads(spec_note_li[0]['spec_data'])
external_ip_li = await sor.R('cpcnode', {'cpcid': cu['instance_info']['cpcid'], 'clusterid': cu['instance_info']['clusterid'], 'role': 'master'}) external_ip_li = await sor.R('cpcnode', {
cu['instance_info']['source_externalip'] = external_ip_li[0]['external_ip'] 'cpcid': cu['instance_info']['cpcid'],
'clusterid': cu['instance_info']['clusterid'],
'role': 'master'
})
if external_ip_li:
cu['instance_info']['source_externalip'] = external_ip_li[0]['external_ip']
provider_id = provider_id_li[0]['providerid'] provider_id = provider_id_li[0]['providerid']
jnorg = await sor.R('organization', {'id': provider_id, 'del_flg': '0'}) jnorg = await sor.R('organization', {'id': provider_id, 'del_flg': '0'})
if jnorg:
cu['providername'] = jnorg[0]['orgname'] cu['providername'] = jnorg[0]['orgname']
if jnorg[0]['orgname'] == '优刻得科技股份有限公司': if jnorg[0]['orgname'] == '优刻得科技股份有限公司':
cu['region'] = 'cn-wlcb' cu['region'] = 'cn-wlcb'
return {'status': True, 'data': customer}
# 应用筛选条件
# 产品名称筛选
if product_name_filter and product_name_filter.lower() not in cu.get('productname', '').lower():
continue
# 日期范围筛选
# create_at字段存在且在指定范围内 格式是:"2025-10-05 22:57:05"
if start_date and cu.get('create_at'):
try:
start_dt = datetime.datetime.strptime(start_date, '%Y-%m-%d').date()
create_at_dt = datetime.datetime.strptime(cu['create_at'], '%Y-%m-%d %H:%M:%S')
if create_at_dt.date() < start_dt:
continue
except Exception as e:
print(f"开始日期解析错误: {e}")
if end_date and cu.get('create_at'):
try:
end_dt = datetime.datetime.strptime(end_date, '%Y-%m-%d').date()
create_at_dt = datetime.datetime.strptime(cu['create_at'], '%Y-%m-%d %H:%M:%S')
if create_at_dt.date() > end_dt:
continue
except Exception as e:
print(f"结束日期解析错误: {e}")
# 通过specdataid读取规格数据
cu['spec_data'] = None
if cu.get('specdataid'):
specdata_li = await sor.R('specificdata', {'id': cu['specdataid']})
if specdata_li:
cu['spec_data'] = json.loads(specdata_li[0]['spec_data'])
processed_goods.append(cu)
# 分页处理
total_count = len(processed_goods)
# 计算当前页的数据
start_index = (page - 1) * page_size
end_index = start_index + page_size
paginated_data = processed_goods[start_index:end_index]
return {
'status': True,
'data': paginated_data,
'pagination': {
'total': total_count,
'page': page,
'page_size': page_size,
}
}
except Exception as e: except Exception as e:
raise e return {'status': False, 'msg': '%s' % str(e)}
return {'status': False, 'msg': '错误'}
ret = await getcustomer_goods(params_kw) ret = await getcustomer_goods(params_kw)
return ret return ret

View File

@ -5,20 +5,46 @@ async def registerUser(ns):
db = DBPools() db = DBPools()
async with db.sqlorContext('kboss') as sor: async with db.sqlorContext('kboss') as sor:
if ns: if ns:
userns = {'username': ns['username']} if ns.get('username'):
isuser = await sor.R('users', userns) userns = {'username': ns['username']}
if len(isuser) >= 1: isuser = await sor.R('users', userns)
return {'status': False, 'msg': '用户名已注册'} if len(isuser) >= 1:
useremai = {'email': ns['email']} return {'status': False, 'msg': '用户名已注册'}
isuser = await sor.R('users', useremai)
if len(isuser) >= 1: if ns.get('email'):
return {'status': False, 'msg': '该邮箱已注册'} useremai = {'email': ns['email']}
isuser = await sor.R('users', useremai)
if len(isuser) >= 1:
return {'status': False, 'msg': '该邮箱已注册'}
usermobile = {'mobile':ns['mobile']} usermobile = {'mobile':ns['mobile']}
isuser = await sor.R('users', usermobile) isuser = await sor.R('users', usermobile)
if len(isuser) >= 1: if len(isuser) >= 1:
return {'status': False, 'msg': '该手机号已注册'} return {'status': False, 'msg': '该手机号已注册'}
if len(ns.get('password')) < 6: # 用户名没有 则用手机号作为用户名
return {'status': False, 'msg': '密码必须6位数以上'} if not ns.get('username'):
ns['username'] = ns['mobile']
if ns.get('password'):
if len(ns.get('password')) < 6:
return {'status': False, 'msg': '密码必须6位数以上'}
if not ns.get('codeid'):
return {'status': False, 'msg': '验证码ID不能为空'}
if ns.get('codeid'):
code = await sor.R('validatecode', {'id': ns.get('codeid'), 'vcode': ns.get('vcode')})
# 验证码五分钟内才有效 create_at是字符串 格式是"2025-11-05 16:00:19"
if code:
create_at = code[0]['create_at']
now = datetime.datetime.now()
create_at_dt = datetime.datetime.strptime(create_at, "%Y-%m-%d %H:%M:%S")
if (now - create_at_dt).seconds > 500:
return {'status': False, 'msg': '验证码过期'}
else:
return {'status': False, 'msg': '验证码不正确'}
#通过邀请码注册 #通过邀请码注册
if ns.get('invitecode'): if ns.get('invitecode'):
invitecodens = {} invitecodens = {}
@ -95,37 +121,64 @@ async def registerUser(ns):
return {'status': False, 'msg': '邀请码不正确'} return {'status': False, 'msg': '邀请码不正确'}
else: else:
try: try:
# 用户orgid
ns['id'] = uuid() ns['id'] = uuid()
org_id = ns['id'] org_id = ns['id']
ns['contactor_phone'] = ns.get('mobile') ns['contactor_phone'] = ns.get('mobile')
# 通过域名注册 # 通过域名注册
if ns.get('domain_name'): if ns.get('domain_name'):
# 通过域名查找分销商信息
reseller = await sor.R('reseller', {'domain_name': ns.get('domain_name')}) reseller = await sor.R('reseller', {'domain_name': ns.get('domain_name')})
if len(reseller) >= 1: if len(reseller) >= 1:
# 分销商机构ID 即orgid
org = await sor.R('organization', {'id': reseller[0]['orgid'], 'del_flg': '0'}) org = await sor.R('organization', {'id': reseller[0]['orgid'], 'del_flg': '0'})
else: else:
# 分销商不存在 则查找业主机构ID
org = await sor.R('organization', {'org_type': '0', 'del_flg': '0'}) org = await sor.R('organization', {'org_type': '0', 'del_flg': '0'})
else: else:
# 没有通过域名 则默认是获取业主机构ID
org = await sor.R('organization', {'org_type': '0', 'del_flg': '0'}) org = await sor.R('organization', {'org_type': '0', 'del_flg': '0'})
# 获取所在机构父级ID
ns['parentid'] = org[0]['id'] ns['parentid'] = org[0]['id']
await sor.C('organization', ns)
# 新增用户机构信息
ns_org = {
'id': ns['id'],
'orgname': ns['username'],
'parentid': ns['parentid'],
'org_type': ns['org_type'],
'contactor_phone': ns.get('mobile'),
}
await sor.C('organization', ns_org)
# 生成用户userid
ns['id'] = uuid() ns['id'] = uuid()
userid = ns['id'] userid = ns['id']
ns['password'] = password_encode(ns['password'])
# 加密用户密码
if ns.get('password'):
ns['password'] = password_encode(ns['password'])
ns['orgid'] = org_id ns['orgid'] = org_id
# 新增用户信息
await sor.C('users', ns) await sor.C('users', ns)
# 新增用户角色信息
listrole = ['管理员', '客户'] listrole = ['管理员', '客户']
for i in listrole: for i in listrole:
role = await sor.R('role', {'role': i, 'org_type': ns['org_type']}) role = await sor.R('role', {'role': i, 'org_type': ns['org_type']})
await sor.C('userrole', {'id': uuid(), 'userid': userid, 'roleid': role[0]['id']}) await sor.C('userrole', {'id': uuid(), 'userid': userid, 'roleid': role[0]['id']})
# 新增客户信息并使用openCustomerAccounts为客户开账
ns['id'] = uuid() ns['id'] = uuid()
ns['customerid'] = org_id ns['customerid'] = org_id
await sor.C('customer', ns) await sor.C('customer', ns)
await openCustomerAccounts(sor, org[0]['id'], org_id) await openCustomerAccounts(sor, org[0]['id'], org_id)
return {'status': True, 'msg': '注册成功'} return {'status': True, 'msg': '注册成功'}
except Exception as error: except Exception as error:
raise error # raise error
return {'status': False, 'msg': '注册失败'} return {'status': False, 'msg': '注册失败, %s' % str(error)}
ret = await registerUser(params_kw) ret = await registerUser(params_kw)

View File

@ -16,7 +16,7 @@ async def get_recharge_record(ns={}):
try: try:
user_id = await get_user() user_id = await get_user()
if not user_id: if not user_id:
return {'status': False, 'message': 'user_id is missing'} server_error(401)
result = await sor.R('users', {'id': user_id}) result = await sor.R('users', {'id': user_id})
if not result: if not result:
@ -29,16 +29,34 @@ async def get_recharge_record(ns={}):
recharge_path = ns.get('recharge_path') recharge_path = ns.get('recharge_path')
params = {'start_time': start_time, 'end_time': end_time, 'recharge_path': recharge_path, 'orgid': orgid} params = {'start_time': start_time, 'end_time': end_time, 'recharge_path': recharge_path, 'orgid': orgid}
# 增加分页功能
page = ns.get('page', 1)
size = ns.get('size', 20)
offset = (page - 1) * size
# 构建COUNT查询
total_sql = "SELECT COUNT(*) AS total_count FROM recharge_log WHERE del_flg = 0 AND customerid = ${orgid}$"
sql = "SELECT * FROM recharge_log WHERE del_flg = 0 AND customerid = ${orgid}$" sql = "SELECT * FROM recharge_log WHERE del_flg = 0 AND customerid = ${orgid}$"
if start_time and end_time: if start_time and end_time:
sql += " AND create_at BETWEEN ${start_time}$ AND ${end_time}$" sql += " AND create_at BETWEEN ${start_time}$ AND ${end_time}$"
total_sql += " AND create_at BETWEEN ${start_time}$ AND ${end_time}$"
if recharge_path is not None: if recharge_path is not None:
sql += " AND recharge_path = ${recharge_path}$" sql += " AND recharge_path = ${recharge_path}$"
total_sql += " AND recharge_path = ${recharge_path}$"
# 添加排序但不添加分页限制到主查询
sql += " ORDER BY create_at DESC"
# 执行COUNT查询获取总记录数
total_result = await sor.sqlExe(total_sql, params)
total_count = total_result[0]['total_count'] if total_result else 0
# 执行查询获取所有匹配记录
reacs = await sor.sqlExe(sql, params) reacs = await sor.sqlExe(sql, params)
if not reacs: if not reacs:
return {'status': True, 'message': 'No recharge records'} return {'status': True, 'message': 'No recharge records', 'pagination': {'page': page, 'size': size, 'total': 0}}
for recharge in reacs: for recharge in reacs:
if recharge['recharge_sno']: if recharge['recharge_sno']:
@ -75,7 +93,11 @@ async def get_recharge_record(ns={}):
recharge_amount += round(float(recharge['recharge_amt']), 2) recharge_amount += round(float(recharge['recharge_amt']), 2)
elif recharge['action'] in ['RECHARGE_REVERSE', 'RECHARGE_ALIPAY_REVERSE']: elif recharge['action'] in ['RECHARGE_REVERSE', 'RECHARGE_ALIPAY_REVERSE']:
recharge_reverse_amount += round(float(recharge['recharge_amt']), 2) recharge_reverse_amount += round(float(recharge['recharge_amt']), 2)
# 在过滤后应用分页
recharge_records.sort(key=lambda x: x['create_at'], reverse=True) recharge_records.sort(key=lambda x: x['create_at'], reverse=True)
# 应用分页
paginated_records = recharge_records[offset:offset + size]
except Exception as e: except Exception as e:
raise raise
@ -83,10 +105,15 @@ async def get_recharge_record(ns={}):
return { return {
'status': True, 'status': True,
'message': 'ok', 'message': 'ok',
'recharge_records': recharge_records, 'recharge_records': paginated_records,
'actual_amount': round(total_amount, 2), 'actual_amount': round(total_amount, 2),
'recharge_amount': round(recharge_amount, 2), 'recharge_amount': round(recharge_amount, 2),
'charged_amount': round(recharge_reverse_amount, 2) 'charged_amount': round(recharge_reverse_amount, 2),
'pagination': {
'page': page,
'size': size,
'total': len(recharge_records) # 使用过滤后的总记录数
}
} }
ret = await get_recharge_record(params_kw) ret = await get_recharge_record(params_kw)

View File

@ -4,12 +4,20 @@ async def get_unreadmsg(ns={}):
:param ns: :param ns:
:return: :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() db = DBPools()
async with db.sqlorContext('kboss') as sor: async with db.sqlorContext('kboss') as sor:
# if 'userid' not in ns or not ns['userid']: # if 'userid' not in ns or not ns['userid']:
# return {'status': False, 'msg': '收件人 userid 未提供'} # return {'status': False, 'msg': '收件人 userid 未提供'}
mas = await sor.R('message', {'receiverid': await get_user(), 'del_flg': 0, 'msgstatus': 0}) mas = await sor.R('message', {'receiverid': ns['userid'], 'del_flg': 0, 'msgstatus': 0})
if not mas: if not mas:
return {'status': True, 'count': 0} return {'status': True, 'count': 0}

View File

@ -3,7 +3,8 @@ async def delpermission(ns):
async with db.sqlorContext('kboss') as sor: async with db.sqlorContext('kboss') as sor:
if ns: if ns:
ns['del_flg'] = '1' ns['del_flg'] = '1'
await sor.U('permission', ns) update_sql = """update permission set del_flg = '1' where id = '%s'""" % ns['id']
await sor.sqlExe(update_sql, {})
dictns = {'parentid': ns['id']} dictns = {'parentid': ns['id']}
reacs = await sor.R('permission', dictns) reacs = await sor.R('permission', dictns)
for i in reacs: for i in reacs:

View File

@ -0,0 +1,82 @@
async def baidu_resource_query(ns={}):
"""
用户资源查询
:param ns:
:return:
"""
if ns.get('userid'):
userid = ns.get('userid')
else:
userid = await get_user()
db = DBPools()
async with db.sqlorContext('kboss') as sor:
baiduids = await sor.R('baidu_users', {'user_id': userid})
if baiduids:
baiduid = baiduids[0]['baidu_id']
else:
return {
'status': False,
'msg': 'User not synchronized'
}
ns['queryAccountId'] = baiduid
ns['pageSize'] = 200
method = 'POST'
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://billing.baidubce.com/v1/resource/query?%s' % ns_format
header = {
"Host": "billing.baidubce.com"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=ns) as res:
result = await res.json()
return {'1': result}
result_new = []
for i in result['result']:
if i.get('status') != 'STOPPED':
result_new.append(i)
result['result'] = result_new
return {
'status': True,
'msg': 'get resource success',
'data': result
}
async def resource_overview(ns={}):
if ns.get('userid'):
userid = ns.get('userid')
else:
userid = await get_user()
init_data = [
{'id': 1, 'name': '云服务器', 'count': 0, 'unit': '实例'},
{'id': 2, 'name': '私有网络', 'count': 0, 'unit': 'VPC'},
{'id': 3, 'name': '负载均衡', 'count': 0, 'unit': '负载均衡'},
{'id': 4, 'name': '弹性块存储', 'count': 0, 'unit': '云盘'},
{'id': 5, 'name': 'NAT网关', 'count': 0, 'unit': '实例'},
{'id': 6, 'name': 'VPN连接', 'count': 0, 'unit': 'VPN网关'},
]
baidu_resource_data = await baidu_resource_query({'userid': userid})
print(baidu_resource_data)
if baidu_resource_data and baidu_resource_data.get('data') and baidu_resource_data['data'].get('result'):
for baidu_resource in baidu_resource_data['data']['result']:
if baidu_resource.get('serviceType') == 'CDS' and baidu_resource['status'] == 'RUNNING':
init_data[3]['count'] += 1
elif baidu_resource.get('serviceType') == 'EIP' and baidu_resource['status'] == 'RUNNING':
init_data[1]['count'] += 1
elif (baidu_resource.get('serviceType') == 'BCC' or baidu_resource.get('serviceType') == 'LS') and baidu_resource['status'] == 'RUNNING':
init_data[0]['count'] += 1
return {
'status': True,
'msg': 'get resource success',
'data': init_data
}
ret = await baidu_resource_query(params_kw)
return ret

View File

@ -1113,7 +1113,7 @@ detailDataLJS = {
{ {
"title": "NVIDIA-4090-48G", "title": "NVIDIA-4090-48G",
"description": "High-performance GPU server with powerful computing capabilities, suitable for AI training, deep learning, etc.", "description": "High-performance GPU server with powerful computing capabilities, suitable for AI training, deep learning, etc.",
"price": "8000", "price": "8800",
"pre_price": None, "pre_price": None,
"price_unit": "台/月", "price_unit": "台/月",
"discount": None, "discount": None,
@ -1207,7 +1207,7 @@ detailDataLJS = {
{ {
"title": "NVIDIA-4090", "title": "NVIDIA-4090",
"description": "High-performance GPU server with powerful computing capabilities, suitable for AI training, deep learning, etc.", "description": "High-performance GPU server with powerful computing capabilities, suitable for AI training, deep learning, etc.",
"price": "6500", "price": "7200",
"pre_price": None, "pre_price": None,
"price_unit": "台/月", "price_unit": "台/月",
"discount": None, "discount": None,

View File

@ -2,32 +2,33 @@ async def getpromoting(ns):
"""促销展示""" """促销展示"""
db = DBPools() db = DBPools()
async with db.sqlorContext('kboss') as sor: async with db.sqlorContext('kboss') as sor:
if ns: # if ns:
# 生成邀请码展示促销活动 # 生成邀请码展示促销活动
users_id = await get_user() users_id = await get_user()
if ns.get('type'): if ns.get('type'):
ns['sort'] = 'create_at desc' ns['sort'] = 'create_at desc'
orgid = await sor.R('users', {'id': users_id}) orgid = await sor.R('users', {'id': users_id})
ns['orgid'] = orgid[0]['orgid'] ns['orgid'] = orgid[0]['orgid']
# reacs = await sor.R('promoting', ns) # reacs = await sor.R('promoting', ns)
dates = datetime.datetime.now() dates = datetime.datetime.now()
promoting = """select * from promoting where del_flg = 0 and orgid = ${orgid}$ and end_date > ${dates}$ order by create_at desc""" promoting = """select * from promoting where del_flg = 0 and orgid = ${orgid}$ and end_date > ${dates}$ order by create_at desc"""
reacs = await sor.sqlExe(promoting, {'orgid': ns['orgid'],'dates':dates}) reacs = await sor.sqlExe(promoting, {'orgid': ns['orgid'],'dates':dates})
date = await get_business_date(sor=None) date = await get_business_date(sor=None)
listdata = [] listdata = []
for i in reacs: for i in reacs:
if i['end_date'] > date: if i['end_date'] > date:
listdata.append(i) listdata.append(i)
return {'status': True, 'data': listdata} return {'status': True, 'data': listdata}
else: else:
ns['del_flg'] = '0' ns['del_flg'] = '0'
ns['sort'] = 'create_at desc' ns['sort'] = 'create_at desc'
orgid = await sor.R('users', {'id': users_id}) orgid = await sor.R('users', {'id': users_id})
ns['orgid'] = orgid[0]['orgid'] ns['orgid'] = orgid[0]['orgid']
reacs = await sor.R('promoting', ns) reacs = await sor.R('promoting', ns)
return {'status': True, 'data': reacs} return {'status': True, 'data': reacs}
return {'status': False, 'msg': '参数不正确'}
# return {'status': False, 'msg': '参数不正确'}
ret = await getpromoting(params_kw) ret = await getpromoting(params_kw)
return ret return ret

View File

@ -1,26 +1,67 @@
async def mobilecode(ns): async def mobilecode(ns):
"""登录发送短信验证码""" """发送短信验证码,支持注册和登录筛选"""
db = DBPools() db = DBPools()
async with db.sqlorContext('kboss') as sor: async with db.sqlorContext('kboss') as sor:
type = 0 # 获取操作类型register 或 login
ns['del_flg'] = '0' action_type = ns.get('action_type') # register 或 login
userreacs = await sor.R('users', ns)
if len(userreacs) >= 1: if not action_type:
type += 1 return {'status': False, 'msg': '操作类型action_type不能为空'}
else:
userreacs = await sor.R('users', {'mobile': ns['username'], 'del_flg': '0'}) # 通过手机号查找用户
if len(userreacs) >= 1: mobile = ns.get('mobile')
type += 1 if not mobile:
if type >= 1: return {'status': False, 'msg': '手机号不能为空'}
code = await generate_vcode()
nss = await send_vcode(userreacs[0]['mobile'], '用户注册登录验证', {'SMSvCode': code.get('vcode')}) userreacs = await sor.R('users', {'mobile': mobile, 'del_flg': '0'})
# return {'1':nss}
if nss: # 注册逻辑:检查手机号是否已存在
return {'status': True, 'msg': '发送成功', 'codeid': code.get('id')} if action_type == 'register':
if len(userreacs) >= 1:
return {'status': False, 'msg': '手机号已注册,请直接登录'}
else: else:
return {'status': False, 'msg': '发送失败'} # 注册时手机号不存在,可以发送验证码
code = await generate_vcode()
nss = await send_vcode(mobile, '用户注册登录验证', {'SMSvCode': code.get('vcode')})
if nss['status']:
return {'status': True, 'msg': '注册验证码发送成功', 'codeid': code.get('id')}
else:
return {'status': False, 'msg': '发送失败'}
# 登录逻辑:检查手机号是否存在
elif action_type == 'login':
if len(userreacs) >= 1:
# 登录时手机号存在,可以发送验证码
code = await generate_vcode()
nss = await send_vcode(userreacs[0]['mobile'], '用户注册登录验证', {'SMSvCode': code.get('vcode')})
if nss['status']:
return {'status': True, 'msg': '登录验证码发送成功', 'codeid': code.get('id')}
else:
return {'status': False, 'msg': '发送失败'}
else:
return {'status': False, 'action': 'redirect', 'msg': '用户未注册, 请到注册页面注册'}
# 原有逻辑如果没有指定action_type保持原有逻辑
else: else:
return {'status': False, 'action': 'redirect', 'msg': '用户未注册, 请到注册页面注册'} type = 0
ns['del_flg'] = '0'
userreacs = await sor.R('users', ns)
if len(userreacs) >= 1:
type += 1
else:
userreacs = await sor.R('users', {'mobile': ns['username'], 'del_flg': '0'})
if len(userreacs) >= 1:
type += 1
if type >= 1:
code = await generate_vcode()
nss = await send_vcode(userreacs[0]['mobile'], '用户注册登录验证', {'SMSvCode': code.get('vcode')})
# return {'1':nss}
if nss:
return {'status': True, 'msg': '发送成功', 'codeid': code.get('id')}
else:
return {'status': False, 'msg': '发送失败'}
else:
return {'status': False, 'action': 'redirect', 'msg': '用户未注册, 请到注册页面注册'}
ret = await mobilecode(params_kw) ret = await mobilecode(params_kw)

View File

@ -85,8 +85,8 @@
"session_redis_delete":{ "session_redis_delete":{
"url":"redis://127.0.0.1:6379" "url":"redis://127.0.0.1:6379"
}, },
"session_max_time":3000, "session_max_time":30000,
"session_issue_time":2500 "session_issue_time":25000
}, },
"langMapping":{ "langMapping":{
"zh-Hans-CN":"zh-cn", "zh-Hans-CN":"zh-cn",

View File

@ -78,8 +78,8 @@
"privatekey":"$[workdir]$/conf/rsa_private_key.pem", "privatekey":"$[workdir]$/conf/rsa_private_key.pem",
"publickey":"$[workdir]$/conf/rsa_public_key.pem" "publickey":"$[workdir]$/conf/rsa_public_key.pem"
}, },
"session_max_time":3000, "session_max_time":30000,
"session_issue_time":2500 "session_issue_time":25000
}, },
"langMapping":{ "langMapping":{
"zh-Hans-CN":"zh-cn", "zh-Hans-CN":"zh-cn",

View File

@ -2,7 +2,7 @@
*/20 * * * * curl https://dev.kaiyuancloud.cn/zj/zj_get_order.dspy */20 * * * * curl https://dev.kaiyuancloud.cn/zj/zj_get_order.dspy
49 9-10 * * * curl https://dev.kaiyuancloud.cn/zj/zj_get_bill.dspy 49 9-10 * * * curl https://dev.kaiyuancloud.cn/zj/zj_get_bill.dspy
*/20 * * * * curl https://www.kaiyuancloud.cn/dev/hpc/GetUserBill.dspy > /d/zhc/crontab_dev.log 2>&1 #*/20 * * * * curl https://www.kaiyuancloud.cn/dev/hpc/GetUserBill.dspy > /d/zhc/crontab_dev.log 2>&1
0 0 * * * curl https://www.kaiyuancloud.cn/dev/lease/update_stock.dspy > /d/zhc/crontab_dev.log 2>&1 0 0 * * * curl https://www.kaiyuancloud.cn/dev/lease/update_stock.dspy > /d/zhc/crontab_dev.log 2>&1
# 30 9 * * * curl https://www.kaiyuancloud.cn/dev/provider_settle/auto_provider_settle_cron_job.dspy > /d/zhc/crontab_dev.log 2>&1 # 30 9 * * * curl https://www.kaiyuancloud.cn/dev/provider_settle/auto_provider_settle_cron_job.dspy > /d/zhc/crontab_dev.log 2>&1
# 0 1 * * * curl https://www.kaiyuancloud.cn/dev/handover/params_time.dspy > /d/zhc/crontab_dev.log 2>&1 # 0 1 * * * curl https://www.kaiyuancloud.cn/dev/handover/params_time.dspy > /d/zhc/crontab_dev.log 2>&1
@ -13,7 +13,7 @@
* * * * * curl https://www.kaiyuancloud.cn/dev/baiduc/baidu_new_update_resouce.dspy > /d/zhc/crontab_dev.log 2>&1 * * * * * curl https://www.kaiyuancloud.cn/dev/baiduc/baidu_new_update_resouce.dspy > /d/zhc/crontab_dev.log 2>&1
#* * * * * curl https://www.kaiyuancloud.cn/dev/baiduc/baidu_sms_kafka_consumer.dspy > /d/zhc/crontab_dev.log 2>&1 #* * * * * curl https://www.kaiyuancloud.cn/dev/baiduc/baidu_sms_kafka_consumer.dspy > /d/zhc/crontab_dev.log 2>&1
*/20 * * * * curl https://dev.opencomputing.cn/hpc/GetUserBill.dspy > /d/zhc/crontab_dev.log 2>&1 #*/20 * * * * curl https://dev.opencomputing.cn/hpc/GetUserBill.dspy > /d/zhc/crontab_dev.log 2>&1
0 0 * * * curl https://dev.opencomputing.cn/lease/update_stock.dspy > /d/zhc/crontab_dev.log 2>&1 0 0 * * * curl https://dev.opencomputing.cn/lease/update_stock.dspy > /d/zhc/crontab_dev.log 2>&1
# 30 9 * * * curl https://dev.opencomputing.cn/provider_settle/auto_provider_settle_cron_job.dspy > /d/zhc/crontab_dev.log 2>&1 # 30 9 * * * curl https://dev.opencomputing.cn/provider_settle/auto_provider_settle_cron_job.dspy > /d/zhc/crontab_dev.log 2>&1
# 0 1 * * * curl https://dev.opencomputing.cn/handover/params_time.dspy > /d/zhc/crontab_dev.log 2>&1 # 0 1 * * * curl https://dev.opencomputing.cn/handover/params_time.dspy > /d/zhc/crontab_dev.log 2>&1
@ -24,7 +24,7 @@
* * * * * curl https://dev.opencomputing.cn/baiduc/baidu_new_update_resouce.dspy > /d/zhc/crontab_dev.log 2>&1 * * * * * curl https://dev.opencomputing.cn/baiduc/baidu_new_update_resouce.dspy > /d/zhc/crontab_dev.log 2>&1
#* * * * * curl https://dev.opencomputing.cn/baiduc/baidu_sms_kafka_consumer.dspy > /d/zhc/crontab_dev.log 2>&1 #* * * * * curl https://dev.opencomputing.cn/baiduc/baidu_sms_kafka_consumer.dspy > /d/zhc/crontab_dev.log 2>&1
*/20 * * * * curl https://www.opencomputing.cn/hpc/GetUserBill.dspy > /d/zhc/crontab_prod.log 2>&1 #*/20 * * * * curl https://www.opencomputing.cn/hpc/GetUserBill.dspy > /d/zhc/crontab_prod.log 2>&1
0 0 * * * curl https://www.opencomputing.cn/lease/update_stock.dspy > /d/zhc/crontab_prod.log 2>&1 0 0 * * * curl https://www.opencomputing.cn/lease/update_stock.dspy > /d/zhc/crontab_prod.log 2>&1
# 30 9 * * * curl https://www.opencomputing.cn/provider_settle/auto_provider_settle_cron_job.dspy > /d/zhc/crontab_prod.log 2>&1 # 30 9 * * * curl https://www.opencomputing.cn/provider_settle/auto_provider_settle_cron_job.dspy > /d/zhc/crontab_prod.log 2>&1
# 0 1 * * * curl https://www.opencomputing.cn/handover/params_time.dspy > /d/zhc/crontab_prod.log 2>&1 # 0 1 * * * curl https://www.opencomputing.cn/handover/params_time.dspy > /d/zhc/crontab_prod.log 2>&1

14775
docs/API模块文档.md Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,10 +1,8 @@
.DS_Store .DS_Store
node_modules/ node_modules/
dist/ dist/
<<<<<<< HEAD
======= =======
# src/ # src/
>>>>>>> a3d0bd5845e8b37373bf85c7c40401a7c67884b9
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*

View File

@ -112,6 +112,7 @@ export default {
}, },
mounted() { mounted() {
this.audioElement = new Audio('https://www.kaiyuancloud.cn/dev/idfile?path=/batch_upload/phone-ring.mp3'); this.audioElement = new Audio('https://www.kaiyuancloud.cn/dev/idfile?path=/batch_upload/phone-ring.mp3');
// //
this.audioElement.loop = true; this.audioElement.loop = true;
if (sessionStorage.getItem('juese') === '销售' && !window.location.href.includes('login')) { if (sessionStorage.getItem('juese') === '销售' && !window.location.href.includes('login')) {
@ -270,11 +271,6 @@ export default {
padding: 5px 20px; padding: 5px 20px;
} }
.el-message--success {
/* border:1px dashed blue;
height: 45px; */
}
.el-table { .el-table {
z-index: 0 !important; z-index: 0 !important;
} }

View File

@ -0,0 +1,16 @@
import request from '@/utils/request'
// 获取token
export function baiducloudAPI() {
return request({
url: `/baiduc/get_tokenid.dspy`,
method: 'get',
})
}
// 退订回调
export function cancelCallbackAPI(params) {
return request({
url: `/baiducloud/get_baidu_orderlist.dspy`,
method: 'get',
params: params
})
}

View File

@ -28,7 +28,7 @@ export function getReachargelogAPI(params) {
//客户充值冲账 //客户充值冲账
export function editReachargelogAPI(params) { export function editReachargelogAPI(params) {
return request({ return request({
url: `examine/upledger_examine${suffix}`, url: `customer/mybalance.dspy`,
method: 'get', method: 'get',
params: params params: params
}) })

View File

@ -42,11 +42,11 @@ export function logoutAPI(params) {
}) })
} }
//获取验证码 1 //获取验证码
export function getCodeAPI(params) { export function getCodeAPI(params) {
return request({ return request({
url: `/user/mobilecode${suffix}`, url: `/user/mobilecode${suffix}`,
method: 'get', method: 'post',
params: params params: params
}) })
} }
@ -263,3 +263,23 @@ export function reqGetCodeAPI(data) {
}, },
}) })
} }
// 注册/登录获取验证码
export function sendCode(data) {
return request({
url: `/user/mobilecode.dspy`,
method: 'post',
data,
})
}
// 注册
export function register(data) {
console.log(data);
return request({
url: `/customer/registerUser${suffix}`,
method: 'post',
data,
})
}

View File

@ -94,3 +94,10 @@ export const reqQuickNav = () => {
method: 'post', method: 'post',
}) })
} }
// 待办数量
export const todoCount = () => {
return request({
url: '/bz_order/todo_info.dspy',
method: 'post',
})
}

View File

@ -119,3 +119,13 @@ export const reqSearchProductList = (data) => {
data data
}) })
} }
// 累计消费 共优惠
export const reqDiscount = (data) => {
return request({
url: '/bz_order/cumulative_order.dspy',
method: 'get',
headers: {'Content-Type': 'application/json'},
data
})
}

View File

@ -0,0 +1,539 @@
/* Logo 字体 */
@font-face {
font-family: "iconfont logo";
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
}
.logo {
font-family: "iconfont logo";
font-size: 160px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* tabs */
.nav-tabs {
position: relative;
}
.nav-tabs .nav-more {
position: absolute;
right: 0;
bottom: 0;
height: 42px;
line-height: 42px;
color: #666;
}
#tabs {
border-bottom: 1px solid #eee;
}
#tabs li {
cursor: pointer;
width: 100px;
height: 40px;
line-height: 40px;
text-align: center;
font-size: 16px;
border-bottom: 2px solid transparent;
position: relative;
z-index: 1;
margin-bottom: -1px;
color: #666;
}
#tabs .active {
border-bottom-color: #f00;
color: #222;
}
.tab-container .content {
display: none;
}
/* 页面布局 */
.main {
padding: 30px 100px;
width: 960px;
margin: 0 auto;
}
.main .logo {
color: #333;
text-align: left;
margin-bottom: 30px;
line-height: 1;
height: 110px;
margin-top: -50px;
overflow: hidden;
*zoom: 1;
}
.main .logo a {
font-size: 160px;
color: #333;
}
.helps {
margin-top: 40px;
}
.helps pre {
padding: 20px;
margin: 10px 0;
border: solid 1px #e7e1cd;
background-color: #fffdef;
overflow: auto;
}
.icon_lists {
width: 100% !important;
overflow: hidden;
*zoom: 1;
}
.icon_lists li {
width: 100px;
margin-bottom: 10px;
margin-right: 20px;
text-align: center;
list-style: none !important;
cursor: default;
}
.icon_lists li .code-name {
line-height: 1.2;
}
.icon_lists .icon {
display: block;
height: 100px;
line-height: 100px;
font-size: 42px;
margin: 10px auto;
color: #333;
-webkit-transition: font-size 0.25s linear, width 0.25s linear;
-moz-transition: font-size 0.25s linear, width 0.25s linear;
transition: font-size 0.25s linear, width 0.25s linear;
}
.icon_lists .icon:hover {
font-size: 100px;
}
.icon_lists .svg-icon {
/* 通过设置 font-size 来改变图标大小 */
width: 1em;
/* 图标和文字相邻时,垂直对齐 */
vertical-align: -0.15em;
/* 通过设置 color 来改变 SVG 的颜色/fill */
fill: currentColor;
/* path stroke 溢出 viewBox 部分在 IE 下会显示
normalize.css 中也包含这行 */
overflow: hidden;
}
.icon_lists li .name,
.icon_lists li .code-name {
color: #666;
}
/* markdown 样式 */
.markdown {
color: #666;
font-size: 14px;
line-height: 1.8;
}
.highlight {
line-height: 1.5;
}
.markdown img {
vertical-align: middle;
max-width: 100%;
}
.markdown h1 {
color: #404040;
font-weight: 500;
line-height: 40px;
margin-bottom: 24px;
}
.markdown h2,
.markdown h3,
.markdown h4,
.markdown h5,
.markdown h6 {
color: #404040;
margin: 1.6em 0 0.6em 0;
font-weight: 500;
clear: both;
}
.markdown h1 {
font-size: 28px;
}
.markdown h2 {
font-size: 22px;
}
.markdown h3 {
font-size: 16px;
}
.markdown h4 {
font-size: 14px;
}
.markdown h5 {
font-size: 12px;
}
.markdown h6 {
font-size: 12px;
}
.markdown hr {
height: 1px;
border: 0;
background: #e9e9e9;
margin: 16px 0;
clear: both;
}
.markdown p {
margin: 1em 0;
}
.markdown>p,
.markdown>blockquote,
.markdown>.highlight,
.markdown>ol,
.markdown>ul {
width: 80%;
}
.markdown ul>li {
list-style: circle;
}
.markdown>ul li,
.markdown blockquote ul>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown>ul li p,
.markdown>ol li p {
margin: 0.6em 0;
}
.markdown ol>li {
list-style: decimal;
}
.markdown>ol li,
.markdown blockquote ol>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown code {
margin: 0 3px;
padding: 0 5px;
background: #eee;
border-radius: 3px;
}
.markdown strong,
.markdown b {
font-weight: 600;
}
.markdown>table {
border-collapse: collapse;
border-spacing: 0px;
empty-cells: show;
border: 1px solid #e9e9e9;
width: 95%;
margin-bottom: 24px;
}
.markdown>table th {
white-space: nowrap;
color: #333;
font-weight: 600;
}
.markdown>table th,
.markdown>table td {
border: 1px solid #e9e9e9;
padding: 8px 16px;
text-align: left;
}
.markdown>table th {
background: #F7F7F7;
}
.markdown blockquote {
font-size: 90%;
color: #999;
border-left: 4px solid #e9e9e9;
padding-left: 0.8em;
margin: 1em 0;
}
.markdown blockquote p {
margin: 0;
}
.markdown .anchor {
opacity: 0;
transition: opacity 0.3s ease;
margin-left: 8px;
}
.markdown .waiting {
color: #ccc;
}
.markdown h1:hover .anchor,
.markdown h2:hover .anchor,
.markdown h3:hover .anchor,
.markdown h4:hover .anchor,
.markdown h5:hover .anchor,
.markdown h6:hover .anchor {
opacity: 1;
display: inline-block;
}
.markdown>br,
.markdown>p>br {
clear: both;
}
.hljs {
display: block;
background: white;
padding: 0.5em;
color: #333333;
overflow-x: auto;
}
.hljs-comment,
.hljs-meta {
color: #969896;
}
.hljs-string,
.hljs-variable,
.hljs-template-variable,
.hljs-strong,
.hljs-emphasis,
.hljs-quote {
color: #df5000;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-type {
color: #a71d5d;
}
.hljs-literal,
.hljs-symbol,
.hljs-bullet,
.hljs-attribute {
color: #0086b3;
}
.hljs-section,
.hljs-name {
color: #63a35c;
}
.hljs-tag {
color: #333333;
}
.hljs-title,
.hljs-attr,
.hljs-selector-id,
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo {
color: #795da3;
}
.hljs-addition {
color: #55a532;
background-color: #eaffea;
}
.hljs-deletion {
color: #bd2c00;
background-color: #ffecec;
}
.hljs-link {
text-decoration: underline;
}
/* 代码高亮 */
/* PrismJS 1.15.0
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection,
pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection,
code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection,
pre[class*="language-"] ::selection,
code[class*="language-"]::selection,
code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre)>code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre)>code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #9a6e3a;
background: hsla(0, 0%, 100%, .5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function,
.token.class-name {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}

View File

@ -0,0 +1,418 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>iconfont Demo</title>
<link rel="shortcut icon" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg" type="image/x-icon"/>
<link rel="icon" type="image/svg+xml" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg"/>
<link rel="stylesheet" href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css">
<link rel="stylesheet" href="demo.css">
<link rel="stylesheet" href="iconfont.css">
<script src="iconfont.js"></script>
<!-- jQuery -->
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/7bfddb60-08e8-11e9-9b04-53e73bb6408b.js"></script>
<!-- 代码高亮 -->
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/a3f714d0-08e6-11e9-8a15-ebf944d7534c.js"></script>
<style>
.main .logo {
margin-top: 0;
height: auto;
}
.main .logo a {
display: flex;
align-items: center;
}
.main .logo .sub-title {
margin-left: 0.5em;
font-size: 22px;
color: #fff;
background: linear-gradient(-45deg, #3967FF, #B500FE);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
</style>
</head>
<body>
<div class="main">
<h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 首页" target="_blank">
<img width="200" src="https://img.alicdn.com/imgextra/i3/O1CN01Mn65HV1FfSEzR6DKv_!!6000000000514-55-tps-228-59.svg">
</a></h1>
<div class="nav-tabs">
<ul id="tabs" class="dib-box">
<li class="dib active"><span>Unicode</span></li>
<li class="dib"><span>Font class</span></li>
<li class="dib"><span>Symbol</span></li>
</ul>
<a href="https://www.iconfont.cn/manage/index?manage_type=myprojects&projectId=5043107" target="_blank" class="nav-more">查看项目</a>
</div>
<div class="tab-container">
<div class="content unicode" style="display: block;">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont">&#xe61b;</span>
<div class="name">复制</div>
<div class="code-name">&amp;#xe61b;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe64c;</span>
<div class="name">大类-全部产品</div>
<div class="code-name">&amp;#xe64c;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe641;</span>
<div class="name">资源管理器</div>
<div class="code-name">&amp;#xe641;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe616;</span>
<div class="name">社区服务</div>
<div class="code-name">&amp;#xe616;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe648;</span>
<div class="name">复制</div>
<div class="code-name">&amp;#xe648;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe602;</span>
<div class="name">订单管理</div>
<div class="code-name">&amp;#xe602;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe625;</span>
<div class="name">客服</div>
<div class="code-name">&amp;#xe625;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xebbb;</span>
<div class="name">地图_地球_o</div>
<div class="code-name">&amp;#xebbb;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe60a;</span>
<div class="name">消息</div>
<div class="code-name">&amp;#xe60a;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe65f;</span>
<div class="name">AI助手</div>
<div class="code-name">&amp;#xe65f;</div>
</li>
</ul>
<div class="article markdown">
<h2 id="unicode-">Unicode 引用</h2>
<hr>
<p>Unicode 是字体在网页端最原始的应用方式,特点是:</p>
<ul>
<li>支持按字体的方式去动态调整图标大小,颜色等等。</li>
<li>默认情况下不支持多色,直接添加多色图标会自动去色。</li>
</ul>
<blockquote>
<p>注意:新版 iconfont 支持两种方式引用多色图标SVG symbol 引用方式和彩色字体图标模式。(使用彩色字体图标需要在「编辑项目」中开启「彩色」选项后并重新生成。)</p>
</blockquote>
<p>Unicode 使用步骤如下:</p>
<h3 id="-font-face">第一步:拷贝项目下面生成的 <code>@font-face</code></h3>
<pre><code class="language-css"
>@font-face {
font-family: 'iconfont';
src: url('iconfont.woff2?t=1760930186762') format('woff2'),
url('iconfont.woff?t=1760930186762') format('woff'),
url('iconfont.ttf?t=1760930186762') format('truetype');
}
</code></pre>
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
<pre><code class="language-css"
>.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
</code></pre>
<h3 id="-">第三步:挑选相应图标并获取字体编码,应用于页面</h3>
<pre>
<code class="language-html"
>&lt;span class="iconfont"&gt;&amp;#x33;&lt;/span&gt;
</code></pre>
<blockquote>
<p>"iconfont" 是你项目下的 font-family。可以通过编辑项目查看默认是 "iconfont"。</p>
</blockquote>
</div>
</div>
<div class="content font-class">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont icon-fuzhi"></span>
<div class="name">
复制
</div>
<div class="code-name">.icon-fuzhi
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-dalei-quanbuchanpin"></span>
<div class="name">
大类-全部产品
</div>
<div class="code-name">.icon-dalei-quanbuchanpin
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-ziyuanguanliqi"></span>
<div class="name">
资源管理器
</div>
<div class="code-name">.icon-ziyuanguanliqi
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-shequfuwu"></span>
<div class="name">
社区服务
</div>
<div class="code-name">.icon-shequfuwu
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-fuzhi-"></span>
<div class="name">
复制
</div>
<div class="code-name">.icon-fuzhi-
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-dingdanguanli"></span>
<div class="name">
订单管理
</div>
<div class="code-name">.icon-dingdanguanli
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-kefu"></span>
<div class="name">
客服
</div>
<div class="code-name">.icon-kefu
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-ditu_diqiu_o"></span>
<div class="name">
地图_地球_o
</div>
<div class="code-name">.icon-ditu_diqiu_o
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-xiaoxi"></span>
<div class="name">
消息
</div>
<div class="code-name">.icon-xiaoxi
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-AIzhushou"></span>
<div class="name">
AI助手
</div>
<div class="code-name">.icon-AIzhushou
</div>
</li>
</ul>
<div class="article markdown">
<h2 id="font-class-">font-class 引用</h2>
<hr>
<p>font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。</p>
<p>与 Unicode 使用方式相比,具有如下特点:</p>
<ul>
<li>相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。</li>
<li>因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。</li>
</ul>
<p>使用步骤如下:</p>
<h3 id="-fontclass-">第一步:引入项目下面生成的 fontclass 代码:</h3>
<pre><code class="language-html">&lt;link rel="stylesheet" href="./iconfont.css"&gt;
</code></pre>
<h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3>
<pre><code class="language-html">&lt;span class="iconfont icon-xxx"&gt;&lt;/span&gt;
</code></pre>
<blockquote>
<p>"
iconfont" 是你项目下的 font-family。可以通过编辑项目查看默认是 "iconfont"。</p>
</blockquote>
</div>
</div>
<div class="content symbol">
<ul class="icon_lists dib-box">
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-fuzhi"></use>
</svg>
<div class="name">复制</div>
<div class="code-name">#icon-fuzhi</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-dalei-quanbuchanpin"></use>
</svg>
<div class="name">大类-全部产品</div>
<div class="code-name">#icon-dalei-quanbuchanpin</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-ziyuanguanliqi"></use>
</svg>
<div class="name">资源管理器</div>
<div class="code-name">#icon-ziyuanguanliqi</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-shequfuwu"></use>
</svg>
<div class="name">社区服务</div>
<div class="code-name">#icon-shequfuwu</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-fuzhi-"></use>
</svg>
<div class="name">复制</div>
<div class="code-name">#icon-fuzhi-</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-dingdanguanli"></use>
</svg>
<div class="name">订单管理</div>
<div class="code-name">#icon-dingdanguanli</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-kefu"></use>
</svg>
<div class="name">客服</div>
<div class="code-name">#icon-kefu</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-ditu_diqiu_o"></use>
</svg>
<div class="name">地图_地球_o</div>
<div class="code-name">#icon-ditu_diqiu_o</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-xiaoxi"></use>
</svg>
<div class="name">消息</div>
<div class="code-name">#icon-xiaoxi</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-AIzhushou"></use>
</svg>
<div class="name">AI助手</div>
<div class="code-name">#icon-AIzhushou</div>
</li>
</ul>
<div class="article markdown">
<h2 id="symbol-">Symbol 引用</h2>
<hr>
<p>这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a href="">文章</a>
这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:</p>
<ul>
<li>支持多色图标了,不再受单色限制。</li>
<li>通过一些技巧,支持像字体那样,通过 <code>font-size</code>, <code>color</code> 来调整样式。</li>
<li>兼容性较差,支持 IE9+,及现代浏览器。</li>
<li>浏览器渲染 SVG 的性能一般,还不如 png。</li>
</ul>
<p>使用步骤如下:</p>
<h3 id="-symbol-">第一步:引入项目下面生成的 symbol 代码:</h3>
<pre><code class="language-html">&lt;script src="./iconfont.js"&gt;&lt;/script&gt;
</code></pre>
<h3 id="-css-">第二步:加入通用 CSS 代码(引入一次就行):</h3>
<pre><code class="language-html">&lt;style&gt;
.icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
&lt;/style&gt;
</code></pre>
<h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3>
<pre><code class="language-html">&lt;svg class="icon" aria-hidden="true"&gt;
&lt;use xlink:href="#icon-xxx"&gt;&lt;/use&gt;
&lt;/svg&gt;
</code></pre>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function () {
$('.tab-container .content:first').show()
$('#tabs li').click(function (e) {
var tabContent = $('.tab-container .content')
var index = $(this).index()
if ($(this).hasClass('active')) {
return
} else {
$('#tabs li').removeClass('active')
$(this).addClass('active')
tabContent.hide().eq(index).fadeIn()
}
})
})
</script>
</body>
</html>

View File

@ -0,0 +1,55 @@
@font-face {
font-family: "iconfont"; /* Project id 5043107 */
src: url('iconfont.woff2?t=1760930186762') format('woff2'),
url('iconfont.woff?t=1760930186762') format('woff'),
url('iconfont.ttf?t=1760930186762') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-fuzhi:before {
content: "\e61b";
}
.icon-dalei-quanbuchanpin:before {
content: "\e64c";
}
.icon-ziyuanguanliqi:before {
content: "\e641";
}
.icon-shequfuwu:before {
content: "\e616";
}
.icon-fuzhi-:before {
content: "\e648";
}
.icon-dingdanguanli:before {
content: "\e602";
}
.icon-kefu:before {
content: "\e625";
}
.icon-ditu_diqiu_o:before {
content: "\ebbb";
}
.icon-xiaoxi:before {
content: "\e60a";
}
.icon-AIzhushou:before {
content: "\e65f";
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,79 @@
{
"id": "5043107",
"name": "kboos",
"font_family": "iconfont",
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "300409",
"name": "复制",
"font_class": "fuzhi",
"unicode": "e61b",
"unicode_decimal": 58907
},
{
"icon_id": "10621831",
"name": "大类-全部产品",
"font_class": "dalei-quanbuchanpin",
"unicode": "e64c",
"unicode_decimal": 58956
},
{
"icon_id": "11121510",
"name": "资源管理器",
"font_class": "ziyuanguanliqi",
"unicode": "e641",
"unicode_decimal": 58945
},
{
"icon_id": "12459826",
"name": "社区服务",
"font_class": "shequfuwu",
"unicode": "e616",
"unicode_decimal": 58902
},
{
"icon_id": "12562411",
"name": "复制",
"font_class": "fuzhi-",
"unicode": "e648",
"unicode_decimal": 58952
},
{
"icon_id": "19657695",
"name": "订单管理",
"font_class": "dingdanguanli",
"unicode": "e602",
"unicode_decimal": 58882
},
{
"icon_id": "2674476",
"name": "客服",
"font_class": "kefu",
"unicode": "e625",
"unicode_decimal": 58917
},
{
"icon_id": "5388029",
"name": "地图_地球_o",
"font_class": "ditu_diqiu_o",
"unicode": "ebbb",
"unicode_decimal": 60347
},
{
"icon_id": "31157387",
"name": "消息",
"font_class": "xiaoxi",
"unicode": "e60a",
"unicode_decimal": 58890
},
{
"icon_id": "44896696",
"name": "AI助手",
"font_class": "AIzhushou",
"unicode": "e65f",
"unicode_decimal": 58975
}
]
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1001 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

@ -26,10 +26,11 @@
<div @click="open2" <div @click="open2"
style="position:absolute;bottom:-40px;display: flex;justify-content: center;align-items: center;cursor: pointer"> style="position:absolute;bottom:-40px;display: flex;justify-content: center;align-items: center;cursor: pointer">
<el-tooltip v-if="getHomePath()!=='/ncmatchHome/index'" class="item" effect="light" content="联系销售" placement="left"> <!-- 摄像头 -->
<!-- <el-tooltip v-if="getHomePath()!=='/ncmatchHome/index'" class="item" effect="light" content="联系销售" placement="left">
<span class="el-icon-video-camera" <span class="el-icon-video-camera"
style="font-weight: 550;font-size: 22px;"></span> style="font-weight: 550;font-size: 22px;"></span>
</el-tooltip> </el-tooltip> -->
<!-- </div>--> <!-- </div>-->
<!-- <div class="cart-entry-wrapper" style="visibility: visible;">--> <!-- <div class="cart-entry-wrapper" style="visibility: visible;">-->
@ -88,13 +89,13 @@
class="cloud-contact-us-icon"></span> class="cloud-contact-us-icon"></span>
<p class="cloud-contact-us-tit" style="font-size: 14px;">售前咨询</p> <p class="cloud-contact-us-tit" style="font-size: 14px;">售前咨询</p>
</div> </div>
<div style=";display: flex;justify-content: center;align-items: center;" <div style="display: flex;justify-content: center;align-items: center;"
> >
<div v-if="!phone" <div v-if="!phone"
style="width: 80px;height: 25px;display: flex!important;justify-content: center;align-items: center"> style="width: 80px;height: 25px;display: flex!important;justify-content: center;align-items: center">
<el-skeleton <el-skeleton
style="width: 100%;padding: 0;margin: 0;height: 100%;margin-top: -25px" style="width: 100%;padding: 0;margin: 0;height: 100%;margin-top: -25px"
rows="1" :rows="1"
animated/> animated/>
</div> </div>
<p v-else class="cloud-contact-us-con" style="font-size: 12px;height: 20px;margin-top: 5px"> <p v-else class="cloud-contact-us-con" style="font-size: 12px;height: 20px;margin-top: 5px">
@ -991,6 +992,7 @@ export default {
background-color: white; background-color: white;
box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.5); box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.5);
padding: 10px; padding: 10px;
z-index: 11;
} }
@keyframes slideInRight { @keyframes slideInRight {

View File

@ -0,0 +1,95 @@
<template>
<div>
<div class="sticky" v-show="shouldShow">
<div
class="sticky-box"
@click="navigateTo(index)"
v-for="(item, index) in sections"
:key="index"
>
{{ item.title }}
</div>
</div>
</div>
</template>
<script>
export default {
name: 'StickyNavigation',
props: {
//
sections: {
type: Array,
required: true,
default: () => []
}
},
data() {
return {
shouldShow: false
}
},
methods: {
// handleScroll(){
// console.log("");
// },
checkScreenHeight() {
console.log(9999);
const screenHeight = window.innerHeight;
//
this.shouldShow = screenHeight >= 900;
},
//
navigateTo(index) {
// console.log(':', index);
// $emit 'navigate'
this.$emit('navigate', index);
}
},
mounted() {
this.checkScreenHeight();
// window.addEventListener('scroll', this.handleScroll);
},
beforeDestroy() {
// window.removeEventListener('scroll', this.handleScroll);
}
}
</script>
<style lang="less" scoped>
.sticky {
position: fixed;
top: 0;
left: 0;
width: 100%;
display: flex;
background-color: #fff;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
z-index: 100;
padding: 10px 0;
}
.sticky-box {
font-size: 16px;
font-weight: 500;
margin: 0 20px;
padding: 10px 20px;
color: #000;
cursor: pointer;
border-radius: 4px;
transition: all 0.3s ease;
}
.sticky-box:hover {
color: #366EF4;
background-color: #f0f8ff;
}
</style>

View File

@ -0,0 +1,793 @@
<template>
<div class="message-center-wrapper">
<!-- 移动端通知弹框 -->
<el-drawer
:visible.sync="internalVisible"
v-if="isMobile"
direction="rtl"
:with-header="false"
size="90%"
class="drawerMobile"
:modal="true"
:modal-append-to-body="true"
:append-to-body="true"
@close="handleClose"
>
<el-container class="container">
<el-aside width="95px" class="aside">
<div class="header">消息中心</div>
<div class="title">
<div @click="tab(1)" :class="{ active: tab_index === 1 }" class="info">全部消息</div>
<div @click="tab(2)" :class="{ active: tab_index === 2 }" class="info">未读消息</div>
<div @click="tab(3)" :class="{ active: tab_index === 3 }" class="info">已读消息</div>
</div>
</el-aside>
<el-container class="content_box">
<el-header class="header">| {{ tabTitle }}</el-header>
<el-main class="content">
<!-- 全部信息 -->
<div v-if="tab_index == 1" class="allinfo">
<div class="button">
<el-button size="mini" type="primary" @click="readMassage">已读</el-button>
<el-button size="mini" type="danger" @click="delMessage">删除</el-button>
</div>
<el-table
:header-cell-style="rowClass"
@expand-change="expandChangeHandler"
ref="table"
@row-click="expandChangeHandler1"
class="table"
:row-class-name="rowStyle"
:data="alliInformationList ? alliInformationList : []"
height="680"
tooltip-effect="dark"
@selection-change="handleSelectionChange"
style="width: 100%"
>
<el-table-column type="expand" width="30px">
<template slot-scope="props">
<div class="msgtext">
{{ props.row.msgtext }}
</div>
</template>
</el-table-column>
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column label="消息内容" prop="msgtype" :show-overflow-tooltip="true">
</el-table-column>
<el-table-column prop="sendtime" label="接收时间">
</el-table-column>
</el-table>
</div>
<!-- 未读信息 -->
<div v-if="tab_index == 2" class="noreadinfo">
<div class="button">
<el-button size="mini" type="primary" @click="readMassage">已读</el-button>
<el-button size="mini" type="danger" @click="delMessage">删除</el-button>
</div>
<el-table
:header-cell-style="rowClass"
@row-click="expandChangeHandler1"
class="table"
ref="table"
@expand-change="expandChangeHandler"
:row-class-name="rowStyle"
:data="unreadMessageList"
height="680"
tooltip-effect="dark"
@selection-change="handleSelectionChange"
style="width: 100%"
>
<el-table-column type="expand" width="30px">
<template slot-scope="props">
<div class="msgtext">
{{ props.row.msgtext }}
</div>
</template>
</el-table-column>
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column label="消息内容" prop="msgtype" :show-overflow-tooltip="true">
</el-table-column>
<el-table-column prop="sendtime" label="接收时间">
</el-table-column>
</el-table>
</div>
<!-- 已读信息 -->
<div v-if="tab_index == 3" class="readinfo">
<div class="button">
<el-button size="mini" type="danger" @click="delMessage">删除</el-button>
</div>
<el-table
:header-cell-style="rowClass"
ref="table"
class="table"
@row-click="expandChangeHandler2"
@expand-change="expandChangeHandler"
@selection-change="handleSelectionChange"
:row-class-name="rowStyle"
:data="readInformationList"
height="680"
tooltip-effect="dark"
style="width: 100%"
>
<el-table-column type="expand" width="30px">
<template slot-scope="props">
<div class="msgtext">
{{ props.row.msgtext }}
</div>
</template>
</el-table-column>
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column label="消息内容" prop="msgtype" :show-overflow-tooltip="true">
</el-table-column>
<el-table-column prop="sendtime" label="接收时间">
</el-table-column>
</el-table>
</div>
</el-main>
</el-container>
</el-container>
</el-drawer>
<!-- 桌面端通知弹框 -->
<el-drawer
:visible.sync="internalVisible"
v-else
direction="rtl"
:with-header="false"
size="70%"
class="drawer"
:modal="true"
:modal-append-to-body="true"
:append-to-body="true"
@close="handleClose"
>
<el-container style="height: 100vh">
<el-aside width="200px" class="aside">
<div class="header" style="font-size:16px;">消息中心</div>
<div class="title">
<div @click="tab(1)" :class="{ active: tab_index === 1 }" style="font-size:16px;">全部消息</div>
<div @click="tab(2)" :class="{ active: tab_index === 2 }" style="font-size:16px;">未读消息</div>
<div @click="tab(3)" :class="{ active: tab_index === 3 }" style="font-size:16px;">已读消息</div>
</div>
</el-aside>
<el-container class="content_box">
<el-header class="header">| {{ tabTitle }}</el-header>
<el-main class="content">
<!-- 全部信息 -->
<div v-if="tab_index == 1">
<div class="button" style="display:flex;">
<el-button size="small" type="primary" @click="readMassage">已读</el-button>
<el-button size="small" type="danger" @click="delMessage">删除</el-button>
</div>
<el-table
@expand-change="expandChangeHandler"
ref="table"
@row-click="expandChangeHandler1"
class="table"
:row-class-name="rowStyle"
:data="alliInformationList ? alliInformationList : []"
height="780"
tooltip-effect="dark"
style="width: 100%"
@selection-change="handleSelectionChange"
>
<el-table-column type="expand" width="30px">
<template slot-scope="props">
<div class="msgtext">
{{ props.row.msgtext }}
</div>
</template>
</el-table-column>
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column label="消息内容" prop="msgtype" :show-overflow-tooltip="true">
</el-table-column>
<el-table-column prop="sendtime" label="接收时间">
</el-table-column>
</el-table>
</div>
<!-- 未读信息 -->
<div v-if="tab_index == 2">
<div class="button" style="display:flex;">
<el-button size="small" type="primary" @click="readMassage">已读</el-button>
<el-button size="small" type="danger" @click="delMessage">删除</el-button>
</div>
<el-table
@row-click="expandChangeHandler1"
ref="table"
@expand-change="expandChangeHandler"
:row-class-name="rowStyle"
:data="unreadMessageList"
height="780"
tooltip-effect="dark"
style="width: 100%"
@selection-change="handleSelectionChange"
>
<el-table-column type="expand" width="30px">
<template slot-scope="props">
<div class="msgtext">
{{ props.row.msgtext }}
</div>
</template>
</el-table-column>
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column label="消息内容" prop="msgtype" :show-overflow-tooltip="true">
</el-table-column>
<el-table-column prop="sendtime" label="接收时间">
</el-table-column>
</el-table>
</div>
<!-- 已读信息 -->
<div v-if="tab_index == 3">
<div class="button" style="display:flex;">
<el-button size="small" type="danger" @click="delMessage">删除</el-button>
</div>
<el-table
ref="table"
@row-click="expandChangeHandler2"
@expand-change="expandChangeHandler"
@selection-change="handleSelectionChange"
:row-class-name="rowStyle"
:data="readInformationList"
height="780"
tooltip-effect="dark"
style="width: 100%"
>
<el-table-column type="expand" width="30px">
<template slot-scope="props">
<div class="msgtext">
{{ props.row.msgtext }}
</div>
</template>
</el-table-column>
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column label="消息内容" prop="msgtype" :show-overflow-tooltip="true">
</el-table-column>
<el-table-column prop="sendtime" label="接收时间">
</el-table-column>
</el-table>
</div>
</el-main>
</el-container>
</el-container>
</el-drawer>
</div>
</template>
<script>
import {
getUnreadmsgAPI,
getMsgAPI,
getReadmsgAPI,
upMsgAPI,
delMsgAPI
} from "@/api/login";
export default {
name: 'MessageCenter',
props: {
userId: {
type: [String, Number],
required: false,
default: null
},
visible: {
type: Boolean,
default: false
}
},
data() {
return {
isMobile: false,
alliInformationList: [], //
unreadMessageList: [], //
readInformationList: [], //
readIdList: [],
count: 0,
internalVisible: false, //
tabTitle: "消息中心",
tab_index: 1,
isUpdate: false,
oneId: '',
isOne: false,
originalBodyOverflow: '' // body overflow
};
},
watch: {
// visible
visible: {
immediate: true,
handler(newVal) {
console.log('MessageCenter visible changed:', newVal);
this.internalVisible = newVal;
if (newVal) {
this.getMsg();
this.preventBodyScroll();
} else {
this.restoreBodyScroll();
}
}
},
// visible
internalVisible(newVal) {
if (newVal !== this.visible) {
this.$emit('update:visible', newVal);
}
if (!newVal) {
this.getUnreadmsg();
this.restoreBodyScroll();
}
}
},
mounted() {
//
this.checkMobile();
this.getUnreadmsg();
},
beforeDestroy() {
// body
this.restoreBodyScroll();
},
methods: {
//
checkMobile() {
const userAgent = window.navigator.userAgent;
this.isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent);
console.log('Is mobile device:', this.isMobile);
},
// body
preventBodyScroll() {
this.originalBodyOverflow = document.body.style.overflow;
document.body.style.overflow = 'hidden';
},
// body
restoreBodyScroll() {
document.body.style.overflow = this.originalBodyOverflow || '';
},
//
open() {
console.log('MessageCenter open method called');
this.internalVisible = true;
this.getMsg();
this.preventBodyScroll();
},
//
close() {
console.log('MessageCenter close method called');
this.internalVisible = false;
this.restoreBodyScroll();
},
//
handleClose() {
console.log('MessageCenter handleClose called');
this.close();
},
rowClass() {
return "font-size:14px;";
},
getUnreadmsg() {
//
const userId = sessionStorage.getItem('userId');
if (!userId) {
console.log('用户未登录,跳过获取未读消息');
return;
}
getUnreadmsgAPI().then(res => {
if (res.status) {
this.count = res.count;
this.unreadMessageList = res.messages;
//
this.$emit('unread-count-update', res.count);
} else {
this.$message({
message: res.msg,
type: "error",
});
}
}).catch(error => {
console.error('获取未读消息失败:', error);
// 401
if (error.response && error.response.status !== 401) {
this.$message({
message: "获取未读消息失败",
type: "error",
});
}
});
},
getReadmsg() {
//
const userId = sessionStorage.getItem('userId');
if (!userId) {
console.log('用户未登录,跳过获取已读消息');
return;
}
getReadmsgAPI().then(res => {
if (res.status) {
this.readInformationList = res.msg;
} else {
this.$message({
message: res.msg,
type: "error",
});
}
}).catch(error => {
console.error('获取已读消息失败:', error);
this.$message({
message: "获取已读消息失败",
type: "error",
});
});
},
rowStyle({ row, rowIndex }) {
if (this.isOne == true && row.id == this.oneId) {
return 'unReadColor';
} else if (row.msgstatus == 1) {
return 'unReadColor';
}
return '';
},
handleSelectionChange(selection) {
if (selection) {
this.readIdList = [];
selection.forEach(item => {
this.readIdList.push(item.id);
});
console.log('Selected messages:', this.readIdList);
}
},
getMsg() {
//
const userId = sessionStorage.getItem('userId');
if (!userId) {
console.log('用户未登录,跳过获取消息');
return;
}
getMsgAPI({ userid: userId }).then(res => {
if (res.status && res.msg) {
this.alliInformationList = res.msg;
} else {
this.$message({
message: res.msg || "获取消息失败",
type: "error",
});
}
}).catch(error => {
console.error('获取消息失败:', error);
this.$message({
message: "获取消息失败",
type: "error",
});
});
},
readMassage() {
this.isUpdate = true;
if (this.readIdList.length) {
this.upMsg(this.readIdList);
} else {
this.$message({
message: "请选择要标记为已读的消息",
type: "warning",
});
}
},
upMsg(data) {
let params = {
msgids: data
};
upMsgAPI(params).then(res => {
if (res.status) {
this.$message({
message: "一键已读成功",
type: "success",
});
if (this.tab_index == 1) {
this.getMsg();
} else if (this.tab_index == 2) {
this.getUnreadmsg();
}
//
this.getUnreadmsg();
} else {
this.$message({
message: res.msg,
type: "error",
});
}
}).catch(error => {
console.error('标记已读失败:', error);
this.$message({
message: "标记已读失败",
type: "error",
});
});
},
delMsg(data) {
let params = {
id: data
};
delMsgAPI(params).then(res => {
if (res.status) {
this.$message({
message: "删除成功",
type: "success",
});
if (this.tab_index == 1) {
this.getMsg();
} else if (this.tab_index == 2) {
this.getUnreadmsg();
} else if (this.tab_index == 3) {
this.getReadmsg();
}
//
this.getUnreadmsg();
} else {
this.$message({
message: res.msg,
type: "error",
});
}
}).catch(error => {
console.error('删除消息失败:', error);
this.$message({
message: "删除消息失败",
type: "error",
});
});
},
delMessage() {
if (this.readIdList.length) {
this.$confirm('确定要删除选中的消息吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.delMsg(this.readIdList);
}).catch(() => {
//
});
} else {
this.$message({
message: "请选择要删除的消息",
type: "warning",
});
}
},
expandChangeHandler(row) {
this.isOne = true;
this.oneId = row.id;
let params = {
msgids: [row.id]
};
upMsgAPI(params).then(res => {
if (res.status) {
this.rowStyle(row);
//
this.getUnreadmsg();
} else {
this.$message({
message: res.msg,
type: "error",
});
}
}).catch(error => {
console.error('标记消息已读失败:', error);
});
},
expandChangeHandler1(row) {
this.isUpdate = true;
if (this.$refs.table) {
this.$refs.table.toggleRowExpansion(row);
}
this.expandChangeHandler(row);
},
expandChangeHandler2(row) {
if (this.$refs.table) {
this.$refs.table.toggleRowExpansion(row);
}
},
tab(i) {
this.tab_index = i;
if (i == 1) {
this.tabTitle = "全部消息";
this.getMsg();
} else if (i == 2) {
this.tabTitle = "未读消息";
this.getUnreadmsg();
} else {
this.tabTitle = "已读消息";
this.getReadmsg();
}
}
}
};
</script>
<style scoped lang="scss">
.message-center-wrapper {
position: relative;
z-index: 10000;
}
.drawer, .drawerMobile {
z-index: 10001 !important;
::v-deep .el-drawer {
z-index: 10002 !important;
}
::v-deep .el-drawer__wrapper {
z-index: 10001 !important;
}
::v-deep .el-drawer__container {
z-index: 10001 !important;
}
::v-deep .el-drawer__header {
margin-bottom: 0;
}
}
.aside {
padding: 0;
margin: 0;
background-color: #f5f7fa;
.header {
padding-left: 20px;
height: 60px;
line-height: 60px;
font-weight: 600;
background-color: #d9dee4;
border-bottom: 1px solid #e6e6e6;
}
.title div {
padding-left: 35px;
height: 50px;
line-height: 50px;
cursor: pointer;
transition: background-color 0.3s;
&:hover {
background-color: #ebedf0;
}
&.active {
background-color: #e1e5eb;
color: #409eff;
font-weight: bold;
}
}
}
.content_box {
background-color: #fff;
padding: 0 10px;
.header {
font-size: 22px;
line-height: 60px;
border-bottom: 1px solid #e6e6e6;
font-weight: bold;
color: #333;
}
.msgtext {
padding: 15px;
background-color: #f9f9f9;
border-radius: 4px;
line-height: 1.6;
color: #666;
}
.button {
padding-bottom: 15px;
border-bottom: 1px solid #e6e6e6;
margin-bottom: 15px;
}
}
/* 表格样式优化 */
::v-deep .el-table {
.el-table__row {
cursor: pointer;
&:hover {
background-color: #f5f7fa !important;
}
}
.el-table__expanded-cell {
padding: 10px !important;
}
}
/* 移动端样式优化 */
.drawerMobile {
.container {
height: 100vh;
.aside {
.header {
font-size: 14px;
}
.title {
.info {
font-size: 12px;
padding-left: 20px;
}
}
}
.content_box {
.header {
font-size: 16px;
}
.content {
.allinfo, .readinfo, .noreadinfo {
.button {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.table {
width: 100%;
}
}
}
}
}
}
/* 响应式调整 */
@media (max-width: 768px) {
.drawerMobile {
::v-deep .el-drawer {
width: 90% !important;
}
}
}
/* 确保所有交互元素可点击 */
::v-deep .el-button {
cursor: pointer !important;
}
::v-deep .el-table__row {
cursor: pointer !important;
}
::v-deep .el-drawer__body {
overflow: auto;
}
</style>

View File

@ -1,101 +1,545 @@
<template> <template>
<div :class="{'hidden':hidden}" class="pagination-container"> <div v-loading="loading" class="customerGood">
<el-pagination <!-- 搜索部分 -->
:background="background" <div>
:current-page.sync="currentPage" <ul class="search-box">
:page-size.sync="pageSize" <li>
:layout="layout" <el-input-group class="search-input">
:page-sizes="pageSizes" <el-input
:total="total" size="mini"
v-bind="$attrs" placeholder="请输入关键词"
@size-change="handleSizeChange" v-model="queryParams.productname"
@current-change="handleCurrentChange" clearable
/> @keyup.enter.native="handleSearch"
></el-input>
<el-button
slot="append"
icon="el-icon-search"
size="mini"
@click="handleSearch"
></el-button>
</el-input-group>
</li>
<li>
<span class="search-label">创建日期:</span>
<el-date-picker
size="mini"
style="width: 220px;"
type="datetimerange"
align="right"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="['00:00:00', '23:59:59']"
format="yyyy-MM-dd"
value-format="yyyy-MM-dd"
v-model="dateRange"
@change="handleDateChange"
></el-date-picker>
</li>
<li>
<el-button size="mini" @click="handleReset">重置</el-button>
<el-button type="primary" size="mini" @click="handleSearch">查询</el-button>
</li>
</ul>
</div>
<!-- 表格部分 -->
<el-card class="tableCard">
<el-table
:data="tableData"
style="width: 100%;font-size: 12px"
height="calc(100vh - 230px)"
border
v-loading="loading"
>
<el-table-column min-width="90px" align="center" prop="productname" label="产品名称"></el-table-column>
<el-table-column min-width="150px" align="center" prop="productdesc" label="产品描述" :show-overflow-tooltip="true">
<template slot-scope="{row}">
{{ row.productdesc ? row.productdesc : '-' }}
</template>
</el-table-column>
<el-table-column min-width="150px" align="center" prop="orderid" label="订单号" :show-overflow-tooltip="true"></el-table-column>
<el-table-column min-width="60px" align="center" prop="start_date" label="购买日期"></el-table-column>
<el-table-column prop="expire_date" label="到期日期">
<template slot-scope="scope">
{{ scope.row.expire_date == null ? '-' : scope.row.expire_date }}
</template>
</el-table-column>
<el-table-column prop="" label="操作" align="center" width="120px">
<template slot-scope="scope">
<el-button type="primary" size="mini" @click="goJiNanChaoSuan()" v-if="scope.row.providername === '济南超算'">
<div style="display: flex;justify-content: center;align-items: center">
<img style="width: 12px;margin-right: 5px;height: 12px;" src="./svg/跳转.svg" alt="">超算产品
</div>
</el-button>
<el-button type="primary" size="mini" @click="goBaiDu(scope.row.product_url)" v-else-if="(scope.row.providername === '百度智能云')">
<div style="display: flex;justify-content: center;align-items: center">
<img style="width: 12px;margin-right: 5px;height: 12px;" src="./svg/跳转.svg" alt="">实例使用
</div>
</el-button>
<el-button type="primary" size="mini" @click="goJd" v-else-if="(scope.row.providername === '京东云')">
<div style="display: flex;justify-content: center;align-items: center">
<img style="width: 12px;margin-right: 5px;height: 12px;" src="./svg/跳转.svg" alt="">京东产品
</div>
</el-button>
<el-button type="primary" size="mini" @click="goUcloud(scope.row.region)" v-else-if="(scope.row.providername === '优刻得科技股份有限公司')">
<div style="display: flex;justify-content: center;align-items: center">
<img style="width: 12px;margin-right: 5px;height: 12px;" src="./svg/跳转.svg" alt="">集群二
</div>
</el-button>
<el-button size="mini" @click="nodeThree(scope.row)" v-else-if="(scope.row.classify === 'E')">
详情
</el-button>
<div v-else-if="scope.row.classify === 'CPCC'">
<el-button size="mini" type="primary" @click="openCpccDetail(scope.row)">
容器化详情
</el-button>
<el-button size="mini" type="primary" @click="$router.push('/customer/SshTerminal')">
登录
</el-button>
</div>
<el-button type="primary" size="mini" @click="goCaption()" v-else-if="(scope.row.providername === '北京首都在线科技股份有限公司')">
<div style="display: flex;justify-content: center;align-items: center">
<img style="width: 12px;margin-right: 5px;height: 12px;" src="./svg/跳转.svg" alt="">集群一
</div>
</el-button>
<span v-else>-</span>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<pagination
v-show="total > 0"
:total="total"
:page.sync="queryParams.page"
:limit.sync="queryParams.page_size"
@pagination="handlePagination"
/>
</el-card>
<!-- 详情对话框 -->
<el-dialog title="详情" :visible.sync="dialogTableVisible">
<el-table :data="datailList">
<el-table-column min-width="200px" property="date" label="实例编号/名称">
<template slot-scope="scope">
{{ scope.row.id }}
</template>
</el-table-column>
<el-table-column min-width="200px" property="name" label="状态">
<template slot-scope="scope">
{{ scope.row.status === "1" ? '运行中' : '已关机' }}
</template>
</el-table-column>
<el-table-column min-width="200px" property="address" label="规格详情">
<template slot-scope="scope">
<div class="guige">
<span>{{ scope.row.productname }}* {{ scope.row.gpu }}</span>
<el-popover placement="top" title="" width="200" trigger="hover">
<span class="tipStyle" slot="reference">查看详情</span>
<div>
<p>存储: {{ scope.row.storage }} G</p>
<p>CPU: {{ scope.row.cpu }} </p>
<p>内存: {{ scope.row.memory }} G</p>
<p>GPU: {{ scope.row.gpu }} </p>
<p>显存: {{ scope.row.gpumem }} G</p>
</div>
</el-popover>
</div>
</template>
</el-table-column>
<el-table-column min-width="120px" property="address" label="健康状态">
<template slot-scope="scope">
正常
</template>
</el-table-column>
<el-table-column min-width="100px" property="address" label="付费方式">
<template slot-scope="scope">
核时
</template>
</el-table-column>
<el-table-column min-width="100px" property="address" label="登录指令">
<template slot-scope="scope">
<div class="itemOut">
<div>登录指令</div>
<div>ssh ****** <span class="copyBtn">
<i @click="copyText('ssh -p ' + scope.row.port + ' ' + scope.row.loginname + '@' + scope.row.ip_region)" class="el-icon-copy-document"></i>
</span>
</div>
</div>
<div class="itemOut">
<div>密码</div>
<div>****** <span class="copyBtn"> <i @click="copyText(scope.row.loginpwd)" class="el-icon-copy-document"></i> </span></div>
</div>
</template>
</el-table-column>
<el-table-column min-width="150px" fixed="right" property="address" label="操作">
<template slot-scope="scope">
<el-popconfirm @confirm="shutDownThree(scope.row)" title="确定将该设备关机吗?">
<el-button slot="reference" :loading="deleteBtnLoading" type="danger" size="mini">
关机
</el-button>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-dialog>
<!-- 登录信息对话框 -->
<el-dialog title="登录信息" :visible.sync="rqyVisible" width="800">
<el-descriptions title="" direction="vertical" :column="4" border>
<el-descriptions-item label="实例id">{{ cpccDetail.id }}</el-descriptions-item>
<el-descriptions-item label="实例名称">{{ cpccDetail.source_name }}</el-descriptions-item>
<el-descriptions-item label="状态">进行中</el-descriptions-item>
<el-descriptions-item label="健康状态">
<el-tag type="success" effect="dark">
正常
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="登录账号">{{ cpccDetail.source_authuser }}</el-descriptions-item>
<el-descriptions-item label="密码">
<div class="pasStyle">
<span v-if="!isShowPass"> **** </span>
<span v-if="isShowPass"> {{ cpccDetail.source_authpasswd }}</span>
<img @click="isShowPass = !isShowPass" v-if="!isShowPass" src="./svg/showEye.svg" alt="">
<img @click="isShowPass = !isShowPass" v-if="isShowPass" src="./svg/hidenEye.svg" alt="">
</div>
</el-descriptions-item>
<el-descriptions-item label="IP">{{ cpccDetail.source_externalip }}</el-descriptions-item>
<el-descriptions-item label="端口号">{{ cpccDetail.source_outsideport }}</el-descriptions-item>
<el-descriptions-item label="内存量">{{ cpccDetail.source_memrate }}</el-descriptions-item>
<el-descriptions-item label="核心数">{{ cpccDetail.source_cpurate }}</el-descriptions-item>
<el-descriptions-item label="数据盘">{{ cpccDetail.source_storagelimits }}</el-descriptions-item>
<el-descriptions-item label="系统盘">{{ cpccDetail.disk_sys_limit }}</el-descriptions-item>
<el-descriptions-item v-if="cpccDetail.source_gpu !== '0'" label="卡数">{{ cpccDetail.source_gpu }}
</el-descriptions-item>
</el-descriptions>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="rqyVisible = false"> </el-button>
</span>
</el-dialog>
</div> </div>
</template> </template>
<script> <script>
import { scrollTo } from '@/utils/scroll-to' import { getCustomerGoodsAPI, HpcAccessTimeAPI } from '@/api/customer/userResource'
import { getJinanchaosuanSign } from '@/api/JiNanChaoSuan/jiNanChaoSuanUserList'
import { goJdUrl } from "@/api/product/jdApi";
import { reqDeleteK8sCloud, reqGetInstance } from "@/api/k8s";
import { Terminal } from "xterm";
import SshTerminal from "@/views/customer/userResource/SshTerminal.vue";
import Pagination from '../../components/Pagination/index.vue';
export default { export default {
name: 'Pagination', name: "userResource",
props: { components: {
total: { SshTerminal,
required: true, Pagination
type: Number
},
page: {
type: Number,
default: 1
},
limit: {
type: Number,
default: 20
},
pageSizes: {
type: Array,
default() {
return [10, 20, 30, 50]
}
},
layout: {
type: String,
default: 'total, sizes, prev, pager, next, jumper'
},
background: {
type: Boolean,
default: true
},
autoScroll: {
type: Boolean,
default: true
},
hidden: {
type: Boolean,
default: false
}
}, },
computed: { data() {
currentPage: { return {
get() { isShowPass: false,
return this.page cpccDetail: {},
}, rqyVisible: false,
set(val) { deleteBtnLoading: false,
this.$emit('update:page', val) visible: false,
detailBtnLoading: false,
userid: sessionStorage.getItem("userId"),
tableData: [],
loading: false,
dialogTableVisible: false,
datailList: [],
total: 0,
dateRange: [],
queryParams: {
productname: '', //
start_date: '', //
end_date: '', //
page: 1, //
page_size: 10, //
} }
}, };
pageSize: { },
get() { mounted() {
return this.limit this.loading = true;
}, this.getCustomerGoods();
set(val) { console.log("用户资源的路由信息是", this.$route);
this.$emit('update:limit', val)
}
}
}, },
methods: { methods: {
handleSizeChange(val) { //
this.$emit('pagination', { page: this.currentPage, limit: val }) handleSearch() {
if (this.autoScroll) { this.queryParams.page = 1; //
scrollTo(0, 800) this.getCustomerGoods();
},
//
handleReset() {
this.queryParams = {
productname: '',
start_date: '',
end_date: '',
page: 1,
page_size: 10,
};
this.dateRange = [];
this.getCustomerGoods();
},
//
handleDateChange(value) {
if (value && value.length === 2) {
this.queryParams.start_date = value[0];
this.queryParams.end_date = value[1];
} else {
this.queryParams.start_date = '';
this.queryParams.end_date = '';
} }
}, },
handleCurrentChange(val) {
this.$emit('pagination', { page: val, limit: this.pageSize }) //
if (this.autoScroll) { handlePagination(pagination) {
scrollTo(0, 800) this.queryParams.page = pagination.page;
this.queryParams.page_size = pagination.limit;
this.getCustomerGoods();
},
//
async getCustomerGoods() {
this.loading = true;
try {
const res = await getCustomerGoodsAPI(this.queryParams);
if (res.status === true) {
this.tableData = res.data;
this.total = res.pagination.total;
} else {
this.$message.error('获取数据失败');
}
} catch (error) {
console.error('获取用户资源失败:', error);
this.$message.error('获取数据失败');
} finally {
this.loading = false;
} }
} },
}
} openCpccDetail(row) {
this.rqyVisible = true;
this.cpccDetail = row.instance_info;
},
copyText(value) {
const textarea = document.createElement('textarea');
textarea.value = value;
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
document.body.removeChild(textarea);
this.$message.success('已复制到剪贴板');
},
shutDownThree(item) {
this.deleteBtnLoading = true;
let ploay = {
id: item.id,
podname: item.podname,
pvcname: item.pvcname,
customer_goods_id: item.customer_goods_id
};
reqDeleteK8sCloud(ploay).then(res => {
this.deleteBtnLoading = false;
if (res.status) {
this.$message.success("删除成功~");
reqGetInstance({ customer_goods_id: item.id, orgid: sessionStorage.getItem('orgid') }).then(res => {
if (res.status) {
this.datailList = res.data;
}
});
} else {
this.$message.warning("删除失败~");
}
});
},
nodeThree(row) {
this.detailBtnLoading = true;
reqGetInstance({ customer_goods_id: row.id, orgid: sessionStorage.getItem('orgid') }).then(res => {
this.detailBtnLoading = false;
if (res.status) {
this.dialogTableVisible = true;
this.datailList = res.data;
}
});
},
goCaption() {
this.$router.push('/product/gpu/showGpu');
},
goUcloud(region) {
sessionStorage.setItem('region', region);
this.$router.push('/product/ucloudProduct/showCloudHost');
},
goJd() {
this.loading = true;
goJdUrl(this.userid).then(res => {
this.loading = false;
if (res.status) {
window.open(res.data);
} else {
this.$message.error('跳转京东界面失败');
}
});
},
goBaiDu(listUrl) {
this.$store.commit('setRedirectUrl', listUrl);
localStorage.setItem('redirectUrl', listUrl);
this.$router.push({
name: 'baiduProductShow',
params: {
listUrl: listUrl,
}
});
},
HpcAccessTime() {
HpcAccessTimeAPI({ orgid: sessionStorage.getItem("orgid") }).then(res => {
if (res.status == true) {
// 访
}
});
},
goJiNanChaoSuan() {
this.HpcAccessTime();
var orgid = sessionStorage.getItem("orgid");
var username = sessionStorage.getItem("user");
let ploay = {
username: username
};
getJinanchaosuanSign(ploay).then(res => {
if (res.status && res.warn_msg == null) {
window.open(
'https://hpc.kaiyuancloud.cn/kyy_test/?key=' + res.data,
"_blank"
);
} else if (res.warn_msg != null) {
this.$message({
duration: 0,
showClose: true,
message: res.warn_msg,
type: 'warning'
});
window.open(
'https://hpc.kaiyuancloud.cn/kyy_test/?key=' + res.data,
"_blank"
);
}
});
},
},
};
</script> </script>
<style scoped> <style lang="less" scoped>
.pagination-container { .tip {
color: #ff9120;
height: 35px;
img {
width: 15px;
height: 15px;
margin-right: 3px;
}
padding-left: 2px;
background: #fff; background: #fff;
padding: 32px 16px; font-size: 14px;
display: flex;
justify-content: flex-start;
align-items: center;
} }
.pagination-container.hidden {
display: none; .guige {
display: flex;
flex-direction: column;
}
.tipStyle {
transition: all .3s ease-in-out;
cursor: pointer;
&:hover {
transition: all .3s ease-in-out;
color: #0a04e1;
}
}
.itemOut {
display: flex;
flex-direction: column;
align-items: flex-start;
}
.copyBtn {
transition: all .3s ease-in-out;
i {
color: blue;
}
&:hover {
transition: all .3s ease-in-out;
cursor: pointer;
color: #a3b3e8;
}
}
.pasStyle {
img {
width: 20px;
height: 20px;
cursor: pointer;
margin-left: 8px;
&:hover {
fill: blue;
}
}
display: flex;
justify-content: flex-start;
align-items: center;
}
.search-input {
display: flex;
}
.search-box {
display: flex;
align-items: center;
justify-content: flex-start;
background-color: white;
padding: 10px;
margin-bottom: 10px;
border-radius: 8px;
}
.search-box li {
margin-right: 15px;
display: flex;
align-items: center;
justify-content: flex-start;
}
.search-label {
margin-right: 8px;
font-size: 14px;
color: #606266;
}
.tableCard {
margin-top: 20px;
height: calc(100vh - 180px);
}
.pagination-container {
margin-top: 20px;
text-align: right;
} }
</style> </style>

View File

@ -40,6 +40,9 @@ export default {
<style lang="scss" > <style lang="scss" >
$n: 9; //items.length $n: 9; //items.length
$t: .1s; $t: .1s;
*{
box-sizing: border-box;
}
.share-dropdown-menu { .share-dropdown-menu {
width: 250px; width: 250px;
position: relative; position: relative;

File diff suppressed because it is too large Load Diff

View File

@ -1,33 +1,20 @@
<template> <template>
<div class="sidebar-logo-container" style="pointer-events: none!important;" :class="{ collapse: collapse }"> <div class="sidebar-logo-container" :class="{ collapse: collapse }">
<transition name="sidebarLogoFade"> <transition name="sidebarLogoFade">
<span style="cursor: default" v-if="collapse" key="collapse" class="sidebar-logo-link" <span style="cursor: default" v-if="collapse" key="collapse" class="sidebar-logo-link">
>
<img :src="logoImg" alt="" style="width:55px;height:40px;margin-top: 20px"/> <img :src="logoImg" alt="" style="width:55px;height:40px;margin-top: 20px"/>
</span> </span>
<router-link v-else key="expand" class="sidebar-logo-link" to="/"> <div v-else key="expand" class="sidebar-logo-link" @click="goHome">
<!-- <span style="display: flex" class="tip1">测试中</span>-->
<el-row class="logo" :span="24"> <el-row class="logo" :span="24">
<el-row class="logoimg myLogo" :span="24"> <el-row class="logoimg myLogo" :span="24">
<!-- <div class="imgGo"></div>--> <img v-if="logoImg" :src="logoImg" alt=""
<img v-if="logoImg" @click="goHome" :src="logoImg" alt="" style="margin-left: 5px;width:50px;height:35px;cursor: pointer;"/>
style="margin-left: 5px;width:50px;height:35px;"/>
<!-- <el-col :span="6">-->
<!-- <img :src="logoImg" alt="" style="margin-left: 5px;width:50px;height:35px;"/>-->
<!-- </el-col>-->
<!-- <el-col class="text" :span="18">-->
<!-- <div v-if="photosUrl && photosUrl.orgname != '业主机构'">-->
<!-- {{ logoText }}-->
<!-- </div>-->
<!-- <img v-else src="../../../assets/kyy/logo_text.png" alt=""-->
<!-- style="width: 100%;height:100%;padding: 5px 7px 0 7px"/>-->
<!-- </el-col>-->
</el-row> </el-row>
<el-row v-if="false" class="logotext" :span="24"> <el-row v-if="false" class="logotext" :span="24">
<span class="sidebar-title" style="color: black">{{ title }} </span> <span class="sidebar-title" style="color: black">{{ title }} </span>
</el-row> </el-row>
</el-row> </el-row>
</router-link> </div>
</transition> </transition>
</div> </div>
</template> </template>
@ -49,7 +36,6 @@ export default {
photosUrl: null, photosUrl: null,
title: "平台测试中", title: "平台测试中",
logoImg: "", logoImg: "",
// logoImg: require("../../../assets/test2.png"),
logoText: "", logoText: "",
}; };
}, },
@ -62,15 +48,7 @@ export default {
methods: { methods: {
goHome() { goHome() {
console.log("走了goHome@@") console.log("走了goHome@@")
this.$router.push('/product/productHome') this.$router.push('/homePage/index')
// if (window.location.href.includes('http://localhost/')) {
// window.location.href = 'http://localhost:9527/#/homePage/index'
// } else if (window.location.href.includes('dev')) {
// window.location.href = 'https://www.kaiyuancloud.cn/dev'
// } else {
// window.location.href = 'https://www.kaiyuancloud.cn'
// }
}, },
init() { init() {
@ -100,12 +78,6 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.imgGo {
border: 1px solid red;
width: 100%;
height: 100%;
}
.sidebarLogoFade-enter-active { .sidebarLogoFade-enter-active {
transition: opacity 1.5s; transition: opacity 1.5s;
} }
@ -116,10 +88,6 @@ export default {
} }
.sidebar-logo-container { .sidebar-logo-container {
a {
cursor: default !important;
}
position: relative; position: relative;
width: 100%; width: 100%;
height: 60px; height: 60px;
@ -130,6 +98,7 @@ export default {
& .sidebar-logo-link { & .sidebar-logo-link {
height: 100%; height: 100%;
width: 100%; width: 100%;
cursor: pointer;
.logo { .logo {
width: 100%; width: 100%;
@ -154,18 +123,11 @@ export default {
.el-col { .el-col {
height: 100%; height: 100%;
padding: 3px; padding: 3px;
img {
// width: 100%;
// height: 100%;
}
} }
} }
.logotext { .logotext {
display: inline-block; display: inline-block;
// color: #fff;
// color: rgba(191, 203, 217);
color: rgb(223, 226, 229); color: rgb(223, 226, 229);
font-weight: 600; font-weight: 600;
font-size: 16px; font-size: 16px;
@ -190,7 +152,6 @@ export default {
align-items: center; align-items: center;
position: relative; position: relative;
padding: 5px; padding: 5px;
//border: 1px solid red;
img { img {
width: 75% !important; width: 75% !important;

View File

@ -6,7 +6,6 @@
<item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="onlyOneChild.meta.title" /> <item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="onlyOneChild.meta.title" />
</el-menu-item> </el-menu-item>
</app-link> </app-link>
</template> </template>
<el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body> <el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body>
@ -94,7 +93,17 @@ export default {
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.sider{ .sider {
//
::v-deep .nest-menu {
.el-menu-item {
padding-left: 60px !important; // 10px
}
//
.nest-menu .el-menu-item {
padding-left: 100px !important;
}
}
} }
</style> </style>

View File

@ -1,25 +1,28 @@
<template> <template>
<div class="index"> <div class="index">
<!-- <div class="log"> --> <div :class="{ 'has-logo': showLogo }" class="sidebar-container">
<!-- <div style="color:#fff;height:30px;">1232</div> --> <!-- logo -->
<!-- <el-row :gutter="20"> <Logo v-if="showLogo" :collapse="isCollapse" />
<el-col :span="6"> <!-- 菜单 -->
<img src="../../../../public/logos/logo_rgba/noWhite/kkyLogoNoWhiteNoText.png" alt=""> <happy-scroll color="rgba(0,0,0,0.5)" size="5" class="menu-scroll-container">
</el-col> <el-menu
<el-col :span="18"> :collapse="isCollapse"
<img src="../../../../public/logos/logo_rgba/noWhite/kkyLogoNoWhiteText.png.png" alt=""> :background-color="variables.menuBg"
</el-col> :text-color="variables.menuText"
</el-row> --> :unique-opened="true"
<!-- </div> --> :active-text-color="variables.menuActiveText"
<div :class="{ 'has-logo': showLogo }"> :collapse-transition="false"
<logo @click="$router.push('/homePage/index')" v-if="showLogo" :collapse="isCollapse"/> :default-active="activeMenu"
<happy-scroll color="rgba(0,0,0,0.5)" size="5"> mode="vertical"
<el-menu :collapse="isCollapse" :background-color="variables.menuBg" :text-color="variables.menuText" class="el-menu-vertical"
:unique-opened="true" :active-text-color="variables.menuActiveText" :collapse-transition="false"
:default-active="$route.path" mode="vertical"
style="overflow-y: auto;height: calc(100vh - 80px)"
> >
<sidebar-item v-for="(route, index) in permission_routes" :key="index" :item="route" :base-path="route.path"/> <sidebar-item
v-for="(route, index) in permissionRoutes"
:key="route.path + index"
:item="route"
:base-path="route.path"
:is-collapse="isCollapse"
/>
</el-menu> </el-menu>
</happy-scroll> </happy-scroll>
</div> </div>
@ -27,65 +30,145 @@
</template> </template>
<script> <script>
import {mapGetters} from "vuex"; import { mapGetters } from "vuex";
import Logo from "./Logo"; import SidebarItem from "./SidebarItem.vue";
import SidebarItem from "./SidebarItem";
import variables from "@/styles/variables.scss"; import variables from "@/styles/variables.scss";
import Logo from "./Logo.vue";
export default { export default {
data() { name: "Sidebar",
return { components: { SidebarItem, Logo },
role: ''
}
},
components: {SidebarItem, Logo},
computed: { computed: {
...mapGetters(["permission_routes", "sidebar", "userType", "orgType"]),
...mapGetters(["permission_routes", "sidebar"]),
// activeMenu() {
// const route = this.$route
// const { meta, path } = route
// // if set path, the sidebar will highlight the path you set
// if (meta.activeMenu) {
// return meta.activeMenu
// }
// return path
// },
showLogo() { showLogo() {
return true return true;
}, },
variables() { variables() {
return variables; return variables;
}, },
isCollapse() { isCollapse() {
return !this.sidebar.opened; return !this.sidebar.opened;
}, },
},
mounted() {
permissionRoutes() {
const routes = this.permission_routes || [];
return routes;
},
activeMenu() {
const route = this.$route;
const { meta, path } = route;
if (meta.activeMenu) {
return meta.activeMenu;
}
return path;
}
}, },
methods: {}
mounted() {
console.log("Sidebar mounted - 权限路由:", this.permissionRoutes);
}
}; };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.index { .index {
//margin-top: 50px; width: 100%;
height: 100vh;
position: relative;
.log { .sidebar-container {
width: 100%; width: 100%;
height: 80px; height: 100%;
display: flex;
flex-direction: column;
box-sizing: border-box;
} }
}
::v-deep .happy-scroll { .menu-scroll-container {
overflow-x: hidden; flex: 1;
width: 100%;
overflow-x: hidden;
.happy-scroll-container { ::v-deep .happy-scroll-container {
width: 100% !important;
min-width: unset !important;
.happy-scroll-content {
width: 100%;
min-width: unset !important;
box-sizing: border-box;
}
}
}
//
::v-deep .el-menu-vertical {
border: none;
height: 100%;
width: 100% !important; width: 100% !important;
min-width: 100% !important;
box-sizing: border-box;
.el-submenu__title,
.el-menu-item {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.happy-scroll-content { //
width: 100%; .el-menu--inline {
//
.el-menu-item {
//
&.is-active {
background-color: #d7dafd !important;
color: #296ad9 !important;
&:before {
content: '';
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 3px;
background-color: #296ad9;
}
}
//
&:not(.is-active):hover {
background-color: #f5f7fa !important;
}
}
}
}
//
::v-deep .el-menu--collapse {
width: 64px !important;
min-width: 64px !important;
.el-submenu__title,
.el-menu-item {
text-overflow: clip;
justify-content: center;
}
//
.el-menu--popup {
.el-menu-item {
&.is-active {
background-color: #f5f7fa !important;
color: #296ad9 !important;
}
}
} }
} }
} }

View File

@ -1,9 +1,10 @@
import Vue from 'vue' import Vue from 'vue'
import Cookies from 'js-cookie' import Cookies from 'js-cookie'
import 'normalize.css/normalize.css' // a modern alternative to CSS resets import 'normalize.css/normalize.css' // a modern alternative to CSS resets
import './assets/css/iconfont/iconfont.css'
import Element from 'element-ui' import Element from 'element-ui'
import './styles/element-variables.scss' import './styles/element-variables.scss'
import 'xterm/css/xterm.css' import 'xterm/css/xterm.css'
@ -22,7 +23,7 @@ let ploady={
start_date:'', start_date:'',
end_date:'' end_date:''
} }
reqSaleMoneyList(ploady) // reqSaleMoneyList(ploady)
// import {saveApprovalInfo} from "@/api/finance/approvalList"; // import {saveApprovalInfo} from "@/api/finance/approvalList";
// saveApprovalInfo(JSON.stringify({ // saveApprovalInfo(JSON.stringify({
// "flag":"update", // "flag":"update",
@ -51,11 +52,10 @@ import App from './App'
import store from './store' import store from './store'
import router from './router' import router from './router'
// import 'default-passive-events' // import 'default-passive-events'
import './icons' // icon import './icons' // icon
import './permission' // permission control import './permission' // permission control
// import './utils/error-log' // error log // import './utils/error-log' // error log
import index from '@/styles/index.css'
import { v4 as uuidv4 } from 'uuid';//引入uuid import { v4 as uuidv4 } from 'uuid';//引入uuid
// uuidv4(); // uuidv4();
@ -99,13 +99,67 @@ Vue.use(Element, {
//设置跳转页面时给页面的body属性设置滚动条 //设置跳转页面时给页面的body属性设置滚动条
var onOverflow = ["/shoppingManagement", "/supplierManagement"]; var onOverflow = ["/shoppingManagement", "/supplierManagement"];
router.afterEach((to, from, next) => { // 修复:在路由守卫中恢复用户状态和重新生成路由
router.beforeEach(async (to, from, next) => {
// 清空面包屑状态的代码
// store.commit('tagsView/resetBreadcrumbState');
// 新增如果已登录且有token但Vuex状态丢失从sessionStorage恢复
if (store.getters.token && (!store.getters.user || !store.getters.userType)) {
console.log("检测到状态丢失从sessionStorage恢复用户状态");
const user = sessionStorage.getItem('user');
const auths = sessionStorage.getItem('auths');
const userType = sessionStorage.getItem('userType');
const orgType = sessionStorage.getItem('orgType');
if (user) {
store.commit('user/SET_USER', user);
}
if (auths) {
store.commit('user/SET_AUTHS', JSON.parse(auths));
}
if (userType) {
store.commit('user/SET_USER_TYPE', userType);
}
if (orgType) {
store.commit('user/SET_ORG_TYPE', parseInt(orgType));
}
// 重新生成路由
try {
const accessRoutes = await store.dispatch('permission/generateRoutes', {
user: store.getters.user,
auths: store.getters.auths,
userType: store.getters.userType,
orgType: store.getters.orgType
});
// 重新添加路由
router.addRoutes(accessRoutes);
// 重定向到当前路由以确保路由更新
next({ ...to, replace: true });
return;
} catch (error) {
console.error('重新生成路由失败:', error);
}
}
onOverflow.forEach(element => { onOverflow.forEach(element => {
if (to.path == element) { if (to.path == element) {
document.querySelector("body").setAttribute("style", "overflow: auto !important;") document.querySelector("body").setAttribute("style", "overflow: auto !important;")
} }
}); });
next();
}); });
window.addEventListener('beforeunload', function () {
// 清空面包屑状态的代码
store.commit('tagsView/resetBreadcrumbState');
});
Object.keys(filters).forEach(key => { Object.keys(filters).forEach(key => {
Vue.filter(key, filters[key]) Vue.filter(key, filters[key])
}) })

View File

@ -5,3 +5,4 @@ export default {
document.body.style.userSelect = 'none'; document.body.style.userSelect = 'none';
}, },
}; };

File diff suppressed because it is too large Load Diff

View File

@ -8,10 +8,13 @@ const getters = {
avatar: state => state.user.avatar, avatar: state => state.user.avatar,
name: state => state.user.name, name: state => state.user.name,
introduction: state => state.user.introduction, introduction: state => state.user.introduction,
user: state => state.user.user, user: state => state.user.user || sessionStorage.getItem('user') || '',
auths: state => state.user.auths, auths: state => state.user.auths || JSON.parse(sessionStorage.getItem('auths') || '[]'),
requestCode: state => state.user.requestCode, requestCode: state => state.user.requestCode,
permission_routes: state => state.permission.routes, permission_routes: state => state.permission.routes,
// errorLogs: state => state.errorLog.logs, userType: state => state.user.userType || sessionStorage.getItem('userType') || '',
orgType: state => state.user.orgType || parseInt(sessionStorage.getItem('orgType')) || 0,
// 新增角色获取
roles: state => state.user.roles || JSON.parse(sessionStorage.getItem('roles') || '[]'),
} }
export default getters export default getters

View File

@ -1,5 +1,4 @@
import { asyncRoutes, constantRoutes } from "@/router"; import { asyncRoutes, constantRoutes } from "@/router";
import path from "path";
// 获取用户代理字符串 // 获取用户代理字符串
const userAgent = window.navigator.userAgent; const userAgent = window.navigator.userAgent;
@ -7,32 +6,95 @@ const userAgent = window.navigator.userAgent;
// 判断是否为移动设备 // 判断是否为移动设备
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent); const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent);
function filterAsyncRoutes(data, values) { // 修复:更全面的路由过滤逻辑
return data.reduce((filteredData, item) => { function filterAsyncRoutes(routes, permissions, userRoles = []) {
if (item.meta && item.meta.fullPath) { const res = [];
if (values.includes(item.meta.fullPath)) {
const newItem = { // 定义需要客户角色才能访问的路由
...item, const customerOnlyRoutes = [
}; "/product", "/overview", "/workOrderManagement",
// if (item.children && item.children.length > 0) { "/unsubscribeManagement", "/informationPerfect",
// newItem.children = filterAsyncRoutes(item.children, values); "/rechargeManagement", "/invoiceManagement"
// } ];
filteredData.push(newItem);
} else if (item.children && item.children.length > 0) { routes.forEach(route => {
const filteredChildren = filterAsyncRoutes(item.children, values); // 创建路由副本
if (filteredChildren.length > 0) { const tmpRoute = { ...route };
const newItem = {
...item, // 检查当前路由是否在权限列表中
children: filteredChildren, const hasPermission = permissions.some(p => p.path === route.meta?.fullPath);
};
filteredData.push(newItem); // 特殊处理:确保"全部产品"和"资源概览"这两个一级路由在客户角色下显示
} const isCriticalRoute = route.path === "/product" || route.path === "/overview";
}
return filteredData; // 检查是否为仅客户可访问的路由
} else { const isCustomerOnlyRoute = customerOnlyRoutes.includes(route.path);
return filteredData;
// 如果路由需要客户角色,但用户不是客户,则跳过
if (isCustomerOnlyRoute && !userRoles.includes('客户')) {
return; // 跳过当前路由
} }
}, []);
// 如果当前路由有权限,则加入结果
if (hasPermission) {
res.push(tmpRoute);
}
// 如果是关键路由且用户是客户,也要加入结果
else if (isCriticalRoute && userRoles.includes('客户')) {
res.push(tmpRoute);
}
// 如果没有直接权限,但有子路由,递归处理子路由
else if (tmpRoute.children) {
const filteredChildren = filterAsyncRoutes(tmpRoute.children, permissions, userRoles);
if (filteredChildren.length > 0) {
tmpRoute.children = filteredChildren;
res.push(tmpRoute); // 即使父路由本身没有权限,只要有子路由有权限,也要保留父路由
}
}
// 如果当前路由既没有权限,也没有有权限的子路由,则不添加到结果中
});
return res;
}
// 新增:为普通用户添加订单管理和资源管理路由
function addUserRoutes(routes, userType, orgType, userRoles = []) {
console.log("addUserRoutes - userType:", userType, "orgType:", orgType, "userRoles:", userRoles);
const userRoutes = [];
// 如果是普通用户org_type为2或userType为user添加订单管理和资源管理路由
if (userType === 'user' || orgType == 2) {
const orderManagementRoute = routes.find(route => route.path === "/orderManagement");
const resourceManagementRoute = routes.find(route => route.path === "/resourceManagement");
if (orderManagementRoute) {
console.log("添加订单管理路由");
userRoutes.push(JSON.parse(JSON.stringify(orderManagementRoute))); // 深拷贝
}
if (resourceManagementRoute) {
console.log("添加资源管理路由");
userRoutes.push(JSON.parse(JSON.stringify(resourceManagementRoute))); // 深拷贝
}
}
// 新增:为所有用户添加五个新的客户菜单,但只有客户角色才能看到
const newCustomerRoutes = [
routes.find(route => route.path === "/unsubscribeManagement"),
routes.find(route => route.path === "/informationPerfect"),
routes.find(route => route.path === "/rechargeManagement"),
routes.find(route => route.path === "/invoiceManagement"),
routes.find(route => route.path === "/workOrderManagement")
].filter(route => {
// 过滤掉undefined并且只有客户角色才能看到这些路由
return route && userRoles.includes('客户');
});
console.log("添加新的客户菜单路由:", newCustomerRoutes.map(r => r.path));
userRoutes.push(...newCustomerRoutes);
return userRoutes;
} }
function filterRoutesMobile(routes) { function filterRoutesMobile(routes) {
@ -41,20 +103,21 @@ function filterRoutesMobile(routes) {
route.children = filterRoutesMobile(route.children); route.children = filterRoutesMobile(route.children);
return route.children.length > 0; return route.children.length > 0;
} }
if (route.meta.isMobile || route.meta.isMobile == true) { if (route.meta?.isMobile || route.meta?.isMobile === true) {
return true; return true;
} else { } else {
return false; return false;
} }
}); });
} }
function filterRoutesPc(routes) { function filterRoutesPc(routes) {
return routes.filter(route => { return routes.filter(route => {
if (route.children && route.children.length) { if (route.children && route.children.length) {
route.children = filterRoutesPc(route.children); route.children = filterRoutesPc(route.children);
return route.children.length > 0; return route.children.length > 0;
} }
if (!route.meta.isMobile || route.meta.isMobile == false) { if (!route.meta?.isMobile || route.meta?.isMobile === false) {
return true; return true;
} else { } else {
return false; return false;
@ -70,48 +133,85 @@ const state = {
const mutations = { const mutations = {
SET_ROUTES: (state, routes) => { SET_ROUTES: (state, routes) => {
// console.log(state, routes); console.log("MUTATION SET_ROUTES - received routes:", routes);
state.addRoutes = routes; state.addRoutes = routes;
sessionStorage.setItem("routes", JSON.stringify(routes)); sessionStorage.setItem("routes", JSON.stringify(routes));
state.routes = constantRoutes.concat(routes); state.routes = constantRoutes.concat(routes);
console.log("MUTATION SET_ROUTES - final state.routes:", state.routes);
}, },
SETUSERS: (state, user) => { SETUSERS: (state, user) => {
state.users = user state.users = user;
} }
}; };
const actions = { const actions = {
generateRoutes({ commit }, params) { generateRoutes({ commit, rootState }, params) {
// console.log("paramsdispatch:", params); console.log("ACTION generateRoutes - params:", params);
// console.log("commit:", commit);
return new Promise((resolve) => { return new Promise((resolve) => {
let accessedRoutes; let accessedRoutes;
// let filterRoutes;
if (params.user.includes("admin") && params.admin == 1) { // 从参数或sessionStorage中获取用户类型和组织类型
const routes = asyncRoutes.filter((item => { return item.path == '/superAdministrator' })); const userType = params.userType || sessionStorage.getItem('userType') || '';
accessedRoutes = routes; const orgType = params.orgType || parseInt(sessionStorage.getItem('orgType')) || 0;
// 获取用户角色从store或sessionStorage
const userRoles = rootState.user.roles || JSON.parse(sessionStorage.getItem('roles') || '[]');
console.log("用户角色:", userRoles);
console.log("用户类型:", userType, "orgType:", orgType);
if (params.user && params.user.includes("admin") && orgType != 2) {
// 管理员:只显示超级管理员菜单
accessedRoutes = asyncRoutes.filter(item => item.path === '/superAdministrator');
} else { } else {
const auths = JSON.parse(JSON.stringify(params.auths)); const auths = params.auths ? JSON.parse(JSON.stringify(params.auths)) : [];
console.log("ACTION generateRoutes - auths:", auths);
if (auths.length) { if (auths.length) {
// 确保 auths 中的 path 与路由 meta.fullPath 匹配
const paths = auths.map((item) => { const paths = auths.map((item) => {
return item.path; return item.path;
}); });
if (!paths.includes("")) { console.log("ACTION generateRoutes - paths from auths:", paths);
accessedRoutes = filterAsyncRoutes(asyncRoutes, paths);
} else { if (paths.includes("")) {
// 如果权限列表包含空路径,认为用户有所有权限
accessedRoutes = asyncRoutes || []; accessedRoutes = asyncRoutes || [];
} else {
// 使用修复后的过滤函数,传入用户角色
accessedRoutes = filterAsyncRoutes(asyncRoutes, auths, userRoles);
} }
} else { } else {
accessedRoutes = asyncRoutes || []; // 如果没有权限列表,不显示任何动态路由
accessedRoutes = [];
} }
// 新增:为普通用户添加订单管理和资源管理路由以及新的五个客户菜单
console.log("为用户添加特定路由");
const userSpecificRoutes = addUserRoutes(asyncRoutes, userType, orgType, userRoles);
// 确保不重复添加路由,同时检查角色权限
userSpecificRoutes.forEach(route => {
const isCustomerRoute = [
"/workOrderManagement", "/unsubscribeManagement", "/informationPerfect",
"/rechargeManagement", "/invoiceManagement"
].includes(route.path);
// 如果是客户路由但用户不是客户,则不添加
if (isCustomerRoute && !userRoles.includes('客户')) {
return;
}
if (!accessedRoutes.some(r => r.path === route.path)) {
accessedRoutes.push(route);
}
});
console.log("添加用户特定路由后的accessedRoutes:", accessedRoutes);
} }
// debugger
// if (isMobile) { console.log("ACTION generateRoutes - calculated accessedRoutes:", accessedRoutes);
// filterRoutes = filterRoutesMobile(accessedRoutes)
// } else {
// filterRoutes = filterRoutesPc(accessedRoutes)
// }
// console.log(filterRoutes)
commit("SET_ROUTES", accessedRoutes); commit("SET_ROUTES", accessedRoutes);
resolve(accessedRoutes); resolve(accessedRoutes);
}); });

View File

@ -7,19 +7,45 @@ import store from "@/store";
import {myBalanceAPI} from "@/api/finance/customerRechargeManagement"; import {myBalanceAPI} from "@/api/finance/customerRechargeManagement";
import {testData} from "@/views/homePage/components/topBox/testData"; import {testData} from "@/views/homePage/components/topBox/testData";
// 安全转换为字符串的辅助函数
const safeToString = (value, defaultValue = '') => {
if (value == null) return defaultValue;
return value.toString();
};
// 从sessionStorage恢复状态
const getStoredState = () => {
return {
user: sessionStorage.getItem('user') || "",
auths: JSON.parse(sessionStorage.getItem('auths')) || [],
userType: sessionStorage.getItem('userType') || '',
orgType: parseInt(sessionStorage.getItem('orgType')) || '',
mybalance: sessionStorage.getItem('mybalance') || '',
roles: JSON.parse(sessionStorage.getItem('roles')) || []
};
};
const storedState = getStoredState();
const state = { const state = {
token: getToken(), token: getToken(),
name: "", name: "",
avatar: "", avatar: "",
introduction: "", introduction: "",
//用户名称 //用户名称
user: "", user: storedState.user,
//权限列表 //权限列表
auths: [], auths: storedState.auths,
// 当前状态码 // 当前状态码
requestCode: 200, requestCode: 200,
//客户余额 //客户余额
mybalance: '' mybalance: storedState.mybalance,
// 新增用户类型admin/user
userType: storedState.userType,
// 新增:组织类型
orgType: storedState.orgType,
// 新增:用户角色
roles: storedState.roles
}; };
const mutations = { const mutations = {
@ -37,17 +63,42 @@ const mutations = {
}, },
SET_AUTHS: (state, auths) => { SET_AUTHS: (state, auths) => {
state.auths = auths; state.auths = auths;
sessionStorage.setItem("auths", JSON.stringify(state.auths)); sessionStorage.setItem("auths", JSON.stringify(auths));
}, },
SET_USER: (state, user) => { SET_USER: (state, user) => {
state.user = user; state.user = user;
sessionStorage.setItem("user", state.user); sessionStorage.setItem("user", user);
}, },
SET_REQUESTSTATE: (state, code) => { SET_REQUESTSTATE: (state, code) => {
state.requestCode = code; state.requestCode = code;
}, },
SETMYBANLANCE(state, mybalance) { SETMYBANLANCE(state, mybalance) {
state.mybalance = mybalance state.mybalance = mybalance;
sessionStorage.setItem('mybalance', mybalance);
},
// 新增:设置用户类型
SET_USER_TYPE: (state, userType) => {
state.userType = userType;
sessionStorage.setItem("userType", userType);
},
// 修复:设置组织类型 - 添加防御性检查
SET_ORG_TYPE: (state, orgType) => {
state.orgType = orgType;
// 防御性检查,确保 orgType 不为 null 或 undefined
if (orgType == null) {
console.warn('SET_ORG_TYPE: orgType is null or undefined, setting to empty string');
sessionStorage.setItem("orgType", '');
return;
}
// 安全地调用 toString()
sessionStorage.setItem("orgType", orgType.toString());
},
// 新增:设置用户角色
SET_ROLES: (state, roles) => {
state.roles = roles;
sessionStorage.setItem("roles", JSON.stringify(roles));
} }
}; };
@ -55,14 +106,13 @@ const actions = {
//客户获取余额 //客户获取余额
async getCustmoersMoney({commit}) { async getCustmoersMoney({commit}) {
let result = await myBalanceAPI() let result = await myBalanceAPI()
if (result.status) { if (result.status) {
commit('SETMYBANLANCE', result.data) commit('SETMYBANLANCE', result.data)
sessionStorage.setItem('mybalance', result.data)
} }
}, },
// user login // user login
async login({commit}, userInfo) { async login({commit}, userInfo) {
const {username, password, codeid, vcode} = userInfo; const {username, password, codeid, vcode} = userInfo;
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
loginUserAPI(userInfo) loginUserAPI(userInfo)
@ -75,15 +125,31 @@ const actions = {
type: 'error', type: 'error',
}) })
} else { } else {
const {data, admin} = response; const {data, org_type} = response;
commit("SET_USER", username); commit("SET_USER", username);
// 新增:根据 org_type 设置用户类型和角色
// org_type 为 2 表示客户,其他为管理员
const userType = org_type == 2 ? 'user' : 'admin';
// 设置用户角色 - 如果是客户,则添加'客户'角色
const userRoles = org_type == 2 ? ['客户'] : ['管理员'];
commit("SET_USER_TYPE", userType);
// 确保 org_type 不为 undefined
commit("SET_ORG_TYPE", org_type || '');
commit("SET_ROLES", userRoles); // 新增:设置用户角色
console.log("登录用户类型:", userType, "org_type:", org_type, "用户角色:", userRoles);
data ? commit("SET_AUTHS", data) : commit("SET_AUTHS", []); data ? commit("SET_AUTHS", data) : commit("SET_AUTHS", []);
const accessRoutes = await store.dispatch( const accessRoutes = await store.dispatch(
"permission/generateRoutes", "permission/generateRoutes",
{ {
user: username, user: username,
auths: data, auths: data,
admin: admin userType: userType,
orgType: org_type,
roles: userRoles // 新增:传递角色信息
} }
) )
resetRouter(); resetRouter();
@ -104,46 +170,68 @@ const actions = {
// get user info // get user info
getInfo({commit, state}) { getInfo({commit, state}) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
// getInfo(state.token).then(response => { // 从sessionStorage恢复用户信息
// const { data } = response const user = sessionStorage.getItem('user');
// if (!data) { const auths = sessionStorage.getItem('auths');
// reject('Verification failed, please Login again.') const userType = sessionStorage.getItem('userType');
// } const orgType = sessionStorage.getItem('orgType');
// const { roles, name, avatar, introduction } = data const roles = sessionStorage.getItem('roles');
// // roles must be a non-empty array
// if (!roles || roles.length <= 0) { if (user) {
// reject('getInfo: roles must be a non-null array!') commit("SET_USER", user);
// } }
// commit('SET_ROLES', roles) if (auths) {
// commit('SET_NAME', name) commit("SET_AUTHS", JSON.parse(auths));
// commit('SET_AVATAR', avatar) }
// commit('SET_INTRODUCTION', introduction) if (userType) {
// }).catch(error => { commit("SET_USER_TYPE", userType);
// reject(error) }
// }) if (orgType) {
// 确保 orgType 不为 null 或 undefined
const safeOrgType = orgType ? parseInt(orgType) : '';
commit("SET_ORG_TYPE", safeOrgType);
}
if (roles) {
commit("SET_ROLES", JSON.parse(roles));
}
resolve({
user: state.user,
auths: state.auths,
userType: state.userType,
orgType: state.orgType,
roles: state.roles
});
}); });
}, },
// user logout // user logout
logout({commit, state, dispatch}) { logout({commit, state, dispatch}) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
logout(state.token) commit("SET_TOKEN", "");
.then(() => { commit("SET_ROLES", []);
commit("SET_TOKEN", ""); commit("SET_USER_TYPE", ""); // 新增:清除用户类型
commit("SET_ROLES", []); commit("SET_ORG_TYPE", ""); // 新增:清除组织类型
removeToken(); commit("SET_USER", "");
resetRouter(); commit("SET_AUTHS", []);
removeToken();
resetRouter();
// reset visited views and cached views // 清除sessionStorage
// to fixed https://github.com/PanJiaChen/vue-element-admin/issues/2485 sessionStorage.removeItem('user');
dispatch("tagsView/delAllViews", null, {root: true}); sessionStorage.removeItem('auths');
sessionStorage.removeItem('userType');
sessionStorage.removeItem('orgType');
sessionStorage.removeItem('mybalance');
sessionStorage.removeItem('roles'); // 新增:清除角色信息
resolve(); // reset visited views and cached views
}) // to fixed https://github.com/PanJiaChen/vue-element-admin/issues/2485
.catch((error) => { dispatch("tagsView/delAllViews", null, {root: true});
reject(error);
}); resolve();
}); });
}, },
// remove token // remove token
@ -151,7 +239,18 @@ const actions = {
return new Promise((resolve) => { return new Promise((resolve) => {
commit("SET_TOKEN", ""); commit("SET_TOKEN", "");
commit("SET_ROLES", []); commit("SET_ROLES", []);
commit("SET_USER_TYPE", ""); // 新增:清除用户类型
commit("SET_ORG_TYPE", ""); // 新增:清除组织类型
commit("SET_USER", "");
commit("SET_AUTHS", []);
removeToken(); removeToken();
// 清除sessionStorage
sessionStorage.removeItem('user');
sessionStorage.removeItem('auths');
sessionStorage.removeItem('userType');
sessionStorage.removeItem('orgType');
sessionStorage.removeItem('roles'); // 新增:清除角色信息
resolve(); resolve();
}); });
}, },
@ -185,3 +284,4 @@ export default {
mutations, mutations,
actions, actions,
}; };

View File

@ -0,0 +1,94 @@
.backgroundColor{
background-color: #fff;
height: calc(100vh - 80px);
padding: 10px;
}
.bf{
background-color: #fff;
}
.p10{
padding: 10px;
}
.p20{
padding: 20px;
}
.h100{
height: calc(100vh - 100px);
}
.p0{
padding: 0;
}
.flex{
display: flex;
justify-content: center;
align-items: center;
}
.ml10{
margin-left: 10px;
}
.mt10{
margin-top: 10px;
}
.mt20{
margin-top: 20px;
}
/* ::v-deep .table-header {
background: !important;
color: #ffffff !important;
font-weight: bold;
text-align: center;
} */
/* 全局表格头部样式 - 蓝色渐变 */
.el-table .el-table__header th,
.el-table .el-table__header .el-table__cell {
background: #409EFF !important;
color: #ffffff !important;
font-weight: bold !important;
text-align: center !important;
border-bottom: none !important;
}
/* 处理表格边框情况 */
.el-table--border .el-table__header th,
.el-table--border .el-table__header .el-table__cell {
border-right: 1px solid #a0cfff !important;
}
.el-table--border .el-table__header th:last-child,
.el-table--border .el-table__header .el-table__cell:last-child {
border-right: none !important;
}
/* 鼠标悬停效果 */
.el-table .el-table__header th:hover,
.el-table .el-table__header .el-table__cell:hover {
background: linear-gradient(135deg, #66b1ff, #409eff) !important;
}
/* 科技蓝紫渐变滚动条 */
::-webkit-scrollbar {
width: 10px;
height: 10px;
}
::-webkit-scrollbar-track {
background: linear-gradient(180deg, #f8faff 0%, #f0f4ff 100%);
border-radius: 6px;
box-shadow: inset 0 0 4px rgba(0, 0, 0, 0.05);
}
::-webkit-scrollbar-thumb {
background: #C6D7EB;
border-radius: 6px;
border: 1.5px solid #f8faff;
box-shadow: 0 1px 4px rgba(99, 102, 241, 0.25);
}
::-webkit-scrollbar-thumb:hover {
background: #C6D7EB;
box-shadow: 0 1px 6px rgba(99, 102, 241, 0.35);
}
::-webkit-scrollbar-thumb:active {
background: #C6D7EB;
}

View File

@ -1,3 +1,4 @@
// variables.scss
// base color // base color
$blue: #324157; $blue: #324157;
$light-blue: #3A71A8; $light-blue: #3A71A8;
@ -9,20 +10,17 @@ $yellow: #FEC171;
$panGreen: #30B08F; $panGreen: #30B08F;
// sidebar // sidebar
$menuText: #000; $menuText: #333;
$menuActiveText: #1b14d9; //当前子菜单的字体颜色 $menuActiveText: #296ad9;
$subMenuActiveText: #100101; // https://github.com/ElemeFE/element/issues/12951 $subMenuActiveText: #000;
$menuBg: #fff; //整体背景颜色 $menuBg: #fff;
$menuHover: #f7f7f7; //鼠标浮动一级菜单背景 $menuHover: #f5f7fa;
$subMenuBg: #fff;
$subMenuBg: #f7f7f7; //子菜单下拉 $subMenuHover: #f0f0f0;
$subMenuHover: #0177f8; //鼠标浮动子菜单背景
$sideBarWidth: 230px; $sideBarWidth: 230px;
// the :export directive is the magic sauce for webpack
// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
:export { :export {
menuText: $menuText; menuText: $menuText;
menuActiveText: $menuActiveText; menuActiveText: $menuActiveText;
@ -33,4 +31,3 @@ $sideBarWidth: 230px;
subMenuHover: $subMenuHover; subMenuHover: $subMenuHover;
sideBarWidth: $sideBarWidth; sideBarWidth: $sideBarWidth;
} }

View File

@ -0,0 +1,84 @@
import Vue from 'vue'
// 创建一个全局的事件总线用于组件通信
export const languageBus = new Vue()
// 语言状态管理
export const languageStore = {
state: {
language: 'zh'
},
setLanguage(lang) {
if (lang === 'zh' || lang === 'en') {
console.log('languageStore: 设置语言为', lang)
this.state.language = lang
localStorage.setItem('language', lang)
// 触发全局语言改变事件
languageBus.$emit('language-changed', lang)
// 确保所有组件都能收到变化,即使有些组件监听器设置较晚
setTimeout(() => {
languageBus.$emit('language-changed', lang)
}, 100)
}
},
getLanguage() {
return this.state.language
},
init() {
const savedLanguage = localStorage.getItem('language')
if (savedLanguage && (savedLanguage === 'zh' || savedLanguage === 'en')) {
this.state.language = savedLanguage
} else {
// 如果没有保存的语言设置,使用默认值
this.state.language = 'zh'
localStorage.setItem('language', 'zh')
}
console.log('languageStore: 初始化完成,当前语言:', this.state.language)
return this.state.language
},
// 调试方法
debug() {
console.log('languageStore 调试信息:')
console.log('- 当前语言:', this.state.language)
console.log('- localStorage:', localStorage.getItem('language'))
console.log('- 事件监听器数量:', languageBus._events['language-changed'] ? languageBus._events['language-changed'].length : 0)
}
}
// 在应用启动时初始化
languageStore.init()
// 添加一个全局状态检查方法
export const checkLanguageState = () => {
console.log('=== 全局语言状态检查 ===');
console.log('languageStore:', languageStore.getLanguage());
console.log('localStorage:', localStorage.getItem('language'));
// 检查所有可能存储语言状态的地方
const stores = [
{ name: 'languageStore', value: languageStore.getLanguage() },
{ name: 'localStorage', value: localStorage.getItem('language') }
];
// 找出不一致的状态
const uniqueValues = [...new Set(stores.map(store => store.value))];
if (uniqueValues.length > 1) {
console.warn('语言状态不一致!', stores);
// 自动修复:以 languageStore 为准
const correctLang = languageStore.getLanguage();
localStorage.setItem('language', correctLang);
console.log('已自动修复语言状态不一致问题');
} else {
console.log('语言状态一致:', uniqueValues[0]);
}
}
// 在应用启动时检查状态一致性
setTimeout(() => {
checkLanguageState();
}, 1000);

View File

@ -2,18 +2,39 @@
<div class="myOranization"> <div class="myOranization">
<el-card> <el-card>
<div class="oranizationInfo"> <div class="oranizationInfo">
<span>机构名称:{{ orgList.orgname }}</span> <!-- 机构名称 -->
<span>联系人:{{ orgList.contactor }}</span> <div class="label-box">
<span>联系人电话:{{ orgList.contactor_phone }}</span> <span class="label">机构名称:</span>
<span>地址:{{ orgList.address }}</span> <span>{{ orgList.orgname }}</span>
<span>主营业务描述:{{ orgList.main_business }}</span> </div>
<!-- 联系人 -->
<div class="label-box">
<span class="label">联系人:</span>
<span>{{ orgList.contactor }}</span>
</div>
<!-- 联系人电话 -->
<div class="label-box">
<span class="label">联系人电话:</span>
<span>{{ orgList.contactor_phone }}</span>
</div>
<!-- 地址 -->
<div class="label-box">
<span class="label">地址:</span>
<span>{{ orgList.address }}</span>
</div>
<!-- 主营业务描述 -->
<div class="label-box">
<span class="label">主营业务描述:</span>
<span>{{ orgList.main_business }}</span>
</div>
</div> </div>
</el-card> </el-card>
<el-card> <el-card>
<div class="main-content" style="margin-top: 8px;display:flex;"> <div class="main-content" style="margin-top: 8px;display:flex;">
<el-select v-model="searchValue" filterable placeholder="请选择账户" @change="selectSearch" @input="input" <el-select v-model="searchValue" filterable placeholder="请选择账户" @change="selectSearch" @input="input" clearable
clearable size="small"> size="small">
<el-option v-for="item in tableData" :key="item.id" :label="item.username" :value="item.id"> <el-option v-for="item in tableData" :key="item.id" :label="item.username" :value="item.id">
</el-option> </el-option>
</el-select> </el-select>
@ -38,7 +59,7 @@
<template slot-scope="scope"> <template slot-scope="scope">
<!-- <el-button size="small" type="danger" @click="outOfService(scope.row)" :disabled="scope.row.user_status==1||scope.row.user_status==2">停用</el-button> --> <!-- <el-button size="small" type="danger" @click="outOfService(scope.row)" :disabled="scope.row.user_status==1||scope.row.user_status==2">停用</el-button> -->
<!-- <el-button size="small" type="success" @click="recover(scope.row)" :disabled="scope.row.user_status==0||scope.row.user_status==2">恢复</el-button> --> <!-- <el-button size="small" type="success" @click="recover(scope.row)" :disabled="scope.row.user_status==0||scope.row.user_status==2">恢复</el-button> -->
<el-button size="small" type="warning" @click="signOut(scope.row)" :disabled="scope.row.user_status==2"> <el-button size="small" type="warning" @click="signOut(scope.row)" :disabled="scope.row.user_status == 2">
注销 注销
</el-button> </el-button>
</template> </template>
@ -46,10 +67,10 @@
<el-table-column align="center" label="操作" width="260px"> <el-table-column align="center" label="操作" width="260px">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button size="small" type="success" @click="addRole(scope.row)" <el-button size="small" type="success" @click="addRole(scope.row)"
:disabled="scope.row.user_status==1||scope.row.user_status==2" class="addBtn">添加角色 :disabled="scope.row.user_status == 1 || scope.row.user_status == 2" class="addBtn">添加角色
</el-button> </el-button>
<el-button size="small" type="primary" @click="editNewUser(scope.row)" <el-button size="small" type="primary" @click="editNewUser(scope.row)"
:disabled="scope.row.user_status==1||scope.row.user_status==2">编辑 :disabled="scope.row.user_status == 1 || scope.row.user_status == 2">编辑
</el-button> </el-button>
<!-- <el-button size="small" type="danger" @click="delNewUser(scope.row)" :disabled="scope.row.user_status==1||scope.row.user_status==2">删除</el-button> --> <!-- <el-button size="small" type="danger" @click="delNewUser(scope.row)" :disabled="scope.row.user_status==1||scope.row.user_status==2">删除</el-button> -->
</template> </template>
@ -59,28 +80,28 @@
<!-- 新增/编辑用户 --> <!-- 新增/编辑用户 -->
<el-dialog :title="isEdit ? '编辑用户' : '新增用户'" :visible.sync="dialogVisible" width="30%" class="myDialog" <el-dialog :title="isEdit ? '编辑用户' : '新增用户'" :visible.sync="dialogVisible" width="30%" class="myDialog"
:append-to-body="true" custom-class="addPeople"> :append-to-body="true" custom-class="addPeople">
<el-form ref="form" :model="form" label-width="100px" :rules="rules"> <el-form ref="form" :model="form" label-width="100px" :rules="rules">
<el-form-item label="用户名称:" prop="username" v-if="!isEdit"> <el-form-item label="用户名称:" prop="username" v-if="!isEdit">
<el-input v-model="form.username"/> <el-input v-model="form.username" />
</el-form-item> </el-form-item>
<el-form-item label="昵称:" prop="nick_name"> <el-form-item label="昵称:" prop="nick_name">
<el-input v-model="form.nick_name"/> <el-input v-model="form.nick_name" />
</el-form-item> </el-form-item>
<el-form-item label="密码:" prop="password" v-if="!isEdit"> <el-form-item label="密码:" prop="password" v-if="!isEdit">
<el-input v-model="form.password" placeholder="请输入密码" show-password/> <el-input v-model="form.password" placeholder="请输入密码" show-password />
</el-form-item> </el-form-item>
<el-form-item label="确认密码:" prop="confirmPassword" v-if="!isEdit"> <el-form-item label="确认密码:" prop="confirmPassword" v-if="!isEdit">
<el-input v-model="form.confirmPassword" placeholder="请输入确认密码" show-password/> <el-input v-model="form.confirmPassword" placeholder="请输入确认密码" show-password />
</el-form-item> </el-form-item>
<el-form-item label="地址:" prop="address"> <el-form-item label="地址:" prop="address">
<el-input v-model="form.address"/> <el-input v-model="form.address" />
</el-form-item> </el-form-item>
<el-form-item label="手机号:" prop="mobile"> <el-form-item label="手机号:" prop="mobile">
<el-input v-model="form.mobile"/> <el-input v-model="form.mobile" />
</el-form-item> </el-form-item>
<el-form-item label="邮箱:" prop="email"> <el-form-item label="邮箱:" prop="email">
<el-input v-model="form.email"/> <el-input v-model="form.email" />
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button size="small" type="primary" @click="onSubmit('form')"> </el-button> <el-button size="small" type="primary" @click="onSubmit('form')"> </el-button>
@ -92,10 +113,10 @@
<!-- 添加角色 --> <!-- 添加角色 -->
<el-dialog :title="'请为' + this.titleName + '添加角色'" :visible.sync="isShow" width="30%" <el-dialog :title="'请为' + this.titleName + '添加角色'" :visible.sync="isShow" width="30%"
:before-close="addRolehandleClose" class="myDialog2" :append-to-body="true" custom-class="addJueSe"> :before-close="addRolehandleClose" class="myDialog2" :append-to-body="true" custom-class="addJueSe">
<div class="roleList"> <div class="roleList">
<Tree :tree-data="treeData" ref="tree" node-key="id" id="roleTree" :default-props="defaultProps" <Tree :tree-data="treeData" ref="tree" node-key="id" id="roleTree" :default-props="defaultProps"
:showCheckbox="true"></Tree> :showCheckbox="true"></Tree>
</div> </div>
<span slot="footer" class="dialog-footer"> <span slot="footer" class="dialog-footer">
<el-button size="small" @click="cancel()"> </el-button> <el-button size="small" @click="cancel()"> </el-button>
@ -129,15 +150,15 @@ export default {
isShow: false, isShow: false,
searchValue: '', searchValue: '',
rules: { rules: {
username: [{required: true, message: "请输入用户名称", trigger: "blur"}], username: [{ required: true, message: "请输入用户名称", trigger: "blur" }],
password: [{required: true, message: "请输入密码", trigger: "blur"}], password: [{ required: true, message: "请输入密码", trigger: "blur" }],
confirmPassword: [{required: true, message: "请再次输入密码", trigger: "blur"}], confirmPassword: [{ required: true, message: "请再次输入密码", trigger: "blur" }],
address: [{required: true, message: "请输入地址", trigger: "blur"}], address: [{ required: true, message: "请输入地址", trigger: "blur" }],
nick_name: [{required: true, message: "请输入昵称", trigger: "blur"}], nick_name: [{ required: true, message: "请输入昵称", trigger: "blur" }],
mobile: [{pattern: /^1(3\d|4[5-9]|5[0-35-9]|6[567]|7[0-8]|8\d|9[0-35-9])\d{8}$/, message: "请输入有效的手机号"}, mobile: [{ pattern: /^1(3\d|4[5-9]|5[0-35-9]|6[567]|7[0-8]|8\d|9[0-35-9])\d{8}$/, message: "请输入有效的手机号" },
{required: true, trigger: "blur", message: "请输入手机号"}], { required: true, trigger: "blur", message: "请输入手机号" }],
email: [{pattern: /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/, message: "请输入有效的邮箱"}, email: [{ pattern: /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/, message: "请输入有效的邮箱" },
{required: true, trigger: "blur", message: "请输入邮箱"}], { required: true, trigger: "blur", message: "请输入邮箱" }],
}, },
treeData: [], treeData: [],
tableData: [], tableData: [],
@ -192,7 +213,7 @@ export default {
type: "warning", type: "warning",
}) })
.then(() => { .then(() => {
editUserAPI({id: row.id, user_status: 1}).then((res) => { editUserAPI({ id: row.id, user_status: 1 }).then((res) => {
if (res.status == true) { if (res.status == true) {
this.$message({ this.$message({
message: "停用成功", message: "停用成功",
@ -221,7 +242,7 @@ export default {
type: "warning", type: "warning",
}) })
.then(() => { .then(() => {
editUserAPI({id: row.id, user_status: 0}).then((res) => { editUserAPI({ id: row.id, user_status: 0 }).then((res) => {
if (res.status == true) { if (res.status == true) {
this.$message({ this.$message({
message: "恢复成功", message: "恢复成功",
@ -250,7 +271,7 @@ export default {
type: "warning", type: "warning",
}) })
.then(() => { .then(() => {
editUserAPI({id: row.id, user_status: 2}).then((res) => { editUserAPI({ id: row.id, user_status: 2 }).then((res) => {
if (res.status == true) { if (res.status == true) {
this.$message({ this.$message({
message: "注销成功", message: "注销成功",
@ -320,7 +341,7 @@ export default {
this.isShow = true; this.isShow = true;
this.userid = row.id; this.userid = row.id;
this.titleName = row.username; this.titleName = row.username;
getOrgroleAPI({org_type: this.org_type}).then((res) => { //org_type getOrgroleAPI({ org_type: this.org_type }).then((res) => { //org_type
this.treeData = res.data; this.treeData = res.data;
}); });
this.getuserroles(); this.getuserroles();
@ -349,7 +370,7 @@ export default {
}); });
}, },
getuserroles() {// getuserroles() {//
getuserrolesAPI({userid: this.userid}).then((res) => { getuserrolesAPI({ userid: this.userid }).then((res) => {
if (res) { if (res) {
this.treeNode = res.data.map((item) => { this.treeNode = res.data.map((item) => {
if (item.roleid.role == "管理员") { if (item.roleid.role == "管理员") {
@ -401,7 +422,7 @@ export default {
type: "warning", type: "warning",
}) })
.then(() => { .then(() => {
delUserAPI({id: row.id}).then((res) => { delUserAPI({ id: row.id }).then((res) => {
if (res.status == true) { if (res.status == true) {
this.$message({ this.$message({
message: "用户删除成功", message: "用户删除成功",
@ -533,7 +554,7 @@ export default {
<style lang="scss" scope> <style lang="scss" scope>
.myOranization { .myOranization {
height: 81vh; height: 86vh;
.oranizationInfo { .oranizationInfo {
// height: 2rem; // height: 2rem;
@ -563,12 +584,22 @@ export default {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
} }
.label-box{
display: flex;
width: 100%;
}
.label{
display: block;
width: 120px;
text-align: right;
margin-right: 10px;
margin-bottom: 6px;
}
</style> </style>
<style> <style>
@media screen and (max-width: 760px) { @media screen and (max-width: 760px) {
.addPeople { .addPeople {
//border:10px solid red; /* border:10px solid red; */
width: 100vw !important; width: 100vw !important;
} }

View File

@ -3,8 +3,8 @@
<el-row :gutter="10"> <el-row :gutter="10">
<el-col :span="8" style="overflow-x: auto;min-width: 100px;" class="treeCard"> <el-col :span="8" style="overflow-x: auto;min-width: 100px;" class="treeCard">
<el-card class="left" style="font-size: 14px;overflow-x: auto!important;padding: 0!important;min-width: 200px;"> <el-card class="left" style="font-size: 14px;overflow-x: auto!important;padding: 0!important;min-width: 200px;">
<el-button type="primary" size="small" v-if="treeData.length==[]" @click="addDepartment()">请添加部门</el-button> <el-button type="primary" size="small" v-if="treeData.length==[]" @click="addDepartment()" style="margin-left: 14px;margin-top: 14px;">请添加部门</el-button>
<Tree id="tree" style="overflow-x: auto!important; height: calc(100vh - 106px);!important;" v-else ref="tree" node-key="id" :tree-data="treeData" :add-form-arr="addFormArr" :add-form="addForm" @treeDelChange="treeDelChange" :default-props="defaultProps" :default-expand-all="true" :is-add-del="true" @treeSubmitChange="treeSubmitChange" @treeUpdateChange="treeUpdateChange" @treeEditChange="treeEditChange"></Tree> <Tree id="tree" style="overflow-x: auto!important; height: calc(100vh - 106px);" v-else ref="tree" node-key="id" :tree-data="treeData" :add-form-arr="addFormArr" :add-form="addForm" @treeDelChange="treeDelChange" :default-props="defaultProps" :default-expand-all="true" :is-add-del="true" @treeSubmitChange="treeSubmitChange" @treeUpdateChange="treeUpdateChange" @treeEditChange="treeEditChange"></Tree>
</el-card> </el-card>
</el-col> </el-col>
<el-col :span="16"> <el-col :span="16">
@ -349,16 +349,19 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.el-button{
margin-bottom: 10px;
}
.departmentManagement { .departmentManagement {
height: 85vh; height: 90vh;
.left { .left {
height: 85vh; height:90vh;
} }
.right { .right {
.button{ .button{
display:flex; display:flex;
} }
height: 85vh; height: 90vh;
.userdeparment { .userdeparment {
// font-size: 18px; // font-size: 18px;
} }
@ -376,7 +379,3 @@ padding: 0;
} }
} }
</style> </style>
<style>
</style>

File diff suppressed because it is too large Load Diff

View File

@ -452,7 +452,7 @@ export default {
padding-top: 25px; padding-top: 25px;
//margin-top: -20px; //margin-top: -20px;
display: flex; display: flex;
justify-content: flex-start; justify-content: center ;
align-items: center; align-items: center;
//margin-right: 25%; //margin-right: 25%;
list-style: none; list-style: none;
@ -516,6 +516,7 @@ export default {
} }
.itemMobile { .itemMobile {
height: auto !important; height: auto !important;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,28 +1,26 @@
<template> <template>
<div> <div class="backgroundColor">
<qualificationBox :approveInfo="approveInfo"></qualificationBox> <qualificationBox :approveInfo="approveInfo"></qualificationBox>
</div> </div>
</template> </template>
<script> <script>
import qualificationBox from '../qualificationBox/index.vue'; import qualificationBox from '../qualificationBox/index.vue';
export default { export default {
name: 'apprvedInfo', name: 'apprvedInfo',
components: { components: {
qualificationBox qualificationBox
}, },
data() { data() {
return { return {
approveInfo:{ approveInfo: {
audit_status:"approved,rejected", audit_status: "approved,rejected",
} }
} }
}, },
created(){ created() {
// this.initData() // this.initData()
}, },
} }
</script> </script>
<style scoped> <style scoped></style>
</style>

View File

@ -1,5 +1,5 @@
<template> <template>
<div> <div class="backgroundColor">
<qualificationBox :approveInfo="approveInfo"></qualificationBox> <qualificationBox :approveInfo="approveInfo"></qualificationBox>
</div> </div>

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="leftTable"> <div class="leftTable backgroundColor">
<div class="findButtonMobile" v-if="isMobile"> <div class="findButtonMobile" v-if="isMobile">
<el-row class="searchOne"> <el-row class="searchOne">
<el-col :span="24" class="colOne"> <el-col :span="24" class="colOne">
@ -24,7 +24,10 @@
</div> </div>
<div class="findButton" v-else> <div class="findButton" v-else>
<el-row class="rowBottom"> <el-row class="rowBottom">
<el-col :span="8" class="colOne"> <el-col :span="2" class="colCharge">
<el-button class="recharge-btn" @click="$router.push('/kbossCharge')" >充值</el-button>
</el-col>
<el-col :span="4" class="colOne">
<el-select size="small" v-model="recharge_path" placeholder="请选择充值途径" @change="changeSelect"> <el-select size="small" v-model="recharge_path" placeholder="请选择充值途径" @change="changeSelect">
<el-option label="支付宝" value='0'> <el-option label="支付宝" value='0'>
</el-option> </el-option>
@ -303,4 +306,26 @@ export default {
.really-price { .really-price {
color: #6a7581; color: #6a7581;
} }
.recharge-btn {
background: linear-gradient(135deg, #4fc3f7, #29b6f6);
color: white;
padding: 12px 34px;
border: none;
border-radius: 8px;
font-size: 16px;
font-weight: bold;
cursor: pointer;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
transition: all 0.3s ease;
}
.recharge-btn:hover {
background: linear-gradient(135deg, #4fc3f7, #29b6f6);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
}
.recharge-btn:active {
transform: translateY(2px);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
</style> </style>

View File

@ -0,0 +1,393 @@
<template>
<div class="box">
<!-- 实名认证通知 -->
<div v-if="showAuthNotification" class="auth-notification-container">
<!-- 展开状态完整提示窗口 -->
<div v-show="isNotificationExpanded" class="notification-card">
<div class="notification-header">
<div class="notification-title">
<i class="notification-icon el-icon-warning"></i>
<span>实名认证提示</span>
</div>
<button class="collapse-btn" @click="toggleNotification" aria-label="收起提示">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9 18L15 12L9 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
</div>
<div class="notification-content">
<p>您当前还没有完成实名认证部分功能可能受限请先完成<span class="link-text" @click="goToAuth">实名认证</span>以确保正常使用所有服务</p>
</div>
</div>
<!-- 收起状态简化按钮 -->
<div v-show="!isNotificationExpanded" class="notification-minimized" @click="toggleNotification">
<div class="minimized-content">
<i class="minimized-icon el-icon-warning"></i>
<span>实名认证</span>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15 18L9 12L15 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</div>
</div>
</div>
<!-- 添加全屏加载效果 -->
<div v-loading="loading" class="loading-container">
<iframe v-if="url" :src="url" frameborder="0" class="baidu-style">
</iframe>
</div>
</div>
</template>
<script>
import { baiducloudAPI } from '@/api/BaiDuTokenapi'
import { reqBaiduJudgePrice, reqConfirmBtn } from '@/api/baidu'
import { reqIsReallyPeople } from '@/api/baidu' // API
export default {
name: 'baiduProductShow',
data() {
return {
userToken: '',
url: '',
loading: true,
userid: '',
showAuthNotification: false, //
isNotificationExpanded: true, //
}
},
async created() {
await this.checkRealNameAuth();
await this.getToken();
},
mounted() {
window.addEventListener('message', this.receiveMessage, false);
},
beforeDestroy() {
window.removeEventListener('message', this.receiveMessage, false);
},
methods: {
//
async checkRealNameAuth() {
try {
this.userid = sessionStorage.getItem('userId');
if (!this.userid) {
console.warn('未获取到用户ID无法检查实名认证状态');
return;
}
const response = await reqIsReallyPeople({user_id: this.userid});
// APIres.statustruefalse
this.showAuthNotification = !response.status;
if (!response.status) {
console.log('用户未完成实名认证,显示通知');
}
} catch (error) {
console.error('检查实名认证状态失败:', error);
//
}
},
//
goToAuth() {
window.open('https://console.vcp.baidu.com/qualify/#/qualify/index', '_blank');
},
// /
toggleNotification() {
this.isNotificationExpanded = !this.isNotificationExpanded;
},
// token
async getToken() {
try {
this.loading = true;
const response = await baiducloudAPI();
this.userToken = response.data;
if (this.userToken) {
const baseUrl = 'https://console.vcp.baidu.com/api/loginvcp/login/securitytoken';
const redirectUrl = encodeURIComponent('https://console.vcp.baidu.com/billing/#/refund/list');
const token = encodeURIComponent(this.userToken);
this.url = `${baseUrl}?redirectUrl=${redirectUrl}&signinSecurityToken=${token}`;
} else {
console.error('未能从API响应中获取到token:', response);
}
} catch (error) {
console.error('获取百度云Token失败:', error);
} finally {
this.loading = false;
}
},
receiveMessage(event) {
console.log('接收到消息:', event);
const data = event.data;
console.log('接收到的 data 是:', data);
// 2. refundInfo uuidList
if (data && data.refundInfo && Array.isArray(data.refundInfo.uuidList) && data.refundInfo.uuidList.length > 0) {
const uuidListArray = data.refundInfo.uuidList; //
console.log('提取到的订单ID:', uuidListArray);
// 4. ID
this.userid = sessionStorage.getItem('userId');
if (!this.userid) {
console.error('未获取到用户ID (sessionStorage 中缺少 userId)');
this.$message.error('用户信息获取失败,请重新登录');
return;
}
// 5.
const payload = {
order_id: uuidListArray,
userid: this.userid
};
// 6.
this.loading = true;
// 7. 退API
reqConfirmBtn(payload)
.then((res) => {
console.log("调用 reqBaiduJudgePrice 接口返回:", res);
if (res.status) { // status true
this.$message.success('退订成功');
//
window.location.reload();
} else {
//
this.$message.error(res.msg || '退订失败,请稍后重试');
}
})
.catch((error) => {
// ()
console.error("调用退订接口 reqBaiduJudgePrice 失败 (网络/请求错误):", error);
this.$message.error('网络请求失败或服务异常,请检查网络连接后重试');
})
.finally(() => {
//
this.loading = false;
});
} else {
console.log('接收到的消息不包含有效的退款信息或 uuidList 为空');
}
}
}
}
</script>
<style lang="less" scoped>
.box {
padding: 10px;
height: calc(100vh - 100px);
position: relative;
}
.loading-container {
width: 100%;
height: calc(100vh - 100px);
position: relative;
}
.login-prompt {
height: calc(100vh - 100px);
display: flex;
align-items: center;
justify-content: center;
text-align: center;
}
.prompt-content {
max-width: 300px;
padding: 30px;
border-radius: 8px;
background: #f8f9fa;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}
.prompt-icon {
font-size: 48px;
color: #ffc107;
margin-bottom: 16px;
}
.prompt-content p {
font-size: 16px;
color: #606266;
margin-bottom: 20px;
}
.retry-btn {
background: #1890ff;
color: white;
border: none;
padding: 8px 20px;
border-radius: 4px;
cursor: pointer;
transition: background 0.3s;
&:hover {
background: #40a9ff;
}
}
.baidu-style {
width: 100%;
height: calc(100vh - 100px);
}
/* 实名认证通知容器 */
.auth-notification-container {
position: absolute;
top: 20px;
right: 20px;
z-index: 1000;
max-width: 380px;
}
/* 通知卡片样式 */
.notification-card {
background: #ffffff;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12);
border: 1px solid #e8e8e8;
overflow: hidden;
animation: slideIn 0.3s ease-out;
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateX(20px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
/* 通知头部 */
.notification-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px 20px 12px;
border-bottom: 1px solid #f0f0f0;
}
.notification-title {
display: flex;
align-items: center;
font-weight: 600;
font-size: 16px;
color: #333;
}
.notification-icon {
color: #FFBA00;
margin-right: 8px;
font-size: 18px;
}
.collapse-btn {
background: none;
border: none;
color: #999;
cursor: pointer;
padding: 4px;
border-radius: 4px;
transition: all 0.2s;
display: flex;
align-items: center;
justify-content: center;
&:hover {
background-color: #f5f5f5;
color: #666;
}
}
/* 通知内容 */
.notification-content {
padding: 16px 20px 20px;
p {
margin: 0;
line-height: 1.6;
color: #666;
font-size: 14px;
}
}
.link-text {
color: #1890ff;
cursor: pointer;
text-decoration: none;
margin: 0 4px;
font-weight: 500;
transition: color 0.2s;
&:hover {
color: #40a9ff;
text-decoration: underline;
}
}
/* 收起状态样式 */
.notification-minimized {
background: #ffffff;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
border: 1px solid #e8e8e8;
cursor: pointer;
transition: all 0.2s;
&:hover {
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
transform: translateY(-2px);
}
}
.minimized-content {
display: flex;
align-items: center;
padding: 10px 14px;
font-size: 14px;
font-weight: 500;
color: #333;
}
.minimized-icon {
color: #FFBA00;
margin-right: 8px;
font-size: 16px;
}
/* 响应式设计 */
@media (max-width: 768px) {
.auth-notification-container {
top: 10px;
right: 10px;
left: 10px;
max-width: none;
}
.notification-card {
border-radius: 8px;
}
.notification-header {
padding: 12px 16px 8px;
}
.notification-content {
padding: 12px 16px 16px;
}
}
</style>

View File

@ -0,0 +1,15 @@
<template>
<div>
<router-view></router-view>
</div>
</template>
<script>
export default {
}
</script>
<style lang="less" scoped>
</style>

View File

@ -1,97 +1,144 @@
<template> <template>
<div v-loading="loading" class="customerGood"> <div v-loading="loading" class="customerGood">
<!-- <div class="tip"><img src="./svg/tip.svg" alt="">资源列表只展示未到期产品</div>--> <!-- 搜索部分 -->
<!-- <SshTerminal></SshTerminal>--> <div>
<el-table :data="tableData" style="width: 100%;font-size: 12px" height="calc(100vh - 130px)" border> <ul class="search-box">
<el-table-column min-width="150px" align="center" prop="productname" label="产品名称"></el-table-column> <li>
<el-table-column min-width="150px" align="center" prop="productdesc" label="产品描述" <el-input-group class="search-input">
:show-overflow-tooltip="true"> <el-input
<template slot-scope="{row}"> size="mini"
{{ row.productdesc ? row.productdesc : '-' }} placeholder="请输入关键词"
</template> v-model="queryParams.productname"
</el-table-column> clearable
<el-table-column min-width="150px" align="center" prop="orderid" label="订单号" @keyup.enter.native="handleSearch"
:show-overflow-tooltip="true"></el-table-column> ></el-input>
<el-table-column min-width="60px" align="center" prop="start_date" label="购买日期"></el-table-column> <el-button
<el-table-column prop="expire_date" label="到期日期"> slot="append"
<template slot-scope="scope"> icon="el-icon-search"
{{ scope.row.expire_date == null ? '-' : scope.row.expire_date }} size="mini"
</template> @click="handleSearch"
</el-table-column> ></el-button>
<!-- </el-input-group>
<el-table-column prop="total_quantity" label="总量"> </li>
<el-table-column prop="used_quantity" label="已用量"> <li>
</el-table-column> <span class="search-label">创建日期:</span>
<el-table-column prop="rest_quantity" label="剩余量"> <el-date-picker
</el-table-column> --> size="mini"
<el-table-column prop="" label="操作" align="center" width="120px"> style="width: 220px;"
<template slot-scope="scope"> type="datetimerange"
<el-button type="primary" size="mini" @click="goJiNanChaoSuan()" v-if="scope.row.providername==='济南超算'"> align="right"
<div style="display: flex;justify-content: center;align-items: center"> start-placeholder="开始日期"
<img style="width: 12px;margin-right: 5px;height: 12px;" src="./svg/跳转.svg" end-placeholder="结束日期"
alt="">超算产品 :default-time="['00:00:00', '23:59:59']"
</div> format="yyyy-MM-dd"
</el-button> value-format="yyyy-MM-dd"
<el-button type="primary" size="mini" @click="goBaiDu(scope.row.product_url)" v-model="dateRange"
v-else-if="(scope.row.providername==='百度智能云')"> @change="handleDateChange"
<div style="display: flex;justify-content: center;align-items: center"> ></el-date-picker>
<img style="width: 12px;margin-right: 5px;height: 12px;" src="./svg/跳转.svg" </li>
alt="">百度产品 <li>
</div> <el-button size="mini" @click="handleReset">重置</el-button>
</el-button> <el-button type="primary" size="mini" @click="handleSearch">查询</el-button>
<el-button type="primary" size="mini" @click="goJd" </li>
v-else-if="(scope.row.providername==='京东云')" </ul>
> </div>
<!-- <i class="el-icon-edit-outline"></i> -->
<div style="display: flex;justify-content: center;align-items: center">
<img style="width: 12px;margin-right: 5px;height: 12px;" src="./svg/跳转.svg"
alt="">京东产品
</div>
</el-button>
<el-button type="primary" size="mini" @click="goUcloud(scope.row.region)"
v-else-if="(scope.row.providername==='优刻得科技股份有限公司')">
<!-- <i class="el-icon-edit-outline"></i> -->
<div style="display: flex;justify-content: center;align-items: center">
<img style="width: 12px;margin-right: 5px;height: 12px;" src="./svg/跳转.svg"
alt="">集群二
</div>
</el-button>
<el-button size="mini" @click="nodeThree(scope.row)" v-else-if="(scope.row.classify === 'E')">
详情
</el-button>
<div v-else-if="scope.row.classify ==='CPCC' ">
<el-button size="mini" type="primary"
@click="openCpccDetail(scope.row)">
容器化详情
</el-button>
<el-button size="mini" type="primary"
@click="$router.push('/customer/SshTerminal')">
登录
</el-button>
</div>
<!-- <el-dropdown @command="handleCommand(scope.row, $event)" v-else-if="(scope.row.classify === 'E')"-->
<!-- trigger="click">-->
<!-- <span style="cursor: pointer" class="el-dropdown-link">-->
<!-- 集群三<i class="el-icon-arrow-down el-icon&#45;&#45;right"></i>-->
<!-- </span>-->
<!-- <el-dropdown-menu slot="dropdown">-->
<!-- <el-dropdown-item command="detail" icon="el-icon-warning-outline">详情</el-dropdown-item>-->
<!-- <el-dropdown-item command="shutDown" icon="el-icon-switch-button">关机</el-dropdown-item>-->
<!-- </el-dropdown-menu>-->
<!-- </el-dropdown>-->
<el-button type="primary" size="mini" @click="goCaption()" <!-- 表格部分 -->
v-else-if="(scope.row.providername==='北京首都在线科技股份有限公司')"> <el-card class="tableCard">
<!-- <i class="el-icon-edit-outline"></i> --> <el-table
<div style="display: flex;justify-content: center;align-items: center"> :data="tableData"
<img style="width: 12px;margin-right: 5px;height: 12px;" src="./svg/跳转.svg" style="width: 100%;font-size: 12px"
alt="">集群一 height="calc(100vh - 280px)"
border
v-loading="loading"
>
<el-table-column min-width="150px" align="center" prop="productname" label="产品名称"></el-table-column>
<!-- <el-table-column min-width="150px" align="center" prop="productdesc" label="产品描述" :show-overflow-tooltip="true">
<template slot-scope="{row}">
{{ row.productdesc ? row.productdesc : '-' }}
</template>
</el-table-column> -->
<el-table-column min-width="150px" align="center" prop="resourceid" label="资源ID">
</el-table-column>
<el-table-column min-width="150px" align="center" prop="orderid" label="订单号" :show-overflow-tooltip="true"></el-table-column>
<!-- 修改后的产品配置列渲染 spec_data -->
<el-table-column min-width="150px" align="center" label="产品配置">
<template slot-scope="scope">
<span v-if="scope.row.spec_data && scope.row.spec_data.length">
{{ scope.row.spec_data.join(', ') }}
</span>
<span v-else>--</span>
</template>
</el-table-column>
<el-table-column min-width="60px" align="center" prop="start_date" label="购买日期"></el-table-column>
<el-table-column prop="expire_date" label="到期日期">
<template slot-scope="scope">
{{ scope.row.expire_date == null ? '-' : scope.row.expire_date }}
</template>
</el-table-column>
<el-table-column prop="" label="操作" align="center" width="120px">
<template slot-scope="scope">
<el-button type="primary" size="mini" @click="goJiNanChaoSuan()" v-if="scope.row.providername === '济南超算'">
<div style="display: flex;justify-content: center;align-items: center">
<img style="width: 12px;margin-right: 5px;height: 12px;" src="./svg/跳转.svg" alt="">超算产品
</div>
</el-button>
<el-button type="primary" size="mini" @click="goBaiDu(scope.row.product_url)" v-else-if="(scope.row.providername === '百度智能云')">
<div style="display: flex;justify-content: center;align-items: center">
<img style="width: 12px;margin-right: 5px;height: 12px;" src="./svg/跳转.svg" alt="">实例使用
</div>
</el-button>
<el-button type="primary" size="mini" @click="goJd" v-else-if="(scope.row.providername === '京东云')">
<div style="display: flex;justify-content: center;align-items: center">
<img style="width: 12px;margin-right: 5px;height: 12px;" src="./svg/跳转.svg" alt="">京东产品
</div>
</el-button>
<el-button type="primary" size="mini" @click="goUcloud(scope.row.region)" v-else-if="(scope.row.providername === '优刻得科技股份有限公司')">
<div style="display: flex;justify-content: center;align-items: center">
<img style="width: 12px;margin-right: 5px;height: 12px;" src="./svg/跳转.svg" alt="">集群二
</div>
</el-button>
<el-button size="mini" @click="nodeThree(scope.row)" v-else-if="(scope.row.classify === 'E')">
详情
</el-button>
<div v-else-if="scope.row.classify === 'CPCC'">
<el-button size="mini" type="primary" @click="openCpccDetail(scope.row)">
容器化详情
</el-button>
<el-button size="mini" type="primary" @click="$router.push('/customer/SshTerminal')">
登录
</el-button>
</div> </div>
</el-button> <el-button type="primary" size="mini" @click="goCaption()" v-else-if="(scope.row.providername === '北京首都在线科技股份有限公司')">
<span v-else>-</span> <div style="display: flex;justify-content: center;align-items: center">
</template> <img style="width: 12px;margin-right: 5px;height: 12px;" src="./svg/跳转.svg" alt="">集群一
</el-table-column> </div>
</el-table> </el-button>
<span v-else>-</span>
</template>
</el-table-column>
</el-table>
<!-- Element UI 分页组件 -->
<div class="pagination-container">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="queryParams.page"
:page-sizes="[10, 20, 50, 100]"
:page-size="queryParams.page_size"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
>
</el-pagination>
</div>
</el-card>
<!-- 详情对话框 -->
<el-dialog title="详情" :visible.sync="dialogTableVisible"> <el-dialog title="详情" :visible.sync="dialogTableVisible">
<el-table :data="datailList"> <el-table :data="datailList">
<el-table-column min-width="200px" property="date" label="实例编号/名称"> <el-table-column min-width="200px" property="date" label="实例编号/名称">
@ -108,14 +155,8 @@
<template slot-scope="scope"> <template slot-scope="scope">
<div class="guige"> <div class="guige">
<span>{{ scope.row.productname }}* {{ scope.row.gpu }}</span> <span>{{ scope.row.productname }}* {{ scope.row.gpu }}</span>
<el-popover placement="top" title="" width="200" trigger="hover">
<el-popover
placement="top"
title=""
width="200"
trigger="hover">
<span class="tipStyle" slot="reference">查看详情</span> <span class="tipStyle" slot="reference">查看详情</span>
<div> <div>
<p>存储: {{ scope.row.storage }} G</p> <p>存储: {{ scope.row.storage }} G</p>
<p>CPU: {{ scope.row.cpu }} </p> <p>CPU: {{ scope.row.cpu }} </p>
@ -127,7 +168,6 @@
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column min-width="120px" property="address" label="健康状态"> <el-table-column min-width="120px" property="address" label="健康状态">
<template slot-scope="scope"> <template slot-scope="scope">
正常 正常
@ -143,103 +183,77 @@
<div class="itemOut"> <div class="itemOut">
<div>登录指令</div> <div>登录指令</div>
<div>ssh ****** <span class="copyBtn"> <div>ssh ****** <span class="copyBtn">
<i @click="copyText('ssh -p '+scope.row.port+' '+scope.row.loginname+'@'+scope.row.ip_region)" <i @click="copyText('ssh -p ' + scope.row.port + ' ' + scope.row.loginname + '@' + scope.row.ip_region)" class="el-icon-copy-document"></i>
class="el-icon-copy-document"></i> </span>
</span>
</div> </div>
</div> </div>
<div class="itemOut"> <div class="itemOut">
<div>密码</div> <div>密码</div>
<div>****** <span class="copyBtn"> <i @click="copyText(scope.row.loginpwd)" <div>****** <span class="copyBtn"> <i @click="copyText(scope.row.loginpwd)" class="el-icon-copy-document"></i> </span></div>
class="el-icon-copy-document"></i> </span></div>
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
<!-- <el-table-column min-width="200px" property="address" label="创建时间/到期时间">-->
<!-- <template slot-scope="scope">-->
<!-- {{ scope.row.id }}-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column min-width="150px" fixed="right" property="address" label="操作"> <el-table-column min-width="150px" fixed="right" property="address" label="操作">
<template slot-scope="scope"> <template slot-scope="scope">
<el-popconfirm <el-popconfirm @confirm="shutDownThree(scope.row)" title="确定将该设备关机吗?">
@confirm="shutDownThree(scope.row)"
title="确定将该设备关机吗?"
>
<el-button slot="reference" :loading="deleteBtnLoading" type="danger" size="mini"> <el-button slot="reference" :loading="deleteBtnLoading" type="danger" size="mini">
关机 关机
</el-button> </el-button>
</el-popconfirm> </el-popconfirm>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
</el-dialog> </el-dialog>
<el-dialog <!-- 登录信息对话框 -->
title="登录信息" <el-dialog title="登录信息" :visible.sync="rqyVisible" width="800">
:visible.sync="rqyVisible"
width="800"
>
<el-descriptions title="" direction="vertical" :column="4" border> <el-descriptions title="" direction="vertical" :column="4" border>
<el-descriptions-item label="实例id">{{ cpccDetail.id }}</el-descriptions-item> <el-descriptions-item label="实例id">{{ cpccDetail.id }}</el-descriptions-item>
<el-descriptions-item label="实例名称">{{ cpccDetail.source_name }}</el-descriptions-item> <el-descriptions-item label="实例名称">{{ cpccDetail.source_name }}</el-descriptions-item>
<el-descriptions-item label="状态">进行中</el-descriptions-item> <el-descriptions-item label="状态">进行中</el-descriptions-item>
<el-descriptions-item label="健康状态"> <el-descriptions-item label="健康状态">
<el-tag type="success" effect="dark">
<el-tag
type="success"
effect="dark">
正常 正常
</el-tag> </el-tag>
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="登录账号">{{ cpccDetail.source_authuser }}</el-descriptions-item> <el-descriptions-item label="登录账号">{{ cpccDetail.source_authuser }}</el-descriptions-item>
<el-descriptions-item label="密码"> <el-descriptions-item label="密码">
<div class="pasStyle"> <div class="pasStyle">
<span v-if="!isShowPass"> **** </span> <span v-if="!isShowPass"> **** </span>
<span v-if="isShowPass"> {{ cpccDetail.source_authpasswd }}</span> <span v-if="isShowPass"> {{ cpccDetail.source_authpasswd }}</span>
<img @click="isShowPass = !isShowPass" v-if="!isShowPass" src="./svg/showEye.svg" alt=""> <img @click="isShowPass = !isShowPass" v-if="!isShowPass" src="./svg/showEye.svg" alt="">
<img @click="isShowPass = !isShowPass" v-if="isShowPass" src="./svg/hidenEye.svg" alt=""> <img @click="isShowPass = !isShowPass" v-if="isShowPass" src="./svg/hidenEye.svg" alt="">
</div> </div>
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="IP">{{ cpccDetail.source_externalip }}</el-descriptions-item> <el-descriptions-item label="IP">{{ cpccDetail.source_externalip }}</el-descriptions-item>
<el-descriptions-item label="端口号">{{ cpccDetail.source_outsideport }}</el-descriptions-item> <el-descriptions-item label="端口号">{{ cpccDetail.source_outsideport }}</el-descriptions-item>
<el-descriptions-item label="内存量">{{ cpccDetail.source_memrate }}</el-descriptions-item> <el-descriptions-item label="内存量">{{ cpccDetail.source_memrate }}</el-descriptions-item>
<el-descriptions-item label="核心数">{{ cpccDetail.source_cpurate }}</el-descriptions-item> <el-descriptions-item label="核心数">{{ cpccDetail.source_cpurate }}</el-descriptions-item>
<el-descriptions-item label="数据盘">{{ cpccDetail.source_storagelimits }}</el-descriptions-item> <el-descriptions-item label="数据盘">{{ cpccDetail.source_storagelimits }}</el-descriptions-item>
<el-descriptions-item label="系统盘">{{ cpccDetail.disk_sys_limit }}</el-descriptions-item> <el-descriptions-item label="系统盘">{{ cpccDetail.disk_sys_limit }}</el-descriptions-item>
<el-descriptions-item v-if="cpccDetail.source_gpu!=='0'" label="卡数">{{ <el-descriptions-item v-if="cpccDetail.source_gpu !== '0'" label="卡数">{{ cpccDetail.source_gpu }}
cpccDetail.source_gpu
}}
</el-descriptions-item> </el-descriptions-item>
</el-descriptions> </el-descriptions>
<span slot="footer" class="dialog-footer"> <span slot="footer" class="dialog-footer">
<!-- <el-button @click="rqyVisible = false"> </el-button>--> <el-button type="primary" @click="rqyVisible = false"> </el-button>
<el-button type="primary" @click="rqyVisible = false"> </el-button> </span>
</span>
</el-dialog> </el-dialog>
</div> </div>
</template> </template>
<script> <script>
import {getCustomerGoodsAPI, HpcAccessTimeAPI} from '@/api/customer/userResource' import { getCustomerGoodsAPI, HpcAccessTimeAPI } from '@/api/customer/userResource'
import {getJinanchaosuanSign} from '@/api/JiNanChaoSuan/jiNanChaoSuanUserList' import { getJinanchaosuanSign } from '@/api/JiNanChaoSuan/jiNanChaoSuanUserList'
import {goJdUrl} from "@/api/product/jdApi"; import { goJdUrl } from "@/api/product/jdApi";
import {reqDeleteK8sCloud, reqGetInstance} from "@/api/k8s"; import { reqDeleteK8sCloud, reqGetInstance } from "@/api/k8s";
import {Terminal} from "xterm"; import { Terminal } from "xterm";
import SshTerminal from "@/views/customer/userResource/SshTerminal.vue"; import SshTerminal from "@/views/customer/userResource/SshTerminal.vue";
export default { export default {
name: "userResource", name: "userResource",
components: {SshTerminal}, components: {
SshTerminal
},
data() { data() {
return { return {
isShowPass: false, isShowPass: false,
@ -252,132 +266,181 @@ export default {
tableData: [], tableData: [],
loading: false, loading: false,
dialogTableVisible: false, dialogTableVisible: false,
datailList: [] datailList: [],
total: 0,
dateRange: [],
queryParams: {
productname: '', //
start_date: '', //
end_date: '', //
page: 1, //
page_size: 10, //
}
}; };
}, },
mounted() { mounted() {
this.loading = true this.loading = true;
this.getCustomerGoods() this.getCustomerGoods();
console.log("用户资源的路由信息是", this.$route) console.log("用户资源的路由信息是", this.$route);
// this.initTerminal()
}, },
methods: { methods: {
//
handleSearch() {
this.queryParams.page = 1; //
this.getCustomerGoods();
},
//
handleReset() {
this.queryParams = {
productname: '',
start_date: '',
end_date: '',
page: 1,
page_size: 10,
};
this.dateRange = [];
this.getCustomerGoods();
},
//
handleDateChange(value) {
if (value && value.length === 2) {
this.queryParams.start_date = value[0];
this.queryParams.end_date = value[1];
} else {
this.queryParams.start_date = '';
this.queryParams.end_date = '';
}
},
//
handleSizeChange(val) {
this.queryParams.page_size = val;
this.getCustomerGoods();
},
//
handleCurrentChange(val) {
this.queryParams.page = val;
this.getCustomerGoods();
},
//
async getCustomerGoods() {
this.loading = true;
try {
const res = await getCustomerGoodsAPI(this.queryParams);
if (res.status === true) {
this.tableData = res.data;
this.total = res.pagination.total;
} else {
this.$message.error('获取数据失败');
}
} catch (error) {
console.error('获取用户资源失败:', error);
this.$message.error('获取数据失败');
} finally {
this.loading = false;
}
},
openCpccDetail(row) { openCpccDetail(row) {
this.rqyVisible = true;
this.rqyVisible = true this.cpccDetail = row.instance_info;
this.cpccDetail = row.instance_info
},
initTerminal() {
let term = new Terminal();
term.open(document.getElementById('terminal'));
term.write('Hello from \x1B[1;3;31mxterm.js\x1B[0m $ ');
}, },
copyText(value) { copyText(value) {
// textarea
const textarea = document.createElement('textarea'); const textarea = document.createElement('textarea');
textarea.value = value; textarea.value = value;
document.body.appendChild(textarea); document.body.appendChild(textarea);
//
textarea.select(); textarea.select();
document.execCommand('copy'); document.execCommand('copy');
// textarea
document.body.removeChild(textarea); document.body.removeChild(textarea);
//
this.$message.success('已复制到剪贴板'); this.$message.success('已复制到剪贴板');
}, },
shutDownThree(item) { shutDownThree(item) {
this.deleteBtnLoading = true this.deleteBtnLoading = true;
let ploay = { let ploay = {
id: item.id, id: item.id,
podname: item.podname, podname: item.podname,
pvcname: item.pvcname, pvcname: item.pvcname,
customer_goods_id: item.customer_goods_id customer_goods_id: item.customer_goods_id
} };
reqDeleteK8sCloud(ploay).then(res => { reqDeleteK8sCloud(ploay).then(res => {
this.deleteBtnLoading = false this.deleteBtnLoading = false;
if (res.status) { if (res.status) {
this.$message.success("删除成功~") this.$message.success("删除成功~");
reqGetInstance({customer_goods_id: item.id, orgid: sessionStorage.getItem('orgid')}).then(res => { reqGetInstance({ customer_goods_id: item.id, orgid: sessionStorage.getItem('orgid') }).then(res => {
if (res.status) { if (res.status) {
this.datailList = res.data this.datailList = res.data;
} }
}) });
} else { } else {
this.$message.warning("删除失败~") this.$message.warning("删除失败~");
} }
}) });
}, },
nodeThree(row) { nodeThree(row) {
this.detailBtnLoading = true this.detailBtnLoading = true;
reqGetInstance({customer_goods_id: row.id, orgid: sessionStorage.getItem('orgid')}).then(res => { reqGetInstance({ customer_goods_id: row.id, orgid: sessionStorage.getItem('orgid') }).then(res => {
this.detailBtnLoading = false this.detailBtnLoading = false;
if (res.status) { if (res.status) {
this.dialogTableVisible = true this.dialogTableVisible = true;
this.datailList = res.data this.datailList = res.data;
} }
}) });
}, },
goCaption() { goCaption() {
this.$router.push('/product/gpu/showGpu') this.$router.push('/product/gpu/showGpu');
}, },
//
goUcloud(region) { goUcloud(region) {
sessionStorage.setItem('region', region) sessionStorage.setItem('region', region);
this.$router.push('/product/ucloudProduct/showCloudHost') this.$router.push('/product/ucloudProduct/showCloudHost');
}, },
//jd
goJd() { goJd() {
this.loading = true this.loading = true;
//
goJdUrl(this.userid).then(res => { goJdUrl(this.userid).then(res => {
this.loading = false this.loading = false;
if (res.status) { if (res.status) {
window.open(res.data) window.open(res.data);
} else { } else {
this.$message.error('跳转京东界面失败') this.$message.error('跳转京东界面失败');
} }
});
})
}, },
//
goBaiDu(listUrl) { goBaiDu(listUrl) {
this.$store.commit('setRedirectUrl', listUrl) this.$store.commit('setRedirectUrl', listUrl);
localStorage.setItem('redirectUrl', listUrl) localStorage.setItem('redirectUrl', listUrl);
this.$router.push({ this.$router.push({
name: 'baiduProductShow', name: 'baiduProductShow',
params: { params: {
listUrl: listUrl, listUrl: listUrl,
} }
}) });
}, },
HpcAccessTime() {
HpcAccessTimeAPI({orgid: sessionStorage.getItem("orgid")}).then(res => {
if (rs.status == true) {
} HpcAccessTime() {
}) HpcAccessTimeAPI({ orgid: sessionStorage.getItem("orgid") }).then(res => {
},
getCustomerGoods() {//
getCustomerGoodsAPI({}).then(res => {
this.loading = false
if (res.status == true) { if (res.status == true) {
this.tableData = res.data // 访
} }
}) });
}, },
goJiNanChaoSuan() {//
this.HpcAccessTime() goJiNanChaoSuan() {
this.HpcAccessTime();
var orgid = sessionStorage.getItem("orgid"); var orgid = sessionStorage.getItem("orgid");
var username = sessionStorage.getItem("user"); var username = sessionStorage.getItem("user");
let ploay = { let ploay = {
username: username username: username
} };
getJinanchaosuanSign(ploay).then(res => { getJinanchaosuanSign(ploay).then(res => {
if (res.status && res.warn_msg == null) { if (res.status && res.warn_msg == null) {
window.open( window.open(
@ -396,35 +459,27 @@ export default {
"_blank" "_blank"
); );
} }
}) });
}, },
}, },
}; };
</script> </script>
<style lang="scss" scoped> <style lang="less" scoped>
.customerGood {
}
.tip { .tip {
color: #ff9120; color: #ff9120;
height: 35px; height: 35px;
img { img {
width: 15px; width: 15px;
height: 15px; height: 15px;
margin-right: 3px; margin-right: 3px;
} }
padding-left: 2px; padding-left: 2px;
background: #fff; background: #fff;
font-size: 14px; font-size: 14px;
//border: 1px solid red;
display: flex; display: flex;
justify-content: flex-start; justify-content: flex-start;
align-items: center; align-items: center;
} }
.guige { .guige {
@ -435,7 +490,6 @@ export default {
.tipStyle { .tipStyle {
transition: all .3s ease-in-out; transition: all .3s ease-in-out;
cursor: pointer; cursor: pointer;
&:hover { &:hover {
transition: all .3s ease-in-out; transition: all .3s ease-in-out;
color: #0a04e1; color: #0a04e1;
@ -450,11 +504,9 @@ export default {
.copyBtn { .copyBtn {
transition: all .3s ease-in-out; transition: all .3s ease-in-out;
i { i {
color: blue; color: blue;
} }
&:hover { &:hover {
transition: all .3s ease-in-out; transition: all .3s ease-in-out;
cursor: pointer; cursor: pointer;
@ -468,14 +520,53 @@ export default {
height: 20px; height: 20px;
cursor: pointer; cursor: pointer;
margin-left: 8px; margin-left: 8px;
&:hover { &:hover {
fill: blue; fill: blue;
} }
} }
display: flex; display: flex;
justify-content: flex-start; justify-content: flex-start;
align-items: center; align-items: center;
} }
.search-input {
display: flex;
}
.search-box {
display: flex;
align-items: center;
justify-content: flex-start;
background-color: white;
padding: 10px;
margin-bottom: 10px;
border-radius: 8px;
}
.search-box li {
margin-right: 15px;
display: flex;
align-items: center;
justify-content: flex-start;
}
.search-label {
margin-right: 8px;
font-size: 14px;
color: #606266;
}
.tableCard {
margin-top: 20px;
height: calc(100vh - 180px);
}
.pagination-container {
margin-top: 20px;
text-align: center;
padding: 10px 0;
}
.el-table{
height: 100%;
}
</style> </style>

View File

@ -10,7 +10,7 @@
</el-option> </el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="充值金额:" prop="balance"> <el-form-item label="充值金额:" prop="balance" label-width="130px">
<el-input v-model="form.balance"></el-input> <el-input v-model="form.balance"></el-input>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 KiB

View File

Before

Width:  |  Height:  |  Size: 790 KiB

After

Width:  |  Height:  |  Size: 790 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

View File

@ -1,162 +1,161 @@
<template> <template>
<div style="width: 100%;"> <div style="width: 100%;">
<div class="banner"> <div class="banner">
<span v-if="JSON.stringify(logoInfoNew)!=='{}'" style="font-size: 38px"> <div v-if="JSON.stringify(logoInfoNew) !== '{}'" style="font-size: 38px;">
{{ logoInfoNew.home.bannerTitle }} <span style="color: #0e0b0b">全球领先的AI服务运营商</span> <!-- 开元云 标题 -->
</span> <div>{{ logoInfoNew.home.bannerTitle }}</div>
<!-- <span style="color: #0e0b0b">Company Introduction</span>--> <p style="color: #0e0b0b">全球领先的AI服务运营商</p>
</div>
</div> </div>
<div class="mainBox" style="padding-top: 35px"> <div class="mainBox" style="padding-top: 35px">
<!-- <div style="text-align: center;font-weight: bold;font-size: 26px;margin: 50px 0 15px;">公司介绍</div>-->
<div class="inBox"> <div class="inBox">
<div class="leftBox"> <div class="leftBox">
<img v-if="JSON.stringify(logoInfoNew)!=='{}'" <p class="leftBoxtitle">关于<span class="gradient-text">我们</span></p>
:src="logoInfoNew.home.logoImg" <!-- <img v-if="JSON.stringify(logoInfoNew) !== '{}'" :src="logoInfoNew.home.logoImg" alt=""> -->
alt="">
</div> </div>
<div v-if="JSON.stringify(logoInfoNew)!=='{}'" class="rightBox"> <div v-if="JSON.stringify(logoInfoNew) !== '{}'" class="rightBox">
<p v-for="(i, index) in logoInfoNew.about.content" :key="index">
<p v-for="(i,index) in logoInfoNew.about.content" :key="index">
{{ i }} {{ i }}
</p> </p>
</div> </div>
</div> </div>
</div> </div>
<!-- 公司资质 -->
<div class="zizhi"> <div class="zizhi">
<div style="width: 1400px;"> <div style="width: 1400px;">
<div <div style="text-align:center;font-size: 30px;font-weight: bold;margin: 55px 0;width: 100%;margin-bottom: 50px">
style="text-align:center;font-size: 26px;font-weight: bold;margin: 55px 0;width: 100%;margin-bottom: 50px "> 公司<span class="gradient-text">资质</span>
公司资质
</div> </div>
<LogoTwo></LogoTwo> <LogoTwo></LogoTwo>
</div> </div>
</div> </div>
<div class="why"> <!-- 企业文化 -->
<!-- <div style="font-size: 26px;font-weight: bold;margin: 55px 0">--> <div class="enterprise">
<!-- 使命愿景价值观--> <div class="enterprise-inner">
<!-- </div>--> <div class="left-box">
<ul class="whyUl"> <div class="left-title">
<li> <span>企业<span class="gradient-text">文化</span></span>
<span class="icon"><img
src="./img/1.png"
alt=""></span>
<div class="title">使命</div>
<div class="description">
<span
style="color:#222F60;font-weight: bold;margin-bottom: 10px;display: flex;justify-content: center;align-items: center">让AI无处不在让智能如此简单</span>
<!-- 公司将通过生态合作形式构建强大的算力基础设施让算力能够随时随地为客户所用同时简化人工智能的应用流程降低使用门槛使智能技术能够更加便捷地服务于各行各业-->
</div> </div>
</li> </div>
<li> <div class="right-box">
<span class="icon"><img <div class="item">
src="./img/2.png" <div class="item-img">
alt=""></span> <img src="./img/sm.png" alt="使命图标">
<div class="title">愿景</div> </div>
<div class="description"> <div class="item-content">
<span <div class="item-tit">
style="color:#222F60;font-weight: bold;margin-bottom: 10px;display: flex;justify-content: center;align-items: center">全球领先的AI服务运营商</span> <div>使命</div>
<!-- 成为全球领先的人工智能服务运营商公司不满足于国内外AI发展和服务现状追求在人工智能领域持续创新和发展公司将不断探索新的技术和商业模式引领AI智能服务的发展潮流--> <div>Mission</div>
</div>
<div class="item-text">
<p>让AI无处不在让智能如此简单</p>
</div>
</div>
</div> </div>
</li> <div class="item">
<li> <div class="item-img">
<span class="icon"><img <img src="./img/yj.png" alt="愿景图标">
src="./img/3.png" </div>
alt=""></span> <div class="item-content">
<div class="title">价值观</div> <div class="item-tit">
<div class="description"> <div>愿景</div>
<span <div>Vision</div>
style="color:#222F60;font-weight: bold;margin-bottom: 10px;display: flex;justify-content: center;align-items: center">卓越开放创新</span> </div>
<!-- 卓越价值观意味着精益求精永争第一开放价值观鼓励公司与外部合作伙伴进行广泛的合作--> <div class="item-text">
<!-- 创新则要求公司不断探索新的技术和业务模式推动产品和服务的升级--> <p>全球领先的AI服务运营商</p>
</div>
</div>
</div> </div>
</li> <div class="item">
</ul> <div class="item-img">
</div> <img src="./img/jzg.png" alt="价值观图标">
<div class="ad"> </div>
<div <div class="item-content">
style="text-align:center;font-size: 26px;font-weight: bold;margin: 55px 0;width: 100%;margin-bottom: 50px "> <div class="item-tit">
平台优势 <div>价值观</div>
<div>Value</div>
</div>
<div class="item-text">
<p>卓越开放创新</p>
</div>
</div>
</div>
</div>
</div> </div>
<ul class="adUl"> </div>
<li>
<div class="iconBox">
<img
src="./img/5.png"
alt="">
</div>
<div class="content">
<span>精准定位</span>
<span
class="description">专注于为各行业提供专业高效的人工智能解决方案助力企业智能化转型</span>
</div>
</li>
<li>
<div class="iconBox">
<img
src="./img/6.png"
alt="">
</div>
<div class="content">
<span>技术服务</span>
<span
class="description">提供人工智能相关的技术服务为企业解决复杂的技术难题</span>
</div>
</li>
<li>
<div class="iconBox">
<img
src="./img/7.png"
alt="">
</div>
<div class="content">
<span>产品定制</span>
<span
class="description">根据企业的特定需求定制开发人工智能产品满足不同场景的应用需求</span>
</div>
</li>
<li> <!-- 优势 -->
<div class="iconBox"> <div class="advantage">
<img <div class="advantage-tit">
src="./img/4.png" <span>平台<span class="gradient-text">优势</span></span>
alt=""> </div>
<!-- 优势列表 -->
<div class="advantage-content">
<div class="advantage-grid">
<div class="advantage-item" :style="{ backgroundImage: 'url(' + require('./img/advantage1.png') + ')' }">
<div class="content-wrapper">
<div class="top-tit">
精准定位
</div>
<div class="btm-tit">
专注于为各行业提供专业高效的人工智能解决方案助力企业智能化转型
</div>
</div>
</div> </div>
<div class="content"> <div class="advantage-item" :style="{ backgroundImage: 'url(' + require('./img/advantage2.png') + ')' }">
<span>产业赋能 </span> <div class="content-wrapper">
<span <div class="top-tit">
class="description">通过人工智能技术为传统产业赋能提升产业的竞争力和创新能力</span> 技术服务
</div>
<div class="btm-tit">
提供人工智能相关的技术服务为企业解决复杂的技术难题
</div>
</div>
</div> </div>
</li> <div class="advantage-item" :style="{ backgroundImage: 'url(' + require('./img/advantage3.png') + ')' }">
<li> <div class="content-wrapper">
<div class="iconBox"> <div class="top-tit">
<img 产品定制
src="./img/2.png" </div>
alt=""> <div class="btm-tit">
根据企业的特定需求定制开发人工智能产品满足不同场景的应用需求
</div>
</div>
</div> </div>
<div class="content"> <div class="advantage-item" :style="{ backgroundImage: 'url(' + require('./img/advantage4.png') + ')' }">
<span>一站式本地化服务</span> <div class="content-wrapper">
<span <div class="top-tit">
class="description">从售前售中到售后提供一站式全方位服务</span> 产业赋能
</div>
<div class="btm-tit">
通过人工智能技术为传统产业赋能提升产业的竞争力和创新能力
</div>
</div>
</div> </div>
</li> <div class="advantage-item" :style="{ backgroundImage: 'url(' + require('./img/advantage5.png') + ')' }">
<li> <div class="content-wrapper">
<div class="iconBox"> <div class="top-tit">
<img 一站式本地化服务
src="./img/8.png" </div>
alt=""> <div class="btm-tit">
从售前售中到售后提供一站式全方位服务
</div>
</div>
</div> </div>
<div class="content"> <div class="advantage-item" :style="{ backgroundImage: 'url(' + require('./img/advantage6.png') + ')' }">
<span>提供AI基础设施与模型服务</span> <div class="content-wrapper">
<span <div class="top-tit">
class="description">提供整体底层技术架构和系统支持及模型服务</span> 提供AI基础设施与模型服务
</div>
<div class="btm-tit">
提供整体底层技术架构和系统支持及模型服务
</div>
</div>
</div> </div>
</li> </div>
</div>
</ul> <!-- 优势列表完 -->
</div> </div>
</div> </div>
</template> </template>
@ -164,11 +163,16 @@
<script> <script>
import Vue from 'vue' import Vue from 'vue'
import LogoTwo from "@/views/homePage/mainPage/logoG/logoTwo.vue"; import LogoTwo from "@/views/homePage/mainPage/logoG/logoTwo.vue";
import {mapGetters, mapState} from "vuex"; import { mapGetters, mapState } from "vuex";
export default Vue.extend({ export default Vue.extend({
name: "aboubt", name: "about",
components: {LogoTwo}, components: { LogoTwo },
data() {
return {
// languagetranslations
}
},
computed: { computed: {
...mapGetters(["sidebar", "avatar", "device"]), ...mapGetters(["sidebar", "avatar", "device"]),
...mapState({ ...mapState({
@ -179,8 +183,6 @@ export default Vue.extend({
logoutUrl: state => state.login.logoutUrl, logoutUrl: state => state.login.logoutUrl,
loginState: state => state.login.loginState, loginState: state => state.login.loginState,
logoInfoNew: state => state.product.logoInfoNew, logoInfoNew: state => state.product.logoInfoNew,
}), }),
showRegisterButton() { showRegisterButton() {
const orgType = window.sessionStorage.getItem('org_type'); const orgType = window.sessionStorage.getItem('org_type');
@ -191,29 +193,31 @@ export default Vue.extend({
username() { username() {
return sessionStorage.getItem('username') || ''; return sessionStorage.getItem('username') || '';
}, },
}, },
methods: {
// initLanguage
}
}) })
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.banner { .banner {
background: url("./img/banner.png") no-repeat center center; background: url("./img/Newbanner.png") no-repeat top center;
display: flex; display: flex;
justify-content: center; justify-content: center;
background-size: cover; background-size: cover;
align-items: center; align-items: center;
height: 250px; height: 500px;
flex-direction: column; flex-direction: column;
font-weight: bold; font-weight: bold;
//color: white;
span { div {
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;
text-align: center;
} }
} }
@ -223,6 +227,7 @@ export default Vue.extend({
justify-content: flex-start; justify-content: flex-start;
align-items: center; align-items: center;
flex-direction: column; flex-direction: column;
background: linear-gradient(180deg, #fff 0%, #f6f8fd 40%, #fff 100%);
.inBox { .inBox {
display: flex; display: flex;
@ -233,6 +238,14 @@ export default Vue.extend({
.leftBox { .leftBox {
width: 25%; width: 25%;
height: 100%; height: 100%;
display: flex;
justify-content: center;
align-items: flex-start;
.leftBoxtitle {
font-size: 30px;
font-weight: bold;
}
img { img {
width: 300px; width: 300px;
@ -245,113 +258,277 @@ export default Vue.extend({
line-height: 2; line-height: 2;
} }
} }
} }
.why { /* 企业文化部分样式 */
.enterprise {
width: 100%; width: 100%;
background: linear-gradient(180deg, #d7e9ff 0%, #fff 100%);
padding: 80px 0;
display: flex; display: flex;
flex-direction: column; justify-content: center;
justify-content: flex-start;
align-items: center;
height: 500px;
background: url("./img/jiajiebg.png");
background-position: center;
background-size: cover;
.whyUl {
padding-top: 90px;
width: 1300px;
display: flex;
justify-content: space-around;
align-items: center;
li {
width: 280px;
height: 310px;
background: white;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 0 20px;
img {
width: 47px;
height: 45px;
}
.title {
margin: 15px 0;
font-size: 26px;
font-weight: bold;
}
.description {
color: #999;
font-size: 14px;
line-height: 2;
//margin-top: 15px;
}
}
}
}
.ad {
flex-direction: column;
width: 100%;
display: flex;
justify-content: flex-start;
align-items: center; align-items: center;
.adUl { .enterprise-inner {
width: 1400px; width: 1400px;
display: flex; display: flex;
flex-wrap: wrap; align-items: center;
justify-content: center;
.left-box {
li { width: 25%;
margin-bottom: 45px;
display: flex; display: flex;
justify-content: flex-start; justify-content: center;
align-items: center; align-items: flex-start;
width: 30% !important;
max-width: 30%;
padding-right: 15px;
.left-title {
.content { font-size: 30px;
font-weight: bold;
display: flex; display: flex;
flex-direction: column; justify-content: center;
justify-content: space-around;
align-items: flex-start;
padding-left: 15px;
font-size: 16px;
.description {
margin-top: 8px;
color: #666;
font-size: 14px;
line-height: 1.5;
}
} }
}
img { .right-box {
width: 50px; width: 70%;
height: 50px; display: flex;
flex-direction: column;
gap: 40px;
.item {
display: flex;
align-items: center;
border-radius: 12px;
padding: 30px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
&:hover {
transform: translateY(-5px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
}
.item-img {
flex-shrink: 0;
margin-right: 25px;
img {
width: 70px;
height: 70px;
object-fit: contain;
}
}
.item-content {
flex: 1;
display: flex;
align-items: center;
.item-tit {
margin-bottom: 15px;
div:first-child {
font-size: 24px;
font-weight: bold;
color: #333;
margin-right: 15px;
}
div:last-child {
font-size: 16px;
color: #666;
font-style: italic;
}
}
.item-text {
margin-left: 40px;
p {
font-size: 18px;
line-height: 1.6;
color: #444;
margin: 0;
}
}
}
} }
} }
} }
} }
.zizhi { .zizhi {
height: 900px;
width: 100%; width: 100%;
background: url("./img/zizhi.png") no-repeat;
background-size: 100% 100%;
padding-bottom: 15px; padding-bottom: 15px;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
/* 新增渐变文字样式 */
.gradient-text {
background: linear-gradient(to right, #0066FF, #66CCFF);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
display: inline-block;
}
//
.advantage {
padding: 80px 0;
background:#fff;
.advantage-tit {
text-align: center;
font-size: 30px;
font-weight: bold;
margin-bottom: 60px;
}
.advantage-content {
display: flex;
justify-content: center;
.advantage-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 30px;
width: 1200px;
.advantage-item {
position: relative;
border-radius: 12px;
padding: 40px 30px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
height: 140px;
display: flex;
flex-direction: column;
justify-content: center;
overflow: hidden;
cursor: pointer;
/* 背景图设置 */
background-size: cover !important;
background-position: center !important;
background-repeat: no-repeat !important;
/* 默认状态:白色半透明遮罩,黑色文字 */
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(255, 255, 255, 0.85);
border-radius: 12px;
z-index: 1;
transition: all 0.3s ease;
}
.content-wrapper {
position: relative;
z-index: 2;
transition: all 0.3s ease;
}
.top-tit {
font-size: 22px;
font-weight: bold;
margin-bottom: 15px;
color: #333;
transition: all 0.3s ease;
}
.btm-tit {
font-size: 16px;
line-height: 1.6;
color: #666;
transition: all 0.3s ease;
}
/* 悬停状态:蓝色半透明遮罩,白色文字 */
&:hover {
transform: translateY(-5px);
box-shadow: 0 8px 25px rgba(0, 102, 255, 0.2);
&::before {
background: rgba(0, 102, 255, 0.9);
}
.top-tit {
color: #fff;
}
.btm-tit {
color: rgba(255, 255, 255, 0.9);
}
}
}
}
}
}
/* 响应式设计 - 适配不同屏幕尺寸 */
@media (max-width: 1200px) {
.mainBox .inBox,
.enterprise .enterprise-inner,
.advantage-content .advantage-grid {
width: 95% !important;
}
.advantage-content .advantage-grid {
grid-template-columns: 1fr;
}
}
@media (max-width: 768px) {
.banner {
height: 300px;
font-size: 28px !important;
p {
font-size: 16px;
}
}
.mainBox .inBox {
flex-direction: column;
.leftBox, .rightBox {
width: 100% !important;
}
.leftBox {
margin-bottom: 30px;
}
}
.enterprise .enterprise-inner {
flex-direction: column;
.left-box, .right-box {
width: 100% !important;
}
.left-box {
margin-bottom: 40px;
justify-content: flex-start;
}
}
.zizhi {
height: auto;
padding: 50px 0;
}
.advantage-item {
height: 160px !important;
}
}
</style> </style>

View File

@ -9,17 +9,17 @@
</div> </div>
<ul class="titleWord"> <ul class="titleWord">
<li>首页</li> <li>{{ translations[language].home }}</li>
<li @click="goOtherPage('product')">产品服务</li> <li @click="goOtherPage('product')">{{ translations[language].products }}</li>
<li @click="goOtherPage('solve')">解决方案</li> <li @click="goOtherPage('solve')">{{ translations[language].solutions }}</li>
<li @click="goOtherPage('service')">服务中心</li> <li @click="goOtherPage('service')">{{ translations[language].serviceCenter }}</li>
<li @click="goOtherPage('news')">新闻资讯</li> <li @click="goOtherPage('news')">{{ translations[language].news }}</li>
<li @click="goOtherPage('aboutUs')">关于我们</li> <li @click="goOtherPage('aboutUs')">{{ translations[language].aboutUs }}</li>
</ul> </ul>
</div> </div>
<div class="right-style"> <div class="right-style">
<el-button @click="login" class="loginBtn-style" style="color: white">登录</el-button> <el-button @click="login" class="loginBtn-style" style="color: white">{{ translations[language].login }}</el-button>
<el-button @click="register" class="register-style">注册</el-button> <el-button @click="register" class="register-style">{{ translations[language].register }}</el-button>
</div> </div>
</header> </header>
@ -32,9 +32,6 @@
<el-carousel-item style="height: 50vh;" class="banner-item"> <el-carousel-item style="height: 50vh;" class="banner-item">
<img src="../../assets/kyy/temporaryPic/bann2.png"> <img src="../../assets/kyy/temporaryPic/bann2.png">
</el-carousel-item> </el-carousel-item>
<!-- <el-carousel-item style="height: 420px;" class="banner-item">-->
<!-- <img src="../../assets/kyy/temporaryPic/banew.png">-->
<!-- </el-carousel-item>-->
<el-carousel-item style="height: 50vh;" class="banner-item"> <el-carousel-item style="height: 50vh;" class="banner-item">
<img src="../../assets/kyy/temporaryPic/banner5.jpg"> <img src="../../assets/kyy/temporaryPic/banner5.jpg">
</el-carousel-item> </el-carousel-item>
@ -46,144 +43,67 @@
<li class="content-footer-item" style="display: flex;flex-direction:row;justify-content: center;align-items: center"> <li class="content-footer-item" style="display: flex;flex-direction:row;justify-content: center;align-items: center">
<img class="icon-footer" src="../../assets/kyy/Icon-kexuejishu-.svg" alt=""> <img class="icon-footer" src="../../assets/kyy/Icon-kexuejishu-.svg" alt="">
<div style="display: flex;flex-direction: column;justify-content: center;align-items: center"> <div style="display: flex;flex-direction: column;justify-content: center;align-items: center">
<span class="footer-title" style="cursor: pointer" @click="goProduct('http://tmpweb.opencomputing.cn/col.jsp?id=146')">公有云</span> <span class="footer-title" style="cursor: pointer" @click="goProduct('http://tmpweb.opencomputing.cn/col.jsp?id=146')">{{ translations[language].publicCloud }}</span>
<!-- <span class="footer-content">算力互联网络和算力调度核心技术</span>-->
</div> </div>
</li> </li>
<li class="content-footer-item" style="display: flex;flex-direction:row;justify-content: center;align-items: center"> <li class="content-footer-item" style="display: flex;flex-direction:row;justify-content: center;align-items: center">
<img class="icon-footer" src="../../assets/kyy/Icon-_khgx.svg" alt=""> <img class="icon-footer" src="../../assets/kyy/Icon-_khgx.svg" alt="">
<div style="display: flex;flex-direction: column;justify-content: center;align-items: center"> <div style="display: flex;flex-direction: column;justify-content: center;align-items: center">
<span class="footer-title" style="cursor: pointer" @click="goProduct('http://tmpweb.opencomputing.cn/col.jsp?id=138')">超算</span> <span class="footer-title" style="cursor: pointer" @click="goProduct('http://tmpweb.opencomputing.cn/col.jsp?id=138')">{{ translations[language].superComputing }}</span>
<!-- <span class="footer-content" >中立的全国性网络资源算力中心资源</span>-->
</div> </div>
</li> </li>
<li class="content-footer-item" style="display: flex;flex-direction:row;justify-content: center;align-items: center"> <li class="content-footer-item" style="display: flex;flex-direction:row;justify-content: center;align-items: center">
<img class="icon-footer" src="../../assets/kyy/Icon-a-01changjing.svg" alt=""> <img class="icon-footer" src="../../assets/kyy/Icon-a-01changjing.svg" alt="">
<div style="display: flex;flex-direction: column;justify-content: center;align-items: center"> <div style="display: flex;flex-direction: column;justify-content: center;align-items: center">
<span class="footer-title" style="cursor: pointer" @click="goProduct('http://tmpweb.opencomputing.cn/col.jsp?id=139')">智算</span> <span class="footer-title" style="cursor: pointer" @click="goProduct('http://tmpweb.opencomputing.cn/col.jsp?id=139')">{{ translations[language].intelligentComputing }}</span>
<!-- <span class="footer-content">面向行业<br/>-->
<!--面向应用</span>-->
</div> </div>
</li> </li>
<li class="content-footer-item" style="display: flex;flex-direction:row;justify-content: center;align-items: center"> <li class="content-footer-item" style="display: flex;flex-direction:row;justify-content: center;align-items: center">
<img class="icon-footer" src="../../assets/kyy/Icon-yunyingzhongxin.svg" alt=""> <img class="icon-footer" src="../../assets/kyy/Icon-yunyingzhongxin.svg" alt="">
<div style="display: flex;flex-direction: column;justify-content: center;align-items: center"> <div style="display: flex;flex-direction: column;justify-content: center;align-items: center">
<span class="footer-title" style="cursor: pointer" @click="goProduct('http://tmpweb.opencomputing.cn/col.jsp?id=140')">网络</span> <span class="footer-title" style="cursor: pointer" @click="goProduct('http://tmpweb.opencomputing.cn/col.jsp?id=140')">{{ translations[language].network }}</span>
<!-- <span class="footer-content">多年运营服务经验 <br/>市场客户沉淀</span>-->
</div> </div>
</li> </li>
</ul> </ul>
</div> </div>
<!-- 核心业务--> <!-- 核心业务-->
<div class="business"> <div class="business">
<span class="business-title" style="margin-bottom: 15px;margin-top: 85px">核心业务</span> <span class="business-title" style="margin-bottom: 15px;margin-top: 85px">{{ translations[language].coreBusiness }}</span>
<span class="business-content" style="margin-bottom: 15px">提供领先可靠多场景的应用解决方案安全稳定确定</span> <span class="business-content" style="margin-bottom: 15px">{{ translations[language].coreBusinessDesc }}</span>
<!-- 四个li--> <!-- 四个li-->
<ul style="display: flex;justify-content: center"> <ul style="display: flex;justify-content: center">
<li class="content-footer-item"> <li class="content-footer-item">
<img style="width: 200px;height: 200px;" src="../../assets/kyy/temporaryPic/w1.png" alt=""> <img style="width: 200px;height: 200px;" src="../../assets/kyy/temporaryPic/w1.png" alt="">
<span class="footer-title">智算中心</span> <span class="footer-title">{{ translations[language].business1Title }}</span>
<span class="footer-content">智算中心咨询 <span class="footer-content">{{ translations[language].business1Desc }}</span>
////</span>
</li> </li>
<li class="content-footer-item"> <li class="content-footer-item">
<img style="width: 200px;height: 200px;" src="../../assets/kyy/temporaryPic/w2.png" alt=""> <img style="width: 200px;height: 200px;" src="../../assets/kyy/temporaryPic/w2.png" alt="">
<span class="footer-title">算力网络</span> <span class="footer-title">{{ translations[language].business2Title }}</span>
<span class="footer-content">云互联超算互联智算互联</span> <span class="footer-content">{{ translations[language].business2Desc }}</span>
</li> </li>
<li class="content-footer-item"> <li class="content-footer-item">
<img style="width: 200px;height: 200px;" src="../../assets/kyy/temporaryPic/w3.png" alt=""> <img style="width: 200px;height: 200px;" src="../../assets/kyy/temporaryPic/w3.png" alt="">
<span class="footer-title">算力服务</span> <span class="footer-title">{{ translations[language].business3Title }}</span>
<span class="footer-content">融合云HPCAI算力信创</span> <span class="footer-content">{{ translations[language].business3Desc }}</span>
</li> </li>
<li class="content-footer-item"> <li class="content-footer-item">
<img style="width: 200px;height: 200px;" src="../../assets/kyy/temporaryPic/w4.png" alt=""> <img style="width: 200px;height: 200px;" src="../../assets/kyy/temporaryPic/w4.png" alt="">
<span class="footer-title">应用解决方案</span> <span class="footer-title">{{ translations[language].business4Title }}</span>
<span class="footer-content">企业多场景云服务高校科学计算大模型架构及应用</span> <span class="footer-content">{{ translations[language].business4Desc }}</span>
</li> </li>
</ul> </ul>
<span class="business-title" style="margin-top: 50px;margin-bottom: 15px">深入业务场景的算网解决方案</span> <span class="business-title" style="margin-top: 50px;margin-bottom: 15px">{{ translations[language].solutionTitle }}</span>
<span class="business-content" style="margin-bottom: 25px">以高水平算网调度解决方案助力各行业高质量发展</span> <span class="business-content" style="margin-bottom: 25px">{{ translations[language].solutionDesc }}</span>
<!-- 图片--> <!-- 图片-->
<div> <div>
<img class="business-pic" style="width: 100%;height: 300px;" src="../../assets/kyy/深入方案bg.png"> <img class="business-pic" style="width: 100%;height: 300px;" src="../../assets/kyy/深入方案bg.png">
</div> </div>
</div> </div>
<!-- 全国高校算力网络-->
<!-- <div class="shcool" style="margin-bottom: 50px;margin-top: 55px">-->
<!-- <span class="business-title" style="margin-bottom: 15px">全国算力网络</span>-->
<!-- <span class="business-content" style="margin-bottom: 15px">算力统一管理 算网一体服务</span>-->
<!-- <div class="shcool-main">-->
<!-- <img alt="" src="../../assets/kyy/Map.png">-->
<!-- 1di -->
<!-- 新闻板块-->
<!-- <div class="news-block">-->
<!-- <span class="title-news">创新论坛</span>-->
<!-- <p class="news-content"> 2023全国高校算力网络创新论坛聚焦高校数字化转型背景下针对高校科研领域的新要求分享算力网络最新的前沿技术共话算力网络技术与服务企业产业布局研讨高校科研需求与算力技术的供应</p>-->
<!-- <div style="display: flex;justify-content: center;align-items: center">-->
<!-- <div class="pic-news">-->
<!-- <img src="../../assets/kyy/temporaryPic/640(1).jpg" alt="">-->
<!-- </div>-->
<!-- <div class="pic-news">-->
<!-- <img src="../../assets/kyy/temporaryPic/640.jpg" alt="">-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- 1di -->
<!-- <div class="left-content">-->
<!-- <div class="top-school">-->
<!-- <div class="c-one">-->
<!-- <span class="school-title">二级ROADM节点</span>-->
<!-- <span class="school-school">106-->
<!-- <span class="school-title"></span>-->
<!-- </span>-->
<!-- </div>-->
<!-- <div class="c-two">-->
<!-- <span class="school-title">核心节点</span>-->
<!-- <span class="school-school">106-->
<!-- <span class="school-title"></span></span>-->
<!-- </div>-->
<!-- <div class="c-thr">-->
<!-- <span class="school-title" style="font-size: 14px">OA节点</span>-->
<!-- <span class="school-school" style="font-size: 24px">306-->
<!-- <span class="school-title"></span></span>-->
<!-- </div>-->
<!-- <span class="tip-word">-->
<!-- 局部配套-->
<!-- </span>-->
<!-- &lt;!&ndash; 系统组成&ndash;&gt;-->
<!-- <div class="main-content">-->
<!-- <span class="main-title"> 系统组成</span>-->
<!-- <div class="shcool-dscribtion">-->
<!-- <ul>-->
<!-- <li>· 华为OSN9800</li>-->
<!-- <li>· 40x100G ROADM平台</li>-->
<!-- <li>· 40x400G演进能力</li>-->
<!-- </ul>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!--中国地图-->
<!-- <div class="wrapper">-->
<!-- <div class="map-container" ref="myEchart"></div>-->
<!-- </div>-->
<!-- 企业资讯--> <!-- 企业资讯-->
<div class="business" style="margin-top: 100px"> <div class="business" style="margin-top: 100px">
<span class="business-title" style="margin-top: 50px;margin-bottom: 15px">企业资讯</span> <span class="business-title" style="margin-top: 50px;margin-bottom: 15px">{{ translations[language].enterpriseNews }}</span>
<div> <div>
<img @click="goNewsPage" style="height: 800px;cursor: pointer" class="business-pic" src="../../assets/kyy/temporaryPic/ff.png"> <img @click="goNewsPage" style="height: 800px;cursor: pointer" class="business-pic" src="../../assets/kyy/temporaryPic/ff.png">
</div> </div>
@ -191,8 +111,8 @@
<!-- 核心业务--> <!-- 核心业务-->
<div class="business" style="height: 550px;"> <div class="business" style="height: 550px;">
<span class="business-title" style="margin-bottom: 15px;margin-top: 35px">全国高校算力网络创新论坛</span> <span class="business-title" style="margin-bottom: 15px;margin-top: 35px">{{ translations[language].forumTitle }}</span>
<span class="business-content" style="width: 1200px;margin-bottom: 25px">由江苏未来网络集团主办中国高等教育学会教育信息化分会指导开元云北京科技有限公司协办的全国高校算力网络创新论坛成功举办该论坛聚焦高校数字化转型背景下针对高校科研领域的新要求分享算力网络最新的前沿技术共话算力网络技术与服务企业产业布局研讨高校科研需求与算力技术的供应</span> <span class="business-content" style="width: 1200px;margin-bottom: 25px">{{ translations[language].forumDesc }}</span>
<!-- 图片--> <!-- 图片-->
<div style="display: flex;justify-content: center;align-items: space-between;padding-top: 15px" class="ckl"> <div style="display: flex;justify-content: center;align-items: space-between;padding-top: 15px" class="ckl">
<div style="width: 350px;height: 300px;"> <div style="width: 350px;height: 300px;">
@ -209,7 +129,7 @@
<!-- 合作伙伴--> <!-- 合作伙伴-->
<div class="friends"> <div class="friends">
<span class="business-title" style="margin-top: 50px;margin-bottom: 15px">合作伙伴</span> <span class="business-title" style="margin-top: 50px;margin-bottom: 15px">{{ translations[language].partners }}</span>
<div class="logo-item-s"> <div class="logo-item-s">
<img src="../../assets/kyy/temporaryPic/logo1.jpg" style="width: 100px;height: 65px;" alt=""> <img src="../../assets/kyy/temporaryPic/logo1.jpg" style="width: 100px;height: 65px;" alt="">
<img src="../../assets/kyy/temporaryPic/logo8.png" style="width: 100px;height: 65px;" alt=""> <img src="../../assets/kyy/temporaryPic/logo8.png" style="width: 100px;height: 65px;" alt="">
@ -219,7 +139,6 @@
<img src="../../assets/kyy/temporaryPic/logo4.jpg" alt=""> <img src="../../assets/kyy/temporaryPic/logo4.jpg" alt="">
<img src="../../assets/kyy/temporaryPic/logo6.png" alt=""> <img src="../../assets/kyy/temporaryPic/logo6.png" alt="">
<img src="../../assets/kyy/temporaryPic/logo7.jpg" alt=""> <img src="../../assets/kyy/temporaryPic/logo7.jpg" alt="">
</div> </div>
</div> </div>
@ -227,8 +146,8 @@
<div class="like"> <div class="like">
<img src="../../assets/kyy/编组_10.png" alt=""> <img src="../../assets/kyy/编组_10.png" alt="">
<div class="pic-word"> <div class="pic-word">
<span class="hiTitle">欢迎体验开元云</span> <span class="hiTitle">{{ translations[language].welcome }}</span>
<span class="goLogin-style" @click="login">立即体验</span> <span class="goLogin-style" @click="login">{{ translations[language].experienceNow }}</span>
</div> </div>
</div> </div>
@ -237,26 +156,26 @@
<div> <div>
<img src="../../assets/kyy/temporaryPic/Icon-1.png" alt=""> <img src="../../assets/kyy/temporaryPic/Icon-1.png" alt="">
</div> </div>
<span class="resource">资源全覆盖</span> <span class="resource">{{ translations[language].feature1 }}</span>
</div> </div>
<div class="item-footer-top"> <div class="item-footer-top">
<div> <div>
<img src="../../assets/kyy/temporaryPic/Icon-2.png" alt=""> <img src="../../assets/kyy/temporaryPic/Icon-2.png" alt="">
</div> </div>
<span class="resource">体验极速</span> <span class="resource">{{ translations[language].feature2 }}</span>
</div> </div>
<div class="item-footer-top"> <div class="item-footer-top">
<div> <div>
<img src="../../assets/kyy/temporaryPic/Icon-3.png" alt=""> <img src="../../assets/kyy/temporaryPic/Icon-3.png" alt="">
</div> </div>
<span class="resource">用户满意</span> <span class="resource">{{ translations[language].feature3 }}</span>
</div> </div>
<div class="item-footer-top"> <div class="item-footer-top">
<div> <div>
<img src="../../assets/kyy/temporaryPic/Icon-4.png" alt=""> <img src="../../assets/kyy/temporaryPic/Icon-4.png" alt="">
</div> </div>
<span class="resource">省心计算</span> <span class="resource">{{ translations[language].feature4 }}</span>
</div> </div>
</div> </div>
<!-- footer--> <!-- footer-->
@ -268,24 +187,21 @@
</div> </div>
<div class="content-main"> <div class="content-main">
<ul> <ul>
<li>地址:{{address}}</li> <li>{{ translations[language].address }}:{{address}}</li>
<li>电话400-6150805 &nbsp;&nbsp;&nbsp;&nbsp; <span style="margin-left: 20px">010-65917875 </span> <li>{{ translations[language].phone }}400-6150805 &nbsp;&nbsp;&nbsp;&nbsp; <span style="margin-left: 20px">010-65917875 </span></li>
</li> <li>{{ translations[language].email }}Open-computing@kaiyuancloud.cn</li>
<li>邮箱Open-computing@kaiyuancloud.cn</li> <li>{{ translations[language].icp }}:{{ICP}} <span style="margin-left: 20px">{{ translations[language].copyright }}</span></li>
<li>IPC备案号:{{ICP}} <span style="margin-left: 20px">版权所有 @kaiyuanyun 2023</span></li>
<li> <li>
<img src="../../image/login/policeInsignia/policeInsignia.png" alt="" style="width:17px;height:17px;margin-right: 2px;"> <img src="../../image/login/policeInsignia/policeInsignia.png" alt="" style="width:17px;height:17px;margin-right: 2px;">
<a href="https://beian.mps.gov.cn/#/query/webSearch?code=11010502054007" rel="noreferrer" target="_blank" style="margin-right:30px;">京公网安备11010502054007</a> <a href="https://beian.mps.gov.cn/#/query/webSearch?code=11010502054007" rel="noreferrer" target="_blank" style="margin-right:30px;">京公网安备11010502054007</a>
<span> <span>
<router-link tag="a" target="_blank" :to="{ name: 'homePageImage' }">经营许可证:京B2-20232313</router-link> <router-link tag="a" target="_blank" :to="{ name: 'homePageImage' }">{{ translations[language].license }}</router-link>
</span> </span>
</li> </li>
<li> <li>
<!-- <a href="" rel="noreferrer" target="_blank"></a> --> <!-- <a href="" rel="noreferrer" target="_blank"></a> -->
</li> </li>
</ul> </ul>
</div> </div>
</div> </div>
<div class="right-box"> <div class="right-box">
@ -293,19 +209,18 @@
<div class="qr-code"> <div class="qr-code">
<img src="../../assets/kyy/客服wechat.png" style="padding: 6px" alt=""> <img src="../../assets/kyy/客服wechat.png" style="padding: 6px" alt="">
</div> </div>
<span class="qr-content">微信客服</span> <span class="qr-content">{{ translations[language].wechatService }}</span>
</div> </div>
<div class="qr-box" style="margin-left: 50px"> <div class="qr-box" style="margin-left: 50px">
<div class="qr-code"> <div class="qr-code">
<img src="../../assets/kyy/kyy公众号.jpg" alt=""> <img src="../../assets/kyy/kyy公众号.jpg" alt="">
</div> </div>
<span class="qr-content">扫描关注二维码</span> <span class="qr-content">{{ translations[language].scanQRCode }}</span>
</div> </div>
</div> </div>
<div class="intrudceMessage"> <div class="intrudceMessage">
<span style="margin-left: 2em">开元云科技北京公司是一家注册于2020年的高科技企业在上海南京深圳济南设有分支机构公司通过自主研发的开元算力应用服务平台将算力资源和算力应用进行整合利用算力调度和确定性 <span style="margin-left: 2em">{{ translations[language].companyDesc1 }}</span>
</span> <span>{{ translations[language].companyDesc2 }}</span>
<span>网络技术为科研XR数字孪生和AI等行业提供专业算力服务形成算力服务+算力网络+算力应用的一体化解决方案</span>
</div> </div>
</div> </div>
</div> </div>
@ -324,12 +239,14 @@ _MICHAT("domain", "emdchk.xianshangkefu.net");
})(window, document, "script"); })(window, document, "script");
</script> </script>
<script> <script>
import { getLogoAPI } from "@/api/login"; import { getLogoAPI } from "@/api/login";
import echarts from "echarts"; import echarts from "echarts";
import china from 'echarts/map/json/china.json' import china from 'echarts/map/json/china.json'
import "../../../node_modules/echarts/map/js/china.js"; // import "../../../node_modules/echarts/map/js/china.js"; //
//
import { languageStore, languageBus } from '@/utils/language'
export default { export default {
name: "indexNew", name: "indexNew",
data() { data() {
@ -342,22 +259,123 @@ export default {
photosUrl: [], photosUrl: [],
ICP: "京ICP备2022001945号-1", ICP: "京ICP备2022001945号-1",
address: "农业展览馆13号瑞辰国际中心518B(团结湖地铁站c东南口步行420米)", address: "农业展览馆13号瑞辰国际中心518B(团结湖地铁站c东南口步行420米)",
//
language: 'zh',
translations: {
zh: {
home: '首页',
products: '产品服务',
solutions: '解决方案',
serviceCenter: '服务中心',
news: '新闻资讯',
aboutUs: '关于我们',
login: '登录',
register: '注册',
publicCloud: '公有云',
superComputing: '超算',
intelligentComputing: '智算',
network: '网络',
coreBusiness: '核心业务',
coreBusinessDesc: '提供领先、可靠、多场景的应用解决方案安全、稳定、确定',
business1Title: '智算中心',
business1Desc: '智算中心咨询/规划/建设/运营/运维',
business2Title: '算力网络',
business2Desc: '云互联、超算互联、智算互联',
business3Title: '算力服务',
business3Desc: '融合云、HPC、AI算力、信创',
business4Title: '应用解决方案',
business4Desc: '企业多场景云服务、高校科学计算、大模型架构及应用',
solutionTitle: '深入业务场景的算网解决方案',
solutionDesc: '以高水平算网调度解决方案助力各行业高质量发展',
enterpriseNews: '企业资讯',
forumTitle: '全国高校算力网络创新论坛',
forumDesc: '由江苏未来网络集团主办、中国高等教育学会教育信息化分会指导、开元云(北京)科技有限公司协办的全国高校算力网络创新论坛成功举办,该论坛聚焦高校数字化转型背景下,针对高校科研领域的新要求,分享算力网络最新的前沿技术,共话算力网络技术与服务企业产业布局,研讨高校科研需求与算力技术的供应。',
partners: '合作伙伴',
welcome: '欢迎体验开元云',
experienceNow: '立即体验',
feature1: '资源全覆盖',
feature2: '体验极速',
feature3: '用户满意',
feature4: '省心计算',
address: '地址',
phone: '电话',
email: '邮箱',
icp: 'IPC备案号',
copyright: '版权所有 @kaiyuanyun 2023',
license: '经营许可证:京B2-20232313',
wechatService: '微信客服',
scanQRCode: '扫描关注二维码',
companyDesc1: '开元云科技北京公司是一家注册于2020年的高科技企业在上海、南京、深圳、济南设有分支机构。公司通过自主研发的开元算力应用服务平台将算力资源和算力应用进行整合利用算力调度和确定性',
companyDesc2: '网络技术为科研、XR、数字孪生和AI等行业提供专业算力服务形成"算力服务+算力网络+算力应用"的一体化解决方案。'
},
en: {
home: 'Home',
products: 'Products & Services',
solutions: 'Solutions',
serviceCenter: 'Service Center',
news: 'News & Information',
aboutUs: 'About Us',
login: 'Login',
register: 'Register',
publicCloud: 'Public Cloud',
superComputing: 'Super Computing',
intelligentComputing: 'Intelligent Computing',
network: 'Network',
coreBusiness: 'Core Business',
coreBusinessDesc: 'Providing leading, reliable, multi-scenario application solutions that are safe, stable, and deterministic',
business1Title: 'Intelligent Computing Center',
business1Desc: 'Intelligent computing center consulting/planning/construction/operation/maintenance',
business2Title: 'Computing Power Network',
business2Desc: 'Cloud interconnection, supercomputing interconnection, intelligent computing interconnection',
business3Title: 'Computing Power Service',
business3Desc: 'Converged cloud, HPC, AI computing power, information innovation',
business4Title: 'Application Solutions',
business4Desc: 'Enterprise multi-scenario cloud services, university scientific computing, large model architecture and applications',
solutionTitle: 'In-depth Business Scenario Computing Network Solutions',
solutionDesc: 'Helping various industries achieve high-quality development with high-level computing network scheduling solutions',
enterpriseNews: 'Enterprise News',
forumTitle: 'National University Computing Power Network Innovation Forum',
forumDesc: 'The National University Computing Power Network Innovation Forum, hosted by Jiangsu Future Network Group, guided by the China Higher Education Association Education Informatization Branch, and co-organized by Kaiyuan Cloud (Beijing) Technology Co., Ltd., was successfully held. The forum focuses on new requirements in the university scientific research field under the background of university digital transformation, shares the latest cutting-edge technologies in computing power networks, discusses the industrial layout of computing power network technology and service enterprises, and researches the supply of university scientific research needs and computing power technology.',
partners: 'Partners',
welcome: 'Welcome to Experience Kaiyuan Cloud',
experienceNow: 'Experience Now',
feature1: 'Full Resource Coverage',
feature2: 'Ultra-Fast Experience',
feature3: 'User Satisfaction',
feature4: 'Worry-Free Computing',
address: 'Address',
phone: 'Phone',
email: 'Email',
icp: 'IPC Filing Number',
copyright: 'Copyright @kaiyuanyun 2023',
license: 'Business License: Jing B2-20232313',
wechatService: 'WeChat Customer Service',
scanQRCode: 'Scan to Follow QR Code',
companyDesc1: 'Kaiyuan Cloud Technology (Beijing) Company is a high-tech enterprise registered in 2020, with branches in Shanghai, Nanjing, Shenzhen, and Jinan. Through its self-developed Kaiyuan Computing Power Application Service Platform, the company integrates computing power resources and computing power applications, using computing power scheduling and deterministic',
companyDesc2: 'network technology to provide professional computing power services for scientific research, XR, digital twins, AI and other industries, forming an integrated solution of "computing power service + computing power network + computing power application".'
}
}
} }
}, },
created() { created() {
this.init() this.init()
//
this.language = languageStore.getLanguage()
console.log('indexNew页面初始化语言:', this.language)
//
languageBus.$on('language-changed', (lang) => {
console.log('indexNew页面接收到语言变化:', lang)
this.language = lang
})
},
beforeDestroy() {
//
languageBus.$off('language-changed')
}, },
mounted() { mounted() {
this.$nextTick(() => { this.$nextTick(() => {
// this.initEchartMap(); // ...
// this.initEcahrtkk()
// this.initEcahrtkk1()
//线
// this.initMapOne()
// this.initMapTwo()
}) })
}, },
methods: { methods: {
@ -407,8 +425,7 @@ export default {
window.open('http://tmpweb.opencomputing.cn/col.jsp?id=104') window.open('http://tmpweb.opencomputing.cn/col.jsp?id=104')
} }
}, },
dealWithData() {
dealWithData() {//
let geoCoordMap = { let geoCoordMap = {
北京: [116.46, 39.92, 100], 北京: [116.46, 39.92, 100],
上海: [121.48, 31.22, 200], 上海: [121.48, 31.22, 200],
@ -420,190 +437,10 @@ export default {
return data; return data;
}, },
initMapOne() { initMapOne() {
this.myEchart = echarts.init(this.$refs.myEchart); // ...
let option = {
tooltip: {
show: false
},
geo: {
map: "china",
roam: false,//
zoom: 1.23,
center: [105, 36], //
label: {
normal: {
show: false, //
fontSize: "10",
color: "rgba(0,0,0,0.7)"
},
emphasis: {
show: false
}
},
itemStyle: {
normal: {
areaColor: "#0d0059",
borderColor: "#389dff",
borderWidth: 1, //
shadowBlur: 5,
shadowOffsetY: 8,
shadowOffsetX: 0,
shadowColor: "#ecf0f7"
},
emphasis: {
areaColor: "#184cff",
shadowOffsetX: 0,
shadowOffsetY: 0,
shadowBlur: 5,
borderWidth: 0,
shadowColor: "rgba(0, 0, 0, 0.5)"
}
}
},
series: [
{
type: "map",
map: "china",
roam: false,
zoom: 1.23,
center: [105, 36],
// geoIndex: 1,
// aspectScale: 0.75, //
showLegendSymbol: false, // legend
label: {
normal: {
show: false
},
emphasis: {
show: false,
textStyle: {
color: "#fff"
}
}
},
itemStyle: {
normal: {
areaColor: "#0d0059",
borderColor: "#389dff",
borderWidth: 0.5
},
emphasis: {
areaColor: "#17008d",
shadowOffsetX: 0,
shadowOffsetY: 0,
shadowBlur: 5,
borderWidth: 0,
shadowColor: "rgba(0, 0, 0, 0.5)"
}
}
}
]
};
this.myEchart.setOption(option);
}, },
initMapTwo() { initMapTwo() {
this.myEchart = echarts.init(this.$refs.myEchart); // ...
let dataValue = this.dealWithData();
// var data1 = dataValue.splice(0, 6);
let citySchoolMap = [
{ '北京': ['北京大学', '清华大学', '北京航空航天大学'] },
{ '上海': ['同济大学', '上海交通大学'] },
{ '邢台': ['邢台学院', '邢台一中'] },
{ '泸州': ['泸州大学'] },
]
let option = {
series: [
{
type: "map",
map: "china",
roam: false,
zoom: 1.23,
center: [105, 36],
// geoIndex: 1,
// aspectScale: 0.75, //
showLegendSymbol: false, // legend
label: {
normal: {
show: false
},
emphasis: {
show: false
}
},
itemStyle: {
normal: {
areaColor: "#fbfdff",
borderColor: "#389dff",
borderWidth: 0.5
},
emphasis: {
areaColor: "#fbfdff",
shadowOffsetX: 0,
shadowOffsetY: 0,
shadowBlur: 5,
borderWidth: 0,
shadowColor: "rgba(0, 0, 0, 0.5)"
}
}
},
{
name: "",
type: "scatter",
coordinateSystem: "geo",
data: dataValue,
// symbolSize: function(val) {
// return val[2] / 10;
// },
symbol: "circle",
symbolSize: 10,
hoverSymbolSize: 15,
tooltip: {
formatter(value) {
const cityName = value.data.name;
let schoolInfo = '';
citySchoolMap.forEach(obj => {
if (obj[cityName]) {
schoolInfo = obj[cityName].join("<br/>");
}
});
const resultDiv = '<div class="custom-tooltip">' +
cityName + '市' + "<br/>" +
'<span class="highlight">' + schoolInfo + '</span>' +
'</div>';
// return cityName +''+ "<br/>"+ '<span class="highlight">' + schoolInfo + '</span>';
return resultDiv
},
show: true,
backgroundColor: '#f4f6f8',
textStyle: {
color: "#333",
fontSize: 12
},
borderColor: '#333',
padding: 7
},
encode: {
value: 2
},
label: {
formatter: "{b}",
position: "right",
show: true, //
fontWeight: 'bolder'
},
itemStyle: {
color: "#1907f8"
},
emphasis: {
label: {
show: false
}
}
}
]
};
this.myEchart.setOption(option);
}, },
GetQueryString(name) { GetQueryString(name) {
if (name.indexOf("#") != -1) { if (name.indexOf("#") != -1) {
@ -634,8 +471,6 @@ ul {
list-style: none; list-style: none;
} }
//
.logo { .logo {
background-color: #32abfc; background-color: #32abfc;
margin-left: 35px; margin-left: 35px;
@ -693,10 +528,8 @@ ul {
// //
.banner { .banner {
position: relative; position: relative;
//width: 1200px;
width: 1.25rem; width: 1.25rem;
height: 4.5rem; height: 4.5rem;
border:1px solid red; border:1px solid red;
margin: 0 auto; margin: 0 auto;
} }
@ -750,12 +583,9 @@ ul {
width: 300px; width: 300px;
} }
//
.action { .action {
position: relative; position: relative;
height: 868px; height: 868px;
//border: 1px solid red;
//background-color: blue;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
@ -815,16 +645,13 @@ ul {
} }
.num { .num {
//margin-top: px;
width: 35%; width: 35%;
height: 500px; height: 500px;
} }
.pic-right { .pic-right {
width: 40%; width: 40%;
height: 100%; height: 100%;
//background-color: skyblue;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -832,7 +659,6 @@ ul {
margin: 15px 0; margin: 15px 0;
margin-left: 150px; margin-left: 150px;
width: 200px; width: 200px;
height: 200px; height: 200px;
} }
} }
@ -982,8 +808,6 @@ ul {
position: relative; position: relative;
width: 1212px; width: 1212px;
height: 616px; height: 616px;
//border:1px solid red;
img { img {
width: 100%; width: 100%;
height: 100%; height: 100%;
@ -1117,7 +941,6 @@ ul {
.left-box { .left-box {
width: 50%; width: 50%;
//border: 1px solid red;
height: 100%; height: 100%;
display: flex; display: flex;
justify-content: center; justify-content: center;
@ -1126,7 +949,6 @@ ul {
.right-box { .right-box {
width: 50%; width: 50%;
//border: 1px solid red;
height: 100%; height: 100%;
display: flex; display: flex;
justify-content: center; justify-content: center;
@ -1161,7 +983,6 @@ ul {
width: 139px; width: 139px;
height: 139px; height: 139px;
//border:1px solid red;
} }
.qr-content { .qr-content {
@ -1237,7 +1058,6 @@ ul {
padding: 12px; padding: 12px;
opacity: 0.8; opacity: 0.8;
mix-blend-mode: normal; mix-blend-mode: normal;
color: #f35626; color: #f35626;
font-weight: 700; font-weight: 700;
background: coral; background: coral;
@ -1363,7 +1183,6 @@ ul {
img { img {
margin-right: 20px; margin-right: 20px;
//border:1px solid red;
width: 100px; width: 100px;
} }

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Some files were not shown because too many files have changed in this diff Show More