init
|
@ -0,0 +1,13 @@
|
|||
### 该问题是怎么引起的?
|
||||
|
||||
|
||||
|
||||
### 重现步骤
|
||||
|
||||
|
||||
|
||||
### 报错信息
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
|
@ -0,0 +1,6 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
</profile>
|
||||
</component>
|
|
@ -0,0 +1,6 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.6 (model)" project-jdk-type="Python SDK" />
|
||||
</project>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/se2021-app-model-merge.iml" filepath="$PROJECT_DIR$/.idea/se2021-app-model-merge.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="jdk" jdkName="Python 3.6 (model)" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
|
@ -0,0 +1,592 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding:utf-8 -*-
|
||||
# @Time : 2021/6/2 13:56 下午
|
||||
# @Author : Tang Jiaxin,Chen wenjie,Wang Jiajie
|
||||
# 对一个app的多个模型进行合并
|
||||
# 1、合并state_list
|
||||
# 2、合并transition
|
||||
# 3、根据得到的state_list,确定当前app所包含的states
|
||||
|
||||
import sys
|
||||
sys.path.append('../Model')
|
||||
from BuildModel import Model
|
||||
from Transition import Transition
|
||||
from Event import Event
|
||||
import pandas as pd
|
||||
import xml.etree.ElementTree as ET
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
from PIL import Image
|
||||
from networkx.drawing.nx_pydot import to_pydot
|
||||
import networkx as nx
|
||||
import random
|
||||
|
||||
|
||||
class Merge:
|
||||
def __init__(self): # 初始构造函数
|
||||
self.app_id = None
|
||||
self.app_apk_name = None
|
||||
self.app_package_name = None
|
||||
self.app_version = None
|
||||
self.model_list = [] # 待合并的model列表
|
||||
self.res_state_list = [] # 合并后的state_list
|
||||
self.res_transitions = [] # 合并后的transitions
|
||||
self.res_states = {} # 合并后的states
|
||||
|
||||
def get_model_id(self):
|
||||
"""读取模型列表中的模型以获取app_id"""
|
||||
try:
|
||||
return self.model_list[0].app_id
|
||||
except:
|
||||
return -1
|
||||
|
||||
def add_model(self, model): # 向model_list中添加一个模型
|
||||
if len(self.model_list) == 0:
|
||||
self.app_id = model.get_id()
|
||||
self.app_apk_name = model.get_apk_name()
|
||||
self.app_package_name = model.get_package_name()
|
||||
self.app_version = model.get_version()
|
||||
elif model.get_id() != self.app_id:
|
||||
return
|
||||
self.model_list.append(model)
|
||||
|
||||
def get_res_model(self): # 返回一个合并后的模型
|
||||
res_model = Model()
|
||||
res_model.set_id(self.get_model_id())
|
||||
print(res_model.app_id)
|
||||
res_model.set_apk_name(self.app_apk_name)
|
||||
res_model.set_package_name(self.app_package_name)
|
||||
res_model.set_version(self.app_version)
|
||||
res_model.state_list = self.res_state_list
|
||||
res_model.transitions = self.res_transitions
|
||||
res_model.states = self.res_states
|
||||
return res_model
|
||||
|
||||
def search_state(self, state_list, state): # 在state_list中查找某个state,返回其下标
|
||||
for i in range(len(state_list)):
|
||||
if self.cmp_xml(state_list[i].layout, state.layout) > 0.9:
|
||||
return i
|
||||
return -1
|
||||
|
||||
def add_states(self, model):
|
||||
# 将当前model中的所有state加入res_state_list中,返回旧state_id与新state_id的对应关系字典
|
||||
res_dict = {}
|
||||
for state in model.state_list:
|
||||
# 在res_state_list中查找state是否已经存在
|
||||
new_id = self.search_state(self.res_state_list, state)
|
||||
if new_id != -1: # 如果查找到,则更新state_id
|
||||
res_dict[state.get_state_id()] = new_id
|
||||
state.set_state_id(new_id)
|
||||
else: # 如果没有查找到,则设置state_id,并将state加入res_state_list
|
||||
new_id = len(self.res_state_list)
|
||||
res_dict[state.get_state_id()] = new_id
|
||||
state.set_state_id(new_id)
|
||||
self.res_state_list.append(state)
|
||||
return res_dict
|
||||
|
||||
def merge_models(self):
|
||||
# 建立一个用于存储合并后的transition信息的dataframe
|
||||
res_df = pd.DataFrame(columns=('source_id', 'target_id', 'action', 'identifier'))
|
||||
for model in self.model_list: # 依次遍历每个model
|
||||
model.generate_trans_df() # 为model建立trans_df,用于合并
|
||||
t_dict = self.add_states(model) # 将model的state加入到res_state_list中
|
||||
# 根据获得的对应结果,更新transitions中的state_id
|
||||
for transition in model.transitions:
|
||||
transition.set_source_id(t_dict[transition.get_source_id()])
|
||||
transition.set_target_id(t_dict[transition.get_target_id()])
|
||||
# 根据获得的对应结果,更新trans_df中的state_id,并将更新后的row加入res_df
|
||||
for index, row in model.trans_df.iterrows():
|
||||
row['source_id'] = t_dict[row['source_id']]
|
||||
row['target_id'] = t_dict[row['target_id']]
|
||||
res_df = res_df.append(row, ignore_index=True)
|
||||
res_df = res_df.drop_duplicates() # 对合并完成后的dataframe进行去重
|
||||
self.res_transitions = []
|
||||
transition_id = 0
|
||||
# 根据去重后的dataframe生成合并后的transitions
|
||||
for index, row in res_df.iterrows():
|
||||
transition = Transition()
|
||||
transition.set_transition_id(transition_id)
|
||||
transition.set_source_id(row['source_id'])
|
||||
transition.set_target_id(row['target_id'])
|
||||
event = Event(row['action'], row['identifier'], '')
|
||||
transition.set_event(event)
|
||||
transition_id += 1
|
||||
self.res_transitions.append(transition)
|
||||
# 根据res_state_list生成states
|
||||
for state in self.res_state_list:
|
||||
self.res_states[state.state_id] = state
|
||||
|
||||
def cmp_xml(self, layout1, layout2): # 计算两个xml字符串的相似度
|
||||
# tree1 = ET.parse(file1)
|
||||
# tree2 = ET.parse(file2) # 根据xml文件建立element tree
|
||||
# root1 = tree1.getroot()
|
||||
# root2 = tree2.getroot() # 获取两棵树的根节点
|
||||
root1 = ET.fromstring(layout1)
|
||||
root2 = ET.fromstring(layout2)
|
||||
return self.cmp_xml_node(root1, root2)
|
||||
|
||||
def cmp_xml_node(self, node1, node2): # 计算以两个节点为根的子树的相似度
|
||||
if node1.tag != node2.tag: # 若两个节点的名称不同
|
||||
return 0 # 两个节点的相似度为0
|
||||
if len(node1) == 0 and len(node2) == 0: # 若两个节点均为叶子节点
|
||||
return self.cmp_xml_leaf(node1, node2)
|
||||
if len(node1) == 0 or len(node2) == 0: # 若node1或node2是叶子节点而另一个不是
|
||||
return 0
|
||||
child_dict1 = self.genenate_child_dict(node1) # 生成node1对应的子节点字典
|
||||
child_dict2 = self.genenate_child_dict(node2) # 生成node2对应的子节点字典
|
||||
sim_value = 0 # 两节点的相似度评分
|
||||
for tag1, child_list1 in child_dict1.items(): # 依次遍历node1的子节点字典
|
||||
child_list2 = child_dict2.get(tag1) # 在node2的子节点字典中查找由同名子节点构成的列表
|
||||
if child_list2 is None: # 若查找不到
|
||||
continue
|
||||
sim_value += self.cmp_xml_same_tag(child_list1, child_list2) # 计算两个同名的子节点列表的相似度
|
||||
return sim_value / max(len(child_dict1), len(child_dict2))
|
||||
|
||||
def cmp_xml_same_tag(self, list1, list2): # 计算两个同名子节点列表的相似度
|
||||
sim_value = 0 # 两列表的相似度评分
|
||||
sim_values = np.zeros((len(list1), len(list2))) # 创建评分矩阵
|
||||
for i in range(len(list1)):
|
||||
for j in range(len(list2)):
|
||||
sim_values[i, j] = self.cmp_xml_node(list1[i], list2[j]) # 计算两两之间的相似度
|
||||
while sim_values.shape[0] != 0 and sim_values.shape[1] != 0:
|
||||
max_index = np.argmax(sim_values) # 从所有相似度中找最大值所在的位置
|
||||
max_row = max_index // sim_values.shape[1]
|
||||
max_col = max_index % sim_values.shape[1] # 计算最大值所在的行和列
|
||||
max_sim_value = sim_values[max_row, max_col]
|
||||
if max_sim_value == 0:
|
||||
break
|
||||
sim_value += max_sim_value
|
||||
sim_values = np.delete(sim_values, max_row, axis=0)
|
||||
sim_values = np.delete(sim_values, max_col, axis=1) # 删除最大值所在的行和列
|
||||
return sim_value / max(len(list1), len(list2))
|
||||
|
||||
def genenate_child_dict(self, node): # 产生某个节点的子节点字典
|
||||
children = {}
|
||||
for child in node:
|
||||
if child.tag not in children:
|
||||
children[child.tag] = [child]
|
||||
else:
|
||||
children[child.tag].append(child)
|
||||
return children
|
||||
|
||||
def cmp_xml_node_key(self, key, value1, value2): # 根据属性名称,计算两个属性值的相似度
|
||||
if key == 'index':
|
||||
return 1
|
||||
return value1 == value2
|
||||
|
||||
def cmp_xml_leaf(self, node1, node2): # 计算两个同名叶子节点的相似度
|
||||
attrib1 = node1.attrib
|
||||
attrib2 = node2.attrib
|
||||
sim_value = 0
|
||||
for key1, value1 in attrib1.items(): # 依次遍历node1的属性列表
|
||||
value2 = attrib2.get(key1) # 在node2中查找相应属性的属性值
|
||||
if value2 is None: # 如果node2中不存在该名字的属性
|
||||
continue
|
||||
sim_value += self.cmp_xml_node_key(key1, value1, value2) # 计算两个属性值的相似度
|
||||
return sim_value / max(len(attrib1), len(attrib2))
|
||||
|
||||
def hierarchy_pos(self, G, root=None, width=1., vert_gap=0.2, vert_loc=0, xcenter=0.5):
|
||||
'''
|
||||
G: the graph (must be a tree)
|
||||
|
||||
root: the root node of current branch
|
||||
- if the tree is directed and this is not given,
|
||||
the root will be found and used
|
||||
- if the tree is directed and this is given, then
|
||||
the positions will be just for the descendants of this node.
|
||||
- if the tree is undirected and not given,
|
||||
then a random choice will be used.
|
||||
|
||||
width: horizontal space allocated for this branch - avoids overlap with other branches
|
||||
|
||||
vert_gap: gap between levels of hierarchy
|
||||
|
||||
vert_loc: vertical location of root
|
||||
|
||||
xcenter: horizontal location of root
|
||||
'''
|
||||
if not nx.is_tree(G):
|
||||
raise TypeError('cannot use hierarchy_pos on a graph that is not a tree')
|
||||
|
||||
if root is None:
|
||||
if isinstance(G, nx.DiGraph):
|
||||
root = next(iter(nx.topological_sort(G))) # allows back compatibility with nx version 1.11
|
||||
else:
|
||||
root = random.choice(list(G.nodes))
|
||||
|
||||
def _hierarchy_pos(G, root, width=1., vert_gap=0.2, vert_loc=0, xcenter=0.5, pos=None, parent=None):
|
||||
'''
|
||||
see hierarchy_pos docstring for most arguments
|
||||
|
||||
pos: a dict saying where all nodes go if they have been assigned
|
||||
parent: parent of this branch. - only affects it if non-directed
|
||||
|
||||
'''
|
||||
|
||||
if pos is None:
|
||||
pos = {root: (xcenter, vert_loc)}
|
||||
else:
|
||||
pos[root] = (xcenter, vert_loc)
|
||||
children = list(G.neighbors(root))
|
||||
if not isinstance(G, nx.DiGraph) and parent is not None:
|
||||
children.remove(parent)
|
||||
if len(children) != 0:
|
||||
dx = width / len(children)
|
||||
nextx = xcenter - width / 2 - dx / 2
|
||||
for child in children:
|
||||
nextx += dx
|
||||
pos = _hierarchy_pos(G, child, width=dx, vert_gap=vert_gap,
|
||||
vert_loc=vert_loc - vert_gap, xcenter=nextx,
|
||||
pos=pos, parent=root)
|
||||
return pos
|
||||
|
||||
return _hierarchy_pos(G, root, width, vert_gap, vert_loc, xcenter)
|
||||
|
||||
def model1_transitions_visualization(self, model): # type1对应的model1可视化
|
||||
source_id_list = []
|
||||
target_id_list = []
|
||||
test_list = [0]
|
||||
data_list = []
|
||||
j = 0
|
||||
for transition in model.transitions:
|
||||
source_id_list.append(transition.source_id)
|
||||
target_id_list.append(transition.target_id)
|
||||
visualization_tuple = sorted(zip(source_id_list, target_id_list))
|
||||
#print(visualization_tuple) # visualization_tuple索引0存储souece_id,索引1存储target_id
|
||||
plt.figure(figsize=(48, 36))
|
||||
for i in range(len(visualization_tuple)): # 依次遍历visualization_tuple的元组
|
||||
if visualization_tuple[i][0] == test_list[j]: # 如果visualization_tuple中的source_id已存在于test_list
|
||||
data_list.append(visualization_tuple[i]) # 将元组添加至data_list
|
||||
else: #使用现有data_list中的元组画图
|
||||
G = nx.Graph()
|
||||
G.add_edges_from(data_list)
|
||||
k = test_list[j] #确定source_id作为根节点
|
||||
try:
|
||||
plt.subplot(9, 9, 0 + len(test_list)) #创建子图
|
||||
nx.draw(G, with_labels=True, node_size=300)
|
||||
G.remove_node(k)
|
||||
except:
|
||||
pass
|
||||
j += 1
|
||||
test_list.append(visualization_tuple[i][0])
|
||||
data_list.clear() #画图后清空data_list
|
||||
data_list.append(visualization_tuple[i]) #添加新元组
|
||||
plt.subplots_adjust(bottom=0.1, right=0.8, top=0.9)
|
||||
plt.savefig('model1.png')
|
||||
|
||||
def model2_transitions_visualization(self, model): # type1对应的model2可视化
|
||||
source_id_list = []
|
||||
target_id_list = []
|
||||
test_list = [0]
|
||||
data_list = []
|
||||
j = 0
|
||||
for transition in model.transitions:
|
||||
source_id_list.append(transition.source_id)
|
||||
target_id_list.append(transition.target_id)
|
||||
visualization_tuple = sorted(zip(source_id_list, target_id_list))
|
||||
#print(visualization_tuple)
|
||||
plt.figure(figsize=(16, 12))
|
||||
for i in range(len(visualization_tuple)):
|
||||
if visualization_tuple[i][0] == test_list[j]:
|
||||
data_list.append(visualization_tuple[i])
|
||||
else:
|
||||
G = nx.Graph()
|
||||
G.add_edges_from(data_list)
|
||||
k = test_list[j]
|
||||
try:
|
||||
plt.subplot(330 + len(test_list))
|
||||
nx.draw(G, with_labels=True, node_size=300)
|
||||
G.remove_node(k)
|
||||
except:
|
||||
pass
|
||||
j += 1
|
||||
test_list.append(visualization_tuple[i][0])
|
||||
data_list.clear()
|
||||
data_list.append(visualization_tuple[i])
|
||||
plt.subplots_adjust(bottom=0.1, right=0.8, top=0.9)
|
||||
plt.savefig('model2.png')
|
||||
|
||||
def model1_transitions_visualization2(self, model): # type2对应的model1可视化
|
||||
source_id_list = []
|
||||
target_id_list = []
|
||||
test_list = [0]
|
||||
data_list = []
|
||||
dot_list = []
|
||||
j = 0
|
||||
for transition in model.transitions:
|
||||
source_id_list.append(transition.source_id)
|
||||
target_id_list.append(transition.target_id)
|
||||
visualization_tuple = sorted(zip(source_id_list, target_id_list))
|
||||
#print(visualization_tuple)
|
||||
plt.figure(figsize=(48, 36))
|
||||
for i in range(len(visualization_tuple)):
|
||||
if visualization_tuple[i][0] == test_list[j]:
|
||||
data_list.append(visualization_tuple[i])
|
||||
else:
|
||||
G = nx.Graph()
|
||||
k = test_list[j]
|
||||
plt.subplot(9, 9, 0 + len(test_list))
|
||||
plt.axis('off')
|
||||
try:
|
||||
G.add_edges_from(data_list)
|
||||
pos = self.hierarchy_pos(G, k)
|
||||
nx.draw(G, pos=pos, with_labels=True, node_size=300)
|
||||
except: #source_id与target_id相同时使用dot画图
|
||||
G.add_edges_from(data_list)
|
||||
dot_list.append(j + 1)
|
||||
P = to_pydot(G)
|
||||
P.write_jpeg('pydot.png')
|
||||
plt.imshow(Image.open('pydot.png'))
|
||||
G.remove_node(k)
|
||||
j += 1
|
||||
test_list.append(visualization_tuple[i][0])
|
||||
data_list.clear()
|
||||
data_list.append(visualization_tuple[i])
|
||||
plt.subplots_adjust(bottom=0.1, right=0.8, top=0.9)
|
||||
plt.savefig('model1_2.png')
|
||||
|
||||
def model2_transitions_visualization2(self, model): # type2对应的model2可视化
|
||||
source_id_list = []
|
||||
target_id_list = []
|
||||
test_list = [0]
|
||||
data_list = []
|
||||
dot_list = []
|
||||
j = 0
|
||||
for transition in model.transitions:
|
||||
source_id_list.append(transition.source_id)
|
||||
target_id_list.append(transition.target_id)
|
||||
visualization_tuple = sorted(zip(source_id_list, target_id_list))
|
||||
#print(visualization_tuple)
|
||||
plt.figure(figsize=(16, 12))
|
||||
for i in range(len(visualization_tuple)):
|
||||
if visualization_tuple[i][0] == test_list[j]:
|
||||
data_list.append(visualization_tuple[i])
|
||||
else:
|
||||
G = nx.Graph()
|
||||
plt.subplot(330 + len(test_list))
|
||||
plt.axis('off')
|
||||
k = test_list[j]
|
||||
try:
|
||||
G.add_edges_from(data_list)
|
||||
pos = self.hierarchy_pos(G, k)
|
||||
nx.draw(G, pos=pos, with_labels=True, node_size=300)
|
||||
except:
|
||||
G.add_edges_from(data_list)
|
||||
dot_list.append(j + 1)
|
||||
P = to_pydot(G)
|
||||
P.write_jpeg('pydot.png')
|
||||
plt.imshow(Image.open('pydot.png'))
|
||||
G.remove_node(k)
|
||||
j += 1
|
||||
test_list.append(visualization_tuple[i][0])
|
||||
data_list.clear()
|
||||
data_list.append(visualization_tuple[i])
|
||||
plt.subplots_adjust(bottom=0.1, right=0.8, top=0.9)
|
||||
plt.savefig('model2_2.png')
|
||||
|
||||
def model1_transitions_visualization3(self, model): # type3对应的model1可视化
|
||||
source_id_list = []
|
||||
target_id_list = []
|
||||
test_list = [0]
|
||||
data_list = []
|
||||
j = 0
|
||||
for transition in model.transitions:
|
||||
source_id_list.append(transition.source_id)
|
||||
target_id_list.append(transition.target_id)
|
||||
visualization_tuple = sorted(zip(source_id_list, target_id_list))
|
||||
#print(visualization_tuple)
|
||||
plt.figure(figsize=(48, 36))
|
||||
for i in range(len(visualization_tuple)):
|
||||
if visualization_tuple[i][0] == test_list[j]:
|
||||
data_list.append(visualization_tuple[i])
|
||||
else:
|
||||
G = nx.Graph()
|
||||
k = test_list[j]
|
||||
plt.subplot(9, 9, 0 + len(test_list))
|
||||
plt.axis('off')
|
||||
G.add_edges_from(data_list)
|
||||
P = to_pydot(G)
|
||||
P.write_jpeg('pydot.png')
|
||||
plt.imshow(Image.open('pydot.png'))
|
||||
G.remove_node(k)
|
||||
j += 1
|
||||
test_list.append(visualization_tuple[i][0])
|
||||
data_list.clear()
|
||||
data_list.append(visualization_tuple[i])
|
||||
plt.subplots_adjust(bottom=0.1, right=0.8, top=0.9)
|
||||
plt.savefig('model1_3.png')
|
||||
|
||||
def model2_transitions_visualization3(self, model): # type3对应的model2可视化
|
||||
source_id_list = []
|
||||
target_id_list = []
|
||||
test_list = [0]
|
||||
data_list = []
|
||||
j = 0
|
||||
for transition in model.transitions:
|
||||
source_id_list.append(transition.source_id)
|
||||
target_id_list.append(transition.target_id)
|
||||
visualization_tuple = sorted(zip(source_id_list, target_id_list))
|
||||
plt.figure(figsize=(16, 12))
|
||||
for i in range(len(visualization_tuple)):
|
||||
if visualization_tuple[i][0] == test_list[j]:
|
||||
data_list.append(visualization_tuple[i])
|
||||
else:
|
||||
G = nx.Graph()
|
||||
plt.subplot(330 + len(test_list))
|
||||
plt.axis('off')
|
||||
k = test_list[j]
|
||||
G.add_edges_from(data_list)
|
||||
P = to_pydot(G)
|
||||
P.write_jpeg('pydot.png')
|
||||
plt.imshow(Image.open('pydot.png'))
|
||||
G.remove_node(k)
|
||||
j += 1
|
||||
test_list.append(visualization_tuple[i][0])
|
||||
data_list.clear()
|
||||
data_list.append(visualization_tuple[i])
|
||||
plt.subplots_adjust(bottom=0.1, right=0.8, top=0.9)
|
||||
plt.savefig('model2_3.png')
|
||||
|
||||
def res_transitions_visualization(self, model): # type1对应的res可视化
|
||||
source_id_list = []
|
||||
target_id_list = []
|
||||
test_list = [0]
|
||||
data_list = []
|
||||
j = 0
|
||||
for transition in model.transitions:
|
||||
source_id_list.append(transition.source_id)
|
||||
target_id_list.append(transition.target_id)
|
||||
visualization_tuple = sorted(zip(source_id_list, target_id_list))
|
||||
#print(visualization_tuple)
|
||||
plt.figure(figsize=(48, 36))
|
||||
for i in range(len(visualization_tuple)):
|
||||
if visualization_tuple[i][0] == test_list[j]:
|
||||
data_list.append(visualization_tuple[i])
|
||||
else:
|
||||
G = nx.Graph()
|
||||
G.add_edges_from(data_list)
|
||||
k = test_list[j]
|
||||
plt.subplot(9, 7, 0 + len(test_list))
|
||||
nx.draw(G, with_labels=True, node_size=300)
|
||||
G.remove_node(k)
|
||||
j += 1
|
||||
test_list.append(visualization_tuple[i][0])
|
||||
data_list.clear()
|
||||
data_list.append(visualization_tuple[i])
|
||||
plt.subplots_adjust(bottom=0.1, right=0.8, top=0.9)
|
||||
plt.savefig('merge.png')
|
||||
|
||||
def res_transitions_visualization2(self, model): # type2对应的res可视化
|
||||
source_id_list = []
|
||||
target_id_list = []
|
||||
test_list = [0]
|
||||
data_list = []
|
||||
dot_list = []
|
||||
j = 0
|
||||
for transition in model.transitions:
|
||||
source_id_list.append(transition.source_id)
|
||||
target_id_list.append(transition.target_id)
|
||||
visualization_tuple = sorted(zip(source_id_list, target_id_list))
|
||||
#print(visualization_tuple)
|
||||
plt.figure(figsize=(48, 36))
|
||||
for i in range(len(visualization_tuple)):
|
||||
if visualization_tuple[i][0] == test_list[j]:
|
||||
data_list.append(visualization_tuple[i])
|
||||
else:
|
||||
G = nx.Graph()
|
||||
plt.subplot(9, 7, 0 + len(test_list))
|
||||
plt.axis('off')
|
||||
k = test_list[j]
|
||||
try:
|
||||
G.add_edges_from(data_list)
|
||||
pos = self.hierarchy_pos(G, k)
|
||||
nx.draw(G, pos=pos, with_labels=True, node_size=300)
|
||||
except:
|
||||
G.add_edges_from(data_list)
|
||||
dot_list.append(j + 1)
|
||||
P = to_pydot(G)
|
||||
P.write_jpeg('pydot.png')
|
||||
plt.imshow(Image.open('pydot.png'))
|
||||
G.remove_node(k)
|
||||
j += 1
|
||||
test_list.append(visualization_tuple[i][0])
|
||||
data_list.clear()
|
||||
data_list.append(visualization_tuple[i])
|
||||
plt.subplots_adjust(bottom=0.1, right=0.8, top=0.9)
|
||||
plt.savefig('merge_2.png')
|
||||
|
||||
def res_transitions_visualization3(self, model): # type3对应的res可视化
|
||||
source_id_list = []
|
||||
target_id_list = []
|
||||
test_list = [0]
|
||||
data_list = []
|
||||
j = 0
|
||||
for transition in model.transitions:
|
||||
source_id_list.append(transition.source_id)
|
||||
target_id_list.append(transition.target_id)
|
||||
visualization_tuple = sorted(zip(source_id_list, target_id_list))
|
||||
#print(visualization_tuple)
|
||||
plt.figure(figsize=(48, 36))
|
||||
for i in range(len(visualization_tuple)):
|
||||
if visualization_tuple[i][0] == test_list[j]:
|
||||
data_list.append(visualization_tuple[i])
|
||||
else:
|
||||
G = nx.Graph()
|
||||
plt.subplot(9, 7, 0 + len(test_list))
|
||||
plt.axis('off')
|
||||
k = test_list[j]
|
||||
G.add_edges_from(data_list)
|
||||
P = to_pydot(G)
|
||||
P.write_jpeg('pydot.png')
|
||||
plt.imshow(Image.open('pydot.png'))
|
||||
G.remove_node(k)
|
||||
j += 1
|
||||
test_list.append(visualization_tuple[i][0])
|
||||
data_list.clear()
|
||||
data_list.append(visualization_tuple[i])
|
||||
plt.subplots_adjust(bottom=0.1, right=0.8, top=0.9)
|
||||
plt.savefig('merge_3.png')
|
||||
|
||||
def get_model_graph(self, type):
|
||||
plt.figure(figsize=(48, 36))
|
||||
if type == 1:
|
||||
plt.subplot(2, 2, 1)
|
||||
plt.title('model1')
|
||||
plt.imshow(Image.open('model1.png'))
|
||||
plt.axis('off')
|
||||
plt.subplot(2, 2, 2)
|
||||
plt.title('model2')
|
||||
plt.imshow(Image.open('model2.png'))
|
||||
plt.axis('off')
|
||||
plt.subplot(2, 2, 3)
|
||||
plt.title('merge')
|
||||
plt.imshow(Image.open('merge.png'))
|
||||
plt.axis('off')
|
||||
elif type == 2:
|
||||
plt.subplot(2, 2, 1)
|
||||
plt.title('model1')
|
||||
plt.imshow(Image.open('model1_2.png'))
|
||||
plt.axis('off')
|
||||
plt.subplot(2, 2, 2)
|
||||
plt.title('model2')
|
||||
plt.imshow(Image.open('model2_2.png'))
|
||||
plt.axis('off')
|
||||
plt.subplot(2, 2, 3)
|
||||
plt.title('merge')
|
||||
plt.imshow(Image.open('merge_2.png'))
|
||||
plt.axis('off')
|
||||
elif type == 1:
|
||||
plt.subplot(2, 2, 1)
|
||||
plt.title('model1')
|
||||
plt.imshow(Image.open('model1_3.png'))
|
||||
plt.axis('off')
|
||||
plt.subplot(2, 2, 2)
|
||||
plt.title('model2')
|
||||
plt.imshow(Image.open('model2_3.png'))
|
||||
plt.axis('off')
|
||||
plt.subplot(2, 2, 3)
|
||||
plt.title('merge')
|
||||
plt.imshow(Image.open('merge_3.png'))
|
||||
plt.axis('off')
|
||||
plt.savefig('total.png')
|
||||
plt.show()
|
|
@ -0,0 +1,88 @@
|
|||
'''
|
||||
|
||||
存储数据库中每个app信息的存储单元;
|
||||
与数据库表项的对应:
|
||||
appId->app_id
|
||||
apkName->apk_name
|
||||
packageName->package_name
|
||||
version->version
|
||||
states->相应app中所有的state数据,以<state_id,state_info>键值对存入hashMap中。
|
||||
scenarios->相应app中的场景集合
|
||||
|
||||
author zhouxinyu
|
||||
|
||||
'''
|
||||
|
||||
from AppRunningPath import AppRunningPath
|
||||
|
||||
|
||||
class App:
|
||||
|
||||
def __init__(self, id=-1, apk=None, pck=None, v=None):
|
||||
self.app_id = id
|
||||
self.apk_name = apk
|
||||
self.package_name = pck
|
||||
self.apk_version = v
|
||||
|
||||
self.states = {}
|
||||
self.app_running_path = AppRunningPath()
|
||||
self.scenarios = []
|
||||
|
||||
def set_id(self, id):
|
||||
self.app_id = id
|
||||
|
||||
def set_apk_name(self, apk):
|
||||
self.apk_name = apk
|
||||
|
||||
def set_package_name(self, pck):
|
||||
self.package_name = pck
|
||||
|
||||
def set_version(self, v):
|
||||
self.apk_version = v
|
||||
|
||||
def set_states(self, s):
|
||||
if self.states == None:
|
||||
self.states = {}
|
||||
|
||||
def set_app_running_path(self, arp):
|
||||
self.app_running_path = arp
|
||||
|
||||
def set_scenarios(self, sc):
|
||||
if self.scenarios == None:
|
||||
self.scenarios = []
|
||||
self.scenarios.extend(sc)
|
||||
|
||||
def get_id(self):
|
||||
return self.app_id
|
||||
|
||||
def get_apk_name(self):
|
||||
return self.apk_name
|
||||
|
||||
def get_package_name(self):
|
||||
return self.package_name
|
||||
|
||||
def get_version(self):
|
||||
return self.apk_version
|
||||
|
||||
def get_states(self):
|
||||
return self.states
|
||||
|
||||
def get_app_running_path(self):
|
||||
return self.app_running_path
|
||||
|
||||
def get_scenarios(self):
|
||||
return self.scenarios
|
||||
|
||||
|
||||
def __str__(self):
|
||||
st = ''
|
||||
for key in self.states:
|
||||
st += str(self.states[key])
|
||||
st += '\n'
|
||||
sc = ''
|
||||
for scene in self.scenarios:
|
||||
sc += str(scene)
|
||||
sc += '\n'
|
||||
return "[app_id:" + str(self.app_id) + " apk_name:" + str(self.apk_name) + " package_name:" + str(
|
||||
self.package_name) + " version:" + self.apk_version + " states:" + st + " appRunningPath:" + str(
|
||||
self.app_running_path) + " scenarios:" + sc + "]"
|
|
@ -0,0 +1,28 @@
|
|||
'''
|
||||
|
||||
按每个app为存储单元,把所有app按<app_id,app>键值对存入hashMap
|
||||
|
||||
author zhouxinyu
|
||||
|
||||
'''
|
||||
|
||||
|
||||
class AppDatabase:
|
||||
|
||||
def __init__(self):
|
||||
self.app_list = {}
|
||||
|
||||
def set_app_list(self, apps):
|
||||
if self.app_list == None:
|
||||
self.app_list = {}
|
||||
self.app_list.update(apps)
|
||||
|
||||
def get_app_list(self):
|
||||
return self.app_list
|
||||
|
||||
def __str__(self):
|
||||
re = ''
|
||||
for key in self.app_list:
|
||||
re += str(self.app_list[key])
|
||||
re += '\n'
|
||||
return re
|
|
@ -0,0 +1,31 @@
|
|||
'''
|
||||
|
||||
相应app中的所有Transition以<transition_id,transition_info>键值对存入hashMap
|
||||
|
||||
author zhouxinyu
|
||||
|
||||
'''
|
||||
|
||||
|
||||
class AppRunningPath:
|
||||
|
||||
def __init__(self, ts={}):
|
||||
self.transitions = {}
|
||||
self.transitions.update(ts)
|
||||
|
||||
def get_trans(self):
|
||||
return self.transitions
|
||||
|
||||
def get_state_related_transition(self, state_id):
|
||||
result = {}
|
||||
for key in self.transitions:
|
||||
if self.transitions[key].get_source_id() == state_id:
|
||||
result[key] = self.transitions[key]
|
||||
return result
|
||||
|
||||
def __str__(self):
|
||||
re = ''
|
||||
for key in self.transitions:
|
||||
re += str(self.transitions[key])
|
||||
re += '\n'
|
||||
return re
|
|
@ -0,0 +1,332 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding:utf-8 -*-
|
||||
# @Time : 2021/6/2 14:20 下午
|
||||
# @Author : Wang Zhixing,Wang Guoxin,Tang Jiaxin,Chen Wenjie
|
||||
# 1、创建Model
|
||||
# 2、保存Model到output文件夹中。
|
||||
# 3、保存Model到database中
|
||||
|
||||
import sys
|
||||
sys.path.append('..')
|
||||
from App import App
|
||||
from Transition import Transition
|
||||
import os
|
||||
from database.api import DBAction
|
||||
from State import State
|
||||
from util.read_file import *
|
||||
from Scenario import Scenario
|
||||
from Event import Event
|
||||
import pandas as pd
|
||||
import json
|
||||
import shutil
|
||||
|
||||
|
||||
class Model(App):
|
||||
def __init__(self):
|
||||
super(Model, self).__init__(id=-1, apk=None, pck=None, v=None)
|
||||
self.transitions = []
|
||||
self.state_list = []
|
||||
self.trans_df = None
|
||||
'''
|
||||
App类:
|
||||
app基础信息:
|
||||
app_id:app的id
|
||||
apk_name:app的安装包的名称
|
||||
package_name:app的包名
|
||||
apk_version:app的安装包的版本号
|
||||
app状态信息:
|
||||
states(dict):整个app所有的state_id到state的索引表
|
||||
元素类型:State
|
||||
scenarios:app的场景列表
|
||||
Model类:
|
||||
transitions(list):模型的跳转信息表
|
||||
元素类型:Transition
|
||||
state_list(list):模型涉及到的app的状态列表
|
||||
元素类型:State
|
||||
用于合并的数据结构:
|
||||
trans_df(DataFrame):存储source_id,target_id,trigger_action和trigger_identifier组合的表格
|
||||
app_running_path
|
||||
'''
|
||||
|
||||
def Build_Model_From_Project(self, project_path):
|
||||
# 从文件中读取Model
|
||||
apk_name, package_name, version, author_id = read_app_info(project_path) # 从文件中读取app信息
|
||||
self.apk_name = apk_name
|
||||
self.apk_version = version
|
||||
self.package_name = package_name
|
||||
states = read_state_info(project_path) # 读取模型涉及到的app状态列表
|
||||
for (state_id, activity_name, binary_data, layout) in states:
|
||||
state = State(self.app_id)
|
||||
state.set_state_id(int(state_id))
|
||||
state.set_activity_name(activity_name)
|
||||
state.set_picture(binary_data)
|
||||
state.set_layout(layout)
|
||||
# file_path = f"./Data/2021Se/screens/{state_id}.uix"
|
||||
# with open(file_path, 'w') as f: # 把layout写成uix文件
|
||||
# f.write(layout)
|
||||
# new_state.set_layout(file_path)
|
||||
self.state_list.append(state) # 存入state_list
|
||||
|
||||
transitions = read_transitions(project_path) # 读取模型的app跳转信息集合
|
||||
transition_id = 0
|
||||
for transition_info in transitions:
|
||||
if len(transition_info) == 3:
|
||||
source_state, target_state, trigger_action = int(transition_info[0]), int(transition_info[1]), \
|
||||
transition_info[2]
|
||||
transition = Transition(self.app_id)
|
||||
transition.set_source_id(self.state_list[source_state].state_id)
|
||||
transition.set_target_id(self.state_list[target_state].state_id)
|
||||
transition.set_transition_id(transition_id)
|
||||
event = Event(trigger_action, '', '')
|
||||
transition.set_event(event)
|
||||
self.transitions.append(transition) # 转换为Transition类型,并存入transitions
|
||||
else: # len(transition_info) == 4
|
||||
source_state, target_state, trigger_action, trigger_identifier = int(transition_info[0]), int(
|
||||
transition_info[1]), transition_info[2], transition_info[3]
|
||||
transition = Transition(self.app_id)
|
||||
transition.set_source_id(self.state_list[source_state].state_id)
|
||||
transition.set_target_id(self.state_list[target_state].state_id)
|
||||
transition.set_transition_id(transition_id)
|
||||
event = Event(trigger_action, trigger_identifier, '')
|
||||
transition.set_event(event)
|
||||
self.transitions.append(transition) # 转换为Transition类型,并存入transitions
|
||||
transition_id += 1
|
||||
|
||||
scenarios = read_scenarios_info(project_path)
|
||||
for scenario in scenarios:
|
||||
scenario_name = scenario[0]
|
||||
desc = scenario[1]
|
||||
path = scenario[2]
|
||||
new_scenarios = Scenario(self.app_id)
|
||||
new_scenarios.set_name(scenario_name)
|
||||
new_scenarios.set_des(desc)
|
||||
new_scenarios.set_path(path)
|
||||
self.scenarios.append(new_scenarios)
|
||||
|
||||
def Build_Model_From_Database(self, package_name):
|
||||
"""修改/增添了从数据库中读取Model的API"""
|
||||
|
||||
self.package_name = package_name
|
||||
db = DBAction()
|
||||
db.change_db("apprepo")
|
||||
|
||||
app_id = db.get_app_id(self.package_name)
|
||||
if app_id == -1:
|
||||
return
|
||||
|
||||
self.app_id = app_id # 将数据库的app_id传给本Model
|
||||
# apk_name, package_name, version, author_id = db.get_app_info(package_name) # 从数据库中读取app信息
|
||||
|
||||
app_info_list = db.get_app_info(package_name) # 从数据库中读取app信息
|
||||
self.apk_name = app_info_list[0][0]
|
||||
self.apk_version = app_info_list[0][2]
|
||||
self.package_name = app_info_list[0][1]
|
||||
author_id = app_info_list[0][3]
|
||||
|
||||
state_data = db.get_state_list_by_app_id(app_id) # 读取模型涉及到的app状态列表
|
||||
for data in state_data:
|
||||
state_id, activity_name, screen_shot, layout = data[0], data[1], data[2], data[3]
|
||||
new_state = State(self.app_id)
|
||||
new_state.set_state_id(int(state_id))
|
||||
new_state.set_activity_name(activity_name)
|
||||
new_state.set_picture(screen_shot)
|
||||
new_state.init_pic('./Data/2021Se/screens')
|
||||
new_state.set_layout(os.path.join('./Data/2021Se', 'screens', str(state_id) + '.uix'))
|
||||
# new_state.set_layout(os.path.join('..Data', 'screens', str(state_id) + '.uix')) # 不确定!
|
||||
self.state_list.append(new_state) # 转换为State类型,并存入state_list
|
||||
|
||||
transition_data = db.get_transition_by_app_id(app_id) # 读取模型的app跳转信息集合
|
||||
transition_id = 0
|
||||
for transition_info in transition_data:
|
||||
if len(transition_info) == 3:
|
||||
source_state, target_state, trigger_action = int(transition_info[0]), int(transition_info[1]), \
|
||||
transition_info[2]
|
||||
transition = Transition(self.app_id)
|
||||
transition.set_source_id(self.state_list[source_state].state_id)
|
||||
transition.set_target_id(self.state_list[target_state].state_id)
|
||||
transition.set_transition_id(transition_id)
|
||||
event = Event(trigger_action, '', '')
|
||||
transition.set_event(event)
|
||||
self.transitions.append(transition) # 转换为Transition类型,并存入transitions
|
||||
else: # len(transition_info) == 4
|
||||
source_state, target_state, trigger_action, trigger_identifier = int(transition_info[0]), int(
|
||||
transition_info[1]), transition_info[2], transition_info[3]
|
||||
transition = Transition(self.app_id)
|
||||
transition.set_source_id(self.state_list[source_state].state_id)
|
||||
transition.set_target_id(self.state_list[target_state].state_id)
|
||||
transition.set_transition_id(transition_id)
|
||||
event = Event(trigger_action, trigger_identifier, '')
|
||||
transition.set_event(event)
|
||||
self.transitions.append(transition) # 转换为Transition类型,并存入transitions
|
||||
transition_id += 1
|
||||
|
||||
scenarios_data = db.get_scenarios_by_app_id(app_id)
|
||||
|
||||
for scenario in scenarios_data:
|
||||
scenario_name = scenario[0]
|
||||
desc = scenario[1]
|
||||
path = scenario[2]
|
||||
new_scenarios = Scenario(self.app_id)
|
||||
new_scenarios.set_name(scenario_name)
|
||||
new_scenarios.set_des(desc)
|
||||
new_scenarios.set_path(path)
|
||||
self.scenarios.append(new_scenarios)
|
||||
|
||||
def Save_Model_To_Database(self):
|
||||
"""
|
||||
将内存中的Model保存到数据库
|
||||
"""
|
||||
print(self.app_id)
|
||||
db = DBAction()
|
||||
# app_id = db.get_app_id(self.package_name)
|
||||
|
||||
db.change_db("Mergeresult") #用于存储Model结果的数据库
|
||||
|
||||
db.insert_row_app_info(self.app_id,self.apk_name,self.package_name,self.version)
|
||||
for state in self.state_list:
|
||||
db.insert_row_state(self.app_id, state.state_id, state.activity_name, state.picture, state.layout)
|
||||
for transition in self.transitions:
|
||||
# db.insert_row_transition(self.app_id, transition.source_state, transition.target_state, transition.event.trigger_action, transition.event.trigger_identifier, transition.event.condition)
|
||||
#SOURCE_STATE / TARGET_STATE UNKNOWN
|
||||
db.insert_row_transition(self.app_id, -1, -1,
|
||||
transition.event.trigger_action, transition.event.trigger_identifier,
|
||||
transition.event.conditions)
|
||||
for scenario in self.scenarios:
|
||||
db.insert_row_scenarios(self.app_id, scenario.scenario_name, scenario.description, scenario.path)
|
||||
|
||||
def Save_Model_To_Local(self, out_dir):
|
||||
# 将内存中的Model保存到文件夹
|
||||
"""
|
||||
保存模型到文件
|
||||
:param out_dir: 目标文件夹
|
||||
"""
|
||||
if not os.path.exists(out_dir):
|
||||
os.mkdir(out_dir)
|
||||
out_path = out_dir + 'screens/' # out_path: res/screens
|
||||
if not os.path.exists(out_path):
|
||||
os.mkdir(out_path)
|
||||
for state in self.state_list:
|
||||
layout_file = os.path.join(out_path, str(state.state_id) + '.uix') # layout_file: res/screens/0.uix
|
||||
with open(layout_file, 'w') as f:
|
||||
f.write(state.layout)
|
||||
f.close()
|
||||
state.init_pic(out_path)
|
||||
|
||||
with open(out_dir + 'app_info.lst', 'w') as f:
|
||||
f.write(self.apk_name + '\n')
|
||||
f.write(self.package_name + '\n')
|
||||
f.write(self.apk_version + '\n')
|
||||
f.close()
|
||||
with open(out_dir + 'transitions.lst', 'w') as f:
|
||||
for transition in self.transitions:
|
||||
f.write(transition.get_line() + '\n')
|
||||
f.close()
|
||||
with open(out_dir + 'scenarios.lst', 'w') as f:
|
||||
for scenario in self.scenarios:
|
||||
f.write(str(scenario) + '\n')
|
||||
f.close()
|
||||
with open(out_dir + 'window_info.lst', 'w') as f:
|
||||
for state in self.state_list:
|
||||
f.write(str(state.state_id) + ' ' + state.get_activity_name() + '\n')
|
||||
f.close()
|
||||
|
||||
def Print_Model(self):
|
||||
# 打印出Model的内容
|
||||
print("============== %s ===============" % self.package_name)
|
||||
print('-------- state_info --------')
|
||||
for state in self.state_list:
|
||||
print(state.state_id, state.activity_name)
|
||||
print('------ transitions_info ------')
|
||||
for transition in self.transitions:
|
||||
print(transition.source_id, transition.target_id, transition.event.trigger_action,
|
||||
transition.event.trigger_identifier)
|
||||
print('------ scenarios_info ------')
|
||||
for scenario in self.scenarios:
|
||||
print(scenario.scenario_name, scenario.path)
|
||||
|
||||
def generate_json(self):
|
||||
# 将内存中的跳转数据转换为一个用dict表示的跳转表
|
||||
data = {}
|
||||
for transition in self.transitions:
|
||||
source_id = transition.get_source_id()
|
||||
target_id = transition.get_target_id()
|
||||
if source_id < target_id:
|
||||
if source_id not in data:
|
||||
data[source_id] = [target_id]
|
||||
elif target_id not in data[source_id]:
|
||||
data[source_id].append(target_id)
|
||||
return data
|
||||
|
||||
def generate_trans_df(self): # 生成包含跳转及对应事件的dataframe
|
||||
self.trans_df = pd.DataFrame(columns=('source_id', 'target_id', 'action', 'identifier'))
|
||||
for transition in self.transitions:
|
||||
t_dict = {'source_id': transition.get_source_id(),
|
||||
'target_id': transition.get_target_id(),
|
||||
'action': transition.get_event().get_trigger_action(),
|
||||
'identifier': transition.get_event().get_trigger_identifier()}
|
||||
self.trans_df = self.trans_df.append(t_dict, ignore_index=True)
|
||||
|
||||
def generate_ifml_json(self):
|
||||
gap = 40
|
||||
elements = []
|
||||
data = []
|
||||
self.genarate_element(0, data, elements)
|
||||
|
||||
def create_element(self, id, type, x, y, width, heigth):
|
||||
element = {"id": id,
|
||||
"type": type,
|
||||
"attributes": {
|
||||
"name": id,
|
||||
"default": False,
|
||||
"landmark": False,
|
||||
"xor": False
|
||||
},
|
||||
"metadata": {
|
||||
"graphics": {
|
||||
"position": {
|
||||
"x": x,
|
||||
"y": y
|
||||
},
|
||||
"size": {
|
||||
"width": width,
|
||||
"height": heigth
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return element
|
||||
|
||||
def generate_element(self, root, data, elements):
|
||||
if root not in data:
|
||||
element = {"id": root,
|
||||
"type": "ifml.ViewContainer",
|
||||
"attributes": {
|
||||
"name": root,
|
||||
"default": False,
|
||||
"landmark": False,
|
||||
"xor": False
|
||||
},
|
||||
"metadata": {
|
||||
"graphics": {
|
||||
"position": {
|
||||
"x": 40,
|
||||
"y": 100
|
||||
},
|
||||
"size": {
|
||||
"width": 180,
|
||||
"height": 100
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return {"id": root}
|
||||
children = []
|
||||
|
||||
def tree_to_dict(self, root, data):
|
||||
if root not in data:
|
||||
return {"id": root}
|
||||
children = []
|
||||
for state_id in data[root]:
|
||||
child = self.tree_to_dict(state_id, data)
|
||||
children.append(child)
|
||||
return {"id": root, "children": children}
|
|
@ -0,0 +1,37 @@
|
|||
'''
|
||||
|
||||
将transition中的Event单独成类。
|
||||
与数据库transition表的对应关系:
|
||||
triggerAction->trigger_action
|
||||
triggerIdentifier->trigger_identifier
|
||||
conditions->conditions
|
||||
|
||||
@author zhouxinyu
|
||||
|
||||
'''
|
||||
|
||||
|
||||
class Event:
|
||||
|
||||
def __init__(self, ta, ti, con):
|
||||
self.trigger_action = ta
|
||||
self.trigger_identifier = ti
|
||||
self.conditions = con
|
||||
|
||||
def get_trigger_action(self):
|
||||
return self.trigger_action
|
||||
|
||||
def set_trigger_action(self, ta):
|
||||
self.trigger_action = ta
|
||||
|
||||
def get_trigger_identifier(self):
|
||||
return self.trigger_identifier
|
||||
|
||||
def set_trigger_identifier(self, ti):
|
||||
self.trigger_identifier = ti
|
||||
|
||||
def get_conditions(self):
|
||||
return self.conditions
|
||||
|
||||
def set_conditions(self, con):
|
||||
self.conditions = con
|
|
@ -0,0 +1,58 @@
|
|||
'''
|
||||
|
||||
场景类,与数据库scenarios表项对应关系:
|
||||
appId->app_id
|
||||
scenarioName->scenario_name
|
||||
description->description
|
||||
path->path
|
||||
|
||||
author zhouxinyu
|
||||
|
||||
'''
|
||||
|
||||
import os
|
||||
|
||||
|
||||
# Todo 将以下代码Scenario1改写到Scenario中
|
||||
#我们模型合并用的是Scenario1代码,我们修改他。整合到标准呢的Scenario中。
|
||||
'''
|
||||
class Scenario1(object):
|
||||
def __init__(self, scenario_name, description, path):
|
||||
self.scenario_name = scenario_name
|
||||
self.description = description
|
||||
self.path = path.split('-')
|
||||
self.state_list = set(self.path)
|
||||
|
||||
def get_line(self):
|
||||
return '[%s] [%s] [%s]' % (self.scenario_name, self.description, '-'.join(self.path))
|
||||
'''
|
||||
|
||||
class Scenario:
|
||||
|
||||
def __init__(self, id=-1):
|
||||
self.app_id = id
|
||||
self.scenario_name = None
|
||||
self.description = None
|
||||
self.path = None
|
||||
|
||||
def set_name(self, n):
|
||||
self.scenario_name = n
|
||||
|
||||
def set_des(self, d):
|
||||
self.description = d
|
||||
|
||||
def set_path(self, p):
|
||||
self.path = p
|
||||
|
||||
def get_name(self):
|
||||
return self.scenario_name
|
||||
|
||||
def get_des(self):
|
||||
return self.description
|
||||
|
||||
def get_path(self):
|
||||
return self.path
|
||||
|
||||
def __str__(self):
|
||||
return "[app_id:" + str(self.app_id) + " scenario_name:" + str(self.scenario_name) + " description:" + str(
|
||||
self.description) + " path:" + str(self.path) + "]"
|
|
@ -0,0 +1,80 @@
|
|||
'''
|
||||
|
||||
状态类,与数据库state表对应关系:
|
||||
appId->app_id
|
||||
stateId->state_id
|
||||
activityName->activity_name
|
||||
picture->screen_shot
|
||||
layout->layout
|
||||
|
||||
由于picture存储为blob 二进制流,通过base64进行编码,因此需要用decoder进行解码,decoder即为此解码对象
|
||||
|
||||
|
||||
author zhouxinyu
|
||||
|
||||
'''
|
||||
|
||||
import base64
|
||||
import os
|
||||
from os import path
|
||||
|
||||
|
||||
class State:
|
||||
|
||||
def __init__(self, id=-1):
|
||||
self.app_id = id
|
||||
self.state_id = -1
|
||||
self.activity_name = None
|
||||
self.picture = None
|
||||
self.layout = None
|
||||
|
||||
def set_state_id(self, id):
|
||||
self.state_id = id
|
||||
|
||||
def set_activity_name(self, ac):
|
||||
self.activity_name = ac
|
||||
|
||||
def set_picture(self, ifstream):
|
||||
self.picture = ifstream
|
||||
|
||||
def set_layout(self, l):
|
||||
self.layout = l
|
||||
|
||||
def get_state_id(self):
|
||||
return self.state_id
|
||||
|
||||
def get_activity_name(self):
|
||||
return self.activity_name
|
||||
|
||||
def get_picture(self):
|
||||
return self.picture
|
||||
|
||||
def get_layout(self):
|
||||
return self.layout
|
||||
|
||||
# initPic()将数据转换为图片文件并保存
|
||||
def init_pic(self, out_path=None):
|
||||
b = base64.b64decode(self.picture)
|
||||
try:
|
||||
if out_path is None:
|
||||
'''pic_file = open('..\\..\\out\\' + str(self.state_id) + '.png','wb')
|
||||
pic_file.write(b)'''
|
||||
# 其他位置调用该模块时,../../out/寻址有问题
|
||||
# 修改为使用os.path寻址的方法
|
||||
curpath = path.dirname(__file__)
|
||||
parent_path = os.path.dirname(curpath)
|
||||
# papa_path = os.path.dirname(parent_path)
|
||||
# papa_path = os.path.dirname(papa_path)
|
||||
# papa_path = os.path.dirname(papa_path)
|
||||
# out_path = papa_path + "\\out\\"
|
||||
out_path = parent_path + "/out/"
|
||||
if not os.path.exists(out_path):
|
||||
os.makedirs(out_path)
|
||||
pic_file = open(out_path + str(self.state_id) + '.png', 'wb')
|
||||
pic_file.write(b)
|
||||
finally:
|
||||
pic_file.close()
|
||||
|
||||
def __str__(self):
|
||||
return "[app_id:" + str(self.app_id) + " state_id:" + str(self.state_id) + " activity_name:" + str(
|
||||
self.activity_name) + " layout:" + str(self.layout) + "]"
|
|
@ -0,0 +1,71 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2021/5/12 0:50 下午
|
||||
# @Author : Chen Wenjie
|
||||
|
||||
# 1. 新增get_line()类方法,用于bulid_model.py中save_model()函数调用。
|
||||
# 2. 修改__str__ ,与transition类最新数据成员适配。
|
||||
|
||||
'''
|
||||
|
||||
迁移类,与数据库transition表的对应关系:
|
||||
appId->app_id
|
||||
transitionId->transition_id
|
||||
sourceId->source_id
|
||||
targetId->target_id
|
||||
triggerAction->trigger_action
|
||||
triggerIdentifier->trigger_identifier
|
||||
condition->conditions
|
||||
|
||||
author zhouxinyu
|
||||
|
||||
'''
|
||||
|
||||
from Model.Event import Event
|
||||
|
||||
|
||||
class Transition:
|
||||
|
||||
def __init__(self, id=-1):
|
||||
self.transition_id = -1
|
||||
self.app_id = id
|
||||
self.source_id = -1
|
||||
self.target_id = -1
|
||||
self.event = None
|
||||
|
||||
def set_transition_id(self, id):
|
||||
self.transition_id = id
|
||||
|
||||
def set_source_id(self, id):
|
||||
self.source_id = id
|
||||
|
||||
def set_target_id(self, id):
|
||||
self.target_id = id
|
||||
|
||||
def set_event(self, eve):
|
||||
self.event = eve
|
||||
|
||||
def get_transition_id(self):
|
||||
return self.transition_id
|
||||
|
||||
def get_source_id(self):
|
||||
return self.source_id
|
||||
|
||||
def get_target_id(self):
|
||||
return self.target_id
|
||||
|
||||
def get_event(self):
|
||||
return self.event
|
||||
|
||||
def get_line(self):
|
||||
|
||||
if self.event.trigger_identifier != "":
|
||||
return str(self.get_source_id()) + ' ' + str(self.get_target_id()) + ' ' + self.event.trigger_action + ' ' + self.event.trigger_identifier
|
||||
else:
|
||||
return str(self.get_source_id()) + ' ' + str(self.get_target_id()) + ' ' + self.event.trigger_action
|
||||
|
||||
def __str__(self):
|
||||
return "[transition_id:" + str(self.transition_id) + " app_id:" + str(self.app_id) + " source->target:" + str(
|
||||
self.source_id) + "->" + str(self.target_id) + " trigger_action:" + str(
|
||||
self.event.get_trigger_action()) + " trigger_identifier:" + str(
|
||||
self.event.get_trigger_identifier()) + " conditions:" + str(self.event.get_conditions()) + "]"
|
|
@ -0,0 +1,237 @@
|
|||
# -*- encoding:utf-8 -*-
|
||||
#!/usr/bin/env python
|
||||
# @Time : 2021/7/11 0:50 上午
|
||||
# @Author : Chen Wenjie
|
||||
|
||||
# 1. 以页面为节点,页面之间的联系方式为边,定义图类
|
||||
# 2. 基于界面关系图进行可视化,并生成circle与force两种不同类型的关系图
|
||||
|
||||
from collections import defaultdict
|
||||
import json
|
||||
import os
|
||||
from pyecharts import options as opts
|
||||
from pyecharts.charts import Graph, Page
|
||||
import pyecharts.charts
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import random
|
||||
|
||||
# --------------- nested Vertex class ------------------
|
||||
|
||||
class Vertex:
|
||||
"""创建节点类"""
|
||||
|
||||
def __init__(self, x, times):
|
||||
"""初始化节点,x为节点的value, times为节点出现的频次"""
|
||||
vertex = {}
|
||||
self.element = x
|
||||
self.times = times
|
||||
try:
|
||||
vertex["name"] = x
|
||||
if times < 5:
|
||||
vertex["symbolSize"] = 15
|
||||
vertex["category"] = 2
|
||||
color = "#FF0000"
|
||||
elif times <= 15:
|
||||
vertex["symbolSize"] = 35
|
||||
vertex["category"] = 1
|
||||
color = "#3CB371"
|
||||
else:
|
||||
vertex["symbolSize"] = 50
|
||||
vertex["category"] = 0
|
||||
color = "#9400D3"
|
||||
except:
|
||||
vertex["symbolSize"] = 10
|
||||
vertex["category"] = 3
|
||||
color = "#00BFFF"
|
||||
try:
|
||||
vertex["value"] = "连接页面数:" + str(times)
|
||||
|
||||
except:
|
||||
vertex["value"] = "连接页面数:0"
|
||||
vertex['draggable'] = "True"
|
||||
# vertex["itemStyle"] = {"normal":{"color":color}}
|
||||
self.vertex = vertex
|
||||
|
||||
def element(self):
|
||||
"""返回节点的元素值"""
|
||||
return self.element
|
||||
|
||||
def vertex(self):
|
||||
"""返回节点"""
|
||||
return self.vertex
|
||||
|
||||
def __hash__(self):
|
||||
"""允许节点作为映射的键"""
|
||||
return hash(id(self))
|
||||
|
||||
|
||||
class Edge:
|
||||
"""创建边类"""
|
||||
|
||||
def __init__(self, u, v, x):
|
||||
"""初始化边"""
|
||||
self.origin = u
|
||||
self.destination = v
|
||||
self.element = x
|
||||
|
||||
def endpoints(self):
|
||||
"""以元组的方式返回边的两个端点(u,v)"""
|
||||
return (self.origin, self.destination)
|
||||
|
||||
def opposite(self, v):
|
||||
"""假设顶点v是边的一个端点,返回另一个端点"""
|
||||
return self.destination if v is self.origin else self.origin
|
||||
|
||||
def element(self):
|
||||
return self.element
|
||||
|
||||
def __hash__(self):
|
||||
"""实现边的映射"""
|
||||
return hash(self.origin, self.destination)
|
||||
|
||||
|
||||
class Graph:
|
||||
"""图类"""
|
||||
|
||||
def __init__(self, vertex_count=0, directed=False):
|
||||
"""首先创建个空图,默认为undirected"""
|
||||
self.vertices = [] # 这里存储了图的节点
|
||||
self.vertex_count = vertex_count # 这里存储了图的节点数
|
||||
self.adjacency_matrix = defaultdict(list) # 这里存储了图的边(字典)
|
||||
self.edges = [] # 这里存储了图的边(列表,节点的连接关系)
|
||||
self.links = [] # 这里存储了图的边(列表,用于绘制关系图)
|
||||
|
||||
def read_edge(self, res):
|
||||
"""从res模型中读取所有的页面连接信息"""
|
||||
# 三元组的形式从模型中读取节点跳转信息
|
||||
edges = []
|
||||
for i in range(len(res.transitions)):
|
||||
edges.append(
|
||||
tuple((res.transitions[i].get_source_id(),
|
||||
res.transitions[i].get_target_id(),
|
||||
res.transitions[i].get_event().get_trigger_action())
|
||||
))
|
||||
|
||||
# 将读取的边附给图类的edges
|
||||
self.edges = edges
|
||||
|
||||
def insert_edge(self):
|
||||
"""用加边的方式添加图的节点"""
|
||||
for i in range(len(self.edges)):
|
||||
u = self.edges[i][0]
|
||||
v = self.edges[i][1]
|
||||
self.adjacency_matrix[u].append(v)
|
||||
|
||||
def insert_vertex(self):
|
||||
"""插入节点"""
|
||||
# 获取最后一个页面的编号
|
||||
max = 0
|
||||
for i in range(len(self.edges)):
|
||||
if self.edges[i][0] > max:
|
||||
max = self.edges[i][0]
|
||||
if self.edges[i][1] > max:
|
||||
max = self.edges[i][1]
|
||||
|
||||
# 测算每个节点所连通的节点数
|
||||
aDict = {}
|
||||
for i in range(len(self.edges)):
|
||||
aDict[self.edges[i][0]] = aDict.get(self.edges[i][0], 0) + 1
|
||||
|
||||
print("max:"+str(max))
|
||||
# 生成系列节点
|
||||
for i in range(1, max + 1):
|
||||
try:
|
||||
v = Vertex(i, aDict[i])
|
||||
except:
|
||||
v = Vertex(i, 0)
|
||||
self.vertices.append(v.vertex)
|
||||
self.vertex_count += 1
|
||||
|
||||
def add_links(self):
|
||||
"""插入节点连接,用于生成关系图"""
|
||||
for i in range(len(self.edges)):
|
||||
self.links.append(
|
||||
{
|
||||
"source": self.edges[i][0],
|
||||
"target": self.edges[i][1],
|
||||
"value": self.edges[i][2]
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def generate_graph(self, res):
|
||||
"""总调函数,传入合并后的模型,生成图"""
|
||||
self.read_edge(res)
|
||||
self.insert_vertex()
|
||||
self.insert_edge()
|
||||
self.add_links()
|
||||
|
||||
def visualization(self):
|
||||
"""关系图的可视化"""
|
||||
categories = [
|
||||
{
|
||||
"name": "重要节点"
|
||||
},
|
||||
{
|
||||
"name": "次重要节点"
|
||||
},
|
||||
{
|
||||
"name": "一般节点"
|
||||
},
|
||||
{
|
||||
"name": "孤立节点"
|
||||
}
|
||||
]
|
||||
|
||||
# circular layout
|
||||
graph = (
|
||||
pyecharts.charts.Graph(init_opts=opts.InitOpts(width="1000px", height="800px"))
|
||||
.add("",
|
||||
self.vertices,
|
||||
self.links,
|
||||
categories=categories,
|
||||
repulsion=50,
|
||||
|
||||
linestyle_opts=opts.LineStyleOpts(curve=0.2),
|
||||
is_rotate_label=True,
|
||||
layout="circular",
|
||||
label_opts=opts.LabelOpts(position="right"),
|
||||
edge_label=opts.LabelOpts(
|
||||
is_show=False, position="middle", formatter="{b} 的数据 {c}"
|
||||
)
|
||||
)
|
||||
.set_global_opts(
|
||||
title_opts=opts.TitleOpts(title="ARP路径关系图"),
|
||||
legend_opts=opts.LegendOpts(orient="vertical", pos_left="2%", pos_top="20%"
|
||||
)
|
||||
)
|
||||
)
|
||||
graph.render("circle_layout_graph.html")
|
||||
|
||||
# force layout
|
||||
graph = (
|
||||
pyecharts.charts.Graph(init_opts=opts.InitOpts(width="960px", height="800px"))
|
||||
.add("",
|
||||
self.vertices,
|
||||
self.links,
|
||||
categories=categories,
|
||||
repulsion=50,
|
||||
edge_length=100,
|
||||
gravity=0.05,
|
||||
# linestyle_opts=opts.LineStyleOpts(curve=0.2),
|
||||
is_rotate_label=True,
|
||||
layout="force",
|
||||
label_opts=opts.LabelOpts(position="right"),
|
||||
edge_label=opts.LabelOpts(
|
||||
is_show=False, position="middle", formatter="{b} 的数据 {c}"
|
||||
)
|
||||
)
|
||||
.set_global_opts(
|
||||
title_opts=opts.TitleOpts(title="ARP路径关系图"),
|
||||
legend_opts=opts.LegendOpts(orient="vertical", pos_left="2%", pos_top="20%"
|
||||
)
|
||||
)
|
||||
)
|
||||
graph.render("force_layout_graph.html")
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
# SE2021-APP-Model-Merge
|
||||
|
||||
#### Description
|
||||
对同一个App不同的ARP模型进行合并,支持对人工标注的泛化(或传播),在此基础上可以进行基于GNN的自动标注
|
||||
|
||||
#### Software Architecture
|
||||
Software architecture description
|
||||
|
||||
#### Installation
|
||||
|
||||
1. xxxx
|
||||
2. xxxx
|
||||
3. xxxx
|
||||
|
||||
#### Instructions
|
||||
|
||||
1. xxxx
|
||||
2. xxxx
|
||||
3. xxxx
|
||||
|
||||
#### Contribution
|
||||
|
||||
1. Fork the repository
|
||||
2. Create Feat_xxx branch
|
||||
3. Commit your code
|
||||
4. Create Pull Request
|
||||
|
||||
|
||||
#### Gitee Feature
|
||||
|
||||
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
|
||||
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
|
||||
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
|
||||
4. The most valuable open source project [GVP](https://gitee.com/gvp)
|
||||
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
|
||||
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
|
|
@ -0,0 +1,49 @@
|
|||
# 模型合并
|
||||
|
||||
# 注意:在修改实验代码时,一定要先将网站上的版本下载下来,再在下载的版本的基础上修改!
|
||||
|
||||
## 一、介绍
|
||||
对同一个App不同的ARP模型进行合并,支持对人工标注的泛化(或传播),
|
||||
|
||||
在此基础上可以进行基于GNN的自动标注
|
||||
|
||||
## 二、软件架构
|
||||
|
||||
### 2.1、数据库架构
|
||||
mysql
|
||||
|
||||
### 2.2、软件体系
|
||||
- python
|
||||
- python3
|
||||
- flask
|
||||
- uwsgi
|
||||
- react
|
||||
- ubuntu
|
||||
|
||||
## 三、安装教程
|
||||
|
||||
## 四、使用要求
|
||||
|
||||
## 五、参与贡献
|
||||
|
||||
1. Fork 本仓库
|
||||
2. 新建 Feat_xxx 分支
|
||||
3. 提交代码
|
||||
4. 新建 Pull Request
|
||||
|
||||
## 六、当前进度
|
||||
|
||||
更新时间:7.14
|
||||
|
||||
已完成:
|
||||
- 从文件中读取模型数据
|
||||
- 从数据库中读取模型数据
|
||||
- 模型合并操作
|
||||
- 服务器搭建
|
||||
- 将代码部署在服务器上
|
||||
- 界面和服务器
|
||||
- 前后端交互
|
||||
- 后端与数据库连接
|
||||
|
||||
待完成:
|
||||
- 使用react重构前端代码
|
|
@ -0,0 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2020/11/4 6:38 下午
|
||||
# @Author : Wang Guoxin
|
|
@ -0,0 +1,284 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2021/6/3 12:40 下午
|
||||
# @Author : Wang Guoxin,Chen Wenjie, Tang Jiaxin
|
||||
|
||||
# 新增读取并执行sql文件的类方法exe_sql(),便于后续直接通过python配置mysql数据库
|
||||
import crypt
|
||||
import re
|
||||
import mysql.connector
|
||||
from pymysql.converters import escape_string
|
||||
'''
|
||||
对数据库进行增删改查
|
||||
'''
|
||||
|
||||
class DBAction(object):
|
||||
#Todo 建议将数据库配置信息配置在yaml文件中。
|
||||
def __init__(self):
|
||||
self.db = mysql.connector.connect(
|
||||
host="localhost",
|
||||
user="root",
|
||||
passwd="wjj",
|
||||
database="apprepo"
|
||||
)
|
||||
print("successfully connected!")
|
||||
|
||||
def close(self):
|
||||
self.db.close()
|
||||
|
||||
def change_db(self,db_name):
|
||||
"""更换数据库"""
|
||||
cursor = self.db.cursor()
|
||||
sql = "use {0}".format(db_name)
|
||||
cursor.execute(sql)
|
||||
cursor.close()
|
||||
self.db.commit()
|
||||
|
||||
def exe_sql(self,path):
|
||||
"""传入本地sql文件path,并执行"""
|
||||
cursor = self.db.cursor()
|
||||
try:
|
||||
with open(path, encoding='utf-8', mode='r') as f:
|
||||
# 读取整个sql文件,以分号切割。[:-1]删除最后一个元素,也就是空字符串
|
||||
sql_list = f.read().split(';')[:-1]
|
||||
for x in sql_list:
|
||||
# 判断包含空行的
|
||||
if '\n' in x:
|
||||
# 替换空行为1个空格
|
||||
x = x.replace('\n', ' ')
|
||||
|
||||
# 判断多个空格时
|
||||
if ' ' in x:
|
||||
# 替换为空
|
||||
x = x.replace(' ', '')
|
||||
|
||||
# sql语句添加分号结尾
|
||||
sql_item = x + ';'
|
||||
# print(sql_item)
|
||||
cursor.execute(sql_item)
|
||||
print("执行成功sql: %s" % sql_item)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print('执行失败sql: %s' % sql_item)
|
||||
|
||||
finally:
|
||||
# 关闭mysql连接
|
||||
cursor.close()
|
||||
self.db.commit()
|
||||
|
||||
def insert_row_app_info(self,app_id, apk_name, package_name, version):
|
||||
cursor = self.db.cursor()
|
||||
sql = "INSERT INTO app_info (app_id, apk_name, package_name, version) VALUES (%s, %s, %s, %s)"
|
||||
cursor.execute(sql, (app_id,apk_name, package_name, version))
|
||||
cursor.close()
|
||||
self.db.commit()
|
||||
|
||||
def insert_row_state(self, app_id, state_id, activity_name, screen_shot, layout):
|
||||
cursor = self.db.cursor()
|
||||
sql = "INSERT INTO state (app_id, state_id, activity_name, screen_shot, layout) VALUES (%s, %s, %s, %s, %s)"
|
||||
cursor.execute(sql, (app_id, state_id, activity_name, screen_shot, layout))
|
||||
cursor.close()
|
||||
self.db.commit()
|
||||
|
||||
def insert_row_transition(self, app_id, source_state, target_state, trigger_action, trigger_identifier, condition):
|
||||
cursor = self.db.cursor()
|
||||
sql = "INSERT INTO transition (app_id, source_state, target_state, trigger_action, trigger_identifier, conditions) VALUES (%s, %s, %s, %s, %s, %s)"
|
||||
cursor.execute(sql, (app_id, source_state, target_state, trigger_action, trigger_identifier, condition))
|
||||
cursor.close()
|
||||
self.db.commit()
|
||||
|
||||
def insert_row_scenarios(self, app_id, scenario_name, description, path):
|
||||
cursor = self.db.cursor()
|
||||
sql = "INSERT INTO scenarios (app_id, scenario_name, description, path) VALUES (%s, %s, %s, %s)"
|
||||
cursor.execute(sql, (app_id, scenario_name, description, path))
|
||||
cursor.close()
|
||||
self.db.commit()
|
||||
|
||||
def get_all_app_package_name(self):
|
||||
cursor = self.db.cursor()
|
||||
query = "SELECT package_name FROM app_info"
|
||||
cursor.execute(query)
|
||||
rows = list(cursor)
|
||||
package_name_list = []
|
||||
for row in rows:
|
||||
package_name_list.append(row[0])
|
||||
return package_name_list
|
||||
|
||||
def get_app_id(self, package_name):
|
||||
cursor = self.db.cursor()
|
||||
query = "SELECT app_id FROM app_info WHERE package_name = %s"
|
||||
cursor.execute(query, (package_name,))
|
||||
rows = list(cursor)
|
||||
found_app_id = -1
|
||||
if len(rows) == 1:
|
||||
(found_app_id,) = rows[0]
|
||||
elif len(rows) > 1:
|
||||
print('ERROR: Multiple records.')
|
||||
else:
|
||||
print('ERROR: No matched record.')
|
||||
cursor.close()
|
||||
return found_app_id
|
||||
|
||||
def get_app_info(self, package_name):
|
||||
"""根据安装包名,读取app_info表,返回info表的所有APP信息,进行初始化"""
|
||||
cursor = self.db.cursor()
|
||||
query = "SELECT apk_name, package_name, version, author FROM app_info WHERE package_name = %s"
|
||||
cursor.execute(query, (package_name,))
|
||||
#获取所有记录表
|
||||
app_info_lst = cursor.fetchall()
|
||||
# for row in results:
|
||||
# apk_name = row[0]
|
||||
# package_name = row[1]
|
||||
# version = row[2]
|
||||
# author_id = row[3]
|
||||
# app_info_lst = [apk_name,package_name,version,author_id]
|
||||
cursor.close()
|
||||
return app_info_lst
|
||||
|
||||
def get_state_by_id(self, state_id):
|
||||
cursor = self.db.cursor()
|
||||
query = "SELECT screen_shot, layout FROM state WHERE state_id = %s"
|
||||
cursor.execute(query, (state_id,))
|
||||
data = cursor.fetchall()
|
||||
return data[0][0], data[0][1]
|
||||
|
||||
def get_state_list_by_app_id(self, app_id):
|
||||
cursor = self.db.cursor()
|
||||
query = "SELECT state_id, activity_name, screen_shot, layout FROM state WHERE app_id = %s"
|
||||
cursor.execute(query, (app_id,))
|
||||
data = cursor.fetchall()
|
||||
return data
|
||||
|
||||
def get_transition_by_app_id(self, app_id):
|
||||
cursor = self.db.cursor()
|
||||
query = "SELECT source_state, target_state, trigger_action, trigger_identifier, conditions FROM transition WHERE app_id = %s"
|
||||
cursor.execute(query, (app_id,))
|
||||
data = cursor.fetchall()
|
||||
return data
|
||||
|
||||
def get_scenarios_by_app_id(self, app_id):
|
||||
cursor = self.db.cursor()
|
||||
query = "SELECT scenario_name, description, path FROM scenarios WHERE app_id = %s"
|
||||
cursor.execute(query, (app_id,))
|
||||
data = cursor.fetchall()
|
||||
return data
|
||||
|
||||
def create_user(self,uid,uname,upassword):
|
||||
"""存储用户信息"""
|
||||
self.db.change_db('users')
|
||||
cursor = self.db.cursor()
|
||||
sql = "INSERT INTO user_info (uid, name, password) VALUES (%s, %s, %s)"
|
||||
cursor.execute(sql, (uid, uname, upassword))
|
||||
cursor.close()
|
||||
self.db.commit()
|
||||
|
||||
def create_email(self,uid,email):
|
||||
"""存入邮箱"""
|
||||
self.db.change_db('users')
|
||||
cursor = self.db.cursor()
|
||||
query = "INSERT INTO user_email (uid, email) VALUES (%s, %s)"
|
||||
cursor.execute(query, (uid, email,))
|
||||
cursor.close()
|
||||
self.db.commit()
|
||||
|
||||
def register_check(self,uname):
|
||||
"""用户注册时检查数据库中是否已存在该用户名,若是则返回失败"""
|
||||
self.db.change_db('users')
|
||||
cursor = self.db.cursor()
|
||||
query = "SELECT * FROM user_info WHERE name = %s"
|
||||
cursor.execute(query, (uname,))
|
||||
result = cursor.fetchall()
|
||||
if result:
|
||||
return False #查询到存在同名name,说明注册冲突,返回False
|
||||
else:
|
||||
return True #查询到未有同名name,说明可以注册,返回True
|
||||
|
||||
def check_email_uid(self,uid):
|
||||
"""使用uid验证邮箱表中是否已存用户邮箱"""
|
||||
self.db.change_db('users')
|
||||
cursor = self.db.cursor()
|
||||
query = "SELECT * FROM user_email WHERE uid = %s"
|
||||
cursor.execute(query, (uid,))
|
||||
result = cursor.fetchall()[0]
|
||||
return result
|
||||
|
||||
def check_email_email(self, email):
|
||||
"""使用email验证邮箱表中是否已存用户邮箱"""
|
||||
self.db.change_db('users')
|
||||
cursor = self.db.cursor()
|
||||
query = "SELECT * FROM user_email WHERE email = %s"
|
||||
cursor.execute(query, (email,))
|
||||
result = cursor.fetchall()[0]
|
||||
return result
|
||||
|
||||
def get_uid(self):
|
||||
"""获取用户表中的最大uid"""
|
||||
self.db.change_db('users')
|
||||
cursor = self.db.cursor()
|
||||
query = "SELECT MAX(uid) FROM user_info"
|
||||
cursor.execute(query,)
|
||||
maxuid = cursor.fetchall()[0]
|
||||
if maxuid:
|
||||
return maxuid + 1
|
||||
else:
|
||||
return 1
|
||||
|
||||
def get_name_uid(self,uname):
|
||||
"""获取用户名对应的uid"""
|
||||
self.db.change_db('users')
|
||||
cursor = self.db.cursor()
|
||||
query = "SELECT uid FROM user_info WHERE name = %s"
|
||||
cursor.execute(query, (uname,))
|
||||
uid = cursor.fetchall()[0]
|
||||
return uid
|
||||
|
||||
def login_check(self,uname,upassword):
|
||||
"""根据用户表单提交的用户名与用户密码,进行登录核验"""
|
||||
self.db.change_db('users')
|
||||
cursor = self.db.cursor()
|
||||
query = "SELECT password FROM user_info WHERE name = %s"
|
||||
cursor.execute(query, (uname,))
|
||||
password = cursor.fetchall()[0]
|
||||
if upassword == password:
|
||||
#("welcome {0} !".format(uname))
|
||||
return True
|
||||
else:
|
||||
#print("password wrong!")
|
||||
return False
|
||||
|
||||
def upload_data(self,uid,app_name,time,file_path):
|
||||
"""向文件数据库中添加记录,字段为用户ID、文件路径"""
|
||||
self.db.change_db('users')
|
||||
cursor = self.db.cursor()
|
||||
query = "INSERT INTO data_info(uid,app_name,time,file_path) values(%s,%s,%s,%s)"
|
||||
cursor.execute(query, (uid, app_name, time, file_path,))
|
||||
cursor.close()
|
||||
|
||||
def delete_data(self,uid,file_path):
|
||||
"""从文件数据库中删除记录,依据为用户ID和文件路径"""
|
||||
self.db.change_db('users')
|
||||
cursor = self.db.cursor()
|
||||
query = "DELETE FROM data_info where uid= %s AND file_path= %s"
|
||||
cursor.execute(query, (uid, file_path,))
|
||||
cursor.close()
|
||||
|
||||
def select_data(self,uid):
|
||||
"""从文件数据库中查找记录,依据为用户ID"""
|
||||
self.db.change_db('users')
|
||||
cursor = self.db.cursor()
|
||||
query = "SELECT * FROM data_info where uid= %s"
|
||||
cursor.execute(query, (uid,))
|
||||
result = cursor.fetchall() # 它的返回值是多个元组,即返回多个行记录
|
||||
cursor.close()
|
||||
di = {}
|
||||
for uid,app_name,time,file_path in result:
|
||||
di[file_path] = [time, app_name]
|
||||
return di
|
||||
|
||||
'''
|
||||
测试
|
||||
if __name__ == "__main__":
|
||||
db = DBAction()
|
||||
print(db.get_app_id("com.forrestguice.suntimeswidget"))
|
||||
|
||||
'''
|
|
@ -0,0 +1,69 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2021/5/24 0:50 下午
|
||||
# @Author : Chen Wenjie
|
||||
|
||||
'''
|
||||
用于初始化构建本地/云数据库
|
||||
新增了对用户数据库(内含用户信息表、数据存储表)的初始化与交互
|
||||
'''
|
||||
|
||||
import mysql.connector
|
||||
from api import DBAction
|
||||
import api
|
||||
|
||||
def sourceData(source_sql_file_path):
|
||||
"""从sql文件中读取数据并存入本地数据库"""
|
||||
db_name = input("select a database to exe data insert:") #输入要使用的数据库名
|
||||
db = DBAction()
|
||||
db.change_db(db_name)
|
||||
db.exe_sql(source_sql_file_path)
|
||||
|
||||
def initDatabase(init_sql_file_path):
|
||||
"""初始化database"""
|
||||
db = DBAction()
|
||||
db.exe_sql(init_sql_file_path)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
# 1.初始化原始数据库
|
||||
# print("__init_database__")
|
||||
# init_sql_path = "./sql/init_apprepo.sql"
|
||||
# initDatabase(init_sql_path)
|
||||
|
||||
# 2.初始化模型合并结果数据库
|
||||
# print("__init_database__")
|
||||
# init_sql_path = "./sql/init_merge.sql"
|
||||
# initDatabase(init_sql_path)
|
||||
|
||||
|
||||
# 3.读取本地数据
|
||||
# print("__source_data__")
|
||||
# source_sql_path = r'./sql/File_Manager_Pro_0.5_2021-02-09.sql'
|
||||
# sourceData(source_sql_path)
|
||||
|
||||
# 4.初始化用户数据库
|
||||
print("_init_database_users")
|
||||
initDatabase('./sql/init_users.sql')
|
||||
# pass
|
||||
|
||||
# 5.尝试插入用户登录数据
|
||||
uname = "wjj"
|
||||
upassword = "123"
|
||||
create_user(uname, upassword)
|
||||
|
||||
# 6.尝试核对用户登录信息
|
||||
uname = "wjj"
|
||||
upassword = "1234"
|
||||
login_check(uname, upassword)
|
||||
|
||||
# 7.尝试插入用户模型数据
|
||||
uid = 2
|
||||
file_path = "E:\\Desktop\\test"
|
||||
app_name = 'QQ'
|
||||
time = '2021/5/31'
|
||||
upload_data(uid, app_name, time, file_path)
|
||||
|
||||
# 8.尝试读取用户模型数据
|
||||
uid = 2
|
||||
result = select_data(uid)
|
|
@ -0,0 +1,158 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2020/11/4 6:56 下午
|
||||
# @Author : Wang Guoxin
|
||||
|
||||
import os
|
||||
from database.api import DBAction
|
||||
import base64
|
||||
import xml.etree.ElementTree
|
||||
|
||||
def convertToBinaryData(filepath):
|
||||
"""
|
||||
将图片转化为二进制格式
|
||||
:param filepath: 图片地址
|
||||
:return: 二进制数据
|
||||
"""
|
||||
with open(filepath, 'rb') as file:
|
||||
binary_data = file.read()
|
||||
encodestring = base64.b64encode(binary_data)
|
||||
return encodestring
|
||||
|
||||
def encode_layout(filepath):
|
||||
tree = xml.etree.ElementTree.parse(filepath)
|
||||
root = tree.getroot()
|
||||
return xml.etree.ElementTree.tostring(root).decode()
|
||||
|
||||
def read_q_testing_result(project_dir):
|
||||
"""
|
||||
读取Q-testing探索App生成的结果
|
||||
:param project_dir: 项目文件夹地址
|
||||
:return: apk_name, package_name, version, states, jump_pairs
|
||||
"""
|
||||
file = open(os.path.join(project_dir, 'app_info.lst'), 'r')
|
||||
apk_name = file.readline().strip()
|
||||
package_name = file.readline().strip()
|
||||
version = file.readline().strip()
|
||||
|
||||
states = []
|
||||
file = open(os.path.join(project_dir, 'window_info.lst'), 'r')
|
||||
for l in file.readlines():
|
||||
line = l.split()
|
||||
state_id, activity_name = line[0], line[1]
|
||||
screen_shot_path = os.path.join(project_dir, 'temp-screen-shot', state_id+'.png')
|
||||
layout_file_path = os.path.join(project_dir, 'temp-gui-hierarchy', state_id+'.xml')
|
||||
if not os.path.exists(screen_shot_path):
|
||||
print(screen_shot_path + ' not exists')
|
||||
exit(0)
|
||||
if not os.path.exists(layout_file_path):
|
||||
print(layout_file_path + ' not exists')
|
||||
exit(0)
|
||||
binary_data = convertToBinaryData(screen_shot_path)
|
||||
layout = encode_layout(layout_file_path)
|
||||
states.append((line[0], line[1], binary_data, layout))
|
||||
|
||||
jump_pairs = []
|
||||
file = open(os.path.join(project_dir, 'jump_pairs.lst'), 'r')
|
||||
for l in file.readlines():
|
||||
line = l.split(maxsplit=2)
|
||||
if len(line) == 3:
|
||||
action_str = line[2].strip()
|
||||
at_pos = action_str.find("@")
|
||||
# TODO 是否要记录不发生跳转的事件
|
||||
if line[0] != line[1]:
|
||||
if at_pos == -1:
|
||||
jump_pairs.append([line[0], line[1], action_str])
|
||||
else:
|
||||
action_str = action_str[at_pos + 1:]
|
||||
if action_str.startswith('click') or action_str.startswith('clickLong') or action_str.startswith('edit'):
|
||||
spilt_index = action_str.find('(')
|
||||
action_type = action_str[:spilt_index]
|
||||
action_identifier = action_str[spilt_index+1:-1]
|
||||
#print([line[0], line[1], action_type, action_identifier])
|
||||
jump_pairs.append([line[0], line[1], action_type, action_identifier])
|
||||
else:
|
||||
jump_pairs.append([line[0], line[1], action_str])
|
||||
#print([line[0], line[1], action_str])
|
||||
else:
|
||||
print("WARNING: Skipped invalid record in " + os.path.join(project_dir, 'jump_pairs.lst'))
|
||||
print(line)
|
||||
|
||||
return apk_name, package_name, version, states, jump_pairs
|
||||
|
||||
def read_scenario_info(project_dir):
|
||||
"""
|
||||
读取功能场景及其路径
|
||||
:param project_dir: 项目文件夹地址
|
||||
:return: scenario_name, path
|
||||
"""
|
||||
scenario_name_list = []
|
||||
path_list = []
|
||||
scenarios = os.listdir(os.path.join(project_dir, 'feature'))
|
||||
for scenario in scenarios:
|
||||
if scenario == '.DS_Store':
|
||||
continue
|
||||
scenario_name = scenario.split(' ')[0]
|
||||
path_str = scenario.split(' ')[1]
|
||||
scenario_name_list.append(scenario_name)
|
||||
path_list.append(path_str)
|
||||
|
||||
return scenario_name_list, path_list
|
||||
|
||||
def process_project(project_path):
|
||||
"""
|
||||
处理单个项目文件夹
|
||||
:param project_path: 项目文件夹路径
|
||||
:return:
|
||||
"""
|
||||
apk_name, package_name, version, states, jump_pairs = read_q_testing_result(project_path)
|
||||
|
||||
db = DBAction()
|
||||
package_name_list = db.get_all_app_package_name()
|
||||
if package_name in package_name_list:
|
||||
print("Skipped exist apk " + package_name)
|
||||
return
|
||||
|
||||
# 插入 app_info
|
||||
db.insert_row_app_info(apk_name, package_name, version)
|
||||
app_id = db.get_app_id(package_name)
|
||||
|
||||
if app_id != -1:
|
||||
# 插入 state
|
||||
for (state_id, activity_name, binary_data, layout) in states:
|
||||
db.insert_row_state(app_id, state_id, activity_name, binary_data, layout)
|
||||
|
||||
# 插入 transition
|
||||
for jump_pair in jump_pairs:
|
||||
if len(jump_pair) == 3:
|
||||
source_state, target_state, trigger_action= jump_pair[0], jump_pair[1], jump_pair[2]
|
||||
db.insert_row_transition(app_id, source_state, target_state, trigger_action, '', '')
|
||||
elif len(jump_pair) == 4:
|
||||
source_state, target_state, trigger_action, trigger_identifier = jump_pair[0], jump_pair[1], jump_pair[2], jump_pair[3]
|
||||
db.insert_row_transition(app_id, source_state, target_state, trigger_action, trigger_identifier, '')
|
||||
else:
|
||||
print("WARNING: error jump_pair")
|
||||
|
||||
# 插入功能场景及其路径
|
||||
# scenario_name_list, path_list = read_scenario_info(project_path)
|
||||
# for index in range(len(scenario_name_list)):
|
||||
# print(app_id, scenario_name_list[index], '', path_list[index])
|
||||
# db.insert_row_scenarios(app_id, scenario_name_list[index], '', path_list[index])
|
||||
|
||||
|
||||
print('## Project processed: ' + project_path)
|
||||
|
||||
def process_whole(path):
|
||||
"""
|
||||
处理包含项目文件夹的整体文件夹
|
||||
:param path: 项目文件夹所在文件夹路径
|
||||
:return:
|
||||
"""
|
||||
for f in os.listdir(path):
|
||||
project_path = os.path.join(path, f)
|
||||
if os.path.isdir(project_path):
|
||||
process_project(project_path)
|
||||
|
||||
if __name__ == "__main__":
|
||||
process_whole('/Users/wangguoxin/Projects/AppRepository/ProjectCollections/Q-testing-out/success')
|
||||
#process_project('/Users/wangguoxin/Projects/AppRepository/ProjectCollections/Q-testing-out/debug_output1/org.asdtm.goodweather_13')
|
|
@ -0,0 +1,39 @@
|
|||
CREATE DATABASE IF NOT EXISTS APPREPO;
|
||||
|
||||
CREATE DATABASE IF NOT EXISTS APPREPO;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS APPREPO.app_info(
|
||||
app_id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
apk_name VARCHAR(128) NOT NULL,
|
||||
package_name VARCHAR(128) NOT NULL,
|
||||
version VARCHAR(32) NOT NULL,
|
||||
author VARCHAR(32)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS APPREPO.state(
|
||||
app_id INT UNSIGNED NOT NULL,
|
||||
state_id INT UNSIGNED NOT NULL PRIMARY KEY,
|
||||
activity_name VARCHAR(128) NOT NULL,
|
||||
screen_shot mediumblob NOT NULL,
|
||||
layout LONGTEXT NOT NULL ,
|
||||
FOREIGN KEY (app_id) REFERENCES app_info(uid)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS APPREPO.transition(
|
||||
transition_id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
app_id INT UNSIGNED NOT NULL,
|
||||
source_state INT UNSIGNED NOT NULL,
|
||||
target_state INT UNSIGNED NOT NULL,
|
||||
trigger_action TEXT NOT NULL,
|
||||
trigger_identifier TEXT,
|
||||
conditions TEXT ,
|
||||
FOREIGN KEY (app_id) REFERENCES app_info(uid)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS APPREPO.scenarios(
|
||||
app_id INT UNSIGNED NOT NULL,
|
||||
scenario_name VARCHAR(128) NOT NULL,
|
||||
description VARCHAR(128) NOT NULL,
|
||||
path VARCHAR(128) NOT NULL ,
|
||||
FOREIGN KEY (app_id) REFERENCES app_info(uid)
|
||||
);
|
|
@ -0,0 +1,58 @@
|
|||
CREATE DATABASE IF NOT EXISTS MergeResult;
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS MergeResult.app_info(
|
||||
app_id INT NOT NULL PRIMARY KEY,
|
||||
apk_name VARCHAR(128) NOT NULL,
|
||||
package_name VARCHAR(128) NOT NULL,
|
||||
version VARCHAR(32) ,
|
||||
author VARCHAR(32)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS MergeResult.state(
|
||||
state_id INT NOT NULL PRIMARY KEY,
|
||||
app_id INT NOT NULL,
|
||||
activity_name VARCHAR(128) ,
|
||||
screen_shot mediumblob ,
|
||||
layout LONGTEXT ,
|
||||
FOREIGN KEY (app_id) REFERENCES app_info(uid)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS MergeResult.transition(
|
||||
transition_id BigInt NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
app_id INT NOT NULL,
|
||||
source_state INT ,
|
||||
target_state INT ,
|
||||
trigger_action TEXT ,
|
||||
trigger_identifier TEXT,
|
||||
conditions TEXT ,
|
||||
FOREIGN KEY (app_id) REFERENCES app_info(uid)
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS MergeResult.scenarios(
|
||||
scenario_name VARCHAR(128) ,
|
||||
app_id INT NOT NULL,
|
||||
description VARCHAR(128) ,
|
||||
path VARCHAR(128),
|
||||
FOREIGN KEY (app_id) REFERENCES app_info(uid)
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
-- @author: Chen wenjie
|
||||
-- @time: 2021-6-2 00:34
|
||||
-- 配置用于存储merge后的数据的数据库
|
||||
--
|
||||
--
|
||||
-- def get_res_model(self): # 返回一个合并后的模型
|
||||
-- res_model = Model()
|
||||
-- res_model.set_id(self.app_id)
|
||||
-- res_model.set_apk_name(self.app_apk_name)
|
||||
-- res_model.set_package_name(self.app_package_name)
|
||||
-- res_model.set_version(self.app_version)
|
||||
-- res_model.state_list = self.res_state_list
|
||||
-- res_model.transitions = self.res_transitions
|
||||
-- res_model.states = self.res_states
|
||||
-- return res_model
|
|
@ -0,0 +1,25 @@
|
|||
CREATE DATABASE IF NOT EXISTS USERS;
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS USERS.user_info(
|
||||
uid VARCHAR(128) PRIMARY KEY,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
password VARCHAR(128) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS USERS.user_email(
|
||||
uid VARCHAR(128) PRIMARY KEY,
|
||||
email VARCHAR(128)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS USERS.data_info(
|
||||
uid VARCHAR(128),
|
||||
app_name VARCHAR(128),
|
||||
time VARCHAR(128),
|
||||
file_path VARCHAR(128)
|
||||
);
|
||||
|
||||
|
||||
-- @author: Chen Wenjie, Wang Jiajie
|
||||
-- @time: 2021-7-12 10:19
|
||||
-- 配置用于存储用户信息与模型数据的数据库
|
|
@ -0,0 +1,51 @@
|
|||
### 模型合并组数据字典
|
||||
#### 一、数据项
|
||||
#####(1)app_id
|
||||
描述:model所属app的id
|
||||
类型:char
|
||||
|
||||
#####(2)apk_name
|
||||
描述:app安装包的名称
|
||||
类型:char
|
||||
|
||||
#####(3)package_name
|
||||
描述:app的package名称
|
||||
类型:char
|
||||
|
||||
#####(4)version
|
||||
描述:app的版本号
|
||||
类型:char
|
||||
|
||||
#####(5)window_info
|
||||
描述:当前聚焦的应用窗口信息
|
||||
类型:char
|
||||
|
||||
#####(6)state_activity
|
||||
描述:当前进行的页面的状态信息
|
||||
类型:char
|
||||
|
||||
#####(7)页面标识
|
||||
描述:对页面进行标识和描述的xml格式文件
|
||||
类型:.uix
|
||||
|
||||
#####(8)页面截屏
|
||||
描述:png格式的页面截屏
|
||||
类型:.png
|
||||
|
||||
#####(9)页面编号
|
||||
描述:该arp模型中页面的标号
|
||||
类型:int
|
||||
|
||||
#### 二、数据结构
|
||||
数据结构反映数据之间的组合关系
|
||||
#####(1)jump_pairs
|
||||
描述:描绘了两两界面的跳转逻辑
|
||||
组成:来源界面编号 目标界面编号 跳转方式
|
||||
|
||||
#####(2)scenarios
|
||||
描述:描述了应用程序某个使用场景的使用方式和界面跳转逻辑
|
||||
组成:操作名(列表) 操作说明(对操作进行的解释组成的列表) 界面跳转表(界面编号组成的列表)
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
import sys
|
||||
sys.path.append('./Model')
|
||||
sys.path.append('./Merge')
|
||||
from BuildModel import Model
|
||||
from Merge import Merge
|
||||
|
||||
|
||||
# 读两个模型
|
||||
model1 = Model()
|
||||
model2 = Model()
|
||||
model1.Build_Model_From_Project('./Data/2020FallSE/181860039_孔鹏翔_AnyMemo')
|
||||
model2.Build_Model_From_Project('./Data/2020Fall软件方法学/MG20330042_毛心怡_MG20330037_刘疏观_MG1633116_李达_AnyMemo')
|
||||
print('model1.state_list:', len(model1.state_list))
|
||||
print('model2.state_list:', len(model2.state_list))
|
||||
print('model1.transitions:', len(model1.transitions))
|
||||
print('model2.transitions:', len(model2.transitions))
|
||||
|
||||
# 以APP名称定义一个Merge类,加入这两个模型
|
||||
AnyMemo = Merge()
|
||||
AnyMemo.add_model(model1)
|
||||
AnyMemo.add_model(model2)
|
||||
|
||||
# 进行模型合并操作,返回合并好的模型
|
||||
AnyMemo.merge_models()
|
||||
res = AnyMemo.get_res_model()
|
||||
print('res.state_list:', len(res.state_list))
|
||||
print('res.states:', len(res.states))
|
||||
print('res.transitions:', len(res.transitions))
|
||||
|
||||
# 模型可视化:关系图
|
||||
g = Graph()
|
||||
g.generate_graph(res)
|
||||
print(g.vertices)
|
||||
g.visualization()
|
|
@ -0,0 +1,13 @@
|
|||
certifi==2020.12.5
|
||||
chardet==4.0.0
|
||||
mkl-fft==1.3.0
|
||||
mkl-random==1.1.1
|
||||
mkl-service==2.3.0
|
||||
mysql==0.0.2
|
||||
mysql-connector==2.2.9
|
||||
mysqlclient==2.0.3
|
||||
numpy==1.19.2
|
||||
opencv-python==4.5.1.48
|
||||
Pillow==8.1.2
|
||||
PyMySQL==1.0.2
|
||||
six==1.15.0
|
|
@ -0,0 +1,32 @@
|
|||
CREATE DATABASE IF NOT EXISTS AppRepo;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS AppRepo.app_info(
|
||||
app_id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
apk_name VARCHAR(128) NOT NULL,
|
||||
package_name VARCHAR(128) NOT NULL,
|
||||
version VARCHAR(32)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS AppRepo.state(
|
||||
app_id INT UNSIGNED NOT NULL,
|
||||
state_id INT UNSIGNED NOT NULL,
|
||||
activity_name VARCHAR(128) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS AppRepo.transition(
|
||||
transition_id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
app_id INT UNSIGNED NOT NULL,
|
||||
source_state INT UNSIGNED NOT NULL,
|
||||
target_state INT UNSIGNED NOT NULL,
|
||||
trigger_action TEXT NOT NULL,
|
||||
trigger_identifier TEXT,
|
||||
conditions TEXT NOT NULL
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS AppRepo.scenarios(
|
||||
app_id INT UNSIGNED NOT NULL,
|
||||
scenario_name VARCHAR(128) NOT NULL,
|
||||
description VARCHAR(128) NOT NULL,
|
||||
path VARCHAR(128) NOT NULL
|
||||
);
|
|
@ -0,0 +1,105 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2021/1/7 4:08 下午
|
||||
# @Author : Wang Guoxin
|
||||
|
||||
"""
|
||||
从作业里读取模型信息,且作业中的各种文件应该是格式化过的,清理过的数据
|
||||
"""
|
||||
|
||||
import os
|
||||
import chardet
|
||||
import xml.etree.ElementTree
|
||||
import base64
|
||||
import re
|
||||
|
||||
|
||||
def get_file_encoding(path):
|
||||
f = open(path, 'rb')
|
||||
data = f.read()
|
||||
return chardet.detect(data).get('encoding')
|
||||
|
||||
|
||||
def image2base64(filepath):
|
||||
"""
|
||||
将图片转化为二进制格式
|
||||
:param filepath: 图片地址
|
||||
:return: 二进制数据的base64编码
|
||||
"""
|
||||
with open(filepath, 'rb') as file:
|
||||
binary_data = file.read()
|
||||
encodestring = base64.b64encode(binary_data)
|
||||
return encodestring
|
||||
|
||||
|
||||
def encode_layout(filepath):
|
||||
tree = xml.etree.ElementTree.parse(filepath)
|
||||
root = tree.getroot()
|
||||
return xml.etree.ElementTree.tostring(root).decode()
|
||||
|
||||
|
||||
def read_app_info(project_path):
|
||||
author_id = None
|
||||
with open(os.path.join(project_path, 'app_info.lst'), 'r', encoding='utf-8') as f:
|
||||
lines = f.readlines()
|
||||
app_name = lines[0].strip()
|
||||
package_name = lines[1].strip()
|
||||
version = lines[2].strip()
|
||||
return app_name, package_name, version, author_id
|
||||
|
||||
|
||||
def read_state_info(project_path):
|
||||
states = []
|
||||
state_activity_file = os.path.join(project_path, 'window_info.lst')
|
||||
file = open(state_activity_file, 'r', encoding=get_file_encoding(state_activity_file))
|
||||
|
||||
for l in file.readlines():
|
||||
l = l.strip()
|
||||
line = l.split()
|
||||
state_id, activity_name = line[0], line[1]
|
||||
screen_shot_path = os.path.join(project_path, 'screens', state_id + '.png')
|
||||
layout_file_path = os.path.join(project_path, 'screens', state_id + '.uix')
|
||||
if not os.path.exists(screen_shot_path):
|
||||
print(screen_shot_path + ' not exists')
|
||||
exit(0)
|
||||
# 对于动态界面可能无法获取布局文件的情况,设layout为空字符
|
||||
if not os.path.exists(layout_file_path):
|
||||
print(layout_file_path + ' not exists')
|
||||
layout = ''
|
||||
else:
|
||||
layout = encode_layout(layout_file_path)
|
||||
binary_data = image2base64(screen_shot_path)
|
||||
states.append((state_id, activity_name, binary_data, layout))
|
||||
return states
|
||||
|
||||
|
||||
def read_transitions(project_path):
|
||||
transitions = []
|
||||
file = open(os.path.join(project_path, 'jump_pairs.lst'), 'r')
|
||||
for line in file.readlines():
|
||||
line = line.strip()
|
||||
fields = re.split(r" (?![^(]*\))", line, maxsplit=3)
|
||||
if len(fields) == 3:
|
||||
transitions.append([fields[0], fields[1], fields[2]])
|
||||
elif len(fields) == 4:
|
||||
transitions.append([fields[0], fields[1], fields[2], fields[3]])
|
||||
else:
|
||||
print("WARNING: Skipped invalid record:" + line)
|
||||
print(len(fields))
|
||||
return transitions
|
||||
|
||||
|
||||
def read_scenarios_info(project_path):
|
||||
scenarios_file = os.path.join(project_path, 'scenarios.lst')
|
||||
file = open(scenarios_file, 'r', encoding=get_file_encoding(scenarios_file))
|
||||
scenarios = []
|
||||
|
||||
for line in file.readlines():
|
||||
if line.startswith('[功能名称]'):
|
||||
continue
|
||||
line = line.strip()
|
||||
fields = re.findall(r'[[](.*?)[]]', line)
|
||||
print(fields)
|
||||
scenarios.append([fields[0], fields[1], fields[2]])
|
||||
|
||||
return scenarios
|
|
@ -0,0 +1,439 @@
|
|||
'''
|
||||
@Time : 2021/7/11 20:30 下午
|
||||
@Author : Tang Jiaxin, Wang Jiajie
|
||||
服务器的各种功能
|
||||
'''
|
||||
# coding: utf-8
|
||||
from flask import Flask, request, jsonify, send_from_directory
|
||||
from flask_cors import *
|
||||
import json
|
||||
import os
|
||||
import io
|
||||
import zipfile
|
||||
import shutil
|
||||
from werkzeug.utils import secure_filename
|
||||
import sys
|
||||
import time
|
||||
import random
|
||||
from PIL import Image, ImageDraw, ImageFont, ImageFilter
|
||||
import string
|
||||
import smtplib
|
||||
import socks
|
||||
import socket
|
||||
from email.mime.text import MIMEText
|
||||
from email.utils import formataddr
|
||||
sys.path.append('./Merge')
|
||||
sys.path.append('./Model')
|
||||
sys.path.append('./database')
|
||||
from BuildModel import Model
|
||||
from Merge import Merge
|
||||
from Visualization import Graph
|
||||
from database.api import DBAction
|
||||
app = Flask(__name__)
|
||||
db = DBAction()
|
||||
CORS(app, supports_credentials=True, resources=r"/*")
|
||||
|
||||
|
||||
@app.route('/', methods = ['GET'])
|
||||
def welcome():
|
||||
return 'welcome!'
|
||||
|
||||
def unfold(file_name, path):
|
||||
if not zipfile.is_zipfile(file_name):
|
||||
return False
|
||||
zip_file = zipfile.ZipFile(file_name)
|
||||
zip_list = zip_file.namelist()
|
||||
for f in zip_list:
|
||||
zip_file.extract(f, path)
|
||||
zip_file.close()
|
||||
return True
|
||||
|
||||
|
||||
def fold(dirpath, resFilePath):
|
||||
print(dirpath, resFilePath)
|
||||
zip_file = zipfile.ZipFile(resFilePath, 'w', zipfile.ZIP_DEFLATED)
|
||||
for path, dirnames, filenames in os.walk(dirpath):
|
||||
fpath = path.replace(dirpath, '')
|
||||
for filename in filenames:
|
||||
zip_file.write(os.path.join(path, filename), os.path.join(fpath, filename))
|
||||
zip_file.close()
|
||||
|
||||
|
||||
@app.route('/file_upload', methods = ['POST'], strict_slashes = False)
|
||||
def receive_file():
|
||||
basedir = os.path.dirname(__file__)
|
||||
usr_name = 'usr' + request.form['cookie'] #usr_name: usr0
|
||||
file_dir = os.path.join(basedir, 'files', usr_name) #file_dir: ./files/usr0
|
||||
if not os.path.exists(os.path.join(basedir, 'files')):
|
||||
os.makedirs(os.path.join(basedir, 'files'))
|
||||
if not os.path.exists(file_dir):
|
||||
os.makedirs(file_dir)
|
||||
app = request.form['app']
|
||||
datetime = time.asctime(time.localtime(time.time()))
|
||||
print(app)
|
||||
print(datetime)
|
||||
f = request.files['input_file']
|
||||
if not f:
|
||||
return jsonify({'state': 1001, 'msg': '无法获取上传的文件'})
|
||||
fname = secure_filename(f.filename) #fname: file_name.zip
|
||||
res_file_name = fname.split('.')[0] #res_file_name: file_name
|
||||
print(fname, res_file_name)
|
||||
file_list = os.listdir(file_dir) #file_list: all file_name in ./files/usr0
|
||||
for file_name in file_list: #file_name: file_name
|
||||
if file_name == res_file_name:
|
||||
return jsonify({'state': 1003, 'msg': '该名称的文件已经存在'})
|
||||
file_path = os.path.join(file_dir, fname) #file_path: ./files/usr0/file_name.zip
|
||||
f.save(file_path)
|
||||
res = unfold(file_path, file_dir) #unfold ./files/usr0/file_name.zip to ./files/usr0
|
||||
print(usr_name, app, datetime, res_file_name)
|
||||
db.upload_data(usr_name, app, datetime, res_file_name)
|
||||
os.remove(file_path)
|
||||
if not res:
|
||||
return jsonify({'state': 1002, 'msg': '无法解压上传的文件'})
|
||||
return jsonify({'state': 200, 'msg': '上传成功'})
|
||||
|
||||
|
||||
@app.route('/file_download', methods = ['GET', 'POST'])
|
||||
def send_download_file():
|
||||
basedir = os.path.dirname(__file__)
|
||||
if request.method == 'GET':
|
||||
return 'ok'
|
||||
else:
|
||||
file_name = request.form['fileName'] #file_name: files/usr0/file_name/ or temp/tempfile0/
|
||||
print(file_name)
|
||||
file_name_list = file_name.split('/')
|
||||
kind = file_name_list[0] #kind :files or temp
|
||||
fname = ''
|
||||
usr_name = ''
|
||||
if kind == 'files':
|
||||
usr_name = file_name_list[1] #usr_name: usr0
|
||||
fname = file_name_list[2] #fname: file_name
|
||||
else:
|
||||
fname = file_name_list[1] #fname: tempfile0
|
||||
fold_name = fname + '.zip' #fold_name: file_name.zip or tempfile0.zip
|
||||
fold_path = os.path.join(os.path.join(kind, usr_name), fold_name) #fold_path: files/usr0/file_name.zip or temp/tempfile0.zip
|
||||
if not os.path.exists(fold_path):
|
||||
fold(file_name, fold_path)
|
||||
return send_from_directory(os.path.join(basedir, kind, usr_name), fold_name, as_attachment=True) #send file_name.zip in ./files/usr0 or tempfile0.zip in ./temp
|
||||
|
||||
|
||||
def get_file_lines(file_name):
|
||||
f = open(file_name, 'r')
|
||||
count = -1
|
||||
for index, line in enumerate(f):
|
||||
count += 1
|
||||
f.close()
|
||||
return count
|
||||
|
||||
|
||||
@app.route('/file_display', methods = ['POST'])
|
||||
def send_display_file():
|
||||
basedir = os.path.dirname(__file__)
|
||||
data = json.loads(request.get_data(as_text=True))
|
||||
file_name = data['file'] #file_name: files/usr0/file_name
|
||||
print(file_name)
|
||||
file_path = os.path.join(basedir, file_name) #file_path: ./files/usr0/file_name
|
||||
if not os.path.exists(file_path):
|
||||
return jsonify({'state': 1004, 'msg': '无法打开希望获取的文件'})
|
||||
transitions_path = os.path.join(file_path, 'transitions.lst') #transitions_path: ./files/usr0/file_name/transitions.lst
|
||||
s = 'transition数:' + str(get_file_lines(transitions_path)) + '<br>'
|
||||
state_path = os.path.join(file_path, 'window_info.lst')
|
||||
s += ('state数:' + str(get_file_lines(state_path)) + '<br>')
|
||||
return jsonify({'state': 200, 'data': s})
|
||||
|
||||
|
||||
@app.route('/file_graph', methods = ['POST'])
|
||||
def send_graph_file():
|
||||
basedir = os.path.dirname(__file__)
|
||||
data = json.loads(request.get_data(as_text=True))
|
||||
file_name = data['file'] #file_name: files/usr0/file_name
|
||||
print(file_name)
|
||||
file_path = os.path.join(basedir, file_name) #file_path: ./files/usr0/file_name
|
||||
if not os.path.exists(file_path):
|
||||
return jsonify({'state': 1004, 'msg': '无法打开希望获取的文件'})
|
||||
model = Model()
|
||||
model.Build_Model_From_Project(file_path)
|
||||
graph = Graph()
|
||||
graph.generate_graph(model)
|
||||
graph.visualization()
|
||||
f = open('force_layout_graph.html', 'r')
|
||||
s = f.read()
|
||||
return jsonify({'state': 200, 'data': s})
|
||||
|
||||
|
||||
@app.route('/file_list', methods = ['POST'])
|
||||
def send_file_list():
|
||||
basedir = os.path.dirname(__file__)
|
||||
data = json.loads(request.get_data(as_text=True))
|
||||
usr_name = 'usr' + data['cookie'] #usr_name: usr0
|
||||
file_dir = os.path.join(basedir, 'files', usr_name) #file_dir: ./files/usr0
|
||||
file_list = os.listdir(file_dir) #file_list: all files in ./files/usr0
|
||||
di = db.select_data(usr_name)
|
||||
li = {}
|
||||
for file_name in file_list:
|
||||
print(file_name) #file_name: file_name or file_name.zip
|
||||
if not os.path.isdir(os.path.join(file_dir, file_name)): #ignore ./files/usr0/file_name.zip
|
||||
continue
|
||||
time, app = di[file_name]
|
||||
file_path = 'files/' + usr_name + '/' + file_name + '/' #file_path: files/usr0/file_name/
|
||||
t_di = {'file': file_path, 'time': time}
|
||||
if not app in li:
|
||||
li[app] = [t_di]
|
||||
else:
|
||||
li[app].append(t_di)
|
||||
return jsonify({'state': 200, 'data': li})
|
||||
|
||||
|
||||
def merge_models(files, resPath):
|
||||
merge = Merge()
|
||||
for f in files:
|
||||
model = Model()
|
||||
model.Build_Model_From_Project(f)
|
||||
merge.add_model(model)
|
||||
merge.merge_models()
|
||||
res = merge.get_res_model()
|
||||
print('resPath:' + resPath)
|
||||
res.Save_Model_To_Local(resPath)
|
||||
|
||||
|
||||
@app.route('/file_merge', methods = ['POST'])
|
||||
def file_merge():
|
||||
basedir = os.path.dirname(__file__)
|
||||
file_dir = os.path.join(basedir, 'temp') #file_dir: ./temp
|
||||
file_cnt = 0
|
||||
if not os.path.exists(file_dir):
|
||||
os.makedirs(file_dir)
|
||||
else:
|
||||
file_cnt = len(os.listdir(file_dir)) #file_cnt: number of files in ./temp
|
||||
data = json.loads(request.get_data(as_text=True))
|
||||
app = data['app']
|
||||
files = data['files']
|
||||
print(app, files)
|
||||
file_name = 'tempfile' + str(file_cnt) + '/' #file_name: tempfile0/
|
||||
file_path = os.path.join(file_dir, file_name) #file_path: ./temp/tempfile0/
|
||||
merge_models(files, file_path)
|
||||
return jsonify({'state': 200, 'file': 'temp/' + file_name}) #send temp/tempfile0/
|
||||
|
||||
|
||||
@app.route('/merge_process', methods = ['POST'])
|
||||
def merge_process():
|
||||
f = open('process.txt', 'r')
|
||||
data = f.readlines()
|
||||
f.close()
|
||||
return jsonify({'state': 200, 'process': data[-1]})
|
||||
|
||||
|
||||
@app.route('/save_result', methods = ['POST'])
|
||||
def save_result():
|
||||
basedir = os.path.dirname(__file__)
|
||||
data = json.loads(request.get_data(as_text=True))
|
||||
usr_name = 'usr' + data['cookie'] #usr_name: usr0
|
||||
temp_name = data['tempname'] #temp_name: temp/tempfile0/
|
||||
file_name = data['filename'] #file_name: file_name
|
||||
app = data['app']
|
||||
file_dir = os.path.join(basedir, 'files', usr_name) #file_dir: ./files/usr0
|
||||
print(temp_name, file_name)
|
||||
file_list = os.listdir(file_dir) #file_list: all file_name in ./files/usr0
|
||||
for fname in file_list: #fname: file_name
|
||||
if file_name == fname:
|
||||
return jsonify({'state': 1003, 'msg': '该名称的文件已经存在'})
|
||||
file_path = os.path.join(file_dir, file_name) #file_path: ./files/usr0/file_name
|
||||
shutil.copytree(temp_name, file_path)
|
||||
shutil.rmtree('temp')
|
||||
os.mkdir('temp')
|
||||
temp_time = time.asctime( time.localtime(time.time()) )
|
||||
db.upload_data(usr_name, app, temp_time, file_name)
|
||||
return jsonify({'state': 200, 'msg': '保存成功'})
|
||||
|
||||
|
||||
@app.route('/abort_result', methods = ['POST'])
|
||||
def abort_result():
|
||||
data = json.loads(request.get_data(as_text=True))
|
||||
temp_name = data['tempname'] #temp_name: temp/tempfile0/
|
||||
shutil.rmtree('temp')
|
||||
os.mkdir('temp')
|
||||
return jsonify({'state': 200, 'msg': '删除成功'})
|
||||
|
||||
|
||||
@app.route('/file_remove', methods = ['POST'])
|
||||
def remove_file():
|
||||
data = json.loads(request.get_data(as_text=True))
|
||||
file_list = data['files'] #file_list: list of files/usr0/file_name
|
||||
for file_name in file_list: #file_name: files/usr0/file_name
|
||||
print(file_name)
|
||||
file_name_list = file_name.split('/')
|
||||
db.delete_data(file_name_list[1], file_name_list[2])
|
||||
shutil.rmtree(file_name)
|
||||
return jsonify({'state': 200, 'msg': '删除成功'})
|
||||
|
||||
|
||||
@app.route('/register', methods=['POST'])
|
||||
def register():
|
||||
data = json.loads(request.get_data(as_text=True))
|
||||
username = data['user_name']
|
||||
password = data['password']
|
||||
print(username, password)
|
||||
uid = db.get_uid()
|
||||
#判断用户名是否已经存在,若数据库中不存在则返回uid,否则返回“注册失败,用户名已存在”
|
||||
if db.register_check(username):
|
||||
db.create_user(uid, username, password)
|
||||
basedir = os.path.dirname(__file__)
|
||||
usr_name = 'usr' + str(uid) #usr_name: usr0
|
||||
file_dir = os.path.join(basedir, 'files', usr_name) #file_dir: ./files/usr0
|
||||
if not os.path.exists(os.path.join(basedir, 'files')):
|
||||
os.makedirs(os.path.join(basedir, 'files'))
|
||||
if not os.path.exists(file_dir):
|
||||
os.makedirs(file_dir)
|
||||
return jsonify({'state': 200, 'uid': uid})
|
||||
else:
|
||||
return jsonify({'state': 1005, 'msg': '注册失败,用户名已存在'})
|
||||
|
||||
|
||||
@app.route('/login', methods = ['POST'])
|
||||
def login():
|
||||
data = json.loads(request.get_data(as_text=True))
|
||||
user_name = data['user_name']
|
||||
password = data['password']
|
||||
uid = db.get_name_uid(user_name)
|
||||
if uid:
|
||||
mail_addr = db.check_email_uid(uid)
|
||||
if db.login_check(user_name, password):
|
||||
#print(username, password)
|
||||
return jsonify({'state': 200, 'uid': uid, 'mail_addr': mail_addr})
|
||||
else:
|
||||
return jsonify({'state': 1006, 'msg': '密码错误'})
|
||||
else:
|
||||
return jsonify({'state': 1007, 'msg': '用户不存在'})
|
||||
|
||||
|
||||
@app.route('/change_password', methods = ['POST'])
|
||||
def change_password():
|
||||
data = json.loads(request.get_data(as_text=True))
|
||||
uid = data['cookie']
|
||||
old_password = data['old_password']
|
||||
new_password = data['new_password']
|
||||
if db.check_password(uid, old_password):
|
||||
db.change_password(uid,new_password)
|
||||
return jsonify({'state': 200, 'msg': '密码修改成功'})
|
||||
else:
|
||||
return jsonify({'state': 1006, 'msg': '密码错误'})
|
||||
|
||||
|
||||
@app.route('/mail_login', methods = ['POST'])
|
||||
def mail_login():
|
||||
data = json.loads(request.get_data(as_text=True))
|
||||
code = data['check_code']
|
||||
if 'user_name' in data:
|
||||
user_name = data['user_name']
|
||||
uid = db.get_name_uid(user_name)
|
||||
mail_addr = db.check_email_uid(uid)
|
||||
if not mail_addr:
|
||||
return jsonify({'state': 1100, 'msg': '用户未绑定邮箱'})
|
||||
else:
|
||||
mail_addr = data['mail_addr']
|
||||
uid = db.check_email_email(mail_addr)
|
||||
if not uid:
|
||||
return jsonify({'state': 1101, 'msg': '邮箱对应的用户不存在'})
|
||||
user_name = db.get_user_name(uid)
|
||||
print(mail_addr, code)
|
||||
ret = send_mail(mail_addr, code)
|
||||
if ret:
|
||||
return jsonify({'state': 200, 'uid': uid, 'user_name': user_name, 'mail_addr': mail_addr})
|
||||
else:
|
||||
return jsonify({'state': 1102, 'msg': '发送邮件时出错'})
|
||||
|
||||
|
||||
@app.route('/mail_bind', methods = ['POST'])
|
||||
def mail_bind():
|
||||
data = json.loads(request.get_data(as_text=True))
|
||||
uid = data['cookie']
|
||||
mail_addr = data['mail_addr']
|
||||
index = db.check_email_email(mail_addr)
|
||||
if index:
|
||||
return jsonify({'state':1105,'msg':'邮箱已被其他用户绑定'})
|
||||
else:
|
||||
if 'check_code' in data:
|
||||
code = data['check_code']
|
||||
print(mail_addr, code)
|
||||
ret = send_mail(mail_addr, code)
|
||||
if ret:
|
||||
return jsonify({'state': 200, 'msg': '邮件发送成功'})
|
||||
else:
|
||||
return jsonify({'state': 1102, 'msg': '发送邮件时出错'})
|
||||
else:
|
||||
db.create_email(uid, mail_addr)
|
||||
return jsonify({'state': 200, 'msg': '邮箱绑定成功'})
|
||||
|
||||
@app.route('/check_code', methods = ['POST'])
|
||||
def check_code():
|
||||
data = json.loads(request.get_data(as_text=True))
|
||||
s = data['str']
|
||||
code = create_check_code(200, 50, s)
|
||||
return code
|
||||
|
||||
|
||||
def send_mail(receiver, code):
|
||||
sender = '405903102@qq.com' # 发件人邮箱账号
|
||||
password = 'xozekekxpckqbjfb' # 发件人邮箱授权码
|
||||
try:
|
||||
socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, '114.212.83.198', 1080)
|
||||
socks.wrapmodule(smtplib)
|
||||
msg = MIMEText('验证码为:' + code + ',如非本人操作,请忽略此邮件', 'plain', 'utf-8') #填写邮件内容
|
||||
msg['From'] = formataddr(["distant east coast", sender]) # 设置发件人邮箱账号
|
||||
msg['To'] = formataddr(["", receiver]) # 设置收件人邮箱账号
|
||||
msg['Subject'] = "验证码" # 设置邮件主题
|
||||
server = smtplib.SMTP_SSL("smtp.qq.com", 465) # 使用发件人邮箱中的SMTP服务器
|
||||
server.login(sender, password) # 登录发件人邮箱
|
||||
server.sendmail(sender, [receiver, ], msg.as_string()) # 发送邮件
|
||||
server.quit() # 关闭连接
|
||||
except Exception:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def create_check_code(w, h, s):
|
||||
'''
|
||||
根据给定的字符串生成一个验证码
|
||||
'''
|
||||
# 随机背景色创建图片
|
||||
bgcolor = (random.randrange(160,255), random.randrange(50,160), 255)
|
||||
img = Image.new(
|
||||
mode = "RGB",
|
||||
size = (w, h),
|
||||
color = bgcolor)
|
||||
draw = ImageDraw.Draw(img, mode = "RGB")
|
||||
|
||||
# 绘制干扰线
|
||||
line_number = random.randint(3, 5)
|
||||
for i in range(line_number):
|
||||
begin = (random.randint(0, w), random.randint(0, h))
|
||||
end = (random.randint(0, w), random.randint(0, h))
|
||||
linecolor = (
|
||||
random.randint(150, 255),
|
||||
random.randint(150, 255),
|
||||
random.randint(150, 255))
|
||||
draw.line([begin, end], fill=linecolor)
|
||||
|
||||
# 绘制字符
|
||||
for i in range(4):
|
||||
char = s[i]
|
||||
textcolor = (
|
||||
random.randint(0, 150),
|
||||
random.randint(0, 150),
|
||||
random.randint(0, 150))
|
||||
fontsize = random.randint(2 * (h // 3), h)
|
||||
font = ImageFont.truetype("Times.ttc", fontsize)
|
||||
draw.text((i * (w // 4) + random.randint(0, (w // 8)), random.randint(0, h - fontsize)), char, textcolor, font)
|
||||
|
||||
# 加边缘滤镜
|
||||
img = img.filter(ImageFilter.EDGE_ENHANCE_MORE)
|
||||
|
||||
# 保存图片
|
||||
buf = io.BytesIO()
|
||||
img.save(buf, "png")
|
||||
|
||||
return buf.getvalue()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(host='0.0.0.0', port='8001')
|
|
@ -0,0 +1,231 @@
|
|||
<!-- /*
|
||||
* @Author: Chen Wenjie
|
||||
* @Date: 2021-06-18 11:06:33
|
||||
* @Last Modified by: Chen Wenjie Fan Runpu
|
||||
* @Last Modified time: 2021-06-18 11:06:33
|
||||
*/ -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>关于我们~</title>
|
||||
<!-- 引入Bootstrap核心样式文件(必须) -->
|
||||
<link rel="stylesheet" href="lib/bootstrap/css/bootstrap.css" />
|
||||
<!-- 引入自己的样式或其他文件 -->
|
||||
<link rel="stylesheet" href="css/index.css" />
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="css/swiper.min.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="css/about.css">
|
||||
</head>
|
||||
<body>
|
||||
<!--头部-->
|
||||
<!-- <header id="lk_header"> -->
|
||||
<!--下部分-->
|
||||
<!-- <nav
|
||||
class="navbar navbar-default navbar-static-top navbar-lk"
|
||||
style="background-color: rgb(86, 61, 124)"
|
||||
>
|
||||
<div class="box">
|
||||
<div class="navbar-header">
|
||||
<button
|
||||
type="button"
|
||||
class="navbar-toggle collapsed"
|
||||
data-toggle="collapse"
|
||||
data-target="#lk_nav"
|
||||
aria-expanded="false"
|
||||
>
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="#">
|
||||
<img src="imgs/success.png" alt="logo" width="70" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="collapse navbar-collapse" id="lk_nav">
|
||||
<ul class="nav navbar-nav">
|
||||
<li ><a href="./fonts/index.html">首页 </a></li>
|
||||
<li><a href="./others.html">Ta的纸条</a></li>
|
||||
<li><a href="./mybook.html">我的日记</a></li>
|
||||
<li class="active">
|
||||
<a href="about.html">关于我们</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="./friend.html"
|
||||
>友情链接</a
|
||||
>
|
||||
</li>
|
||||
<!-- <ul class="nav navbar-nav navbar-right hidden-sm hidden-xs">
|
||||
<li><a href="#">个人中心</a></li>
|
||||
</ul> -->
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header> -->
|
||||
<!--/头部-->
|
||||
|
||||
<!-- team部分 -->
|
||||
<div>
|
||||
<div class="block1">
|
||||
<div class="swiper-container">
|
||||
<div class="swiper-wrapper">
|
||||
<div class="swiper-slide" >
|
||||
<div class="imgBx">
|
||||
<img src = "./pictures/1.jpeg"/>
|
||||
</div>
|
||||
<div class="details">
|
||||
<h3>19 计科 樊润璞<br><span><u>会议操盘手/前端工程师</u></span><p>"相信你的队友,做好自己的事"</p></h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="swiper-slide" >
|
||||
<div class="imgBx">
|
||||
<img src = "./pictures/2.jpeg">
|
||||
</div>
|
||||
|
||||
<div class="details">
|
||||
<h3>19 信管 陈文杰<br><span><u>系统分析师/数据库工程师</u></span><p>"如果第一次你没有成功,那么称之为1.0版,继续加油。"</p></h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="swiper-slide" >
|
||||
<div class="imgBx">
|
||||
<img src = "./pictures/3.jpeg">
|
||||
</div>
|
||||
<div class="details">
|
||||
<h3>18 计科 唐家昕<br><span><u>后端工程师/前端架构师</u></span><p>"所有的程序员都剧作家,而所有计算机都是糟糕的演员。"</p></h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="swiper-slide" >
|
||||
<div class="imgBx">
|
||||
<img src = "./pictures/4.jpeg">
|
||||
</div>
|
||||
<div class="details">
|
||||
<h3>18 信管 王嘉杰<br><span><u>数据库工程师/后端工程师</u></span><p>"程序员的烦恼是,你永远无法知道一个程序员在做什么,直到为时已晚。"</p></h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="swiper-slide" >
|
||||
<div class="imgBx">
|
||||
<img src = "./pictures/5.jpeg">
|
||||
</div>
|
||||
<div class="details">
|
||||
<h3>19 AI 张运筹<br><span><u>规范制定者/前后端交互</u></span><p>"工作拉下得越早,赶上去所需要的时间越多。"</p></h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="swiper-slide" >
|
||||
<div class="imgBx">
|
||||
<img src = "./pictures/6.jpeg">
|
||||
</div>
|
||||
<div class="details">
|
||||
<h3>亲爱的老师&助教<br><span><u>坚实后盾/DDL推进器</u></span><p>"这是我们这个行业的一件咄咄怪事:我们不仅不从错误中学习,我们也不从成功中学习。"</p></h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="swiper-pagination"></div>
|
||||
</div>
|
||||
|
||||
<div class="block" style="margin-top: 0;">
|
||||
<div class="box3">
|
||||
<p>CONTACT US</p>
|
||||
<input type="button" class="button" id="return" value="返回">
|
||||
</div>
|
||||
<script>
|
||||
document.getElementById("return").onclick=function() {
|
||||
window.location.assign("select.html");
|
||||
}
|
||||
</script>
|
||||
</div>
|
||||
<div class="block2" style="margin-top: 0em;">
|
||||
<div class="icons">
|
||||
|
||||
<a href="#">
|
||||
<div class="layer">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span class="icon iconfont"></span>
|
||||
</div>
|
||||
</a>
|
||||
<a href="#">
|
||||
<div class="layer">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span class="icon iconfont"></span>
|
||||
</div>
|
||||
<span class="text">Wechet</span>
|
||||
</a>
|
||||
<a href="#">
|
||||
<div class="layer">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span class="fab fa-facebook-f"></span>
|
||||
</div>
|
||||
<span class="text">Facebook</span>
|
||||
</a>
|
||||
<a href="#">
|
||||
<div class="layer">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span class="icon iconfont"></span>
|
||||
</div>
|
||||
<span class="text">Email</span>
|
||||
</a>
|
||||
<a href="#">
|
||||
<div class="layer">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span class="icon iconfont"></span>
|
||||
</div>
|
||||
<span class="text">Phone</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /team 结束-->
|
||||
|
||||
|
||||
<script src="lib/jquery/jquery.js"></script>
|
||||
<!-- 引入所有的Bootstrap的JS插件 -->
|
||||
<script src="lib/bootstrap/js/bootstrap.js"></script>
|
||||
<!-- 你自己的脚本文件 -->
|
||||
<script src="js/index.js"></script>
|
||||
<script type="text/javascript" src="./js/swiper.min.js"></script>
|
||||
<script>
|
||||
var swiper = new Swiper('.swiper-container', {
|
||||
effect: 'coverflow',
|
||||
grabCursor: true,
|
||||
centeredSlides: true,
|
||||
slidesPerView: 'auto',
|
||||
coverflowEffect: {
|
||||
rotate: 50,
|
||||
stretch: 0,
|
||||
depth: 100,
|
||||
modifier: 1,
|
||||
slideShadows: true,
|
||||
},
|
||||
pagination: {
|
||||
el: '.swiper-pagination',
|
||||
},
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,76 @@
|
|||
<!DOCTYPE html>
|
||||
<!--
|
||||
@Time : 2021/7/11 14:44 下午
|
||||
@Author : Tang Jiaxin
|
||||
密码修改界面,修改密码
|
||||
-->
|
||||
<html lang="zh-cn">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>修改密码</title>
|
||||
<script src="https://ajax.microsoft.com/ajax/jquery/jquery-3.5.1.js"></script>
|
||||
<script src="connect_login.js"></script>
|
||||
</head>
|
||||
<style type="text/css">
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
background: url(pictures/background.jpg);
|
||||
background-size: cover;
|
||||
}
|
||||
p {
|
||||
color: white;
|
||||
font-size: 20px;
|
||||
}
|
||||
form {
|
||||
position: absolute;
|
||||
left: 45%;
|
||||
top: 20%;
|
||||
height: 80%;
|
||||
width: 55%;
|
||||
}
|
||||
h1 {
|
||||
color: white;
|
||||
text-align: center;
|
||||
}
|
||||
.button {
|
||||
position: absolute;
|
||||
top: 70%;
|
||||
width: 8%;
|
||||
height: 6%;
|
||||
font: 16px Arial, sans-serif bold;
|
||||
color: white;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
border-radius: 50px;
|
||||
cursor: pointer;
|
||||
}
|
||||
#confirm {
|
||||
left: 40%;
|
||||
}
|
||||
#return {
|
||||
left: 52%;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<h1>修改密码</h1>
|
||||
<form id="password_change_form" method="POST">
|
||||
<div>
|
||||
<p>请输入旧密码</p>
|
||||
<input type="password" name="old_password" id="old_password">
|
||||
<p>请输入新密码</p>
|
||||
<input type="password" name="new_password1" id="new_password1">
|
||||
<p>请再次输入新密码</p>
|
||||
<input type="password" name="new_password2" id="new_password2">
|
||||
</div>
|
||||
</form>
|
||||
<input type="button" class="button" id="confirm"
|
||||
value="确定" onclick="connect_change_password()">
|
||||
<input type="button" class="button" id="return" value="返回">
|
||||
</body>
|
||||
<script>
|
||||
document.getElementById("return").onclick=function() {
|
||||
window.history.back();
|
||||
}
|
||||
</script>
|
||||
</html>
|
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
@Time : 2021/7/13 15:11 下午
|
||||
@Author : Tang Jiaxin
|
||||
文件下载与展示功能
|
||||
*/
|
||||
|
||||
//以提交表单的形式从服务器下载文件
|
||||
function download_file(file)
|
||||
{
|
||||
var url = "http://114.212.189.166:8001/file_download";
|
||||
var requestForm = document.createElement("form");
|
||||
requestForm.action = url;
|
||||
requestForm.method = "post";
|
||||
var input = document.createElement("input");
|
||||
input.type = "hidden";
|
||||
input.name = "fileName";
|
||||
input.value = file;
|
||||
requestForm.appendChild(input);
|
||||
$(document.body).append(requestForm);
|
||||
requestForm.submit();
|
||||
requestForm.remove();
|
||||
}
|
||||
|
||||
//从服务器下载一个文件
|
||||
function connect_download_file()
|
||||
{
|
||||
var url = document.URL;
|
||||
var index1 = url.indexOf("display_file=");
|
||||
var index2 = url.indexOf("display_app=");
|
||||
var file = "";
|
||||
if(index2 == -1)
|
||||
file = url.substring(index1 + 13);
|
||||
else
|
||||
file = url.substring(index1 + 13, index2 - 1);
|
||||
$.ajax(
|
||||
{
|
||||
url: "http://114.212.189.166:8001/file_download",
|
||||
type: "get",
|
||||
success: function()
|
||||
{
|
||||
download_file(file);
|
||||
},
|
||||
error: function()
|
||||
{
|
||||
alert("服务器连接失败");
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
//从服务器获取一个文件的内容
|
||||
function connect_display_file()
|
||||
{
|
||||
var url = document.URL;
|
||||
var index1 = url.indexOf("display_file=");
|
||||
var index2 = url.indexOf("display_app=");
|
||||
var file = "";
|
||||
if(index2 == -1)
|
||||
file = url.substring(index1 + 13);
|
||||
else
|
||||
file = url.substring(index1 + 13, index2 - 1);
|
||||
$.ajax(
|
||||
{
|
||||
url: "http://114.212.189.166:8001/file_display",
|
||||
type: "post",
|
||||
dataType: "json",
|
||||
data: JSON.stringify({"file": file}),
|
||||
contentType:'application/json; charset=utf-8',
|
||||
success: function(message)
|
||||
{
|
||||
state = message["state"];
|
||||
if(state == 200)
|
||||
{
|
||||
data = message["data"];
|
||||
$("p#response").html(data);
|
||||
}
|
||||
else
|
||||
$("p#response").text("结果获取失败:" + message["msg"]);
|
||||
},
|
||||
error: function()
|
||||
{
|
||||
$("p#response").text("服务器连接失败");
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
//从服务器获取可视化界面
|
||||
function connect_graph_display()
|
||||
{
|
||||
var url = document.URL;
|
||||
var index = url.indexOf("display_file=");
|
||||
var file = url.substring(index + 13);
|
||||
$.ajax(
|
||||
{
|
||||
url: "http://114.212.189.166:8001/file_graph",
|
||||
type: "post",
|
||||
dataType: "json",
|
||||
data: JSON.stringify({"file": file}),
|
||||
contentType:'application/json; charset=utf-8',
|
||||
success: function(message)
|
||||
{
|
||||
state = message["state"];
|
||||
if(state == 200)
|
||||
{
|
||||
data = message["data"];
|
||||
document.write(data);
|
||||
}
|
||||
else
|
||||
alert("可视化结果获取失败:" + message["msg"]);
|
||||
},
|
||||
error: function()
|
||||
{
|
||||
$("p#response").text("服务器连接失败");
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
//跳转到可视化页面
|
||||
function graph_display()
|
||||
{
|
||||
var url = document.URL;
|
||||
var index1 = url.indexOf("display_file=");
|
||||
var index2 = url.indexOf("display_app=");
|
||||
var file = "";
|
||||
if(index2 == -1)
|
||||
file = url.substring(index1 + 13);
|
||||
else
|
||||
file = url.substring(index1 + 13, index2 - 1);
|
||||
window.location.assign("graph.html?display_file=" + file);
|
||||
}
|
||||
|
||||
//展示一个文件列表
|
||||
function display_file_list(file_list, show_input)
|
||||
{
|
||||
var table = document.getElementById("table");
|
||||
table.innerHTML = "<th>编号</th><th>所属APP</th><th>文件名称</th><th>提交时间</th>";
|
||||
var index = 1;
|
||||
for(var app in file_list)
|
||||
{
|
||||
var files = file_list[app];
|
||||
for(let i = 0; i < files.length; i++)
|
||||
{
|
||||
var file = files[i]["file"];
|
||||
var time = files[i]["time"];
|
||||
var arr = file.split('/');
|
||||
var filename = arr[arr.length - 2];
|
||||
table.innerHTML += ("<tr>"
|
||||
+ "<td>" + index + "</td>"
|
||||
+ "<td>" + app + "</td>"
|
||||
+ "<td><a href='javascript:void(0);' onclick='display_file("
|
||||
+ "\"" + file + "\"" + ")'>"
|
||||
+ filename + "</a></td>"
|
||||
+ "<td>" + time + "</td>"
|
||||
+ "<td><input type='checkbox' class='checkbox' value='"
|
||||
+ app + " " + file + "'></td>"
|
||||
+ "</tr>");
|
||||
index++;
|
||||
}
|
||||
}
|
||||
if(!show_input)
|
||||
{
|
||||
var items = document.getElementsByClassName("checkbox");
|
||||
for(let i = 0; i < items.length; i++)
|
||||
items[i].style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
//从服务器获取已经上传的文件的列表
|
||||
function connect_display_file_list(show_input)
|
||||
{
|
||||
$.ajax(
|
||||
{
|
||||
url: "http://114.212.189.166:8001/file_list",
|
||||
type: "post",
|
||||
dataType: "json",
|
||||
data: JSON.stringify({"cookie": window.localStorage["cookie"]}),
|
||||
contentType:'application/json; charset=utf-8',
|
||||
success: function(message)
|
||||
{
|
||||
state = message["state"];
|
||||
if(state == 200)
|
||||
display_file_list(message["data"], show_input);
|
||||
else
|
||||
$("p#response").text("文件读取失败");
|
||||
},
|
||||
error: function()
|
||||
{
|
||||
$("p#response").text("服务器连接失败");
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
//从模型合并界面跳转到文件展示界面,并展示一个文件的内容
|
||||
function display_file(file)
|
||||
{
|
||||
window.location.assign("display.html?display_file="+ file);
|
||||
}
|
|
@ -0,0 +1,401 @@
|
|||
/*
|
||||
@Time : 2021/7/12 20:13 下午
|
||||
@Author : Tang Jiaxin
|
||||
登录注册功能,向服务器提交登录注册等请求
|
||||
*/
|
||||
function connect_register()
|
||||
{
|
||||
var register_info = document.getElementById("register_form");
|
||||
var user_name = register_info["user_name"].value;
|
||||
var password = register_info["password1"].value;
|
||||
var password2 = register_info["password2"].value;
|
||||
if(!user_name)
|
||||
{
|
||||
alert("请输入用户名!");
|
||||
return;
|
||||
}
|
||||
if(!password || !password2)
|
||||
{
|
||||
alert("请输入密码!");
|
||||
return;
|
||||
}
|
||||
if(password != password2)
|
||||
{
|
||||
alert("两次输入的密码不一致!");
|
||||
return;
|
||||
}
|
||||
var user_name_reg = /^\w{1,20}$/;
|
||||
if(!user_name_reg.test(user_name))
|
||||
{
|
||||
alert("输入的用户名不合理!");
|
||||
return;
|
||||
}
|
||||
var password_reg = /^\w{6,20}$/;
|
||||
if(!password_reg.test(password))
|
||||
{
|
||||
alert("输入的密码长度太短或太长!");
|
||||
return;
|
||||
}
|
||||
var data = {"user_name": user_name, "password": password};
|
||||
$.ajax(
|
||||
{
|
||||
url: "http://114.212.189.166:8001/register",
|
||||
type: "post",
|
||||
dataType: "json",
|
||||
data: JSON.stringify(data),
|
||||
contentType:'application/json; charset=utf-8',
|
||||
success: function(message)
|
||||
{
|
||||
var state = message["state"];
|
||||
if(state == 200)
|
||||
{
|
||||
alert("注册成功!");
|
||||
var uid = message["uid"];
|
||||
window.localStorage["cookie"] = uid.toString();
|
||||
window.localStorage["user_name"] = user_name;
|
||||
window.location.assign("select.html");
|
||||
}
|
||||
else
|
||||
alert("注册失败:" + message["msg"]);
|
||||
},
|
||||
error: function()
|
||||
{
|
||||
alert("服务器连接失败");
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function create_check_code()
|
||||
{
|
||||
var alphabet = [];
|
||||
for(let c = 0; c <= 9; c++)
|
||||
alphabet.push(String.fromCharCode(48 + c));
|
||||
for(let c = 0; c <= 25; c++)
|
||||
{
|
||||
alphabet.push(String.fromCharCode(65 + c));
|
||||
alphabet.push(String.fromCharCode(97 + c));
|
||||
}
|
||||
function getRndInteger(min, max) {
|
||||
return Math.floor(Math.random() * (max - min)) + min;
|
||||
}
|
||||
var str = "";
|
||||
for(let i = 0; i < 4; i++)
|
||||
str += alphabet[getRndInteger(0, 62)];
|
||||
window.sessionStorage["check_code"] = str;
|
||||
return str;
|
||||
}
|
||||
|
||||
function connect_check_code()
|
||||
{
|
||||
var request = new XMLHttpRequest();
|
||||
request.open("post", "http://114.212.189.166:8001/check_code", true);
|
||||
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
request.responseType = "blob";
|
||||
request.onload = function()
|
||||
{
|
||||
if(this.status == 200)
|
||||
{
|
||||
var data = this.response;
|
||||
var img = document.createElement("img");
|
||||
img.onload = function(e)
|
||||
{
|
||||
window.URL.revokeObjectURL(img.src);
|
||||
};
|
||||
img.src = window.URL.createObjectURL(data);
|
||||
$("#check_code_img").html(img);
|
||||
}
|
||||
}
|
||||
var check_code_data = create_check_code();
|
||||
request.send(JSON.stringify({"str": check_code_data}));
|
||||
}
|
||||
|
||||
function connect_login()
|
||||
{
|
||||
var login_info = document.getElementById("login_form");
|
||||
var user_name = login_info["user_name"].value;
|
||||
var password = login_info["password"].value;
|
||||
var check_code = login_info["check_code"].value;
|
||||
if(!user_name)
|
||||
{
|
||||
alert("请输入用户名!");
|
||||
return;
|
||||
}
|
||||
if(!password)
|
||||
{
|
||||
alert("请输入密码!");
|
||||
return;
|
||||
}
|
||||
if(!check_code)
|
||||
{
|
||||
alert("请输入验证码!");
|
||||
return;
|
||||
}
|
||||
if(check_code != window.sessionStorage["check_code"])
|
||||
{
|
||||
alert("验证码错误!");
|
||||
return;
|
||||
}
|
||||
var data = {"user_name": user_name, "password": password};
|
||||
$.ajax(
|
||||
{
|
||||
url: "http://114.212.189.166:8001/login",
|
||||
type: "post",
|
||||
dataType: "json",
|
||||
data: JSON.stringify(data),
|
||||
contentType:'application/json; charset=utf-8',
|
||||
success: function(message)
|
||||
{
|
||||
var state = message["state"];
|
||||
var uid = message["uid"];
|
||||
var mail_addr = message["mail_addr"];
|
||||
if(state == 200)
|
||||
{
|
||||
window.localStorage["cookie"] = uid.toString();
|
||||
window.localStorage["user_name"] = user_name;
|
||||
if(mail_addr)
|
||||
window.localStorage["mail_addr"] = mail_addr;
|
||||
window.location.assign("select.html");
|
||||
}
|
||||
else
|
||||
alert("登录失败:" + message["msg"]);
|
||||
},
|
||||
error: function()
|
||||
{
|
||||
alert("服务器连接失败");
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function connect_mail_login()
|
||||
{
|
||||
var login_info = document.getElementById("mail_login_form");
|
||||
var user_mail = login_info["user_mail"].value;
|
||||
if(!user_mail)
|
||||
{
|
||||
alert("请输入用户名或邮箱!");
|
||||
return;
|
||||
}
|
||||
var check_code = create_check_code();
|
||||
var data = {"check_code": check_code};
|
||||
var index = user_mail.indexOf("@");
|
||||
if(index == -1)
|
||||
data["user_name"] = user_mail;
|
||||
else
|
||||
data["mail_addr"] = user_mail;
|
||||
$.ajax(
|
||||
{
|
||||
url: "http://114.212.189.166:8001/mail_login",
|
||||
type: "post",
|
||||
dataType: "json",
|
||||
data: JSON.stringify(data),
|
||||
contentType:'application/json; charset=utf-8',
|
||||
success: function(message)
|
||||
{
|
||||
var state = message["state"];
|
||||
var uid = message["uid"];
|
||||
var mail_addr = message["mail_addr"];
|
||||
var user_name = message["user_name"];
|
||||
if(state == 200)
|
||||
{
|
||||
alert("邮件发送成功,请填写收到的验证码");
|
||||
window.sessionStorage["check_code"] = check_code;
|
||||
window.sessionStorage["cookie"] = uid.toString();
|
||||
window.sessionStorage["mail_addr"] = mail_addr;
|
||||
window.sessionStorage["user_name"] = user_name;
|
||||
}
|
||||
else
|
||||
alert("邮件发送失败:" + message["msg"]);
|
||||
},
|
||||
error: function()
|
||||
{
|
||||
alert("服务器连接失败");
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function mail_login()
|
||||
{
|
||||
var login_info = document.getElementById("mail_login_form");
|
||||
var check_code = login_info["check_code"].value;
|
||||
if(!check_code)
|
||||
{
|
||||
alert("请输入验证码!");
|
||||
return;
|
||||
}
|
||||
if(check_code != window.sessionStorage["check_code"])
|
||||
{
|
||||
alert("验证码错误!");
|
||||
return;
|
||||
}
|
||||
window.localStorage["cookie"] = window.sessionStorage["cookie"];
|
||||
window.localStorage["mail_addr"] = window.sessionStorage["mail_addr"];
|
||||
window.localStorage["user_name"] = window.sessionStorage["user_name"];
|
||||
window.location.assign("select.html");
|
||||
}
|
||||
|
||||
function connect_change_password()
|
||||
{
|
||||
var password_change_info = document.getElementById("password_change_form");
|
||||
var old_password = password_change_info["old_password"].value;
|
||||
var new_password = password_change_info["new_password1"].value;
|
||||
var new_password2 = password_change_info["new_password2"].value;
|
||||
if(!old_password)
|
||||
{
|
||||
alert("请输入旧密码!");
|
||||
return;
|
||||
}
|
||||
if(!new_password)
|
||||
{
|
||||
alert("请输入新密码!");
|
||||
return;
|
||||
}
|
||||
if(!new_password2)
|
||||
{
|
||||
alert("请再次输入新密码!");
|
||||
return;
|
||||
}
|
||||
if(new_password != new_password2)
|
||||
{
|
||||
alert("两次输入的新密码不一致!");
|
||||
return;
|
||||
}
|
||||
if(old_password == new_password)
|
||||
{
|
||||
alert("新密码不能与旧密码相同!");
|
||||
return;
|
||||
}
|
||||
var password_reg = /^\w{6,20}$/;
|
||||
if(!password_reg.test(new_password))
|
||||
{
|
||||
alert("新密码长度太短或太长!");
|
||||
return;
|
||||
}
|
||||
$.ajax(
|
||||
{
|
||||
url: "http://114.212.189.166:8001/change_password",
|
||||
type: "post",
|
||||
dataType: "json",
|
||||
data: JSON.stringify({'old_password': old_password,
|
||||
'new_password': new_password,
|
||||
'cookie': window.localStorage["cookie"]}),
|
||||
contentType:'application/json; charset=utf-8',
|
||||
success: function(message)
|
||||
{
|
||||
var state = message["state"];
|
||||
if(state == 200)
|
||||
alert("密码修改成功");
|
||||
else
|
||||
alert("密码修改失败:" + message["msg"]);
|
||||
},
|
||||
error: function()
|
||||
{
|
||||
alert("服务器连接失败");
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function connect_mail_bind()
|
||||
{
|
||||
var mail_bind_info = document.getElementById("mail_bind_form");
|
||||
var mail_addr = mail_bind_info["mail_addr"].value;
|
||||
if(!mail_addr)
|
||||
{
|
||||
alert("请输入邮箱!");
|
||||
return;
|
||||
}
|
||||
var check_code = create_check_code();
|
||||
$.ajax(
|
||||
{
|
||||
url: "http://114.212.189.166:8001/mail_bind",
|
||||
type: "post",
|
||||
dataType: "json",
|
||||
data: JSON.stringify({"mail_addr": mail_addr,
|
||||
"cookie": window.localStorage["cookie"], "check_code": check_code}),
|
||||
contentType:'application/json; charset=utf-8',
|
||||
success: function(message)
|
||||
{
|
||||
var state = message["state"];
|
||||
if(state == 200)
|
||||
{
|
||||
alert("邮件发送成功,请填写收到的验证码");
|
||||
window.sessionStorage["check_code"] = check_code;
|
||||
}
|
||||
else
|
||||
alert("邮件发送失败:" + message["msg"]);
|
||||
},
|
||||
error: function()
|
||||
{
|
||||
alert("服务器连接失败");
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function connect_mail_update()
|
||||
{
|
||||
var mail_bind_info = document.getElementById("mail_bind_form");
|
||||
var mail_addr = mail_bind_info["mail_addr"].value;
|
||||
var check_code = mail_bind_info["check_code"].value;
|
||||
if(!check_code)
|
||||
{
|
||||
alert("请输入验证码!");
|
||||
return;
|
||||
}
|
||||
if(check_code != window.sessionStorage["check_code"])
|
||||
{
|
||||
alert("验证码错误!");
|
||||
return;
|
||||
}
|
||||
if(!mail_addr)
|
||||
{
|
||||
alert("请输入邮箱!");
|
||||
return;
|
||||
}
|
||||
$.ajax(
|
||||
{
|
||||
url: "http://114.212.189.166:8001/mail_bind",
|
||||
type: "post",
|
||||
dataType: "json",
|
||||
data: JSON.stringify({"mail_addr": mail_addr,
|
||||
"cookie": window.localStorage["cookie"]}),
|
||||
contentType:'application/json; charset=utf-8',
|
||||
success: function(message)
|
||||
{
|
||||
var state = message["state"];
|
||||
if(state == 200)
|
||||
{
|
||||
alert("邮箱绑定成功");
|
||||
window.localStorage["mail_addr"] = mail_addr;
|
||||
}
|
||||
else
|
||||
alert("邮件发送失败:" + message["msg"]);
|
||||
},
|
||||
error: function()
|
||||
{
|
||||
alert("服务器连接失败");
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function get_user_info()
|
||||
{
|
||||
$("p#user_name").text("用户名:" + localStorage["user_name"]);
|
||||
if(window.localStorage.getItem("mail_addr"))
|
||||
$("p#mail_addr").text("邮箱:" + localStorage["mail_addr"]);
|
||||
else
|
||||
$("p#mail_addr").text("邮箱:未绑定");
|
||||
}
|
||||
|
||||
function exit_account()
|
||||
{
|
||||
window.localStorage.removeItem("cookie");
|
||||
window.localStorage.removeItem("user_name");
|
||||
if(window.localStorage.getItem("mail_addr"))
|
||||
window.localStorage.removeItem("mail_addr");
|
||||
window.location.assign("entrance.html");
|
||||
}
|
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
@Time : 2021/7/13 14:49 下午
|
||||
@Author : Tang Jiaxin
|
||||
向服务器发送文件合并和保存合并好的文件的请求
|
||||
*/
|
||||
|
||||
//向服务器发送文件合并请求
|
||||
function connect_merge()
|
||||
{
|
||||
var items = document.getElementsByClassName("checkbox");
|
||||
var files = {"files": []};
|
||||
for(let i = 0; i < items.length; i++)
|
||||
{
|
||||
if(!items[i].checked)
|
||||
continue;
|
||||
var t = items[i].value.split(" ");
|
||||
var app = t[0];
|
||||
var file = t[1];
|
||||
if(!files["app"])
|
||||
files["app"] = app;
|
||||
else if(app != files["app"])
|
||||
{
|
||||
alert("选择的模型不属于同一APP");
|
||||
return;
|
||||
}
|
||||
files["files"].push(file);
|
||||
}
|
||||
if(files["files"].length < 2)
|
||||
{
|
||||
alert("请至少选择两个待合并的模型");
|
||||
return;
|
||||
}
|
||||
var timer = self.setInterval("connect_merge_process()", 1000);
|
||||
$.ajax(
|
||||
{
|
||||
url: "http://114.212.189.166:8001/file_merge",
|
||||
type: "post",
|
||||
dataType: "json",
|
||||
data: JSON.stringify(files),
|
||||
contentType:'application/json; charset=utf-8',
|
||||
success: function(message)
|
||||
{
|
||||
var state = message["state"];
|
||||
var tempname = message["file"];
|
||||
if(state == 200)
|
||||
{
|
||||
window.clearInterval(timer);
|
||||
display_result(tempname, app);
|
||||
}
|
||||
else
|
||||
{
|
||||
window.clearInterval(timer);
|
||||
alert("合并失败:" + message["msg"]);
|
||||
}
|
||||
},
|
||||
error: function()
|
||||
{
|
||||
window.clearInterval(timer);
|
||||
alert("服务器连接失败");
|
||||
}
|
||||
}
|
||||
)
|
||||
var button1 = document.getElementById("button1");
|
||||
button1.style.visibility = "hidden";
|
||||
var button2 = document.getElementById("button2");
|
||||
button2.style.visibility = "hidden";
|
||||
var merge_info = document.getElementById("merge");
|
||||
merge_info.style.visibility = "visible";
|
||||
}
|
||||
|
||||
function connect_merge_process()
|
||||
{
|
||||
$.ajax(
|
||||
{
|
||||
url: "http://114.212.189.166:8001/merge_process",
|
||||
type: "post",
|
||||
success: function(message)
|
||||
{
|
||||
var state = message["state"];
|
||||
if(state == 200)
|
||||
$("p#merge").text(message["process"]);
|
||||
else
|
||||
alert("合并失败:" + message["msg"]);
|
||||
},
|
||||
error: function()
|
||||
{
|
||||
alert("服务器连接失败");
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
//向服务器发送保存合并好的文件的请求
|
||||
function connect_save_result(tempname, filename, app)
|
||||
{
|
||||
$.ajax(
|
||||
{
|
||||
url: "http://114.212.189.166:8001/save_result",
|
||||
type: "post",
|
||||
dataType: "json",
|
||||
data: JSON.stringify({'tempname': tempname,
|
||||
'filename': filename, 'app': app,
|
||||
'cookie': window.localStorage["cookie"]}),
|
||||
contentType:'application/json; charset=utf-8',
|
||||
success: function(message)
|
||||
{
|
||||
var state = message["state"];
|
||||
if(state == 200)
|
||||
merge_file();
|
||||
else
|
||||
alert("保存失败:" + message["msg"]);
|
||||
},
|
||||
error: function()
|
||||
{
|
||||
alert("服务器连接失败");
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
//向服务器发送删除合并好的文件的请求
|
||||
function connect_delete_result(tempname)
|
||||
{
|
||||
$.ajax(
|
||||
{
|
||||
url: "http://114.212.189.166:8001/abort_result",
|
||||
type: "post",
|
||||
dataType: "json",
|
||||
data: JSON.stringify({'tempname': tempname}),
|
||||
contentType:'application/json; charset=utf-8',
|
||||
success: function(message)
|
||||
{
|
||||
var state = message["state"];
|
||||
if(state == 200)
|
||||
merge_file();
|
||||
else
|
||||
alert("删除失败:" + message["msg"]);
|
||||
},
|
||||
error: function()
|
||||
{
|
||||
alert("服务器连接失败");
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
//从模型合并界面跳转到结果展示界面,并展示合并结果
|
||||
function display_result(tempname, app)
|
||||
{
|
||||
window.location.assign("result.html?display_file="+ tempname
|
||||
+ "&display_app=" + app);
|
||||
}
|
||||
|
||||
//从结果展示界面跳转到模型合并界面
|
||||
function merge_file()
|
||||
{
|
||||
window.location.assign("merge.html");
|
||||
}
|
||||
|
||||
//将合并完成后的文件保存至服务器
|
||||
function save_result()
|
||||
{
|
||||
var button1 = document.getElementById("button1");
|
||||
button1.style.visibility = "hidden";
|
||||
var button2 = document.getElementById("button2");
|
||||
button2.style.visibility = "hidden";
|
||||
var button3 = document.getElementById("button3");
|
||||
button3.style.visibility = "hidden";
|
||||
var button4 = document.getElementById("button4");
|
||||
button4.style.visibility = "hidden";
|
||||
var form = document.getElementById("form");
|
||||
form.style.visibility = "visible";
|
||||
}
|
||||
|
||||
//放弃合并结果
|
||||
function abort_result()
|
||||
{
|
||||
var url = document.URL;
|
||||
var index1 = url.indexOf("display_file=");
|
||||
var index2 = url.indexOf("display_app=");
|
||||
var tempname = url.substring(index1 + 13, index2 - 1);
|
||||
connect_delete_result(tempname);
|
||||
}
|
||||
|
||||
//取消保存
|
||||
function cancel_save()
|
||||
{
|
||||
var button1 = document.getElementById("button1");
|
||||
button1.style.visibility = "visible";
|
||||
var button2 = document.getElementById("button2");
|
||||
button2.style.visibility = "visible";
|
||||
var button3 = document.getElementById("button3");
|
||||
button3.style.visibility = "visible";
|
||||
var button4 = document.getElementById("button4");
|
||||
button4.style.visibility = "visible";
|
||||
var form = document.getElementById("form");
|
||||
form.style.visibility = "hidden";
|
||||
}
|
||||
|
||||
//确认保存
|
||||
function save()
|
||||
{
|
||||
filename = document.getElementById("file_name");
|
||||
if(!filename.value)
|
||||
{
|
||||
alert("请输入文件名称");
|
||||
return;
|
||||
}
|
||||
var url = document.URL;
|
||||
var index1 = url.indexOf("display_file=");
|
||||
var index2 = url.indexOf("display_app=");
|
||||
var tempname = url.substring(index1 + 13, index2 - 1);
|
||||
var app = url.substring(index2 + 12);
|
||||
connect_save_result(tempname, filename.value, app);
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
@Time : 2021/6/1 20:04 下午
|
||||
@Author : Tang Jiaxin
|
||||
文件删除功能
|
||||
*/
|
||||
|
||||
//向服务器发送文件删除请求
|
||||
function connect_remove_file()
|
||||
{
|
||||
var items = document.getElementsByClassName("checkbox");
|
||||
var files = {"files": []};
|
||||
for(let i = 0; i < items.length; i++)
|
||||
{
|
||||
if(!items[i].checked)
|
||||
continue;
|
||||
var t = items[i].value.split(" ");
|
||||
var file = t[1];
|
||||
files["files"].push(file);
|
||||
}
|
||||
if(files["files"].length == 0)
|
||||
{
|
||||
alert("请选择待删除的文件");
|
||||
return;
|
||||
}
|
||||
$.ajax(
|
||||
{
|
||||
url: "http://114.212.189.166:8001/file_remove",
|
||||
type: "post",
|
||||
dataType: "json",
|
||||
data: JSON.stringify(files),
|
||||
contentType:'application/json; charset=utf-8',
|
||||
success: function(message)
|
||||
{
|
||||
var state = message["state"];
|
||||
if(state == 200)
|
||||
connect_display_file_list(true);
|
||||
else
|
||||
alert("删除失败:" + message["msg"]);
|
||||
},
|
||||
error: function()
|
||||
{
|
||||
alert("服务器连接失败");
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
//删除文件
|
||||
function remove_file()
|
||||
{
|
||||
var items = document.getElementsByClassName("checkbox");
|
||||
for(let i = 0; i < items.length; i++)
|
||||
items[i].style.display = "inline";
|
||||
var button2 = document.getElementById("button2");
|
||||
button2.style.visibility = "visible";
|
||||
var button4 = document.getElementById("button4");
|
||||
button4.style.visibility = "visible";
|
||||
var button1 = document.getElementById("button1");
|
||||
button1.style.visibility = "hidden";
|
||||
var button3 = document.getElementById("button3");
|
||||
button3.style.visibility = "hidden";
|
||||
}
|
||||
|
||||
//取消删除文件
|
||||
function cancel_remove()
|
||||
{
|
||||
var items = document.getElementsByClassName("checkbox");
|
||||
for(let i = 0; i < items.length; i++)
|
||||
items[i].style.display = "none";
|
||||
var button2 = document.getElementById("button2");
|
||||
button2.style.visibility = "hidden";
|
||||
var button4 = document.getElementById("button4");
|
||||
button4.style.visibility = "hidden";
|
||||
var button1 = document.getElementById("button1");
|
||||
button1.style.visibility = "visible";
|
||||
var button3 = document.getElementById("button3");
|
||||
button3.style.visibility = "visible";
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
@Time : 2021/7/14 9:05 上午
|
||||
@Author : Tang Jiaxin
|
||||
文件上传功能,向服务器上传文件
|
||||
*/
|
||||
|
||||
function connect_upload()
|
||||
{
|
||||
var file = document.getElementById("file_form");
|
||||
var file_name = file["input_file"].value;
|
||||
if(!file_name)
|
||||
{
|
||||
$("p#response").text("请选择文件!");
|
||||
return;
|
||||
}
|
||||
var index1 = file_name.lastIndexOf("_");
|
||||
var index2 = file_name.indexOf(".zip");
|
||||
var app_name = file_name.substring(index1 + 1, index2);
|
||||
var formData = new FormData(file);
|
||||
formData.append("app", app_name);
|
||||
formData.append("cookie", window.localStorage["cookie"]);
|
||||
$.ajax(
|
||||
{
|
||||
url: "http://114.212.189.166:8001/file_upload",
|
||||
type: "post",
|
||||
data: formData,
|
||||
dataType: "json",
|
||||
processData: false,
|
||||
contentType: false,
|
||||
xhr: function()
|
||||
{
|
||||
myXhr = $.ajaxSettings.xhr();
|
||||
if(myXhr.upload)
|
||||
{
|
||||
myXhr.upload.addEventListener("progress",
|
||||
progressHandlingFunction, false);
|
||||
}
|
||||
return myXhr;
|
||||
},
|
||||
beforeSend: function()
|
||||
{
|
||||
ot = new Date().getTime();
|
||||
oloaded = 0;
|
||||
},
|
||||
success: function(message)
|
||||
{
|
||||
state = message["state"];
|
||||
if(state == 200)
|
||||
$("p#response").text("文件上传成功");
|
||||
else
|
||||
$("p#response").text("文件上传失败:" + message["msg"]);
|
||||
var return_button = document.getElementById("return");
|
||||
return_button.style.visibility = "visible";
|
||||
},
|
||||
error: function()
|
||||
{
|
||||
$("p#response").text("服务器连接失败");
|
||||
var return_button = document.getElementById("return");
|
||||
return_button.style.visibility = "visible";
|
||||
}
|
||||
}
|
||||
)
|
||||
function progressHandlingFunction(evt)
|
||||
{
|
||||
var nt = new Date().getTime();
|
||||
var pertime = (nt - ot) / 1000;
|
||||
ot = new Date().getTime();
|
||||
var perload = evt.loaded - oloaded;
|
||||
oloaded = evt.loaded;
|
||||
var speed = perload / pertime;
|
||||
speed = speed.toFixed(1);
|
||||
var resttime = ((evt.total - evt.loaded) / speed).toFixed(1);
|
||||
var percent = evt.loaded / evt.total * 100;
|
||||
$("p#response").text("当前速度:" + (speed / 1024).toFixed(2)
|
||||
+ "KB/s,剩余时间:" + resttime + "s,当前进度:"
|
||||
+ percent.toFixed(2) + "%");
|
||||
}
|
||||
var return_button = document.getElementById("return");
|
||||
return_button.style.visibility = "hidden";
|
||||
}
|
|
@ -0,0 +1,360 @@
|
|||
html,body
|
||||
{
|
||||
background-color: #000;
|
||||
font-family: 'Poppins', sans-serif;
|
||||
/* background: #202626; */
|
||||
font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
color: #000;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100vh;
|
||||
position: relative;
|
||||
background-image: url(../pictures/bg.jpg);
|
||||
background-size: cover;
|
||||
overflow: hidden;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
.block0{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 3vh;
|
||||
position: relative;
|
||||
/* background-image: url(bg.jpg); */
|
||||
/* background-size: cover;
|
||||
background-repeat: no-repeat; */
|
||||
}
|
||||
.block0 .box3{
|
||||
margin-top: 3vh;
|
||||
position: absolute;
|
||||
left: 20%;
|
||||
top: 50%;
|
||||
transform: translate(-50%,-50%);
|
||||
}
|
||||
.box3 h1{
|
||||
font-size: 3em;
|
||||
color: rgba(255, 255, 255, 1);
|
||||
background-image: url(../imgs/water.png);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 8px;
|
||||
/* 注意添加私有前缀 */
|
||||
-webkit-background-clip: text;
|
||||
font-weight: 800;
|
||||
animation: wave 10s linear infinite;
|
||||
}
|
||||
.abstract
|
||||
{
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
transform: translate(-50%,-50%);
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
height: 1vh;
|
||||
}
|
||||
.abstract h1
|
||||
{
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%,-50%);
|
||||
}
|
||||
.swiper-container
|
||||
{
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding-top: 50px;
|
||||
padding-bottom: 50px;
|
||||
}
|
||||
|
||||
.swiper-slide
|
||||
{
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
width: 300px;
|
||||
height: 420px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.swiper-slide .imgBx
|
||||
{
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.swiper-slide .imgBx img
|
||||
{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
/* padding-bottom: 100%; */
|
||||
overflow:hidden;
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
-webkit-background-size:cover;
|
||||
-moz-background-size:cover;
|
||||
background-size:cover;
|
||||
}
|
||||
|
||||
.swiper-slide .details
|
||||
{
|
||||
box-sizing: border-box;
|
||||
height:120px;
|
||||
font-size: 10px;
|
||||
padding: 20px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.swiper-slide .details h3
|
||||
{
|
||||
margin: 0 ;
|
||||
padding: 0;
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.swiper-slide .details h3 span
|
||||
{
|
||||
font-size: 16px;
|
||||
color: burlywood;
|
||||
}
|
||||
|
||||
|
||||
.swiper-slide .details p
|
||||
{
|
||||
font-size: 14px;
|
||||
color:gray;
|
||||
opacity: 0.6;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
|
||||
.block{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 10vh;
|
||||
position: relative;
|
||||
/* background-image: url(bg.jpg); */
|
||||
/* background-size: cover;
|
||||
background-repeat: no-repeat; */
|
||||
}
|
||||
.box3{
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%,-50%);
|
||||
}
|
||||
.box3 p{
|
||||
font-size:2em;
|
||||
color: rgba(255, 255, 255, 0.3);
|
||||
background-image: url("../imgs/water.png");
|
||||
|
||||
background-repeat: round;
|
||||
background-position: bottom;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 8px;
|
||||
text-align: center;
|
||||
/* 注意添加私有前缀 */
|
||||
-webkit-background-clip: text;
|
||||
font-weight: 500;
|
||||
animation: wave 15s linear infinite;
|
||||
}
|
||||
@keyframes wave{
|
||||
from{
|
||||
background-position: 0 0;
|
||||
}
|
||||
to{
|
||||
background-position: 1000px 0;
|
||||
}
|
||||
}
|
||||
|
||||
body .block2
|
||||
{
|
||||
/* position: relative;
|
||||
width: 1080px;
|
||||
height: 100px; */
|
||||
background-color:rgba(0, 0, 0, 0.5);
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
/* padding-bottom: 0;
|
||||
margin-bottom: 0; */
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
.icons{
|
||||
display: inline-flex;
|
||||
position: relative;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.icons a{
|
||||
margin: 0 25px;
|
||||
text-decoration: none;
|
||||
color: #fff;
|
||||
display: block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.icons a .layer{
|
||||
width: 55px;
|
||||
height: 55px;
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
|
||||
.icons a:hover .layer{
|
||||
transform: rotate(-35deg) skew(20deg);
|
||||
}
|
||||
|
||||
.icons a .layer span{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
border: 1px solid #fff;
|
||||
border-radius: 5px;
|
||||
transition: all .3s;
|
||||
}
|
||||
|
||||
.icons a .layer span.fab{
|
||||
font-size: 20px;
|
||||
line-height: 55px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.icons a:hover .layer span:nth-child(1){
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
.icons a:hover .layer span:nth-child(2){
|
||||
opacity: 0.4;
|
||||
transform: translate(5px, -5px);
|
||||
}
|
||||
|
||||
.icons a:hover .layer span:nth-child(3){
|
||||
opacity: 0.6;
|
||||
transform: translate(10px, -10px);
|
||||
}
|
||||
|
||||
.icons a:hover .layer span:nth-child(4){
|
||||
opacity: 0.8;
|
||||
transform: translate(15px, -15px);
|
||||
}
|
||||
|
||||
.icons a:hover .layer span:nth-child(5){
|
||||
opacity: 1;
|
||||
transform: translate(20px, -20px);
|
||||
}
|
||||
|
||||
.icons a:nth-child(1) .layer span,
|
||||
.icons a:nth-child(1) .text{
|
||||
color: #4267B2;
|
||||
border-color: #4267B2;
|
||||
}
|
||||
|
||||
.icons a:nth-child(2) .layer span,
|
||||
.icons a:nth-child(2) .text{
|
||||
color: #1DA1F2;
|
||||
border-color: #1DA1F2;
|
||||
}
|
||||
|
||||
.icons a:nth-child(3) .layer span,
|
||||
.icons a:nth-child(3) .text{
|
||||
color: #E1306C;
|
||||
border-color: #E1306C;
|
||||
}
|
||||
|
||||
.icons a:nth-child(4) .layer span,
|
||||
.icons a:nth-child(4) .text{
|
||||
color: #2867B2;
|
||||
border-color: #2867B2;
|
||||
}
|
||||
|
||||
.icons a:nth-child(5) .layer span,
|
||||
.icons a:nth-child(5) .text{
|
||||
color: #ff0000;
|
||||
border-color: #ff0000;
|
||||
}
|
||||
|
||||
.icons a:nth-child(1) .layer span{
|
||||
box-shadow: -1px 1px 3px #4267B2;
|
||||
}
|
||||
|
||||
.icons a:nth-child(2) .layer span{
|
||||
box-shadow: -1px 1px 3px #1DA1F2;
|
||||
}
|
||||
|
||||
.icons a:nth-child(3) .layer span{
|
||||
box-shadow: -1px 1px 3px #E1306C;
|
||||
}
|
||||
|
||||
.icons a:nth-child(4) .layer span{
|
||||
box-shadow: -1px 1px 3px #4267B2;
|
||||
}
|
||||
|
||||
.icons a:nth-child(5) .layer span{
|
||||
box-shadow: -1px 1px 3px #ff0000;
|
||||
}
|
||||
|
||||
.icons a .text{
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: -5px;
|
||||
opacity: 0;
|
||||
transform: translateX(-50%);
|
||||
transition: bottom .3s ease, opacity .3s ease;
|
||||
}
|
||||
|
||||
.icons a:hover .text{
|
||||
bottom: -35px;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@font-face {font-family: "iconfont";
|
||||
src: url('iconfont.eot?t=1593756665368'); /* IE9 */
|
||||
src: url('iconfont.eot?t=1593756665368#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||
url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAWcAAsAAAAACtQAAAVQAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDMgqIaIcVATYCJAMUCwwABCAFhG0HUxssCREVpAGS/UywY7oMa60OvwwW6dZkz9Omzft/l5LdCLIQMxoRJaIVJzURaB3uHKmawZkIAXBsrjUr6dK3aVx969qRA6bgvyVAgN7BsdTPBMv7SpfqWFsF4GjAA4pI/NAV8AY0son4FvFMM5+T8DgQAAkxyADVN3bsCTUEiMcRABo/ZtQQqD0BCAlMgtqtirhUAL0CEWq2it0H8LLx8/QN8kgNMIgc4qldRzYMh/nz0i84t/qt6K8hYKwuBoC9CuAAMgAIAE2NTIwHtxoZ4JA+vyfADECCGgzs89LPyz+/8wX3+7+WAbkk6R8eIICBwAFSQXQEItZsFybOqBgcZznxgRHnHSIFAr7gTiwvWrxEAqABaCJANyBSTFBSg4OBSyPQhukkata0atIUlTLOvtu6x7HPtlcaYt9udTk8Nrdk8eqj3kIeFXz9eZywxdsQcuuNRHGrr3G0/WRSz7aHvoQ33mjzenu5pefPe1rDndKQXpbtxyWfzwJT1j8vsdidZVVpnmSBfqrkdkpkdirO22V7L6bRWkXo4LFQT2iXvYlsRqPFbZTcdkWK7d4dtt4bfcQr9rSc8BbvCk3R6zHKHhsNqn1Ba2yWbLNNynbTbV/rXZ/Yk3fUl7/u0Fcr77bDYEjt5VqzWlGccGFHp9VwwFvq2hFaLXk8BlK6DbLL0MvgUgmyo9c5T2PfDVVvR6V17KN2tr393VeN1sMpO84oTl/R8edG97nkvUfJeVmxb81fF9nm6+GVPXutCT+yeZ5bCrYrx5+DtWgM3ObrOXi3PW3ojNW7TcE790ZwW+iIPXcc99JHuVBeG1IfI4mH6K7JIWH+TGCfeRGzswqat3TuHNEcoa7bYg3i5dqwXdP7ZYZ3ZkVtIhv0+ryJbCi9OkLX5XDQQJo/ndqi58BtbP305qYk0yz9IJo/jrpQ1/lj4Yq+tGgs6yrndnyx+LtAf1NfGcj9cSPZhhOYGJdDmGWq5YfPTjnhxKcHw9YG5Ci1sxKJiQwYZtWCtKKGNNrZ0tB32cD/9ZWDu/cYUhnnH8Aftr+FW7O0xJjID6XIXbocXnkYI/JK/MsXmjvuOZeG8NldJ/Ihr4+r69uvfmxqEp+kzB5+fs11HDt8QhM3YvEYS2lf6rMTrL1xw/+dO3/wVY+aTlTuMqP/icG4fISOLbcNN9SOyiBWGZyCsh4trSH1IcqpV5ce7amPvPiWsLT/naXIr4PX3ek4XXjrYqS+/qhKlB17w2vYyN6OIWww672Kjfbceq9DFlH42qdXgxYGXT1VXJP1Fq+rz1mZQ0X5W1nv7taKgN/zSvLIUA7L4j3zSvM98S1RUKhWV6CrVUgQMRsA4H/MD/Mcg32QP+Xdjz7J7/JWAOAX2Rdn9mHYOvXvnwaFVPymli/2be+Yvv0L8/6DAooZTk8nMhvPY2PGdcLXLAZF4b1QMbwni9gKNXBOmE7ZeWdvRof3q3EZMjMBchkcYGiHaOBQw4QUsBkgQkYBqKBGNUhIR9PVMvSYCg4SAgCkYRkAQYNDwBCMS8ChwQOkgH0PRBjxHaigIQ4SLKS/pQzCpTHV1SEJyIGeMDG9CzkcKnP6C2VciXObDdYPnZ/K0Dedv/3EHV0VZ/gkhxAECKc3eMDTcF01GKdnZKFRIZixbUXUmBqmt6xydUgCckBPMDG9C23rUAW+/4UyrsQlLPrR/KHz085Br9FlQD4de6ZFuzLXJzkIWBNAsFP1Bh4Yw1VqaGCiD5qRhYYqUDOjFjcTWR1N865tHRsfoiXFQYgx4iSQSCoU13+cjmnP+UR2FUlpbe2t0euwOHU8QuIyywA=') format('woff2'),
|
||||
url('iconfont.woff?t=1593756665368') format('woff'),
|
||||
url('iconfont.ttf?t=1593756665368') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
|
||||
url('iconfont.svg?t=1593756665368#iconfont') format('svg'); /* iOS 4.1- */
|
||||
}
|
||||
|
||||
.block2 .icons .iconfont {
|
||||
font-family: "iconfont" !important;
|
||||
font-size: 30px;
|
||||
line-height: 55px;
|
||||
text-align: center;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-z-weixin:before {
|
||||
content: "\e6c9";
|
||||
}
|
||||
|
||||
.icon-dianhua:before {
|
||||
content: "\e63b";
|
||||
}
|
||||
|
||||
.icon-qq-square:before {
|
||||
content: "\e703";
|
||||
}
|
||||
|
||||
.icon-youxiang:before {
|
||||
content: "\e639";
|
||||
}
|
||||
.button {
|
||||
position: absolute;
|
||||
top: 70%;
|
||||
width: 100%;
|
||||
height: 50%;
|
||||
font: 16px Arial, sans-serif bold;
|
||||
color: white;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
border-radius: 50px;
|
||||
cursor: pointer;
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
/***********************通用的样式***********************/
|
||||
body{
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
color: #000;
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
-webkit-text-size-adjust:100%;
|
||||
|
||||
}
|
||||
|
||||
|
||||
.btn-register {
|
||||
color: #FFFFFF;
|
||||
background-color: #0AB4F7;
|
||||
border-color: #F4F7F7;
|
||||
}
|
||||
|
||||
.btn-register:hover,
|
||||
.btn-register:focus,
|
||||
.btn-register:active,
|
||||
.btn-register.active,
|
||||
.open .dropdown-toggle.btn-register {
|
||||
color: #FFFFFF;
|
||||
background-color: #086DF2;
|
||||
border-color: #F4F7F7;
|
||||
}
|
||||
|
||||
.btn-register:active,
|
||||
.btn-register.active,
|
||||
.open .dropdown-toggle.btn-register {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.btn-register.disabled,
|
||||
.btn-register[disabled],
|
||||
fieldset[disabled] .btn-register,
|
||||
.btn-register.disabled:hover,
|
||||
.btn-register[disabled]:hover,
|
||||
fieldset[disabled] .btn-register:hover,
|
||||
.btn-register.disabled:focus,
|
||||
.btn-register[disabled]:focus,
|
||||
fieldset[disabled] .btn-register:focus,
|
||||
.btn-register.disabled:active,
|
||||
.btn-register[disabled]:active,
|
||||
fieldset[disabled] .btn-register:active,
|
||||
.btn-register.disabled.active,
|
||||
.btn-register[disabled].active,
|
||||
fieldset[disabled] .btn-register.active {
|
||||
background-color: #0AB4F7;
|
||||
border-color: #F4F7F7;
|
||||
}
|
||||
|
||||
.btn-register .badge {
|
||||
color: #0AB4F7;
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: lk;
|
||||
src: url('../fonts/lk.eot') format('embedded-opentype'),
|
||||
url('../fonts/lk.svg') format('svg'),
|
||||
url('../fonts/lk.ttf') format('truetype'),
|
||||
url('../fonts/lk.woff') format('woff');
|
||||
}
|
||||
|
||||
[class^="icon-"],
|
||||
[class*=" icon-"]{
|
||||
font-family: lk;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
|
||||
#lk_about, #lk_hot, #lk_link{
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
#lk_about .title, #lk_hot .title, #lk_link .title{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***********************通用的样式***********************/
|
||||
|
||||
|
||||
/***********************头部的样式***********************/
|
||||
#lk_header{
|
||||
|
||||
}
|
||||
|
||||
|
||||
.icon-phone::before{
|
||||
content: '\e958';
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.icon-tel::before{
|
||||
content: '\e942';
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
|
||||
#lk_header .navbar-lk{
|
||||
/* background-color: #FFF; */
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#lk_header .navbar-lk .navbar-brand{
|
||||
height: 70px;
|
||||
padding: 10px 15px;
|
||||
}
|
||||
|
||||
#lk_header .navbar-lk .navbar-nav a{
|
||||
height: 70px;
|
||||
line-height: 40px;
|
||||
color:white;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
font-family: "Yahei";
|
||||
}
|
||||
|
||||
#lk_header .navbar-lk .navbar-nav li.active a,
|
||||
#lk_header .navbar-lk .navbar-nav li a:hover{
|
||||
background-color: transparent;
|
||||
border-bottom: 2px solid #0AB4F7;
|
||||
}
|
||||
|
||||
#lk_header .navbar-lk .navbar-toggle {
|
||||
margin-top: 18px;
|
||||
}
|
||||
|
||||
#lk_nav a{
|
||||
color: white;
|
||||
}
|
||||
|
||||
/***********************头部的样式***********************/
|
||||
|
||||
/***********************焦点图的样式***********************/
|
||||
#lk_carousel{
|
||||
|
||||
}
|
||||
|
||||
#lk_carousel .item{
|
||||
|
||||
background: no-repeat center center;
|
||||
|
||||
-webkit-background-size: cover;
|
||||
background-si
|
||||
}
|
||||
|
||||
@media screen and ( min-width: 800px){
|
||||
#lk_carousel .item{
|
||||
height: 850px;
|
||||
}
|
||||
}
|
||||
/***********************焦点图的样式***********************/
|
|
@ -0,0 +1,82 @@
|
|||
<!DOCTYPE html>
|
||||
<!--
|
||||
@Time : 2021/7/13 12:55 下午
|
||||
@Author : Tang Jiaxin
|
||||
文件展示界面,展示一个ARP模型文件
|
||||
-->
|
||||
<html lang="zh-cn">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>文件展示</title>
|
||||
<script src="https://ajax.microsoft.com/ajax/jquery/jquery-3.5.1.js"></script>
|
||||
<script src="connect_download.js"></script>
|
||||
</head>
|
||||
<style type="text/css">
|
||||
html, body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
body {
|
||||
background: url(pictures/background.jpg);
|
||||
background-size: cover;
|
||||
}
|
||||
div {
|
||||
position: absolute;
|
||||
left: 5%;
|
||||
top: 10%;
|
||||
height: 75%;
|
||||
width: 90%;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
overflow: auto;
|
||||
}
|
||||
h1 {
|
||||
text-align: center;
|
||||
color: chartreuse;
|
||||
font-family: 楷体;
|
||||
}
|
||||
button {
|
||||
position: absolute;
|
||||
height: 6%;
|
||||
top: 90%;
|
||||
font:16px Arial,sans-serif bold;
|
||||
color: white;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
border-radius:50px;
|
||||
cursor: pointer;
|
||||
}
|
||||
#button1 {
|
||||
left: 35%;
|
||||
width: 8%;
|
||||
}
|
||||
#button2 {
|
||||
left: 46%;
|
||||
width: 10%;
|
||||
}
|
||||
#button3 {
|
||||
left: 60%;
|
||||
width: 6%;
|
||||
}
|
||||
p {
|
||||
position: absolute;
|
||||
left: 10%;
|
||||
top: 10%;
|
||||
font-size: 20px;
|
||||
color: white;
|
||||
font-family: 楷体;
|
||||
}
|
||||
</style>
|
||||
<body onload="connect_display_file()">
|
||||
<h1>文件展示</h1>
|
||||
<div>
|
||||
<p id="response"></p><br>
|
||||
</div>
|
||||
<button id="button1" onclick="connect_download_file()">下载文件</button>
|
||||
<button id="button2" onclick="graph_display()">可视化展示</button>
|
||||
<button id="button3">返回</button>
|
||||
</body>
|
||||
<script>
|
||||
document.getElementById("button3").onclick=function() {
|
||||
window.history.back();
|
||||
}
|
||||
</script>
|
||||
</html>
|
|
@ -0,0 +1,53 @@
|
|||
<!DOCTYPE html>
|
||||
<!--
|
||||
@Time : 2021/5/10 17:44 下午
|
||||
@Author : Tang Jiaxin
|
||||
初始界面,显示APP的标题和入口
|
||||
-->
|
||||
<html lang="zh-cn">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>APP模型合并</title>
|
||||
</head>
|
||||
<style type="text/css">
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
background: url(pictures/background.jpg);
|
||||
background-size: cover;
|
||||
}
|
||||
div {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
.app_title {
|
||||
color: white;
|
||||
font-size: 50px;
|
||||
}
|
||||
.enter_img {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
.enter_img:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<div>
|
||||
<p class="app_title">
|
||||
APP模型合并
|
||||
</p>
|
||||
<img src="pictures/star.png" alt="进入系统" class="enter_img" id="entrance">
|
||||
</div>
|
||||
</body>
|
||||
<script>
|
||||
document.getElementById("entrance").onclick=function() {
|
||||
window.location.assign("login.html");
|
||||
}
|
||||
</script>
|
||||
</html>
|
|
@ -0,0 +1,104 @@
|
|||
<!DOCTYPE html>
|
||||
<!--
|
||||
@Time : 2021/6/1 20:40 下午
|
||||
@Author : Tang Jiaxin
|
||||
文件查看界面,查看当前已经上传至服务器的文件
|
||||
-->
|
||||
<html lang="zh-cn">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>文件查看</title>
|
||||
<script src="https://ajax.microsoft.com/ajax/jquery/jquery-3.5.1.js"></script>
|
||||
<script src="connect_download.js"></script>
|
||||
<script src="connect_remove.js"></script>
|
||||
</head>
|
||||
<style type="text/css">
|
||||
html, body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
body {
|
||||
background: url(pictures/background.jpg);
|
||||
background-size: cover;
|
||||
}
|
||||
div {
|
||||
position: absolute;
|
||||
left: 5%;
|
||||
top: 10%;
|
||||
height: 75%;
|
||||
width: 90%;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
overflow: auto;
|
||||
}
|
||||
h1 {
|
||||
text-align: center;
|
||||
color: chartreuse;
|
||||
font-family: 楷体;
|
||||
}
|
||||
button {
|
||||
position: absolute;
|
||||
height: 6%;
|
||||
top: 90%;
|
||||
font:16px Arial, sans-serif bold;
|
||||
color: white;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
border-radius:50px;
|
||||
cursor: pointer;
|
||||
}
|
||||
#button1, #button2 {
|
||||
left: 40%;
|
||||
width: 8%;
|
||||
}
|
||||
#button3, #button4 {
|
||||
left: 55%;
|
||||
width: 6%;
|
||||
}
|
||||
#button2, #button4 {
|
||||
visibility: hidden;
|
||||
}
|
||||
p {
|
||||
position: absolute;
|
||||
left: 10%;
|
||||
top: 20%;
|
||||
color: white;
|
||||
font-size: 20px;
|
||||
font-family: 楷体;
|
||||
}
|
||||
table {
|
||||
position: absolute;
|
||||
left: 10%;
|
||||
top: 10%;
|
||||
width: 80%;
|
||||
}
|
||||
th, td {
|
||||
color: white;
|
||||
}
|
||||
th {
|
||||
font-size: 25px;
|
||||
font-family: 楷体;
|
||||
}
|
||||
td {
|
||||
text-align: center;
|
||||
}
|
||||
a {
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
<body onload="connect_display_file_list(false)">
|
||||
<h1>当前服务器上的文件列表</h1>
|
||||
<div>
|
||||
<table id="table">
|
||||
</table>
|
||||
<p id="response"></p>
|
||||
</div>
|
||||
<button id="button1" onclick="remove_file()">删除文件</button>
|
||||
<button id="button2" onclick="connect_remove_file()">确认删除</button>
|
||||
<button id="button3">返回</button>
|
||||
<button id="button4" onclick="cancel_remove()">取消</button>
|
||||
</body>
|
||||
<script>
|
||||
document.getElementById("button3").onclick=function() {
|
||||
window.history.back();
|
||||
}
|
||||
</script>
|
||||
</html>
|
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE html>
|
||||
<!--
|
||||
@Time : 2021/7/13 12:54 下午
|
||||
@Author : Tang Jiaxin
|
||||
可视化界面,展示可视化的arp模型
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>可视化展示</title>
|
||||
<script src="https://ajax.microsoft.com/ajax/jquery/jquery-3.5.1.js"></script>
|
||||
<script src="connect_download.js"></script>
|
||||
</head>
|
||||
<body onload="connect_graph_display()">
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,84 @@
|
|||
function contact() {
|
||||
var r = confirm("想要获取我们的联系方式吗?");
|
||||
|
||||
if (r == true) {
|
||||
window.alert("E-mai: 191820019@smail.nju.edu.cn \n author by Chen Wenjie");
|
||||
}
|
||||
}
|
||||
|
||||
$(function () {
|
||||
$(window).on("resize", function () {
|
||||
// 1.1 获取窗口的宽度
|
||||
let clientW = $(window).width();
|
||||
// console.log(clientW);
|
||||
|
||||
// 1.2 设置临界值
|
||||
let isShowBigImage = clientW >= 800;
|
||||
|
||||
// 1.3 获取所有的item
|
||||
let $allItems = $("#lk_carousel .item");
|
||||
// console.log($allItems);
|
||||
|
||||
// 1.4 遍历
|
||||
$allItems.each(function (index, item) {
|
||||
// 1.4.1 取出图片的路径
|
||||
let src = isShowBigImage
|
||||
? $(item).data("lg-img")
|
||||
: $(item).data("sm-img");
|
||||
let imgUrl = 'url("' + src + '")';
|
||||
|
||||
// 1.4.2 设置背景
|
||||
$(item).css({
|
||||
backgroundImage: imgUrl,
|
||||
});
|
||||
|
||||
// 1.4.3 设置img标签
|
||||
if (!isShowBigImage) {
|
||||
let $img = "<img src='" + src + "'>";
|
||||
$(item).empty().append($img);
|
||||
} else {
|
||||
$(item).empty();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$(window).trigger("resize");
|
||||
|
||||
// 2. 工具提示
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
|
||||
// 3. 动态处理宽度
|
||||
$(window).on("resize", function () {
|
||||
let $ul = $("#lk_product .nav");
|
||||
let $allLis = $("[role='presentation']", $ul);
|
||||
// console.log($allLis);
|
||||
|
||||
// 3.1 遍历
|
||||
let totalW = 0;
|
||||
$allLis.each(function (index, item) {
|
||||
totalW += $(item).width();
|
||||
});
|
||||
|
||||
// console.log(totalW);
|
||||
|
||||
let parentW = $ul.parent().width();
|
||||
|
||||
// 3.2 设置宽度
|
||||
if (totalW > parentW) {
|
||||
$ul.css({
|
||||
width: totalW + "px",
|
||||
});
|
||||
} else {
|
||||
$ul.removeAttr("style");
|
||||
}
|
||||
});
|
||||
|
||||
// 4. 导航处理
|
||||
let allLis = $("#lk_nav li");
|
||||
|
||||
$(allLis[2]).on("click", function () {
|
||||
$("html,body").animate({ scrollTop: $("#lk_hot").offset().top }, 1000);
|
||||
});
|
||||
|
||||
$(window).trigger("resize");
|
||||
});
|
|
@ -0,0 +1,107 @@
|
|||
<!DOCTYPE html>
|
||||
<!--
|
||||
@Time : 2021/7/10 9:44 上午
|
||||
@Author : Tang Jiaxin
|
||||
登录界面,用户登录
|
||||
-->
|
||||
<html lang="zh-cn">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>用户登录</title>
|
||||
<script src="https://ajax.microsoft.com/ajax/jquery/jquery-3.5.1.js"></script>
|
||||
<script src="connect_login.js"></script>
|
||||
</head>
|
||||
<style type="text/css">
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
background: url(pictures/background.jpg);
|
||||
background-size: cover;
|
||||
}
|
||||
p {
|
||||
color: white;
|
||||
font-size: 20px;
|
||||
}
|
||||
form {
|
||||
position: absolute;
|
||||
left: 30%;
|
||||
top: 20%;
|
||||
height: 80%;
|
||||
width: 55%;
|
||||
}
|
||||
h1 {
|
||||
color: white;
|
||||
text-align: center;
|
||||
}
|
||||
.button {
|
||||
position: absolute;
|
||||
top: 70%;
|
||||
width: 8%;
|
||||
height: 6%;
|
||||
font: 16px Arial, sans-serif bold;
|
||||
color: white;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
border-radius: 50px;
|
||||
cursor: pointer;
|
||||
}
|
||||
#confirm {
|
||||
left: 30%;
|
||||
}
|
||||
#return {
|
||||
left: 40%;
|
||||
}
|
||||
#mail {
|
||||
left: 50%;
|
||||
}
|
||||
#register {
|
||||
left: 60%;
|
||||
}
|
||||
#user_password {
|
||||
margin-left: 27%;
|
||||
}
|
||||
#check_code_img {
|
||||
position: absolute;
|
||||
left: 40%;
|
||||
top: 40%;
|
||||
}
|
||||
#check_code {
|
||||
position: absolute;
|
||||
left: 10%;
|
||||
top: 35%;
|
||||
}
|
||||
</style>
|
||||
<body onload="connect_check_code()">
|
||||
<h1>用户登录</h1>
|
||||
<form id="login_form" method="POST">
|
||||
<div id="user_password">
|
||||
<p>请输入用户名</p>
|
||||
<input type="text" name="user_name" id="user_name">
|
||||
<p>请输入密码</p>
|
||||
<input type="password" name="password" id="password">
|
||||
</div>
|
||||
<br><br>
|
||||
<div id="check_code">
|
||||
<p>请输入验证码</p>
|
||||
<input type="text" name="check_code" id="check_code_input">
|
||||
</div>
|
||||
<div id="check_code_img" onclick="connect_check_code()"></div>
|
||||
</form>
|
||||
<input type="button" class="button" id="confirm"
|
||||
value="确定" onclick="connect_login()">
|
||||
<input type="button" class="button" id="return" value="返回">
|
||||
<input type="button" class="button" id="mail" value="邮箱验证登录">
|
||||
<input type="button" class="button" id="register" value="用户注册">
|
||||
</body>
|
||||
<script>
|
||||
document.getElementById("return").onclick=function() {
|
||||
window.location.assign("entrance.html");
|
||||
}
|
||||
document.getElementById("mail").onclick=function() {
|
||||
window.location.assign("maillogin.html");
|
||||
}
|
||||
document.getElementById("register").onclick=function() {
|
||||
window.location.assign("register.html");
|
||||
}
|
||||
</script>
|
||||
</html>
|
|
@ -0,0 +1,80 @@
|
|||
<!DOCTYPE html>
|
||||
<!--
|
||||
@Time : 2021/7/11 15:44 下午
|
||||
@Author : Tang Jiaxin
|
||||
邮箱绑定界面,为账户绑定邮箱
|
||||
-->
|
||||
<html lang="zh-cn">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>绑定邮箱</title>
|
||||
<script src="https://ajax.microsoft.com/ajax/jquery/jquery-3.5.1.js"></script>
|
||||
<script src="connect_login.js"></script>
|
||||
</head>
|
||||
<style type="text/css">
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
background: url(pictures/background.jpg);
|
||||
background-size: cover;
|
||||
}
|
||||
p {
|
||||
color: white;
|
||||
font-size: 20px;
|
||||
}
|
||||
form {
|
||||
position: absolute;
|
||||
left: 45%;
|
||||
top: 20%;
|
||||
height: 80%;
|
||||
width: 55%;
|
||||
}
|
||||
h1 {
|
||||
color: white;
|
||||
text-align: center;
|
||||
}
|
||||
.button {
|
||||
position: absolute;
|
||||
top: 70%;
|
||||
width: 8%;
|
||||
height: 6%;
|
||||
font: 16px Arial, sans-serif bold;
|
||||
color: white;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
border-radius: 50px;
|
||||
cursor: pointer;
|
||||
}
|
||||
#send {
|
||||
left: 35%;
|
||||
}
|
||||
#confirm {
|
||||
left: 46%;
|
||||
}
|
||||
#return {
|
||||
left: 57%;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<h1>邮箱绑定</h1>
|
||||
<form id="mail_bind_form" method="POST">
|
||||
<div>
|
||||
<p>请输入邮箱</p>
|
||||
<input type="text" name="mail_addr" id="mail_addr">
|
||||
<br><br><br><br>
|
||||
<p>请输入验证码</p>
|
||||
<input type="text" name="check_code" id="check_code">
|
||||
</div>
|
||||
</form>
|
||||
<input type="button" class="button" id="send"
|
||||
value="发送邮件" onclick="connect_mail_bind()">
|
||||
<input type="button" class="button" id="confirm"
|
||||
value="确定" onclick="connect_mail_update()">
|
||||
<input type="button" class="button" id="return" value="返回">
|
||||
</body>
|
||||
<script>
|
||||
document.getElementById("return").onclick=function() {
|
||||
window.history.back();
|
||||
}
|
||||
</script>
|
||||
</html>
|
|
@ -0,0 +1,90 @@
|
|||
<!DOCTYPE html>
|
||||
<!--
|
||||
@Time : 2021/7/10 15:44 下午
|
||||
@Author : Tang Jiaxin
|
||||
邮箱登录界面,通过邮箱认证登录
|
||||
-->
|
||||
<html lang="zh-cn">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>邮箱登录</title>
|
||||
<script src="https://ajax.microsoft.com/ajax/jquery/jquery-3.5.1.js"></script>
|
||||
<script src="connect_login.js"></script>
|
||||
</head>
|
||||
<style type="text/css">
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
background: url(pictures/background.jpg);
|
||||
background-size: cover;
|
||||
}
|
||||
p {
|
||||
color: white;
|
||||
font-size: 20px;
|
||||
}
|
||||
form {
|
||||
position: absolute;
|
||||
left: 30%;
|
||||
top: 20%;
|
||||
height: 80%;
|
||||
width: 55%;
|
||||
}
|
||||
h1 {
|
||||
color: white;
|
||||
text-align: center;
|
||||
}
|
||||
.button {
|
||||
position: absolute;
|
||||
top: 70%;
|
||||
width: 8%;
|
||||
height: 6%;
|
||||
font: 16px Arial, sans-serif bold;
|
||||
color: white;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
border-radius: 50px;
|
||||
cursor: pointer;
|
||||
}
|
||||
#send {
|
||||
left: 30%;
|
||||
}
|
||||
#confirm {
|
||||
left: 40%;
|
||||
}
|
||||
#return {
|
||||
left: 50%;
|
||||
}
|
||||
#password {
|
||||
left: 60%;
|
||||
}
|
||||
div {
|
||||
margin-left: 27%;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<h1>邮件登录</h1>
|
||||
<form id="mail_login_form" method="POST">
|
||||
<div>
|
||||
<p>请输入用户名或邮箱</p>
|
||||
<input type="text" name="user_name" id="user_name">
|
||||
<br><br><br><br>
|
||||
<p>请输入验证码</p>
|
||||
<input type="text" name="check_code" id="check_code">
|
||||
</div>
|
||||
</form>
|
||||
<input type="button" class="button" id="send"
|
||||
value="发送邮件" onclick="connect_mail_login()">
|
||||
<input type="button" class="button" id="confirm"
|
||||
value="确定" onclick="mail_login()">
|
||||
<input type="button" class="button" id="return" value="返回">
|
||||
<input type="button" class="button" id="password" value="用户名密码登录">
|
||||
</body>
|
||||
<script>
|
||||
document.getElementById("return").onclick=function() {
|
||||
window.location.assign("entrance.html");
|
||||
}
|
||||
document.getElementById("password").onclick=function() {
|
||||
window.location.assign("login.html");
|
||||
}
|
||||
</script>
|
||||
</html>
|
|
@ -0,0 +1,108 @@
|
|||
<!DOCTYPE html>
|
||||
<!--
|
||||
@Time : 2021/6/2 23:40 下午
|
||||
@Author : Tang Jiaxin
|
||||
模型合并界面,选择已经上传至服务器的文件进行合并
|
||||
-->
|
||||
<html lang="zh-cn">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>模型合并</title>
|
||||
<script src="https://ajax.microsoft.com/ajax/jquery/jquery-3.5.1.js"></script>
|
||||
<script src="connect_download.js"></script>
|
||||
<script src="connect_merge.js"></script>
|
||||
</head>
|
||||
<style type="text/css">
|
||||
html, body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
body {
|
||||
background: url(pictures/background.jpg);
|
||||
background-size: cover;
|
||||
}
|
||||
div {
|
||||
position: absolute;
|
||||
left: 5%;
|
||||
top: 10%;
|
||||
height: 75%;
|
||||
width: 90%;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
overflow: auto;
|
||||
}
|
||||
h1 {
|
||||
text-align: center;
|
||||
color: chartreuse;
|
||||
font-family: 楷体;
|
||||
}
|
||||
button {
|
||||
position: absolute;
|
||||
height: 6%;
|
||||
top: 90%;
|
||||
font:16px Arial, sans-serif bold;
|
||||
color: white;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
border-radius:50px;
|
||||
cursor: pointer;
|
||||
}
|
||||
#button1 {
|
||||
left: 40%;
|
||||
width: 8%;
|
||||
}
|
||||
#button2 {
|
||||
left: 55%;
|
||||
width: 6%;
|
||||
}
|
||||
p {
|
||||
color: white;
|
||||
font-size: 20px;
|
||||
font-family: 楷体;
|
||||
}
|
||||
#response {
|
||||
position: absolute;
|
||||
left: 10%;
|
||||
top: 20%;
|
||||
}
|
||||
#merge {
|
||||
position: absolute;
|
||||
left: 47%;
|
||||
top: 88%;
|
||||
visibility: hidden;
|
||||
}
|
||||
table {
|
||||
position: absolute;
|
||||
left: 10%;
|
||||
top: 10%;
|
||||
width: 80%;
|
||||
}
|
||||
th, td {
|
||||
color: white;
|
||||
}
|
||||
th {
|
||||
font-size: 25px;
|
||||
font-family: 楷体;
|
||||
}
|
||||
td {
|
||||
text-align: center;
|
||||
}
|
||||
a {
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
<body onload="connect_display_file_list(true)">
|
||||
<h1>请选择需要合并的文件</h1>
|
||||
<div>
|
||||
<table id="table">
|
||||
</table>
|
||||
<p id="response"></p>
|
||||
</div>
|
||||
<button id="button1" onclick="connect_merge()">开始合并</button>
|
||||
<button id="button2">返回</button>
|
||||
<p id="merge">正在合并中...</p>
|
||||
</body>
|
||||
<script>
|
||||
document.getElementById("button2").onclick=function() {
|
||||
window.location.assign("select.html");
|
||||
}
|
||||
</script>
|
||||
</html>
|
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 56 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 59 KiB |
After Width: | Height: | Size: 1.4 MiB |
After Width: | Height: | Size: 1.9 MiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 7.5 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 4.8 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 109 KiB |
After Width: | Height: | Size: 102 KiB |
|
@ -0,0 +1,74 @@
|
|||
<!DOCTYPE html>
|
||||
<!--
|
||||
@Time : 2021/7/9 10:44 上午
|
||||
@Author : Tang Jiaxin
|
||||
注册界面,注册一个新用户
|
||||
-->
|
||||
<html lang="zh-cn">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>用户注册</title>
|
||||
<script src="https://ajax.microsoft.com/ajax/jquery/jquery-3.5.1.js"></script>
|
||||
<script src="connect_login.js"></script>
|
||||
</head>
|
||||
<style type="text/css">
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
background: url(pictures/background.jpg);
|
||||
background-size: cover;
|
||||
}
|
||||
p {
|
||||
color: white;
|
||||
font-size: 20px;
|
||||
}
|
||||
form {
|
||||
position: absolute;
|
||||
left: 45%;
|
||||
top: 20%;
|
||||
height: 80%;
|
||||
width: 55%;
|
||||
}
|
||||
h1 {
|
||||
color: white;
|
||||
text-align: center;
|
||||
}
|
||||
.button {
|
||||
position: absolute;
|
||||
top: 70%;
|
||||
width: 8%;
|
||||
height: 6%;
|
||||
font: 16px Arial, sans-serif bold;
|
||||
color: white;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
border-radius: 50px;
|
||||
cursor: pointer;
|
||||
}
|
||||
#confirm {
|
||||
left: 40%;
|
||||
}
|
||||
#return {
|
||||
left: 52%;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<h1>用户注册</h1>
|
||||
<form id="register_form" method="POST">
|
||||
<p>请输入用户名</p>
|
||||
<input type="text" name="user_name" id="user_name">
|
||||
<p>请输入密码</p>
|
||||
<input type="password" name="password1" id="password1">
|
||||
<p>请再次输入密码</p>
|
||||
<input type="password" name="password2" id="password2">
|
||||
</form>
|
||||
<input type="button" class="button" id="confirm"
|
||||
value="确定" onclick="connect_register()">
|
||||
<input type="button" class="button" id="return" value="返回">
|
||||
</body>
|
||||
<script>
|
||||
document.getElementById("return").onclick=function() {
|
||||
window.history.back();
|
||||
}
|
||||
</script>
|
||||
</html>
|
|
@ -0,0 +1,107 @@
|
|||
<!DOCTYPE html>
|
||||
<!--
|
||||
@Time : 2021/7/13 11:44 上午
|
||||
@Author : Tang Jiaxin
|
||||
结果展示界面,展示合并结果
|
||||
-->
|
||||
<html lang="zh-cn">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>结果展示</title>
|
||||
<script src="https://ajax.microsoft.com/ajax/jquery/jquery-3.5.1.js"></script>
|
||||
<script src="connect_download.js"></script>
|
||||
<script src="connect_merge.js"></script>
|
||||
</head>
|
||||
<style type="text/css">
|
||||
html, body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
body {
|
||||
background: url(pictures/background.jpg);
|
||||
background-size: cover;
|
||||
}
|
||||
div {
|
||||
position: absolute;
|
||||
left: 5%;
|
||||
top: 10%;
|
||||
height: 75%;
|
||||
width: 90%;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
overflow: auto;
|
||||
}
|
||||
h1 {
|
||||
text-align: center;
|
||||
color: chartreuse;
|
||||
font-family: 楷体;
|
||||
}
|
||||
button, #input1, #input2 {
|
||||
font: 16px Arial,sans-serif bold;
|
||||
color: white;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
border-radius:50px;
|
||||
cursor: pointer;
|
||||
}
|
||||
#input1, #input2 {
|
||||
width: 10%;
|
||||
height: 30%;
|
||||
display: inline;
|
||||
}
|
||||
button {
|
||||
position: absolute;
|
||||
top: 90%;
|
||||
height: 6%;
|
||||
}
|
||||
#button1 {
|
||||
left: 40%;
|
||||
width: 8%;
|
||||
}
|
||||
#button2 {
|
||||
left: 50%;
|
||||
width: 12%;
|
||||
}
|
||||
#button3 {
|
||||
left: 65%;
|
||||
width: 8%;
|
||||
}
|
||||
#button4 {
|
||||
left: 30%;
|
||||
width: 8%;
|
||||
}
|
||||
p {
|
||||
font-size: 20px;
|
||||
color: white;
|
||||
font-family: 楷体;
|
||||
display: inline;
|
||||
}
|
||||
#response {
|
||||
position: absolute;
|
||||
left: 10%;
|
||||
top: 10%;
|
||||
}
|
||||
form {
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
top: 90%;
|
||||
left: 30%;
|
||||
width: 60%;
|
||||
height: 10%;
|
||||
}
|
||||
</style>
|
||||
<body onload="connect_display_file()">
|
||||
<h1>结果展示</h1>
|
||||
<div>
|
||||
<p id="response"></p><br>
|
||||
</div>
|
||||
<button id="button4" onclick="graph_display()">可视化展示</button>
|
||||
<button id="button1" onclick="connect_download_file()">下载结果</button>
|
||||
<button id="button2" onclick="save_result()">保存到服务器</button>
|
||||
<button id="button3" onclick="abort_result()">删除结果</button>
|
||||
<form id="form">
|
||||
<p>请输入希望保存的文件名:</p>
|
||||
<input type="text" name="file_name" id="file_name">
|
||||
<input id="input1" type="button" value="确认" onclick="save()">
|
||||
<input id="input2" type="button" value="取消" onclick="cancel_save()">
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,99 @@
|
|||
<!DOCTYPE html>
|
||||
<!--
|
||||
@Time : 2021/7/13 16:31 下午
|
||||
@Author : Tang Jiaxin
|
||||
功能选择界面,选择需要使用的功能
|
||||
-->
|
||||
<html lang="zh-cn">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>功能选择</title>
|
||||
</head>
|
||||
<style type="text/css">
|
||||
html, body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
body {
|
||||
background: url(pictures/background.jpg);
|
||||
background-size: cover;
|
||||
}
|
||||
div {
|
||||
position: absolute;
|
||||
left: 10%;
|
||||
top: 10%;
|
||||
width: 80%;
|
||||
height: 80%;
|
||||
}
|
||||
.function {
|
||||
width: 15%;
|
||||
}
|
||||
.function:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
#upload {
|
||||
position: absolute;
|
||||
left: 42%;
|
||||
top: 0px;
|
||||
}
|
||||
#doc {
|
||||
position: absolute;
|
||||
left: 60%;
|
||||
top: 28%;
|
||||
}
|
||||
#merge {
|
||||
position: absolute;
|
||||
left: 24%;
|
||||
top: 28%;
|
||||
}
|
||||
#member {
|
||||
position: absolute;
|
||||
left: 31%;
|
||||
top: 66%;
|
||||
}
|
||||
#files {
|
||||
position: absolute;
|
||||
left: 53%;
|
||||
top: 66%;
|
||||
}
|
||||
.user {
|
||||
position: fixed;
|
||||
left: 90%;
|
||||
top: 10%;
|
||||
width: 5%;
|
||||
}
|
||||
.user:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<img src="pictures/user.png" class="user" id="user">
|
||||
<div>
|
||||
<img src="pictures/upload.png" class="function" id="upload">
|
||||
<img src="pictures/doc.png" class="function" id="doc">
|
||||
<img src="pictures/merge.png" class="function" id="merge">
|
||||
<img src="pictures/member.png" class="function" id="member">
|
||||
<img src="pictures/files.png" class="function" id="files">
|
||||
</div>
|
||||
</body>
|
||||
<script>
|
||||
document.getElementById("upload").onclick=function() {
|
||||
window.location.assign("upload.html");
|
||||
}
|
||||
document.getElementById("doc").onclick=function() {
|
||||
window.location.assign("documents.html");
|
||||
}
|
||||
document.getElementById("merge").onclick=function() {
|
||||
window.location.assign("merge.html");
|
||||
}
|
||||
document.getElementById("member").onclick=function() {
|
||||
window.location.assign("about.html");
|
||||
}
|
||||
document.getElementById("files").onclick=function() {
|
||||
window.location.assign("files.html");
|
||||
}
|
||||
document.getElementById("user").onclick=function() {
|
||||
window.location.assign("user.html");
|
||||
}
|
||||
</script>
|
||||
</html>
|
|
@ -0,0 +1,83 @@
|
|||
<!DOCTYPE html>
|
||||
<!--
|
||||
@Time : 2021/7/13 12:50 下午
|
||||
@Author : Tang Jiaxin
|
||||
文件上传界面,从本地上传文件到服务器
|
||||
-->
|
||||
<html lang="zh-cn">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>文件上传</title>
|
||||
<script src="https://ajax.microsoft.com/ajax/jquery/jquery-3.5.1.js"></script>
|
||||
<script src="connect_upload.js"></script>
|
||||
</head>
|
||||
<style type="text/css">
|
||||
html, body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
body {
|
||||
background: url(pictures/background.jpg);
|
||||
background-size: cover;
|
||||
}
|
||||
div {
|
||||
position: absolute;
|
||||
left: 0%;
|
||||
top: 0%;
|
||||
height: 100%;
|
||||
width: 40%;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
p {
|
||||
color: white;
|
||||
font-size: 20px;
|
||||
font-family: 楷体;
|
||||
}
|
||||
form {
|
||||
position: absolute;
|
||||
left: 15%;
|
||||
top: 30%;
|
||||
height: 30%;
|
||||
width: 80%;
|
||||
}
|
||||
.button {
|
||||
width: 30%;
|
||||
height: 15%;
|
||||
font: 16px Arial, sans-serif bold;
|
||||
color: white;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
border-radius: 50px;
|
||||
cursor: pointer;
|
||||
}
|
||||
button {
|
||||
position: absolute;
|
||||
left: 40%;
|
||||
top: 80%;
|
||||
width: 20%;
|
||||
height: 6%;
|
||||
font: 16px Arial, sans-serif bold;
|
||||
color: white;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
border-radius: 50px;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<div>
|
||||
<form enctype="multipart/form-data" id="file_form" method="POST">
|
||||
<p>请选择待上传的文件</p>
|
||||
<input type="file" name="input_file" id="input_file">
|
||||
<br><br><br><br>
|
||||
<input type="button" class="button"
|
||||
value="提交文件" onclick="connect_upload()">
|
||||
</form>
|
||||
<p id="response"></p><br>
|
||||
<button id="return">返回</button>
|
||||
</div>
|
||||
</body>
|
||||
<script>
|
||||
document.getElementById("return").onclick=function() {
|
||||
window.history.back();
|
||||
}
|
||||
</script>
|
||||
</html>
|
|
@ -0,0 +1,97 @@
|
|||
<!DOCTYPE html>
|
||||
<!--
|
||||
@Time : 2021/7/11 23:40 下午
|
||||
@Author : Tang Jiaxin
|
||||
用户主页,显示用户的个人信息
|
||||
-->
|
||||
<html lang="zh-cn">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>用户主页</title>
|
||||
<script src="https://ajax.microsoft.com/ajax/jquery/jquery-3.5.1.js"></script>
|
||||
<script src="connect_login.js"></script>
|
||||
</head>
|
||||
<style type="text/css">
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
background: url(pictures/background.jpg);
|
||||
background-size: cover;
|
||||
}
|
||||
p {
|
||||
position: absolute;
|
||||
color: white;
|
||||
font-size: 20px;
|
||||
}
|
||||
div {
|
||||
position: absolute;
|
||||
left: 30%;
|
||||
top: 0%;
|
||||
height: 100%;
|
||||
width: 40%;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
h1 {
|
||||
color: white;
|
||||
text-align: center;
|
||||
}
|
||||
button {
|
||||
position: absolute;
|
||||
top: 70%;
|
||||
width: 18%;
|
||||
height: 6%;
|
||||
font: 16px Arial, sans-serif bold;
|
||||
color: white;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
border-radius: 50px;
|
||||
cursor: pointer;
|
||||
}
|
||||
#user_name {
|
||||
top: 20%;
|
||||
left: 20%;
|
||||
}
|
||||
#mail_addr {
|
||||
top: 30%;
|
||||
left: 20%;
|
||||
}
|
||||
#user_page {
|
||||
top: 10%;
|
||||
left: 40%;
|
||||
}
|
||||
#mail_bind {
|
||||
left: 10%;
|
||||
}
|
||||
#exit {
|
||||
left: 30%;
|
||||
}
|
||||
#change {
|
||||
left: 50%;
|
||||
}
|
||||
#return {
|
||||
left: 70%;
|
||||
}
|
||||
</style>
|
||||
<body onload="get_user_info()">
|
||||
<div>
|
||||
<h1 id="user_page">个人主页</h1>
|
||||
<p id="user_name">用户名:</p>
|
||||
<p id="mail_addr">邮箱:</p>
|
||||
<button id="mail_bind">绑定邮箱</button>
|
||||
<button id="change">修改密码</button>
|
||||
<button id="exit" onclick="exit_account()">退出账号</button>
|
||||
<button id="return">返回</button>
|
||||
</div>
|
||||
</body>
|
||||
<script>
|
||||
document.getElementById("return").onclick=function() {
|
||||
window.history.back();
|
||||
}
|
||||
document.getElementById("mail_bind").onclick=function() {
|
||||
window.location.assign("mailbind.html");
|
||||
}
|
||||
document.getElementById("change").onclick=function() {
|
||||
window.location.assign("changepassword.html");
|
||||
}
|
||||
</script>
|
||||
</html>
|