加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
system_setup.py 25.10 KB
一键复制 编辑 原始数据 按行查看 历史
jczhang02 提交于 2024-10-31 10:59 . feat(check install)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756
import logging
from flask import request, jsonify
import uuid
from datetime import datetime
from werkzeug.security import generate_password_hash, check_password_hash
import pymysql.cursors
import time
import jwt
import requests
import platform
import json
from configparser import ConfigParser
import OpenSSL.crypto
from pynvml import *
# 读取配置文件
conf = ConfigParser()
conf.read("setting.ini", encoding='utf-8')
# log日志
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# 数据库连接
def mysql():
mydb = pymysql.connect(
host=conf.get("mysql_settings", "host"),
port=int(conf.get("mysql_settings", "port")),
user=conf.get("mysql_settings", "user"),
password=conf.get("mysql_settings", "password"),
database='system_setup',
cursorclass=pymysql.cursors.DictCursor
)
return mydb
# 内存
# redis = redis.Redis(host='127.0.0.1', port=6379,db=0,password='jizhi@123')
# 用户新增
def userAdd():
response = getDecodeToken(request.headers.get("Authorization", "")[7:])
token = json.loads(response.data)
if token['code'] == 1:
return jsonify(
msg=token['msg'],
code=1
)
elif token['code'] == 401:
return jsonify(
msg=token['msg'],
code=token['code']
)
mydb = mysql()
mydb.connect()
cursor = mydb.cursor()
try:
jsons = request.json
if jsons.__contains__('userName') and jsons.__contains__('password') and jsons.__contains__('state'):
sql = "SELECT user_name FROM `user` WHERE user_name = '" + jsons['userName'] + "'"
cursor.execute(sql)
count = cursor.fetchall()
if count.__len__() > 0:
return jsonify(code=1, msg="用户已存在")
# 用户名
user_name = jsons['userName']
if user_name is None: return jsonify(code=1, msg="userName 不能为null")
# 密码
password = jsons['password']
if password == '': return jsonify(code=1, msg="password 不能为null")
# 密码加密
password = generate_password_hash(password, method='pbkdf2:sha1', salt_length=10)
# 状态 1正常 2禁用
state = jsons['state']
if state is None or '': return jsonify(code=1, msg="state 不能为null")
# 创建日期
creation_date = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# 备注
remark = ''
if jsons.__contains__('remark'):
remark = jsons['remark']
id = str(uuid.uuid4())
sql = "insert into user (id,user_name,state,password,creation_date,remark) values('%s','%s',%s,'%s','%s','%s')" % (
id, user_name, state, password, creation_date, remark)
insert = cursor.execute(sql)
mydb.commit()
else:
return jsonify(code=1, msg="缺少必要参数userName、password、state")
except Exception as e:
print(e)
return jsonify(
code=1,
msg="Server internal error"
)
finally:
cursor.close() # 关闭游标
mydb.close() # 关闭连接
return jsonify(
msg="success",
code=0
)
# 用户编辑
def userUpdate():
response = getDecodeToken(request.headers.get("Authorization", "")[7:])
token = json.loads(response.data)
if token['code'] == 1:
return jsonify(
msg=token['msg'],
code=1
)
elif token['code'] == 401:
return jsonify(
msg=token['msg'],
code=token['code']
)
mydb = mysql()
mydb.connect()
cursor = mydb.cursor()
try:
jsons = request.json
if jsons.__contains__('userName') and jsons.__contains__('password') and jsons.__contains__(
'state') and jsons.__contains__('id'):
sql = "SELECT user_name FROM `user` WHERE id = '" + jsons['id'] + "'"
cursor.execute(sql)
userName = cursor.fetchone()
if jsons['userName'] != userName["user_name"]:
sql = "SELECT user_name FROM `user` WHERE user_name = '" + jsons['userName'] + "'"
cursor.execute(sql)
count = cursor.fetchall()
if count.__len__() > 0:
return jsonify(code=1, msg="用户已存在")
# 用户名
user_name = jsons['userName']
if user_name is None: return jsonify(code=1, msg="userName 不能为null")
# 密码
password = jsons['password']
if password == '': return jsonify(code=1, msg="password 不能为null")
# 密码加密
password = generate_password_hash(password, method='pbkdf2:sha1', salt_length=10)
# 状态 1正常 2禁用
state = jsons['state']
if state is None or '': return jsonify(code=1, msg="state 不能为null")
# 创建日期
creation_date = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# 备注
# 备注
remark = ''
if jsons.__contains__('remark'):
remark = jsons['remark']
id = jsons['id']
sql = "UPDATE `user` SET user_name = '%s',state = %s ,password = '%s',creation_date = '%s',remark = '%s' where id = '%s'" % (
user_name, state, password, creation_date, remark, id)
cursor.execute(sql)
mydb.commit()
else:
return jsonify(code=1, msg="缺少必要参数id、userName、password、state")
except Exception as e:
print(e)
return jsonify(
code=1,
msg="Server internal error"
)
finally:
cursor.close() # 关闭游标
mydb.close() # 再关闭数据库连接
return jsonify(
msg="success",
code=0
)
# 用户删除
def userDel():
response = getDecodeToken(request.headers.get("Authorization", "")[7:])
token = json.loads(response.data)
if token['code'] == 1:
return jsonify(
msg=token['msg'],
code=1
)
elif token['code'] == 401:
return jsonify(
msg=token['msg'],
code=token['code']
)
mydb = mysql()
mydb.connect()
cursor = mydb.cursor()
try:
jsons = request.json
if jsons.__contains__('id'):
sql = "DELETE FROM `user` WHERE id = '" + jsons['id'] + "'"
cursor.execute(sql)
mydb.commit()
else:
return jsonify(code=1, msg="缺少必要参数id")
except Exception as e:
print(e)
return jsonify(
code=1,
msg="Server internal error"
)
finally:
cursor.close() # 关闭游标
mydb.close() # 再关闭数据库连接
return jsonify(
msg="success",
code=0
)
# 用户分页列表
def userListPage():
response = getDecodeToken(request.headers.get("Authorization", "")[7:])
token = json.loads(response.data)
if token['code'] == 1:
return jsonify(
msg=token['msg'],
code=1
)
elif token['code'] == 401:
return jsonify(
msg=token['msg'],
code=token['code']
)
mydb = mysql()
mydb.connect()
cursor = mydb.cursor()
try:
jsons = request.args
if jsons.__contains__('page') and jsons.__contains__('limit'):
page = jsons.get("page")
limit = jsons.get("limit")
userName = "AND user_name like '%" + jsons.get("userName") + "%'" if jsons.get(
"userName") is not None else ""
state = " AND state = '" + jsons.get("state") + "'" if jsons.get("state") is not None else ""
sql = "SELECT * from user where 1=1 " + userName + state + " order by creation_date desc"
cursor.execute(sql)
cur_data = cursor.fetchall()
items = []
for item in cur_data[int(limit) * (int(page) - 1):int(limit) * int(page)]:
temp = {}
temp['id'] = item['id']
temp['userName'] = item['user_name']
temp['state'] = item['state']
temp['creationDate'] = item['creation_date']
temp['remark'] = item['remark']
items.append(temp)
rlt_data = {}
num = len(cur_data)
rlt_data["totalSize"] = num
rlt_data["pages"] = num // int(limit) + 1
rlt_data["pageSize"] = limit
rlt_data["Items"] = items
rlt_data["currentPage"] = page
rlt_data["currentSize"] = limit
if int(page) == rlt_data["pages"]:
rlt_data["currentSize"] = num % int(limit)
else:
return jsonify(code=1, msg="缺少必要参数page、limit")
except Exception as e:
print(e)
return jsonify(
code=1,
msg="Server internal error"
)
finally:
cursor.close() # 关闭游标
mydb.close() # 关闭数据库
return jsonify(
msg="success",
code=0,
data=rlt_data
)
# 登录
def login():
mydb = mysql()
mydb.connect()
cursor = mydb.cursor()
try:
jsons = request.json
if jsons.__contains__('userName') and jsons.__contains__('password'):
sql = "SELECT * from `user` WHERE user_name = '" + jsons.get("userName") + "'"
cursor.execute(sql)
user = cursor.fetchone()
if user is None: return jsonify(code=1, msg="用户不存在")
if check_password_hash(user["password"], jsons.get("password")):
print("登录成功")
rlt_data = {}
#rlt_data["token"] = createToken(user).decode(encoding ='utf-8',errors = 'strict')
rlt_data["token"] = createToken(user)
# 校验许可
flag = permit_check()
if flag == 'yes':
rlt_data["permit_check"] = 'yes'
else:
rlt_data["permit_check"] = 'no'
permission = license_permission_analysis()
rlt_data["permission"] = permission
return jsonify(
msg="success",
code=0,
data=rlt_data
)
else:
return jsonify(code=1, msg="密码错误")
else:
return jsonify(code=1, msg="缺少必要参数userName,password")
except Exception as e:
logging.debug("---Exception---%s" % e)
return jsonify(
code=1,
msg="Server internal error"
)
finally:
cursor.close() # 关闭游标
mydb.close() # 再关闭数据库连接
return jsonify(
code=0,
msg="success"
)
# 许可校验
def permit_check():
# cmd = "openssl verify -CAfile rootCA.crt -partial_chain dev.crt"
# result = os.popen(cmd).read()
# if result != '' and 'OK' in result:
# logging.debug("---进来了---")
# cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, open("dev.crt").read())
# certSubject = cert.get_subject()
# for item in certSubject.get_components():
# if item[0].decode("utf-8") == 'CN':
# logging.debug("---item---")
# logging.debug(item)
# logging.debug("---item[0]---")
# board_info = "{"+str(main_board_info())+"}.web"
# logging.debug("---board_info---")
# logging.debug(board_info)
# item[1].decode("utf-8")
# if item[1].decode("utf-8") != board_info:
# logging.debug("no")
# return 'no'
# logging.debug("yes")
# return 'yes'
# else:
# logging.debug("no")
# return 'no'
return "yes"
# 许可权限解析
def license_permission_analysis():
# cmd = "openssl verify -CAfile rootCA.crt -partial_chain dev.crt"
# result = os.popen(cmd).read()
# if result != '' and 'OK' in result:
# logging.debug("---进来了---")
# cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, open("dev.crt").read())
# certSubject = cert.get_subject()
# for item in certSubject.get_components():
# if item[0].decode("utf-8") == 'OU':
# logging.debug("---item---")
# logging.debug(item)
# ou = item[1].decode("utf-8")
# return ou[1:len(ou) - 5]
# return 'yes'
# else:
# logging.debug("no")
# return 'no'
return "yes"
# 创建token
def createToken(user):
# 生成一个字典,包含我们的具体信息
info = {
# 公共声明
'exp': time.time() + 7200, # (Expiration Time) 此token的过期时间的时间戳
# 'iat':time.time(), # (Issued At) 指明此创建时间的时间戳
'iss': 'jizhi', # (Issuer) 指明此token的签发者
'userId': user["id"]
# 私有声明
# 'data':{
# 'username':'xjj',
# 'timestamp':time.time()
# }
}
# jwt_encode = redis.get(user.get('user_name'))
# if jwt_encode is None:
#
# redis.set(user.get('user_name'),jwt_encode)
jwt_encode = jwt.encode(info, 'jizhi@123', algorithm='HS256')
return jwt_encode
# 解析token
def getDecodeToken(token):
if token == '':
return jsonify(
msg="No Token",
code=1,
)
try:
# flag = permit_check()
# if flag == 'no':
# return jsonify(
# code=401,
# msg='许可已过期'
# )
jwt_decode = jwt.decode(token, 'jizhi@123', issuer='jizhi', algorithms=['HS256'])
print(jwt_decode)
return jsonify(
msg="success",
code=0,
data=jwt_decode
)
except Exception as e:
return jsonify(
code=401,
msg='token 已过期'
)
def token_check(token):
headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + token}
url = "http://127.0.0.1:5001/system/getDecodeToken"
response = requests.request("POST", url, headers=headers).text
response = json.loads(response)
return response
# 获取网络信息
def ethList():
response = getDecodeToken(request.headers.get("Authorization", "")[7:])
token = json.loads(response.data)
if token['code'] == 1:
return jsonify(
msg=token['msg'],
code=1
)
elif token['code'] == 401:
return jsonify(
msg=token['msg'],
code=token['code']
)
try:
url = "http://127.0.0.1:8001/rest/v1/dev/ethList"
responseInfo = requests.get(url, timeout=5).text
responseInfo = json.loads(responseInfo)
logging.debug("response:%s" % responseInfo)
except Exception as e:
print(e)
return jsonify(
code=1,
msg="Server internal error"
)
return jsonify(
msg="success",
code=0,
data=responseInfo['data']
)
# 配置网络信息
def updateEth():
response = getDecodeToken(request.headers.get("Authorization", "")[7:])
token = json.loads(response.data)
if token['code'] == 1:
return jsonify(
msg=token['msg'],
code=1
)
elif token['code'] == 401:
return jsonify(
msg=token['msg'],
code=token['code']
)
try:
jsons = request.json
if jsons.__contains__('eth_name') and jsons.__contains__('gateway') and jsons.__contains__(
'dns') and jsons.__contains__('ip_addr') and jsons.__contains__('mask'):
headers = {
"Content-Type": "application/json; charset=UTF-8"
}
url = "http://127.0.0.1:8001/rest/v1/dev/ethList"
responseInfo = requests.post(url, data=json.dumps(jsons), headers=headers, timeout=5).text
responseInfo = json.loads(responseInfo)
logging.debug("response:%s" % responseInfo)
except Exception as e:
print(e)
return jsonify(
code=1,
msg="Server internal error"
)
return jsonify(
msg="success",
code=0,
data=responseInfo['data']
)
# 获取系统信息
def systemInfo():
response = getDecodeToken(request.headers.get("Authorization", "")[7:])
token = json.loads(response.data)
if token['code'] == 1:
return jsonify(
msg=token['msg'],
code=1
)
elif token['code'] == 401:
return jsonify(
msg=token['msg'],
code=token['code']
)
try:
conf.read('setting.ini')
gatewayNumber = conf.get("gateway_box", "gateway_number")
gatewayName = conf.get("gateway_box", "gateway_name")
gatewayType = conf.get("gateway_box", "gateway_type")
gatewaySerialNumber = conf.get("gateway_box", "gateway_serialnumber")
gatewayEdition = conf.get("gateway_box", "gateway_edition")
# gatewayPermit = conf.get("gateway_box", "gateway_permit")
gatewayPermit = main_board_info()
logo = conf.get("gateway_box", "logo")
jsonParam = {"gatewayNumber": gatewayNumber, "gatewayName": gatewayName, "gatewayType": gatewayType,
"gatewaySerialNumber": gatewaySerialNumber, "gatewayEdition": gatewayEdition,
"gatewayPermit": gatewayPermit,"logo":logo}
except Exception as e:
print(e)
return jsonify(
code=1,
msg="Server internal error"
)
return jsonify(
msg="success",
code=0,
data=jsonParam
)
# 获取系统状态
def systemStateList():
response = getDecodeToken(request.headers.get("Authorization", "")[7:])
token = json.loads(response.data)
if token['code'] == 1:
return jsonify(
msg=token['msg'],
code=1
)
elif token['code'] == 401:
return jsonify(
msg=token['msg'],
code=token['code']
)
try:
url = "http://127.0.0.1:8001/rest/v1/dev/info"
responseInfo = requests.get(url, timeout=5).text
responseInfo = json.loads(responseInfo)
logging.debug("response:%s" % responseInfo)
except Exception as e:
print(e)
return jsonify(
code=1,
msg="Server internal error"
)
return jsonify(
msg="success",
code=0,
data=responseInfo['data']
)
# 获取主板序列号
def get_main_board_info():
sys_str = platform.system()
serial_number_cmd = ''
cpu_cmd = ''
if sys_str == "Darwin":
# cmd = 'system_profiler SPHardwareDataType | grep Serial | cut -f 2 -d:'
serial_number_cmd = "nsenter -m -n -t 1 system_profiler SPHardwareDataType | grep Serial |awk -F': ' '{print $2}'"
cpu_cmd = "nsenter -m -n -t 1 system_profiler SPHardwareDataType | grep Serial |awk -F': ' '{print $2}'"
elif sys_str == "Windows":
serial_number_cmd = 'nsenter -m -n -t 1 wmic bios get serialnumber'
cpu_cmd = "nsenter -m -n -t 1 wmic cpu get ProcessorId"
else:
# cmd = "dmidecode -t 4 | grep ID |sort -u |awk -F': ' '{print $2}'"
# cmd = "sudo dmidecode -t 1 | grep Serial |awk -F': ' '{print $2}'"
serial_number_cmd = "nsenter -m -n -t 1 cat /sys/devices/virtual/dmi/id/product_uuid"
cpu_cmd = "nsenter -m -n -t 1 dmidecode -t 4 | grep ID |sort -u |awk -F': ' '{print $2}'"
serial_number = os.popen(serial_number_cmd).read()
serial_number = serial_number.replace('SerialNumber', '').strip()
print(serial_number.replace(" ",""))
serial_number = serial_number.replace(" ","")
serial_number = serial_number.replace("-","")
cpu = os.popen(cpu_cmd).read()
cpu = cpu.replace(' ', '').strip()
result = serial_number+cpu
print(result)
return jsonify(
msg="success",
code=0,
data=result
)
# 获取主板序列号
def main_board_info():
sys_str = platform.system()
serial_number_cmd = ''
cpu_cmd = ''
if sys_str == "Darwin":
# cmd = 'system_profiler SPHardwareDataType | grep Serial | cut -f 2 -d:'
serial_number_cmd = "nsenter -m -n -t 1 system_profiler SPHardwareDataType | grep Serial |awk -F': ' '{print $2}'"
cpu_cmd = "nsenter -m -n -t 1 system_profiler SPHardwareDataType | grep Serial |awk -F': ' '{print $2}'"
elif sys_str == "Windows":
serial_number_cmd = 'nsenter -m -n -t 1 wmic bios get serialnumber'
cpu_cmd = "nsenter -m -n -t 1 wmic cpu get ProcessorId"
else:
# cmd = "dmidecode -t 4 | grep ID |sort -u |awk -F': ' '{print $2}'"
# cmd = "sudo dmidecode -t 1 | grep Serial |awk -F': ' '{print $2}'"
serial_number_cmd = "nsenter -m -n -t 1 cat /sys/devices/virtual/dmi/id/product_uuid"
cpu_cmd = "nsenter -m -n -t 1 dmidecode -t 4 | grep ID |sort -u |awk -F': ' '{print $2}'"
serial_number = os.popen(serial_number_cmd).read()
serial_number = serial_number.replace('SerialNumber', '').strip()
print(serial_number.replace(" ",""))
serial_number = serial_number.replace(" ","")
serial_number = serial_number.replace("-","")
cpu = os.popen(cpu_cmd).read()
cpu = cpu.replace(' ', '').strip()
result = serial_number+cpu
print(result)
return result
# 获取配置文件(数据库)
def get_profile():
if os.path.exists("/mnt/work/www/upload/mysql5.7.tar.gz"):
return jsonify(
msg="success",
code=0,
data="/upload/mysql5.7.tar.gz"
)
else:
return jsonify(
code=1,
msg="请先备份再导出!"
)
# 备份配置文件(数据库)
def backup_profile():
cmd = "nsenter -m -n -t 1 sudo -i tar -zcvf /usr/local/mysql5.7.tar.gz /usr/local/mysql5.7/"
result = os.popen(cmd).read()
cmd = "nsenter -m -n -t 1 sudo -i cp /usr/local/mysql5.7.tar.gz /mnt/work/www/upload"
result = os.popen(cmd).read()
return jsonify(
msg="success",
code=0
)
# Invidia信息
def nvidia_info():
# pip install nvidia-ml-py
nvidia_dict = {
"state": True,
"nvidia_version": "",
"nvidia_count": 0,
"gpus": []
}
try:
nvmlInit()
nvidia_dict["nvidia_version"] = nvmlSystemGetDriverVersion()
nvidia_dict["nvidia_count"] = nvmlDeviceGetCount()
for i in range(nvidia_dict["nvidia_count"]):
handle = nvmlDeviceGetHandleByIndex(i)
memory_info = nvmlDeviceGetMemoryInfo(handle)
gpu = {
"gpu_name": nvmlDeviceGetName(handle),
"total": memory_info.total,
"free": memory_info.free,
"used": memory_info.used,
"temperature": f"{nvmlDeviceGetTemperature(handle, 0)}℃",
"powerStatus": nvmlDeviceGetPowerState(handle)
}
nvidia_dict['gpus'].append(gpu)
except NVMLError as _:
nvidia_dict["state"] = False
except Exception as _:
nvidia_dict["state"] = False
finally:
try:
nvmlShutdown()
except:
pass
return nvidia_dict
# 获取gpu使用率
def check_gpu_mem_usedRate():
max_rate = 0.0
info = nvidia_info()
print(info)
if info['nvidia_count'] != 0:
used = info['gpus'][0]['used']
tot = info['gpus'][0]['total']
print(f"GPU0 used: {used}, tot: {tot}, 使用率:{used/tot}")
if used/tot > max_rate:
max_rate = used/tot
print("GPU0 最大使用率:", max_rate)
return jsonify(
msg="success",
code=0,
data=round(max_rate,2)
)
else:
return jsonify(
msg="success",
code=0,
data=0
)
# 写入系统配置
def set_system_config():
try:
jsons = request.json
if jsons.__contains__('gateway_number') and jsons.get("gateway_number") != '':
conf.set("gateway_box",'gateway_number',jsons.get("gateway_number"))
elif jsons.__contains__('gateway_name') and jsons.get("gateway_name") != '':
conf.set("gateway_box",'gateway_name',jsons.get("gateway_name"))
elif jsons.__contains__('gateway_type') and jsons.get("gateway_type") != '':
conf.set("gateway_box",'gateway_type',jsons.get("gateway_type"))
elif jsons.__contains__('gateway_serialnumber') and jsons.get("gateway_serialnumber") != '':
conf.set("gateway_box",'gateway_serialnumber',jsons.get("gateway_serialnumber"))
elif jsons.__contains__('gateway_edition') and jsons.get("gateway_edition") != '':
conf.set("gateway_box",'gateway_edition',jsons.get("gateway_edition"))
with open('setting.ini', 'w') as f:
conf.write(f)
conf.read('setting.ini')
return jsonify(
msg="success",
code=0
)
except Exception as e:
print(e)
return jsonify(
code=1,
msg="Server internal error"
)
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化