Commit 2dde9429 authored by wanli's avatar wanli

feat: EUI字体生成工具

前端新增EUI字体生成界面,后端新增EUI字体生成接口
parent 0faf429a
...@@ -48,7 +48,7 @@ backend/*.db-journal ...@@ -48,7 +48,7 @@ backend/*.db-journal
backend/backup/* backend/backup/*
backend/upload/ backend/upload/
backend/uploads/ backend/uploads/
backend/static/ backend/temp/
backend/config.ini backend/config.ini
backend/backupData.json backend/backupData.json
*/app-store.db */app-store.db
......
...@@ -61,6 +61,15 @@ class ConvertString(BaseSchema): ...@@ -61,6 +61,15 @@ class ConvertString(BaseSchema):
class Meta: class Meta:
unknown = EXCLUDE unknown = EXCLUDE
class GenerateFont(BaseSchema):
string = fields.String(required=True) # 字典
font = fields.String(required=True) # 字体文件
sizes = fields.List(fields.Int, reuquired=True) # 字体大小列表
text = fields.Raw(required=False) # 字典文件
class Meta:
unknown = EXCLUDE
class ExportProject(BaseSchema): class ExportProject(BaseSchema):
project = fields.List(fields.String, required=True) project = fields.List(fields.String, required=True)
production = fields.List(fields.String, required=True) production = fields.List(fields.String, required=True)
......
#-*- coding: UTF-8 -*-
#!/usr/bin/python
import os
import sys
import fs
import struct
import json
from collections import OrderedDict
import zlib
import pprint
import hashlib
from ctypes import *
import platform
current_abspath = os.path.dirname(os.path.realpath(__file__))
if platform.system() == 'Windows':
pDll = CDLL(os.sep.join([current_abspath, "lib", "eheatshrink.dll"]))
elif platform.system() == 'Linux':
pDll = CDLL(os.sep.join([current_abspath, "lib", "libeheatshrink.so"]))
pDll.ecompress_size.restype = c_uint32
pDll.ecompress_size.argtypes = [c_void_p, c_uint32]
pDll.ecompress.restype = POINTER(c_uint8)
pDll.ecompress.argtypes = [c_void_p, c_uint32]
def heatshrink_compress(buf:bytes, level:int):
count = len(buf)
size = pDll.ecompress_size(buf, count)
pDll.ecompress.restype = POINTER(c_uint8)
pDll.ecompress.argtypes = [c_void_p, c_uint32]
ret = pDll.ecompress(buf, count)
arr = bytearray(size)
i = 0
while i < size:
arr[i] = ret[i]
i = i+1
return arr
def str_to_hex(s):
return ' '.join([hex(ord(c)).replace('0x', '') for c in s])
def hex_to_str(s):
return ''.join([chr(i) for i in [int(b, 16) for b in s.split(' ')]])
def str_to_bin(s):
return ' '.join([bin(ord(c)).replace('0b', '') for c in s])
def bin_to_str(s):
return ''.join([chr(i) for i in [int(b, 2) for b in s.split(' ')]])
class EpkApp(object):
def __init__(self, appName, appDir, algorithm='zlib',appVersion="1.0", output="epks"):
super(EpkApp, self).__init__()
self._appName = appName
self._appDir = os.path.abspath(appDir)
self.algorithm = algorithm
self._appVersion = appVersion
self._appCRCCode = None
self._files = []
self._infoPath = os.sep.join([self._appDir, "%s.json" % self._appName])
self._epksDir = output
if not os.path.exists(self._epksDir):
fs.open_fs(os.getcwd()).makedirs(output)
self._epkName = os.sep.join([self._epksDir, "%s.epk" % self._appName])
def compress(self):
if self.algorithm == 'h':
return heatshrink_compress
return zlib.compress
def epkInfo(self):
epkInfo = OrderedDict({
"appName": self._appName,
"appVersion": self._appVersion,
"files": self.fileinfos(self._appDir),
})
infocontent = json.dumps(epkInfo)
with open(self._infoPath, "w", encoding='utf-8') as f:
f.write(infocontent)
return epkInfo
def fileinfos(self, path):
path = os.path.abspath(path)
home_fs = fs.open_fs(path)
files = []
for jspath in home_fs.glob('*', namespaces=['details']):
fpath = "C:/%s" % jspath.info.name
fname = jspath.info.name
fsize = jspath.info.size
fbasename, fext = os.path.splitext(jspath.info.name)
if fext in ["", ".exe", ".dll", ".nv", ".conf"]:
continue
finfo = {
"path": fpath,
"name": fname,
"size": fsize,
"basename": fbasename,
"ext": fext
}
if self._infoPath == os.sep.join([path, fname]):
files.insert(0, finfo)
else:
files.append(finfo)
if fext == ".evue":
self.fileMD5(finfo)
return files
def header(self, epk_start=0xAAAA, md5_offset=0, file_count=0):
bytes_header = struct.pack("<HLH", epk_start, md5_offset, file_count)
return bytes_header
def fileMD5(self, info):
md5path = os.sep.join([self._appDir, "%s.md5" % info["basename"]])
fpath = os.sep.join([self._appDir, info["name"]])
with open(fpath, "rb") as f:
filecontent = f.read()
newmd5 = self.md5(filecontent)
with open(md5path, "wb") as f:
f.write(newmd5)
return newmd5
def sign(self, content):
ret = b""
for i in range(int(len(content) / 2 )):
ret += struct.pack("<B", int("0x%s" % (content[i*2:i*2+2]), 16))
ret = ret + b'EVM is NB ++!'
return ret
def md5(self, filecontent):
newmd5 = ''
content = filecontent
for i in range(3):
md5 = hashlib.md5() #获取一个md5加密算法对象
md5.update(content) #指定需要加密的字符串
newmd5 = md5.hexdigest() #获取加密后的16进制字符串
content = self.sign(newmd5)
ret = b""
for i in range(int(len(newmd5) / 2 )):
ret += struct.pack("<B", int("0x%s" % (newmd5[i*2:i*2+2]), 16))
return ret
def packFile(self, info, level=9):
fname = info["name"]
fpath = os.sep.join([self._appDir, fname])
fext = info["ext"]
fileBytes = b""
if fext == "md5":
fileBytes += struct.pack("<B", 1)
else:
fileBytes += struct.pack("<B", 2)
_name = fname + "\0"
fileBytes += struct.pack("<B", len(_name))
fileBytes += struct.pack("<%ds" % len(_name), fname.encode("utf-8"))
with open(fpath, "rb") as fc:
fileContentBytes = fc.read()
fileBytes += struct.pack("<L", len(fileContentBytes))
if fext == "md5":
fileCompressBytes = fileContentBytes
else:
fileCompressBytes = self.compress()(fileContentBytes, level)
fileBytes += struct.pack("<L", len(fileCompressBytes))
fileBytes += fileCompressBytes
return fileBytes
def pack(self, level=9):
for i in range(10):
infos = self.epkInfo()
# infos = self.epkInfo()
# infos = self.epkInfo()
epkFileBytes = b""
epkFileContentBytes = b""
file_count = len(infos["files"])
with open(self._epkName, "wb") as f:
for info in infos["files"]:
epkFileContentBytes += self.packFile(info)
epkFileContentLength = len(epkFileContentBytes)
epkFileBytes += self.header(md5_offset= 8 + epkFileContentLength, file_count=file_count)
epkFileBytes += epkFileContentBytes
epkmd5Bytes = self.md5(epkFileBytes)
epkFileBytes += struct.pack("<H", len(epkmd5Bytes))
epkFileBytes += epkmd5Bytes
crcBytes = zlib.crc32(epkFileBytes)
epkFileBytes += struct.pack("<L", crcBytes)
f.write(epkFileBytes)
ret = {
"epkfile": self._epkName,
"epk_filecontent_size": epkFileContentLength,
"md5_offset": 10 + epkFileContentLength,
"file_count": file_count,
"md5_length": len(epkmd5Bytes),
"md5": epkmd5Bytes,
"raw_crc": hex(crcBytes),
"compress_level": level,
"buff_length": len(epkFileBytes)
}
pprint.pprint(ret)
return ret
def main(path, appName, algorithm):
epk = EpkApp(appName, path, algorithm)
epk.pack()
if __name__ == '__main__':
main(sys.argv[1], sys.argv[2], sys.argv[3])
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
#
# FreeType high-level python API - Copyright 2011-2015 Nicolas P. Rougier
# Distributed under the terms of the new BSD license.
#
# -----------------------------------------------------------------------------
'''
Glyph bitmap monochrome rendering
'''
import json
import struct
import sys
import pprint
from pathlib import Path
import mimetypes
from freetype import Face
class EvueFontTool(object):
FONT_DPI = 100
def __init__(self, freetypefile, output_dir, sizes=[10,20,30]):
super().__init__()
self.freetypefile = freetypefile
self.sizes = sizes
self.face = Face(self.freetypefile)
self.infos = []
self.output_dir = Path(output_dir)
if not self.output_dir.exists():
self.output_dir.mkdir()
# raise Exception("{} not exists".format(output_dir))
@property
def fontInfo(self):
return {
'family': str(self.face.family_name, 'utf-8'),
'style': str(self.face.style_name, 'utf-8'),
'charmaps': [charmap.encoding_name for charmap in self.face.charmaps],
'face_number': self.face.num_faces,
'glyph_number': self.face.num_glyphs,
'available_sizes': list(map(lambda x: { 'width': x.width, 'height': x.height, 'size': x.size }, self.face.available_sizes)),
'units_per_em': self.face.units_per_EM,
'ascender': self.face.ascender,
'descender': self.face.descender,
'height': self.face.height,
'max_advance_width': self.face.max_advance_width,
'max_advance_height': self.face.max_advance_height,
'underline_position': self.face.underline_position,
'underline_thickness': self.face.underline_thickness,
'has_horizontal': self.face.has_horizontal,
'has_vertical': self.face.has_vertical,
'has_kerning': self.face.has_kerning,
'is_fixed_width': self.face.is_fixed_width,
'is_scalable': self.face.is_scalable
}
def charInfo(self, cur_char):
self.face.load_char(cur_char)
char_info = {
'glyph': ord(cur_char),
'left': self.face.glyph.bitmap_left,
'top': self.face.glyph.bitmap_top,
'advance': self.face.glyph.advance.x / 64,
'cols': self.face.glyph.bitmap.width,
'rows': self.face.glyph.bitmap.rows,
'bitmap': self.face.glyph.bitmap.buffer, # list[]
'count': len(self.face.glyph.bitmap.buffer),
}
return char_info
def dump(self, used_string):
# 遍历每一个字体
dump_json = {
'name': self.fontInfo.get("family"),
'info': self.fontInfo,
'text': used_string,
'size': self.sizes,
'bitmap': {
'total': 0
}
}
for cur_char in used_string:
# 遍历每一个字体设定的大小值
for size in self.sizes:
# 设置字体大小
self.face.set_char_size(size * 64, 0, self.FONT_DPI, 0)
char_info = self.charInfo(cur_char)
self.infos.append(char_info)
# 文件命名规则:./<output_dir>/<font-size>/<unicode-number>.bin
target_dir = self.output_dir.joinpath(str(size)).joinpath("{}.bin".format(char_info.get('glyph')))
if not target_dir.parent.exists():
target_dir.parent.mkdir()
with open(target_dir.resolve().as_posix(), 'wb+') as f:
f.write(struct.pack("%dB" % char_info['count'], *char_info['bitmap']))
dump_json['bitmap'].update({
size: dump_json.get('bitmap').get(size, 0) + target_dir.stat().st_size
})
for key in dump_json['bitmap']:
if key != 'total':
dump_json['bitmap']['total'] += dump_json['bitmap'][key]
pprint.pprint(dump_json)
# 在输出目录下,生成一个json索引文件
with open(self.output_dir.joinpath("fonts.json").resolve().as_posix(), "wb+") as f:
f.write(json.dumps(dump_json, ensure_ascii=False, indent=2).encode('utf-8'))
def load(self, file):
pass
def show(self, info):
import numpy
import matplotlib.pyplot as plt
data = info['bitmap']
rows = info['rows']
width = info['cols']
# for i in range(rows):
# data.extend(bitmap.buffer[i*pitch:i*pitch+width])
Z = numpy.array(data,dtype=numpy.ubyte).reshape(rows, width)
plt.imshow(Z, interpolation='nearest', cmap=plt.cm.gray)
plt.show()
def test(self, used_string):
for cur_char in used_string:
char_info = self.charInfo(cur_char)
self.infos.append(char_info)
self.show(char_info)
if __name__ == '__main__':
print(mimetypes.guess_type(sys.argv[1])[0])
evueFontTool = EvueFontTool(sys.argv[1], sys.argv[2])
text = '中国'
# evueFontTool.test(text)
evueFontTool.dump(text)
pprint.pprint(evueFontTool.fontInfo)
\ No newline at end of file
#!/usr/bin/env python
import sys
import os
import struct
from pathlib import Path
from collections import namedtuple
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('rootdir', type=str, help='the path to rootfs')
parser.add_argument('output', type=argparse.FileType('wb'), nargs='?', help='output file name')
parser.add_argument('--dump', action='store_true', help='dump the fs hierarchy')
parser.add_argument('--binary', action='store_true', help='output binary file')
parser.add_argument('--appname', default='appname', help='output appname file')
parser.add_argument('--addr', default='0', help='set the base address of the binary file, default to 0.')
class File(object):
def __init__(self, name):
self._name = name
self._data = open(name, 'rb').read()
@property
def name(self):
return self._name
@property
def c_name(self):
return '_' + self._name.replace('.', '_')
@property
def bin_name(self):
# Pad to 4 bytes boundary with \0
pad_len = 4
bn = self._name + '\0' * (pad_len - len(self._name) % pad_len)
return bn
def c_data(self, prefix=''):
'''Get the C code represent of the file content.'''
head = 'static const uint8_t %s[] = {\n' % \
(prefix + self.c_name)
tail = '\n};'
if self.entry_size == 0:
return ''
print([hex(i) for i in self._data])
return head + ','.join((hex(i) for i in self._data)) + tail
@property
def entry_size(self):
return len(self._data)
def bin_data(self, base_addr=0x0):
return bytes(self._data)
def dump(self, indent=0):
print('%s%s' % (' ' * indent, self._name))
class Folder(object):
bin_fmt = struct.Struct('IIII')
bin_item = namedtuple('dirent', 'type, name, data, size')
def __init__(self, name):
self._name = name
self._children = []
@property
def name(self):
return self._name
@property
def c_name(self):
# add _ to avoid conflict with C key words.
return '_' + self._name
@property
def bin_name(self):
# Pad to 4 bytes boundary with \0
pad_len = 4
bn = self._name + '\0' * (pad_len - len(self._name) % pad_len)
return bn
def walk(self):
# os.listdir will return unicode list if the argument is unicode.
# TODO: take care of the unicode names
for ent in os.listdir(u'.'):
if os.path.isdir(ent):
cwd = os.getcwd()
d = Folder(ent)
# depth-first
os.chdir(os.path.join(cwd, ent))
d.walk()
# restore the cwd
os.chdir(cwd)
self._children.append(d)
else:
self._children.append(File(ent))
def sort(self):
import functools
def _sort(x, y):
if x.name == y.name:
return 0
elif x.name > y.name:
return 1
else:
return -1
self._children.sort(key=functools.cmp_to_key(_sort))
# sort recursively
for c in self._children:
if isinstance(c, Folder):
c.sort()
def dump(self, indent=0):
print('%s%s' % (' ' * indent, self._name))
for c in self._children:
c.dump(indent + 1)
def c_data(self, prefix=''):
'''get the C code represent of the folder.
It is recursive.'''
# make the current dirent
# static is good. Only root dirent is global visible.
if self.entry_size == 0:
return ''
dhead = 'static const struct evm_romfs_dirent %s[] = {\n' % (prefix + self.c_name)
dtail = '\n};'
body_fmt = ' {{{type}, "{name}", (uint8_t *){data}, sizeof({data})/sizeof({data}[0])}}'
body_fmt0= ' {{{type}, "{name}", NULL, 0}}'
# prefix of children
cpf = prefix+self.c_name
# print("prefix:", prefix)
# print("self.c_name", self.c_name)
# print(cpf)
body_dict = {}
body_li = []
payload_li = []
# add children
for c in self._children:
entry_size = c.entry_size
if isinstance(c, File):
tp = 'EVM_ROMFS_DIRENT_FILE'
elif isinstance(c, Folder):
tp = 'EVM_ROMFS_DIRENT_DIR'
else:
assert False, 'Unkown instance:%s' % str(c)
if entry_size == 0:
body_dict.update({str(c.name) : body_fmt0.format(type=tp, name = c.name)})
else:
body_dict.update({str(c.name) : body_fmt.format(type=tp,
name=c.name,
data=cpf+c.c_name)})
payload_li.append(c.c_data(prefix=cpf))
# print(self._children)
# sort by name
for n in sorted(body_dict.keys()):
body_li.append(body_dict[n])
# All the data we need is defined in payload so we should append the
# dirent to it. It also meet the depth-first policy in this code.
payload_li.append(dhead + ',\n'.join(body_li) + dtail)
return '\n\n'.join(payload_li)
@property
def entry_size(self):
return len(self._children)
def bin_data(self, base_addr=0x0):
# print("=================bin_data==================", self, self.name)
'''Return StringIO object'''
# The binary layout is different from the C code layout. We put the
# dirent before the payload in this mode. But the idea is still simple:
# Depth-First.
#{
# uint32_t type;
# const char *name;
# const uint8_t *data;
# size_t size;
#}
d_li = []
# payload base
p_base = base_addr + self.bin_fmt.size * self.entry_size
# the length to record how many data is in
v_len = p_base
# payload
p_li = []
for c in self._children:
if isinstance(c, File):
# EVM_ROMFS_DIRENT_FILE
tp = 0
elif isinstance(c, Folder):
# EVM_ROMFS_DIRENT_DIR
tp = 1
else:
assert False, 'Unkown instance:%s' % str(c)
name = bytes(c.bin_name, encoding='utf-8')
name_addr = v_len
v_len += len(name)
data = c.bin_data(base_addr=v_len)
data_addr = v_len
# pad the data to 4 bytes boundary
pad_len = 4
if len(data) % pad_len != 0:
data += b'\0' * (pad_len - len(data) % pad_len)
v_len += len(data)
# print(c.bin_name, tp, name_addr, data_addr, c.entry_size)
d_li.append(self.bin_fmt.pack(*self.bin_item(
type=tp,
name=name_addr,
data=data_addr,
size=c.entry_size)))
p_li.extend((name, data))
# print(self.bin_item(
# type=tp,
# name=name_addr,
# data=data_addr,
# size=c.entry_size))
# print("header", repr(d_li))
# print("name", repr(name))
# print("data", repr(data))
# print("packet", repr(bytes().join(d_li) + bytes().join(p_li)))
# print("=================================packet====================================")
# print("=================================d_li====================================")
# print(repr(bytes().join(d_li)))
# print("=================================p_li====================================")
# print(repr(bytes().join(p_li)))
return bytes().join(d_li) + bytes().join(p_li)
def get_c_data(tree):
# Handle the root dirent specially.
root_dirent_fmt = '''/* Generated by mkromfs. Edit with caution. */
#include "romfs_def.h"
{data}
const struct evm_romfs_dirent {name} = {{
EVM_ROMFS_DIRENT_DIR, "/", (uint8_t *){rootdirent}, sizeof({rootdirent})/sizeof({rootdirent}[0])
}};
'''
return root_dirent_fmt.format(name='romfs_root',
rootdirent=tree.c_name,
data=tree.c_data())
def get_bin_data(romfsDir, tree, base_addr):
v_len = base_addr + Folder.bin_fmt.size
if romfsDir.startswith('/'):
name = bytes('%s\0\0\0' % (romfsDir), encoding='utf-8')
else:
name = bytes('/%s\0\0\0' % (romfsDir), encoding='utf-8')
name_addr = v_len
v_len += len(name)
data_addr = v_len
# root entry
data = Folder.bin_fmt.pack(*Folder.bin_item(type=1,
name=name_addr,
data=data_addr,
size=tree.entry_size))
tree_data = tree.bin_data(v_len)
# print("header", repr(data))
# print("name", repr(name))
# print("data", repr(tree_data))
# print("packet", repr(data + name + tree_data))
# print("=================================end====================================")
return data + name + tree_data
def mkromfs(fsDir, romfsDir, output):
'''
fsDir: 需要转换成romfs对应的目录
romfsDir: 对应的romfs根目录
output:输出的output对应的bin文件
'''
oldcwd = os.getcwd()
if os.path.exists(fsDir):
os.chdir(fsDir)
tree = Folder('romfs_root')
tree.walk()
tree.sort()
data = get_bin_data(romfsDir, tree, 0)
os.chdir(oldcwd)
target_dir = Path(fsDir).joinpath(output).resolve().as_posix()
with open(target_dir, "wb") as f:
f.write(data)
if __name__ == '__main__':
mkromfs('./output', '/com/bytecode/launcher', 'fonts.bin')
# args = parser.parse_args()
# os.chdir(args.rootdir)
# tree = Folder('romfs_root')
# tree.walk()
# tree.sort()
# if args.dump:
# tree.dump()
# if args.binary:
# print(args)
# data = get_bin_data(args.appname, tree, int(args.addr, 16))
# else:
# data = get_c_data(tree)
# output = args.output
# if not output:
# output = sys.stdout
# output.write(data.encode('utf-8'))
#-*- coding: UTF-8 -*-
#!/usr/bin/python
import os
import sys
import fs
import struct
import json
from collections import OrderedDict
import zlib
import pprint
import hashlib
def str_to_hex(s):
return ' '.join([hex(ord(c)).replace('0x', '') for c in s])
def hex_to_str(s):
return ''.join([chr(i) for i in [int(b, 16) for b in s.split(' ')]])
def str_to_bin(s):
return ' '.join([bin(ord(c)).replace('0b', '') for c in s])
def bin_to_str(s):
return ''.join([chr(i) for i in [int(b, 2) for b in s.split(' ')]])
class EpkApp(object):
def __init__(self, appName, appDir, appVersion="1.0", output="epks"):
super(EpkApp, self).__init__()
self._appName = appName
self._appDir = os.path.abspath(appDir)
self._appVersion = appVersion
self._appCRCCode = None
self._files = []
self._infoPath = os.sep.join([self._appDir, "%s.json" % self._appName])
self._epksDir = output
if not os.path.exists(self._epksDir):
fs.open_fs(os.getcwd()).makedirs(output)
self._epkName = os.sep.join([self._epksDir, "%s.epk" % self._appName])
def epkInfo(self):
epkInfo = OrderedDict({
"appName": self._appName,
"appVersion": self._appVersion,
"files": self.fileinfos(self._appDir),
})
infocontent = json.dumps(epkInfo)
with open(self._infoPath, "w", encoding='utf-8') as f:
f.write(infocontent)
return epkInfo
def fileinfos(self, path):
path = os.path.abspath(path)
home_fs = fs.open_fs(path)
files = []
for jspath in home_fs.glob('*', namespaces=['details']):
fpath = "C:/%s" % jspath.info.name
fname = jspath.info.name
fsize = jspath.info.size
fbasename = jspath.info.name.split(".")[0]
fext = jspath.info.name.split(".")[1]
if fext in ["exe", "dll", "nv", "conf"]:
continue
finfo = {
"path": fpath,
"name": fname,
"size": fsize,
"basename": fbasename,
"ext": fext
}
if self._infoPath == os.sep.join([path, fname]):
files.insert(0, finfo)
else:
files.append(finfo)
if fext == "evue":
self.fileMD5(finfo)
return files
def header(self, epk_start=0xAAAA, md5_offset=0, file_count=0):
bytes_header = struct.pack("<HLH", epk_start, md5_offset, file_count)
return bytes_header
def fileMD5(self, info):
md5path = os.sep.join([self._appDir, "%s.md5" % info["basename"]])
fpath = os.sep.join([self._appDir, info["name"]])
with open(fpath, "rb") as f:
filecontent = f.read()
print(fpath)
newmd5 = self.md5(filecontent)
print(md5path)
with open(md5path, "wb") as f:
f.write(newmd5)
return newmd5
def sign(self, content):
ret = b""
for i in range(int(len(content) / 2 )):
ret += struct.pack("<B", int("0x%s" % (content[i*2:i*2+2]), 16))
ret = ret + b'EVM is NB ++!'
return ret
def md5(self, filecontent):
newmd5 = ''
content = filecontent
for i in range(3):
md5 = hashlib.md5() #获取一个md5加密算法对象
md5.update(content) #指定需要加密的字符串
newmd5 = md5.hexdigest() #获取加密后的16进制字符串
print(newmd5)
content = self.sign(newmd5)
ret = b""
for i in range(int(len(newmd5) / 2 )):
ret += struct.pack("<B", int("0x%s" % (newmd5[i*2:i*2+2]), 16))
return ret
def packFile(self, info, level=9):
fname = info["name"]
fpath = os.sep.join([self._appDir, fname])
fext = info["ext"]
fileBytes = b""
if fext == "md5":
fileBytes += struct.pack("<B", 1)
else:
fileBytes += struct.pack("<B", 2)
_name = fname + "\0"
fileBytes += struct.pack("<B", len(_name))
fileBytes += struct.pack("<%ds" % len(_name), fname.encode("utf-8"))
with open(fpath, "rb") as fc:
fileContentBytes = fc.read()
print(info["name"])
print(len(fileContentBytes))
fileBytes += struct.pack("<L", len(fileContentBytes))
if fext == "md5":
fileCompressBytes = fileContentBytes
else:
fileCompressBytes = zlib.compress(fileContentBytes, level)
print(len(fileCompressBytes))
fileBytes += struct.pack("<L", len(fileCompressBytes))
fileBytes += fileCompressBytes
return fileBytes
def pack(self, level=9):
for i in range(10):
infos = self.epkInfo()
# infos = self.epkInfo()
# infos = self.epkInfo()
result = {}
epkFileBytes = b""
epkFileContentBytes = b""
file_count = len(infos["files"])
with open(self._epkName, "wb") as f:
for info in infos["files"]:
epkFileContentBytes += self.packFile(info)
epkFileContentLength = len(epkFileContentBytes)
epkFileBytes += self.header(md5_offset= 8 + epkFileContentLength, file_count=file_count)
epkFileBytes += epkFileContentBytes
epkmd5Bytes = self.md5(epkFileBytes)
epkFileBytes += struct.pack("<H", len(epkmd5Bytes))
epkFileBytes += epkmd5Bytes
crcBytes = zlib.crc32(epkFileBytes)
epkFileBytes += struct.pack("<L", crcBytes)
f.write(epkFileBytes)
ret = {
"epkfile": self._epkName,
"epk_filecontent_size": epkFileContentLength,
"md5_offset": 10 + epkFileContentLength,
"file_count": file_count,
"md5_length": len(epkmd5Bytes),
"md5": epkmd5Bytes,
"raw_crc": hex(crcBytes),
"compress_level": level,
"buff_length": len(epkFileBytes)
}
result = ret
return result
def main(path, appName):
epk = EpkApp(appName, path)
epk.pack()
if __name__ == '__main__':
main(sys.argv[1], sys.argv[2])
...@@ -8,7 +8,6 @@ import traceback ...@@ -8,7 +8,6 @@ import traceback
import uuid import uuid
import time import time
import zipfile import zipfile
import sqlite3
from pathlib import Path from pathlib import Path
from datetime import datetime from datetime import datetime
...@@ -20,10 +19,12 @@ from fullstack.log import logger ...@@ -20,10 +19,12 @@ from fullstack.log import logger
from fullstack.login import Auth from fullstack.login import Auth
from fullstack.response import ResponseCode, response_result from fullstack.response import ResponseCode, response_result
from fullstack.validation import validate_schema from fullstack.validation import validate_schema
from schema.api import UpdatePasswordSchema, ApplicationBuildSchema, ConvertString from schema.api import UpdatePasswordSchema, ApplicationBuildSchema, ConvertString, GenerateFont
import sys import sys
sys.path.append("..") sys.path.append("..")
from utils import vbuild from utils import vbuild
from utils.evuefonttool import EvueFontTool
from utils.mkromfs import mkromfs
api = Blueprint("api", __name__, url_prefix="/api/v1/%s" % config['NAME']) api = Blueprint("api", __name__, url_prefix="/api/v1/%s" % config['NAME'])
...@@ -198,7 +199,7 @@ def action_build(): ...@@ -198,7 +199,7 @@ def action_build():
with open(file, "w+") as fd: with open(file, "w+") as fd:
fd.write(text) fd.write(text)
result = subprocess.call("./executable -c {file}".format(file=file), shell=True) result = subprocess.call("./utils/executable -c {file}".format(file=file), shell=True)
new_name = "{}.{}".format(Path(file).name, "bc") new_name = "{}.{}".format(Path(file).name, "bc")
os.rename(os.sep.join([os.getcwd(), "executable.bc"]), os.sep.join([os.getcwd(), new_name])) os.rename(os.sep.join([os.getcwd(), "executable.bc"]), os.sep.join([os.getcwd(), new_name]))
dst_files.append(Path(os.getcwd()).joinpath(new_name)) dst_files.append(Path(os.getcwd()).joinpath(new_name))
...@@ -304,6 +305,65 @@ def update_db(): ...@@ -304,6 +305,65 @@ def update_db():
return response_result(ResponseCode.OK, data=result) return response_result(ResponseCode.OK, data=result)
@api.route("/system/generateFont", methods=['POST'])
def generate_font():
if not request.form:
return response_result(ResponseCode.PARAMETER_ERROR, msg="form can not be null")
sizes = request.form.get("sizes", None)
if not sizes:
return response_result(ResponseCode.PARAMETER_ERROR, msg="param sizes can not be null")
# 判断用户输入的字体大小是否合法
logger.info(sizes)
font = request.files.get("font", None)
if not font:
return response_result(ResponseCode.PARAMETER_ERROR, msg="param font can not be null")
logger.info(font.content_type)
# 保存字体文件到临时目录
random_str = uuid.uuid4().hex
temp_dir = Path(os.path.dirname(os.path.dirname(__file__))).joinpath("temp").joinpath(random_str)
if not temp_dir.exists():
temp_dir.mkdir()
fontSavePath = temp_dir.joinpath(font.filename).resolve().as_posix()
font.save(fontSavePath)
# 判断用户输入的字典是否为空
text_dict = request.form.get("text", None)
if not text_dict:
return response_result(ResponseCode.PARAMETER_ERROR, msg="param text can not be null")
# 如果通过上面校验,则进行生成文件流程
# 参数一:字体文件、参数二:输出目录
target_dir = Path(config.get("UPLOAD_PATH")).joinpath(config.get("TEMP_DIR")).joinpath(datetime.now().strftime("%Y%m%d%H%M%S%f"))
if not target_dir.exists():
target_dir.mkdir()
# 当生成字体比较大的时候,是否考虑启用线程处理文字?
sizes = sizes.split(",")
ts = []
for s in sizes:
ts.append(int(s))
evueFontTool = EvueFontTool(fontSavePath, target_dir.resolve().as_posix(), sizes=ts)
evueFontTool.dump(text_dict)
# 这里是否有必要让用户输入最终生成的文件名,可选
filename = request.form.get("filename", "fonts.bin")
mkromfs(target_dir.resolve().as_posix(), "/", filename)
# 删除字体文件
os.chdir(temp_dir.parent.resolve().as_posix())
shutil.rmtree(random_str)
return response_result(ResponseCode.OK, data={
'filename': filename,
'url': target_dir.joinpath(filename).resolve().relative_to(config.get("UPLOAD_PATH")).as_posix(),
})
@api.route("/system/convertString", methods=['POST']) @api.route("/system/convertString", methods=['POST'])
@validate_schema(ConvertString) @validate_schema(ConvertString)
def convert_string(): def convert_string():
......
...@@ -325,3 +325,11 @@ export function getDataList(params) { ...@@ -325,3 +325,11 @@ export function getDataList(params) {
params, params,
}); });
} }
export function generateFont(data) {
return request({
url: "/api/v1/evm_store/system/generateFont",
method: "post",
data
});
}
This source diff could not be displayed because it is too large. You can view the blob instead.
["啊","阿","埃","挨","哎","唉","哀","皑","癌","蔼","矮","艾","碍","爱","隘","鞍","氨","安","俺","按","暗","岸","胺","案","肮","昂","盎","凹","敖","熬","翱","袄","傲","奥","懊","澳","芭","捌","扒","叭","吧","笆","八","疤","巴","拔","跋","靶","把","耙","坝","霸","罢","爸","白","柏","百","摆","佰","败","拜","稗","斑","班","搬","扳","般","颁","板","版","扮","拌","伴","瓣","半","办","绊","邦","帮","梆","榜","膀","绑","棒","磅","蚌","镑","傍","谤","苞","胞","包","褒","剥","薄","雹","保","堡","饱","宝","抱","报","暴","豹","鲍","爆","杯","碑","悲","卑","北","辈","背","贝","钡","倍","狈","备","惫","焙","被","奔","苯","本","笨","崩","绷","甭","泵","蹦","迸","逼","鼻","比","鄙","笔","彼","碧","蓖","蔽","毕","毙","毖","币","庇","痹","闭","敝","弊","必","辟","壁","臂","避","陛","鞭","边","编","贬","扁","便","变","卞","辨","辩","辫","遍","标","彪","膘","表","鳖","憋","别","瘪","彬","斌","濒","滨","宾","摈","兵","冰","柄","丙","秉","饼","炳","病","并","玻","菠","播","拨","钵","波","博","勃","搏","铂","箔","伯","帛","舶","脖","膊","渤","泊","驳","捕","卜","哺","补","埠","不","布","步","簿","部","怖","擦","猜","裁","材","才","财","睬","踩","采","彩","菜","蔡","餐","参","蚕","残","惭","惨","灿","苍","舱","仓","沧","藏","操","糙","槽","曹","草","厕","策","侧","册","测","层","蹭","插","叉","茬","茶","查","碴","搽","察","岔","差","诧","拆","柴","豺","搀","掺","蝉","馋","谗","缠","铲","产","阐","颤","昌","猖","场","尝","常","长","偿","肠","厂","敞","畅","唱","倡","超","抄","钞","朝","嘲","潮","巢","吵","炒","车","扯","撤","掣","彻","澈","郴","臣","辰","尘","晨","忱","沉","陈","趁","衬","撑","称","城","橙","成","呈","乘","程","惩","澄","诚","承","逞","骋","秤","吃","痴","持","匙","池","迟","弛","驰","耻","齿","侈","尺","赤","翅","斥","炽","充","冲","虫","崇","宠","抽","酬","畴","踌","稠","愁","筹","仇","绸","瞅","丑","臭","初","出","橱","厨","躇","锄","雏","滁","除","楚","础","储","矗","搐","触","处","揣","川","穿","椽","传","船","喘","串","疮","窗","幢","床","闯","创","吹","炊","捶","锤","垂","春","椿","醇","唇","淳","纯","蠢","戳","绰","疵","茨","磁","雌","辞","慈","瓷","词","此","刺","赐","次","聪","葱","囱","匆","从","丛","凑","粗","醋","簇","促","蹿","篡","窜","摧","崔","催","脆","瘁","粹","淬","翠","村","存","寸","磋","撮","搓","措","挫","错","搭","达","答","瘩","打","大","呆","歹","傣","戴","带","殆","代","贷","袋","待","逮","怠","耽","担","丹","单","郸","掸","胆","旦","氮","但","惮","淡","诞","弹","蛋","当","挡","党","荡","档","刀","捣","蹈","倒","岛","祷","导","到","稻","悼","道","盗","德","得","的","蹬","灯","登","等","瞪","凳","邓","堤","低","滴","迪","敌","笛","狄","涤","翟","嫡","抵","底","地","蒂","第","帝","弟","递","缔","颠","掂","滇","碘","点","典","靛","垫","电","佃","甸","店","惦","奠","淀","殿","碉","叼","雕","凋","刁","掉","吊","钓","调","跌","爹","碟","蝶","迭","谍","叠","丁","盯","叮","钉","顶","鼎","锭","定","订","丢","东","冬","董","懂","动","栋","侗","恫","冻","洞","兜","抖","斗","陡","豆","逗","痘","都","督","毒","犊","独","读","堵","睹","赌","杜","镀","肚","度","渡","妒","端","短","锻","段","断","缎","堆","兑","队","对","墩","吨","蹲","敦","顿","囤","钝","盾","遁","掇","哆","多","夺","垛","躲","朵","跺","舵","剁","惰","堕","蛾","峨","鹅","俄","额","讹","娥","恶","厄","扼","遏","鄂","饿","恩","而","儿","耳","尔","饵","洱","二","贰","发","罚","筏","伐","乏","阀","法","珐","藩","帆","番","翻","樊","矾","钒","繁","凡","烦","反","返","范","贩","犯","饭","泛","坊","芳","方","肪","房","防","妨","仿","访","纺","放","菲","非","啡","飞","肥","匪","诽","吠","肺","废","沸","费","芬","酚","吩","氛","分","纷","坟","焚","汾","粉","奋","份","忿","愤","粪","丰","封","枫","蜂","峰","锋","风","疯","烽","逢","冯","缝","讽","奉","凤","佛","否","夫","敷","肤","孵","扶","拂","辐","幅","氟","符","伏","俘","服","浮","涪","福","袱","弗","甫","抚","辅","俯","釜","斧","脯","腑","府","腐","赴","副","覆","赋","复","傅","付","阜","父","腹","负","富","讣","附","妇","缚","咐","噶","嘎","该","改","概","钙","盖","溉","干","甘","杆","柑","竿","肝","赶","感","秆","敢","赣","冈","刚","钢","缸","肛","纲","岗","港","杠","篙","皋","高","膏","羔","糕","搞","镐","稿","告","哥","歌","搁","戈","鸽","胳","疙","割","革","葛","格","蛤","阁","隔","铬","个","各","给","根","跟","耕","更","庚","羹","埂","耿","梗","工","攻","功","恭","龚","供","躬","公","宫","弓","巩","汞","拱","贡","共","钩","勾","沟","苟","狗","垢","构","购","够","辜","菇","咕","箍","估","沽","孤","姑","鼓","古","蛊","骨","谷","股","故","顾","固","雇","刮","瓜","剐","寡","挂","褂","乖","拐","怪","棺","关","官","冠","观","管","馆","罐","惯","灌","贯","光","广","逛","瑰","规","圭","硅","归","龟","闺","轨","鬼","诡","癸","桂","柜","跪","贵","刽","辊","滚","棍","锅","郭","国","果","裹","过","哈","骸","孩","海","氦","亥","害","骇","酣","憨","邯","韩","含","涵","寒","函","喊","罕","翰","撼","捍","旱","憾","悍","焊","汗","汉","夯","杭","航","壕","嚎","豪","毫","郝","好","耗","号","浩","呵","喝","荷","菏","核","禾","和","何","合","盒","貉","阂","河","涸","赫","褐","鹤","贺","嘿","黑","痕","很","狠","恨","哼","亨","横","衡","恒","轰","哄","烘","虹","鸿","洪","宏","弘","红","喉","侯","猴","吼","厚","候","后","呼","乎","忽","瑚","壶","葫","胡","蝴","狐","糊","湖","弧","虎","唬","护","互","沪","户","花","哗","华","猾","滑","画","划","化","话","槐","徊","怀","淮","坏","欢","环","桓","还","缓","换","患","唤","痪","豢","焕","涣","宦","幻","荒","慌","黄","磺","蝗","簧","皇","凰","惶","煌","晃","幌","恍","谎","灰","挥","辉","徽","恢","蛔","回","毁","悔","慧","卉","惠","晦","贿","秽","会","烩","汇","讳","诲","绘","荤","昏","婚","魂","浑","混","豁","活","伙","火","获","或","惑","霍","货","祸","击","圾","基","机","畸","稽","积","箕","肌","饥","迹","激","讥","鸡","姬","绩","缉","吉","极","棘","辑","籍","集","及","急","疾","汲","即","嫉","级","挤","几","脊","己","蓟","技","冀","季","伎","祭","剂","悸","济","寄","寂","计","记","既","忌","际","妓","继","纪","嘉","枷","夹","佳","家","加","荚","颊","贾","甲","钾","假","稼","价","架","驾","嫁","歼","监","坚","尖","笺","间","煎","兼","肩","艰","奸","缄","茧","检","柬","碱","硷","拣","捡","简","俭","剪","减","荐","槛","鉴","践","贱","见","键","箭","件","健","舰","剑","饯","渐","溅","涧","建","僵","姜","将","浆","江","疆","蒋","桨","奖","讲","匠","酱","降","蕉","椒","礁","焦","胶","交","郊","浇","骄","娇","嚼","搅","铰","矫","侥","脚","狡","角","饺","缴","绞","剿","教","酵","轿","较","叫","窖","揭","接","皆","秸","街","阶","截","劫","节","桔","杰","捷","睫","竭","洁","结","解","姐","戒","藉","芥","界","借","介","疥","诫","届","巾","筋","斤","金","今","津","襟","紧","锦","仅","谨","进","靳","晋","禁","近","烬","浸","尽","劲","荆","兢","茎","睛","晶","鲸","京","惊","精","粳","经","井","警","景","颈","静","境","敬","镜","径","痉","靖","竟","竞","净","炯","窘","揪","究","纠","玖","韭","久","灸","九","酒","厩","救","旧","臼","舅","咎","就","疚","鞠","拘","狙","疽","居","驹","菊","局","咀","矩","举","沮","聚","拒","据","巨","具","距","踞","锯","俱","句","惧","炬","剧","捐","鹃","娟","倦","眷","卷","绢","撅","攫","抉","掘","倔","爵","觉","决","诀","绝","均","菌","钧","军","君","峻","俊","竣","浚","郡","骏","喀","咖","卡","咯","开","揩","楷","凯","慨","刊","堪","勘","坎","砍","看","康","慷","糠","扛","抗","亢","炕","考","拷","烤","靠","坷","苛","柯","棵","磕","颗","科","壳","咳","可","渴","克","刻","客","课","肯","啃","垦","恳","坑","吭","空","恐","孔","控","抠","口","扣","寇","枯","哭","窟","苦","酷","库","裤","夸","垮","挎","跨","胯","块","筷","侩","快","宽","款","匡","筐","狂","框","矿","眶","旷","况","亏","盔","岿","窥","葵","奎","魁","傀","馈","愧","溃","坤","昆","捆","困","括","扩","廓","阔","垃","拉","喇","蜡","腊","辣","啦","莱","来","赖","蓝","婪","栏","拦","篮","阑","兰","澜","谰","揽","览","懒","缆","烂","滥","琅","榔","狼","廊","郎","朗","浪","捞","劳","牢","老","佬","姥","酪","烙","涝","勒","乐","雷","镭","蕾","磊","累","儡","垒","擂","肋","类","泪","棱","楞","冷","厘","梨","犁","黎","篱","狸","离","漓","理","李","里","鲤","礼","莉","荔","吏","栗","丽","厉","励","砾","历","利","傈","例","俐","痢","立","粒","沥","隶","力","璃","哩","俩","联","莲","连","镰","廉","怜","涟","帘","敛","脸","链","恋","炼","练","粮","凉","梁","粱","良","两","辆","量","晾","亮","谅","撩","聊","僚","疗","燎","寥","辽","潦","了","撂","镣","廖","料","列","裂","烈","劣","猎","琳","林","磷","霖","临","邻","鳞","淋","凛","赁","吝","拎","玲","菱","零","龄","铃","伶","羚","凌","灵","陵","岭","领","另","令","溜","琉","榴","硫","馏","留","刘","瘤","流","柳","六","龙","聋","咙","笼","窿","隆","垄","拢","陇","楼","娄","搂","篓","漏","陋","芦","卢","颅","庐","炉","掳","卤","虏","鲁","麓","碌","露","路","赂","鹿","潞","禄","录","陆","戮","驴","吕","铝","侣","旅","履","屡","缕","虑","氯","律","率","滤","绿","峦","挛","孪","滦","卵","乱","掠","略","抡","轮","伦","仑","沦","纶","论","萝","螺","罗","逻","锣","箩","骡","裸","落","洛","骆","络","妈","麻","玛","码","蚂","马","骂","嘛","吗","埋","买","麦","卖","迈","脉","瞒","馒","蛮","满","蔓","曼","慢","漫","谩","芒","茫","盲","氓","忙","莽","猫","茅","锚","毛","矛","铆","卯","茂","冒","帽","貌","贸","么","玫","枚","梅","酶","霉","煤","没","眉","媒","镁","每","美","昧","寐","妹","媚","门","闷","们","萌","蒙","檬","盟","锰","猛","梦","孟","眯","醚","靡","糜","迷","谜","弥","米","秘","觅","泌","蜜","密","幂","棉","眠","绵","冕","免","勉","娩","缅","面","苗","描","瞄","藐","秒","渺","庙","妙","蔑","灭","民","抿","皿","敏","悯","闽","明","螟","鸣","铭","名","命","谬","摸","摹","蘑","模","膜","磨","摩","魔","抹","末","莫","墨","默","沫","漠","寞","陌","谋","牟","某","拇","牡","亩","姆","母","墓","暮","幕","募","慕","木","目","睦","牧","穆","拿","哪","呐","钠","那","娜","纳","氖","乃","奶","耐","奈","南","男","难","囊","挠","脑","恼","闹","淖","呢","馁","内","嫩","能","妮","霓","倪","泥","尼","拟","你","匿","腻","逆","溺","蔫","拈","年","碾","撵","捻","念","娘","酿","鸟","尿","捏","聂","孽","啮","镊","镍","涅","您","柠","狞","凝","宁","拧","泞","牛","扭","钮","纽","脓","浓","农","弄","奴","努","怒","女","暖","虐","疟","挪","懦","糯","诺","哦","欧","鸥","殴","藕","呕","偶","沤","啪","趴","爬","帕","怕","琶","拍","排","牌","徘","湃","派","攀","潘","盘","磐","盼","畔","判","叛","乓","庞","旁","耪","胖","抛","咆","刨","炮","袍","跑","泡","呸","胚","培","裴","赔","陪","配","佩","沛","喷","盆","砰","抨","烹","澎","彭","蓬","棚","硼","篷","膨","朋","鹏","捧","碰","坯","砒","霹","批","披","劈","琵","毗","啤","脾","疲","皮","匹","痞","僻","屁","譬","篇","偏","片","骗","飘","漂","瓢","票","撇","瞥","拼","频","贫","品","聘","乒","坪","苹","萍","平","凭","瓶","评","屏","坡","泼","颇","婆","破","魄","迫","粕","剖","扑","铺","仆","莆","葡","菩","蒲","埔","朴","圃","普","浦","谱","曝","瀑","期","欺","栖","戚","妻","七","凄","漆","柒","沏","其","棋","奇","歧","畦","崎","脐","齐","旗","祈","祁","骑","起","岂","乞","企","启","契","砌","器","气","迄","弃","汽","泣","讫","掐","恰","洽","牵","扦","钎","铅","千","迁","签","仟","谦","乾","黔","钱","钳","前","潜","遣","浅","谴","堑","嵌","欠","歉","枪","呛","腔","羌","墙","蔷","强","抢","橇","锹","敲","悄","桥","瞧","乔","侨","巧","鞘","撬","翘","峭","俏","窍","切","茄","且","怯","窃","钦","侵","亲","秦","琴","勤","芹","擒","禽","寝","沁","青","轻","氢","倾","卿","清","擎","晴","氰","情","顷","请","庆","琼","穷","秋","丘","邱","球","求","囚","酋","泅","趋","区","蛆","曲","躯","屈","驱","渠","取","娶","龋","趣","去","圈","颧","权","醛","泉","全","痊","拳","犬","券","劝","缺","炔","瘸","却","鹊","榷","确","雀","裙","群","然","燃","冉","染","瓤","壤","攘","嚷","让","饶","扰","绕","惹","热","壬","仁","人","忍","韧","任","认","刃","妊","纫","扔","仍","日","戎","茸","蓉","荣","融","熔","溶","容","绒","冗","揉","柔","肉","茹","蠕","儒","孺","如","辱","乳","汝","入","褥","软","阮","蕊","瑞","锐","闰","润","若","弱","撒","洒","萨","腮","鳃","塞","赛","三","叁","伞","散","桑","嗓","丧","搔","骚","扫","嫂","瑟","色","涩","森","僧","莎","砂","杀","刹","沙","纱","傻","啥","煞","筛","晒","珊","苫","杉","山","删","煽","衫","闪","陕","擅","赡","膳","善","汕","扇","缮","墒","伤","商","赏","晌","上","尚","裳","梢","捎","稍","烧","芍","勺","韶","少","哨","邵","绍","奢","赊","蛇","舌","舍","赦","摄","射","慑","涉","社","设","砷","申","呻","伸","身","深","娠","绅","神","沈","审","婶","甚","肾","慎","渗","声","生","甥","牲","升","绳","省","盛","剩","胜","圣","师","失","狮","施","湿","诗","尸","虱","十","石","拾","时","什","食","蚀","实","识","史","矢","使","屎","驶","始","式","示","士","世","柿","事","拭","誓","逝","势","是","嗜","噬","适","仕","侍","释","饰","氏","市","恃","室","视","试","收","手","首","守","寿","授","售","受","瘦","兽","蔬","枢","梳","殊","抒","输","叔","舒","淑","疏","书","赎","孰","熟","薯","暑","曙","署","蜀","黍","鼠","属","术","述","树","束","戍","竖","墅","庶","数","漱","恕","刷","耍","摔","衰","甩","帅","栓","拴","霜","双","爽","谁","水","睡","税","吮","瞬","顺","舜","说","硕","朔","烁","斯","撕","嘶","思","私","司","丝","死","肆","寺","嗣","四","伺","似","饲","巳","松","耸","怂","颂","送","宋","讼","诵","搜","艘","擞","嗽","苏","酥","俗","素","速","粟","僳","塑","溯","宿","诉","肃","酸","蒜","算","虽","隋","随","绥","髓","碎","岁","穗","遂","隧","祟","孙","损","笋","蓑","梭","唆","缩","琐","索","锁","所","塌","他","它","她","塔","獭","挞","蹋","踏","胎","苔","抬","台","泰","酞","太","态","汰","坍","摊","贪","瘫","滩","坛","檀","痰","潭","谭","谈","坦","毯","袒","碳","探","叹","炭","汤","塘","搪","堂","棠","膛","唐","糖","倘","躺","淌","趟","烫","掏","涛","滔","绦","萄","桃","逃","淘","陶","讨","套","特","藤","腾","疼","誊","梯","剔","踢","锑","提","题","蹄","啼","体","替","嚏","惕","涕","剃","屉","天","添","填","田","甜","恬","舔","腆","挑","条","迢","眺","跳","贴","铁","帖","厅","听","烃","汀","廷","停","亭","庭","挺","艇","通","桐","酮","瞳","同","铜","彤","童","桶","捅","筒","统","痛","偷","投","头","透","凸","秃","突","图","徒","途","涂","屠","土","吐","兔","湍","团","推","颓","腿","蜕","褪","退","吞","屯","臀","拖","托","脱","鸵","陀","驮","驼","椭","妥","拓","唾","挖","哇","蛙","洼","娃","瓦","袜","歪","外","豌","弯","湾","玩","顽","丸","烷","完","碗","挽","晚","皖","惋","宛","婉","万","腕","汪","王","亡","枉","网","往","旺","望","忘","妄","威","巍","微","危","韦","违","桅","围","唯","惟","为","潍","维","苇","萎","委","伟","伪","尾","纬","未","蔚","味","畏","胃","喂","魏","位","渭","谓","尉","慰","卫","瘟","温","蚊","文","闻","纹","吻","稳","紊","问","嗡","翁","瓮","挝","蜗","涡","窝","我","斡","卧","握","沃","巫","呜","钨","乌","污","诬","屋","无","芜","梧","吾","吴","毋","武","五","捂","午","舞","伍","侮","坞","戊","雾","晤","物","勿","务","悟","误","昔","熙","析","西","硒","矽","晰","嘻","吸","锡","牺","稀","息","希","悉","膝","夕","惜","熄","烯","溪","汐","犀","檄","袭","席","习","媳","喜","铣","洗","系","隙","戏","细","瞎","虾","匣","霞","辖","暇","峡","侠","狭","下","厦","夏","吓","掀","锨","先","仙","鲜","纤","咸","贤","衔","舷","闲","涎","弦","嫌","显","险","现","献","县","腺","馅","羡","宪","陷","限","线","相","厢","镶","香","箱","襄","湘","乡","翔","祥","详","想","响","享","项","巷","橡","像","向","象","萧","硝","霄","削","哮","嚣","销","消","宵","淆","晓","小","孝","校","肖","啸","笑","效","楔","些","歇","蝎","鞋","协","挟","携","邪","斜","胁","谐","写","械","卸","蟹","懈","泄","泻","谢","屑","薪","芯","锌","欣","辛","新","忻","心","信","衅","星","腥","猩","惺","兴","刑","型","形","邢","行","醒","幸","杏","性","姓","兄","凶","胸","匈","汹","雄","熊","休","修","羞","朽","嗅","锈","秀","袖","绣","墟","戌","需","虚","嘘","须","徐","许","蓄","酗","叙","旭","序","畜","恤","絮","婿","绪","续","轩","喧","宣","悬","旋","玄","选","癣","眩","绚","靴","薛","学","穴","雪","血","勋","熏","循","旬","询","寻","驯","巡","殉","汛","训","讯","逊","迅","压","押","鸦","鸭","呀","丫","芽","牙","蚜","崖","衙","涯","雅","哑","亚","讶","焉","咽","阉","烟","淹","盐","严","研","蜒","岩","延","言","颜","阎","炎","沿","奄","掩","眼","衍","演","艳","堰","燕","厌","砚","雁","唁","彦","焰","宴","谚","验","殃","央","鸯","秧","杨","扬","佯","疡","羊","洋","阳","氧","仰","痒","养","样","漾","邀","腰","妖","瑶","摇","尧","遥","窑","谣","姚","咬","舀","药","要","耀","椰","噎","耶","爷","野","冶","也","页","掖","业","叶","曳","腋","夜","液","一","壹","医","揖","铱","依","伊","衣","颐","夷","遗","移","仪","胰","疑","沂","宜","姨","彝","椅","蚁","倚","已","乙","矣","以","艺","抑","易","邑","屹","亿","役","臆","逸","肄","疫","亦","裔","意","毅","忆","义","益","溢","诣","议","谊","译","异","翼","翌","绎","茵","荫","因","殷","音","阴","姻","吟","银","淫","寅","饮","尹","引","隐","印","英","樱","婴","鹰","应","缨","莹","萤","营","荧","蝇","迎","赢","盈","影","颖","硬","映","哟","拥","佣","臃","痈","庸","雍","踊","蛹","咏","泳","涌","永","恿","勇","用","幽","优","悠","忧","尤","由","邮","铀","犹","油","游","酉","有","友","右","佑","釉","诱","又","幼","迂","淤","于","盂","榆","虞","愚","舆","余","俞","逾","鱼","愉","渝","渔","隅","予","娱","雨","与","屿","禹","宇","语","羽","玉","域","芋","郁","吁","遇","喻","峪","御","愈","欲","狱","育","誉","浴","寓","裕","预","豫","驭","鸳","渊","冤","元","垣","袁","原","援","辕","园","员","圆","猿","源","缘","远","苑","愿","怨","院","曰","约","越","跃","钥","岳","粤","月","悦","阅","耘","云","郧","匀","陨","允","运","蕴","酝","晕","韵","孕","匝","砸","杂","栽","哉","灾","宰","载","再","在","咱","攒","暂","赞","赃","脏","葬","遭","糟","凿","藻","枣","早","澡","蚤","躁","噪","造","皂","灶","燥","责","择","则","泽","贼","怎","增","憎","曾","赠","扎","喳","渣","札","轧","铡","闸","眨","栅","榨","咋","乍","炸","诈","摘","斋","宅","窄","债","寨","瞻","毡","詹","粘","沾","盏","斩","辗","崭","展","蘸","栈","占","战","站","湛","绽","樟","章","彰","漳","张","掌","涨","杖","丈","帐","账","仗","胀","瘴","障","招","昭","找","沼","赵","照","罩","兆","肇","召","遮","折","哲","蛰","辙","者","锗","蔗","这","浙","珍","斟","真","甄","砧","臻","贞","针","侦","枕","疹","诊","震","振","镇","阵","蒸","挣","睁","征","狰","争","怔","整","拯","正","政","帧","症","郑","证","芝","枝","支","吱","蜘","知","肢","脂","汁","之","织","职","直","植","殖","执","值","侄","址","指","止","趾","只","旨","纸","志","挚","掷","至","致","置","帜","峙","制","智","秩","稚","质","炙","痔","滞","治","窒","中","盅","忠","钟","衷","终","种","肿","重","仲","众","舟","周","州","洲","诌","粥","轴","肘","帚","咒","皱","宙","昼","骤","珠","株","蛛","朱","猪","诸","诛","逐","竹","烛","煮","拄","瞩","嘱","主","著","柱","助","蛀","贮","铸","筑","住","注","祝","驻","抓","爪","拽","专","砖","转","撰","赚","篆","桩","庄","装","妆","撞","壮","状","椎","锥","追","赘","坠","缀","谆","准","捉","拙","卓","桌","琢","茁","酌","啄","着","灼","浊","兹","咨","资","姿","滋","淄","孜","紫","仔","籽","滓","子","自","渍","字","鬃","棕","踪","宗","综","总","纵","邹","走","奏","揍","租","足","卒","族","祖","诅","阻","组","钻","纂","嘴","醉","最","罪","尊","遵","昨","左","佐","柞","做","作","坐","座","亍","丌","兀","丐","廿","卅","丕","亘","丞","鬲","孬","噩","丨","禺","丿","匕","乇","夭","爻","卮","氐","囟","胤","馗","毓","睾","鼗","丶","亟","鼐","乜","乩","亓","芈","孛","啬","嘏","仄","厍","厝","厣","厥","厮","靥","赝","匚","叵","匦","匮","匾","赜","卦","卣","刂","刈","刎","刭","刳","刿","剀","剌","剞","剡","剜","蒯","剽","劂","劁","劐","劓","冂","罔","亻","仃","仉","仂","仨","仡","仫","仞","伛","仳","伢","佤","仵","伥","伧","伉","伫","佞","佧","攸","佚","佝","佟","佗","伲","伽","佶","佴","侑","侉","侃","侏","佾","佻","侪","佼","侬","侔","俦","俨","俪","俅","俚","俣","俜","俑","俟","俸","倩","偌","俳","倬","倏","倮","倭","俾","倜","倌","倥","倨","偾","偃","偕","偈","偎","偬","偻","傥","傧","傩","傺","僖","儆","僭","僬","僦","僮","儇","儋","仝","氽","佘","佥","俎","龠","汆","籴","兮","巽","黉","馘","冁","夔","勹","匍","訇","匐","凫","夙","兕","亠","兖","亳","衮","袤","亵","脔","裒","禀","嬴","蠃","羸","冫","冱","冽","冼","凇","冖","冢","冥","讠","讦","讧","讪","讴","讵","讷","诂","诃","诋","诏","诎","诒","诓","诔","诖","诘","诙","诜","诟","诠","诤","诨","诩","诮","诰","诳","诶","诹","诼","诿","谀","谂","谄","谇","谌","谏","谑","谒","谔","谕","谖","谙","谛","谘","谝","谟","谠","谡","谥","谧","谪","谫","谮","谯","谲","谳","谵","谶","卩","卺","阝","阢","阡","阱","阪","阽","阼","陂","陉","陔","陟","陧","陬","陲","陴","隈","隍","隗","隰","邗","邛","邝","邙","邬","邡","邴","邳","邶","邺","邸","邰","郏","郅","邾","郐","郄","郇","郓","郦","郢","郜","郗","郛","郫","郯","郾","鄄","鄢","鄞","鄣","鄱","鄯","鄹","酃","酆","刍","奂","劢","劬","劭","劾","哿","勐","勖","勰","叟","燮","矍","廴","凵","凼","鬯","厶","弁","畚","巯","坌","垩","垡","塾","墼","壅","壑","圩","圬","圪","圳","圹","圮","圯","坜","圻","坂","坩","垅","坫","垆","坼","坻","坨","坭","坶","坳","垭","垤","垌","垲","埏","垧","垴","垓","垠","埕","埘","埚","埙","埒","垸","埴","埯","埸","埤","埝","堋","堍","埽","埭","堀","堞","堙","塄","堠","塥","塬","墁","墉","墚","墀","馨","鼙","懿","艹","艽","艿","芏","芊","芨","芄","芎","芑","芗","芙","芫","芸","芾","芰","苈","苊","苣","芘","芷","芮","苋","苌","苁","芩","芴","芡","芪","芟","苄","苎","芤","苡","茉","苷","苤","茏","茇","苜","苴","苒","苘","茌","苻","苓","茑","茚","茆","茔","茕","苠","苕","茜","荑","荛","荜","茈","莒","茼","茴","茱","莛","荞","茯","荏","荇","荃","荟","荀","茗","荠","茭","茺","茳","荦","荥","荨","茛","荩","荬","荪","荭","荮","莰","荸","莳","莴","莠","莪","莓","莜","莅","荼","莶","莩","荽","莸","荻","莘","莞","莨","莺","莼","菁","萁","菥","菘","堇","萘","萋","菝","菽","菖","萜","萸","萑","萆","菔","菟","萏","萃","菸","菹","菪","菅","菀","萦","菰","菡","葜","葑","葚","葙","葳","蒇","蒈","葺","蒉","葸","萼","葆","葩","葶","蒌","蒎","萱","葭","蓁","蓍","蓐","蓦","蒽","蓓","蓊","蒿","蒺","蓠","蒡","蒹","蒴","蒗","蓥","蓣","蔌","甍","蔸","蓰","蔹","蔟","蔺","蕖","蔻","蓿","蓼","蕙","蕈","蕨","蕤","蕞","蕺","瞢","蕃","蕲","蕻","薤","薨","薇","薏","蕹","薮","薜","薅","薹","薷","薰","藓","藁","藜","藿","蘧","蘅","蘩","蘖","蘼","廾","弈","夼","奁","耷","奕","奚","奘","匏","尢","尥","尬","尴","扌","扪","抟","抻","拊","拚","拗","拮","挢","拶","挹","捋","捃","掭","揶","捱","捺","掎","掴","捭","掬","掊","捩","掮","掼","揲","揸","揠","揿","揄","揞","揎","摒","揆","掾","摅","摁","搋","搛","搠","搌","搦","搡","摞","撄","摭","撖","摺","撷","撸","撙","撺","擀","擐","擗","擤","擢","攉","攥","攮","弋","忒","甙","弑","卟","叱","叽","叩","叨","叻","吒","吖","吆","呋","呒","呓","呔","呖","呃","吡","呗","呙","吣","吲","咂","咔","呷","呱","呤","咚","咛","咄","呶","呦","咝","哐","咭","哂","咴","哒","咧","咦","哓","哔","呲","咣","哕","咻","咿","哌","哙","哚","哜","咩","咪","咤","哝","哏","哞","唛","哧","唠","哽","唔","哳","唢","唣","唏","唑","唧","唪","啧","喏","喵","啉","啭","啁","啕","唿","啐","唼","唷","啖","啵","啶","啷","唳","唰","啜","喋","嗒","喃","喱","喹","喈","喁","喟","啾","嗖","喑","啻","嗟","喽","喾","喔","喙","嗪","嗷","嗉","嘟","嗑","嗫","嗬","嗔","嗦","嗝","嗄","嗯","嗥","嗲","嗳","嗌","嗍","嗨","嗵","嗤","辔","嘞","嘈","嘌","嘁","嘤","嘣","嗾","嘀","嘧","嘭","噘","嘹","噗","嘬","噍","噢","噙","噜","噌","噔","嚆","噤","噱","噫","噻","噼","嚅","嚓","嚯","囔","囗","囝","囡","囵","囫","囹","囿","圄","圊","圉","圜","帏","帙","帔","帑","帱","帻","帼","帷","幄","幔","幛","幞","幡","岌","屺","岍","岐","岖","岈","岘","岙","岑","岚","岜","岵","岢","岽","岬","岫","岱","岣","峁","岷","峄","峒","峤","峋","峥","崂","崃","崧","崦","崮","崤","崞","崆","崛","嵘","崾","崴","崽","嵬","嵛","嵯","嵝","嵫","嵋","嵊","嵩","嵴","嶂","嶙","嶝","豳","嶷","巅","彳","彷","徂","徇","徉","後","徕","徙","徜","徨","徭","徵","徼","衢","彡","犭","犰","犴","犷","犸","狃","狁","狎","狍","狒","狨","狯","狩","狲","狴","狷","猁","狳","猃","狺","狻","猗","猓","猡","猊","猞","猝","猕","猢","猹","猥","猬","猸","猱","獐","獍","獗","獠","獬","獯","獾","舛","夥","飧","夤","夂","饣","饧","饨","饩","饪","饫","饬","饴","饷","饽","馀","馄","馇","馊","馍","馐","馑","馓","馔","馕","庀","庑","庋","庖","庥","庠","庹","庵","庾","庳","赓","廒","廑","廛","廨","廪","膺","忄","忉","忖","忏","怃","忮","怄","忡","忤","忾","怅","怆","忪","忭","忸","怙","怵","怦","怛","怏","怍","怩","怫","怊","怿","怡","恸","恹","恻","恺","恂","恪","恽","悖","悚","悭","悝","悃","悒","悌","悛","惬","悻","悱","惝","惘","惆","惚","悴","愠","愦","愕","愣","惴","愀","愎","愫","慊","慵","憬","憔","憧","憷","懔","懵","忝","隳","闩","闫","闱","闳","闵","闶","闼","闾","阃","阄","阆","阈","阊","阋","阌","阍","阏","阒","阕","阖","阗","阙","阚","丬","爿","戕","氵","汔","汜","汊","沣","沅","沐","沔","沌","汨","汩","汴","汶","沆","沩","泐","泔","沭","泷","泸","泱","泗","沲","泠","泖","泺","泫","泮","沱","泓","泯","泾","洹","洧","洌","浃","浈","洇","洄","洙","洎","洫","浍","洮","洵","洚","浏","浒","浔","洳","涑","浯","涞","涠","浞","涓","涔","浜","浠","浼","浣","渚","淇","淅","淞","渎","涿","淠","渑","淦","淝","淙","渖","涫","渌","涮","渫","湮","湎","湫","溲","湟","溆","湓","湔","渲","渥","湄","滟","溱","溘","滠","漭","滢","溥","溧","溽","溻","溷","滗","溴","滏","溏","滂","溟","潢","潆","潇","漤","漕","滹","漯","漶","潋","潴","漪","漉","漩","澉","澍","澌","潸","潲","潼","潺","濑","濉","澧","澹","澶","濂","濡","濮","濞","濠","濯","瀚","瀣","瀛","瀹","瀵","灏","灞","宀","宄","宕","宓","宥","宸","甯","骞","搴","寤","寮","褰","寰","蹇","謇","辶","迓","迕","迥","迮","迤","迩","迦","迳","迨","逅","逄","逋","逦","逑","逍","逖","逡","逵","逶","逭","逯","遄","遑","遒","遐","遨","遘","遢","遛","暹","遴","遽","邂","邈","邃","邋","彐","彗","彖","彘","尻","咫","屐","屙","孱","屣","屦","羼","弪","弩","弭","艴","弼","鬻","屮","妁","妃","妍","妩","妪","妣","妗","姊","妫","妞","妤","姒","妲","妯","姗","妾","娅","娆","姝","娈","姣","姘","姹","娌","娉","娲","娴","娑","娣","娓","婀","婧","婊","婕","娼","婢","婵","胬","媪","媛","婷","婺","媾","嫫","媲","嫒","嫔","媸","嫠","嫣","嫱","嫖","嫦","嫘","嫜","嬉","嬗","嬖","嬲","嬷","孀","尕","尜","孚","孥","孳","孑","孓","孢","驵","驷","驸","驺","驿","驽","骀","骁","骅","骈","骊","骐","骒","骓","骖","骘","骛","骜","骝","骟","骠","骢","骣","骥","骧","纟","纡","纣","纥","纨","纩","纭","纰","纾","绀","绁","绂","绉","绋","绌","绐","绔","绗","绛","绠","绡","绨","绫","绮","绯","绱","绲","缍","绶","绺","绻","绾","缁","缂","缃","缇","缈","缋","缌","缏","缑","缒","缗","缙","缜","缛","缟","缡","缢","缣","缤","缥","缦","缧","缪","缫","缬","缭","缯","缰","缱","缲","缳","缵","幺","畿","巛","甾","邕","玎","玑","玮","玢","玟","珏","珂","珑","玷","玳","珀","珉","珈","珥","珙","顼","琊","珩","珧","珞","玺","珲","琏","琪","瑛","琦","琥","琨","琰","琮","琬","琛","琚","瑁","瑜","瑗","瑕","瑙","瑷","瑭","瑾","璜","璎","璀","璁","璇","璋","璞","璨","璩","璐","璧","瓒","璺","韪","韫","韬","杌","杓","杞","杈","杩","枥","枇","杪","杳","枘","枧","杵","枨","枞","枭","枋","杷","杼","柰","栉","柘","栊","柩","枰","栌","柙","枵","柚","枳","柝","栀","柃","枸","柢","栎","柁","柽","栲","栳","桠","桡","桎","桢","桄","桤","梃","栝","桕","桦","桁","桧","桀","栾","桊","桉","栩","梵","梏","桴","桷","梓","桫","棂","楮","棼","椟","椠","棹","椤","棰","椋","椁","楗","棣","椐","楱","椹","楠","楂","楝","榄","楫","榀","榘","楸","椴","槌","榇","榈","槎","榉","楦","楣","楹","榛","榧","榻","榫","榭","槔","榱","槁","槊","槟","榕","槠","榍","槿","樯","槭","樗","樘","橥","槲","橄","樾","檠","橐","橛","樵","檎","橹","樽","樨","橘","橼","檑","檐","檩","檗","檫","猷","獒","殁","殂","殇","殄","殒","殓","殍","殚","殛","殡","殪","轫","轭","轱","轲","轳","轵","轶","轸","轷","轹","轺","轼","轾","辁","辂","辄","辇","辋","辍","辎","辏","辘","辚","軎","戋","戗","戛","戟","戢","戡","戥","戤","戬","臧","瓯","瓴","瓿","甏","甑","甓","攴","旮","旯","旰","昊","昙","杲","昃","昕","昀","炅","曷","昝","昴","昱","昶","昵","耆","晟","晔","晁","晏","晖","晡","晗","晷","暄","暌","暧","暝","暾","曛","曜","曦","曩","贲","贳","贶","贻","贽","赀","赅","赆","赈","赉","赇","赍","赕","赙","觇","觊","觋","觌","觎","觏","觐","觑","牮","犟","牝","牦","牯","牾","牿","犄","犋","犍","犏","犒","挈","挲","掰","搿","擘","耄","毪","毳","毽","毵","毹","氅","氇","氆","氍","氕","氘","氙","氚","氡","氩","氤","氪","氲","攵","敕","敫","牍","牒","牖","爰","虢","刖","肟","肜","肓","肼","朊","肽","肱","肫","肭","肴","肷","胧","胨","胩","胪","胛","胂","胄","胙","胍","胗","朐","胝","胫","胱","胴","胭","脍","脎","胲","胼","朕","脒","豚","脶","脞","脬","脘","脲","腈","腌","腓","腴","腙","腚","腱","腠","腩","腼","腽","腭","腧","塍","媵","膈","膂","膑","滕","膣","膪","臌","朦","臊","膻","臁","膦","欤","欷","欹","歃","歆","歙","飑","飒","飓","飕","飙","飚","殳","彀","毂","觳","斐","齑","斓","於","旆","旄","旃","旌","旎","旒","旖","炀","炜","炖","炝","炻","烀","炷","炫","炱","烨","烊","焐","焓","焖","焯","焱","煳","煜","煨","煅","煲","煊","煸","煺","熘","熳","熵","熨","熠","燠","燔","燧","燹","爝","爨","灬","焘","煦","熹","戾","戽","扃","扈","扉","礻","祀","祆","祉","祛","祜","祓","祚","祢","祗","祠","祯","祧","祺","禅","禊","禚","禧","禳","忑","忐","怼","恝","恚","恧","恁","恙","恣","悫","愆","愍","慝","憩","憝","懋","懑","戆","肀","聿","沓","泶","淼","矶","矸","砀","砉","砗","砘","砑","斫","砭","砜","砝","砹","砺","砻","砟","砼","砥","砬","砣","砩","硎","硭","硖","硗","砦","硐","硇","硌","硪","碛","碓","碚","碇","碜","碡","碣","碲","碹","碥","磔","磙","磉","磬","磲","礅","磴","礓","礤","礞","礴","龛","黹","黻","黼","盱","眄","眍","盹","眇","眈","眚","眢","眙","眭","眦","眵","眸","睐","睑","睇","睃","睚","睨","睢","睥","睿","瞍","睽","瞀","瞌","瞑","瞟","瞠","瞰","瞵","瞽","町","畀","畎","畋","畈","畛","畲","畹","疃","罘","罡","罟","詈","罨","罴","罱","罹","羁","罾","盍","盥","蠲","钅","钆","钇","钋","钊","钌","钍","钏","钐","钔","钗","钕","钚","钛","钜","钣","钤","钫","钪","钭","钬","钯","钰","钲","钴","钶","钷","钸","钹","钺","钼","钽","钿","铄","铈","铉","铊","铋","铌","铍","铎","铐","铑","铒","铕","铖","铗","铙","铘","铛","铞","铟","铠","铢","铤","铥","铧","铨","铪","铩","铫","铮","铯","铳","铴","铵","铷","铹","铼","铽","铿","锃","锂","锆","锇","锉","锊","锍","锎","锏","锒","锓","锔","锕","锖","锘","锛","锝","锞","锟","锢","锪","锫","锩","锬","锱","锲","锴","锶","锷","锸","锼","锾","锿","镂","锵","镄","镅","镆","镉","镌","镎","镏","镒","镓","镔","镖","镗","镘","镙","镛","镞","镟","镝","镡","镢","镤","镥","镦","镧","镨","镩","镪","镫","镬","镯","镱","镲","镳","锺","矧","矬","雉","秕","秭","秣","秫","稆","嵇","稃","稂","稞","稔","稹","稷","穑","黏","馥","穰","皈","皎","皓","皙","皤","瓞","瓠","甬","鸠","鸢","鸨","鸩","鸪","鸫","鸬","鸲","鸱","鸶","鸸","鸷","鸹","鸺","鸾","鹁","鹂","鹄","鹆","鹇","鹈","鹉","鹋","鹌","鹎","鹑","鹕","鹗","鹚","鹛","鹜","鹞","鹣","鹦","鹧","鹨","鹩","鹪","鹫","鹬","鹱","鹭","鹳","疒","疔","疖","疠","疝","疬","疣","疳","疴","疸","痄","疱","疰","痃","痂","痖","痍","痣","痨","痦","痤","痫","痧","瘃","痱","痼","痿","瘐","瘀","瘅","瘌","瘗","瘊","瘥","瘘","瘕","瘙","瘛","瘼","瘢","瘠","癀","瘭","瘰","瘿","瘵","癃","瘾","瘳","癍","癞","癔","癜","癖","癫","癯","翊","竦","穸","穹","窀","窆","窈","窕","窦","窠","窬","窨","窭","窳","衤","衩","衲","衽","衿","袂","袢","裆","袷","袼","裉","裢","裎","裣","裥","裱","褚","裼","裨","裾","裰","褡","褙","褓","褛","褊","褴","褫","褶","襁","襦","襻","疋","胥","皲","皴","矜","耒","耔","耖","耜","耠","耢","耥","耦","耧","耩","耨","耱","耋","耵","聃","聆","聍","聒","聩","聱","覃","顸","颀","颃","颉","颌","颍","颏","颔","颚","颛","颞","颟","颡","颢","颥","颦","虍","虔","虬","虮","虿","虺","虼","虻","蚨","蚍","蚋","蚬","蚝","蚧","蚣","蚪","蚓","蚩","蚶","蛄","蚵","蛎","蚰","蚺","蚱","蚯","蛉","蛏","蚴","蛩","蛱","蛲","蛭","蛳","蛐","蜓","蛞","蛴","蛟","蛘","蛑","蜃","蜇","蛸","蜈","蜊","蜍","蜉","蜣","蜻","蜞","蜥","蜮","蜚","蜾","蝈","蜴","蜱","蜩","蜷","蜿","螂","蜢","蝽","蝾","蝻","蝠","蝰","蝌","蝮","螋","蝓","蝣","蝼","蝤","蝙","蝥","螓","螯","螨","蟒","蟆","螈","螅","螭","螗","螃","螫","蟥","螬","螵","螳","蟋","蟓","螽","蟑","蟀","蟊","蟛","蟪","蟠","蟮","蠖","蠓","蟾","蠊","蠛","蠡","蠹","蠼","缶","罂","罄","罅","舐","竺","竽","笈","笃","笄","笕","笊","笫","笏","筇","笸","笪","笙","笮","笱","笠","笥","笤","笳","笾","笞","筘","筚","筅","筵","筌","筝","筠","筮","筻","筢","筲","筱","箐","箦","箧","箸","箬","箝","箨","箅","箪","箜","箢","箫","箴","篑","篁","篌","篝","篚","篥","篦","篪","簌","篾","篼","簏","簖","簋","簟","簪","簦","簸","籁","籀","臾","舁","舂","舄","臬","衄","舡","舢","舣","舭","舯","舨","舫","舸","舻","舳","舴","舾","艄","艉","艋","艏","艚","艟","艨","衾","袅","袈","裘","裟","襞","羝","羟","羧","羯","羰","羲","籼","敉","粑","粝","粜","粞","粢","粲","粼","粽","糁","糇","糌","糍","糈","糅","糗","糨","艮","暨","羿","翎","翕","翥","翡","翦","翩","翮","翳","糸","絷","綦","綮","繇","纛","麸","麴","赳","趄","趔","趑","趱","赧","赭","豇","豉","酊","酐","酎","酏","酤","酢","酡","酰","酩","酯","酽","酾","酲","酴","酹","醌","醅","醐","醍","醑","醢","醣","醪","醭","醮","醯","醵","醴","醺","豕","鹾","趸","跫","踅","蹙","蹩","趵","趿","趼","趺","跄","跖","跗","跚","跞","跎","跏","跛","跆","跬","跷","跸","跣","跹","跻","跤","踉","跽","踔","踝","踟","踬","踮","踣","踯","踺","蹀","踹","踵","踽","踱","蹉","蹁","蹂","蹑","蹒","蹊","蹰","蹶","蹼","蹯","蹴","躅","躏","躔","躐","躜","躞","豸","貂","貊","貅","貘","貔","斛","觖","觞","觚","觜","觥","觫","觯","訾","謦","靓","雩","雳","雯","霆","霁","霈","霏","霎","霪","霭","霰","霾","龀","龃","龅","龆","龇","龈","龉","龊","龌","黾","鼋","鼍","隹","隼","隽","雎","雒","瞿","雠","銎","銮","鋈","錾","鍪","鏊","鎏","鐾","鑫","鱿","鲂","鲅","鲆","鲇","鲈","稣","鲋","鲎","鲐","鲑","鲒","鲔","鲕","鲚","鲛","鲞","鲟","鲠","鲡","鲢","鲣","鲥","鲦","鲧","鲨","鲩","鲫","鲭","鲮","鲰","鲱","鲲","鲳","鲴","鲵","鲶","鲷","鲺","鲻","鲼","鲽","鳄","鳅","鳆","鳇","鳊","鳋","鳌","鳍","鳎","鳏","鳐","鳓","鳔","鳕","鳗","鳘","鳙","鳜","鳝","鳟","鳢","靼","鞅","鞑","鞒","鞔","鞯","鞫","鞣","鞲","鞴","骱","骰","骷","鹘","骶","骺","骼","髁","髀","髅","髂","髋","髌","髑","魅","魃","魇","魉","魈","魍","魑","飨","餍","餮","饕","饔","髟","髡","髦","髯","髫","髻","髭","髹","鬈","鬏","鬓","鬟","鬣","麽","麾","縻","麂","麇","麈","麋","麒","鏖","麝","麟","黛","黜","黝","黠","黟","黢","黩","黧","黥","黪","黯","鼢","鼬","鼯","鼹","鼷","鼽","鼾","齄","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","1","2","3","4","5","6","7","8","9","0"," ","《","》","?","!",",","。","~","!","@","#","$","%","^","&","*","(",")","_","+","-","=","|","[","]","{","}",";",":","\"",".",",","<",">","/","?","`","、","|","¥","×","(",")","’","“","”","‘",":",";","【","】","\t","²","³","μ","㎡","㎞","㎝","㎜","㎏","㎎","℃"]
\ No newline at end of file
...@@ -187,14 +187,14 @@ export const constantRoutes = [ ...@@ -187,14 +187,14 @@ export const constantRoutes = [
}] }]
}, },
{ {
path: '/history', path: '/tool',
redirect: '/history/index', redirect: '/tool/font',
component: Layout, component: Layout,
children: [{ children: [{
path: 'index', path: 'font',
name: 'AppHistoryChart', name: 'FontTool',
component: () => import('@/views/system/history'), component: () => import('@/views/system/font-tool'),
meta: { title: '历史曲线', icon: 'home' } meta: { title: '字体转换工具', icon: 'home' }
}] }]
}, },
{ {
...@@ -231,14 +231,14 @@ export const constantRoutes = [ ...@@ -231,14 +231,14 @@ export const constantRoutes = [
}] }]
}, },
{ {
path: '/evue', path: '/bytecode',
redirect: '/evue/index', redirect: '/bytecode/index',
component: Layout, component: Layout,
children: [{ children: [{
path: 'index', path: 'index',
name: 'ByteCodeFile', name: 'ByteCodeFile',
component: () => import('@/views/system/evue'), component: () => import('@/views/system/bytecode-tool'),
meta: { title: 'evue', icon: 'home' } meta: { title: 'bytecode', icon: 'home' }
}] }]
}, },
{ {
......
...@@ -71,22 +71,22 @@ export default { ...@@ -71,22 +71,22 @@ export default {
// icon: "gongzuotai", // icon: "gongzuotai",
// path: "chart/index", // path: "chart/index",
// }, // },
// { {
// vue: "system/history.vue", vue: "system/font-tool.vue",
// title: "历史曲线", title: "字体转换工具",
// name: "AppHistoryChart", name: "FontTool",
// icon: "gongzuotai", icon: "gongzuotai",
// path: "history/index", path: "tool/font",
// }, },
{ {
vue: "system/tool.vue", vue: "system/tool.vue",
title: "工具", title: "字符串转C文件",
name: "AppTool", name: "AppTool",
icon: "gongzuotai", icon: "gongzuotai",
path: "tool/index", path: "tool/index",
}, },
{ {
vue: "system/evue.vue", vue: "system/bytecode-tool.vue",
title: "字节码文件转换", title: "字节码文件转换",
name: "ByteCodeFile", name: "ByteCodeFile",
icon: "gongzuotai", icon: "gongzuotai",
......
<template>
<div class="app-container">
<el-alert title="字节码文件在线转换" type="success"></el-alert>
<div style="margin: 10px 0px">
<el-form>
<el-form-item>
<el-upload
name="binfile"
drag
multiple
ref="upload"
action="null"
:auto-upload="false"
:http-request="handleUploadFile"
:on-remove="handleUploadRemove"
>
<i class="el-icon-upload"></i>
<div class="el-upload__text">
将文件拖到此处,或<em>点击上传</em>
</div>
<div class="el-upload__tip" slot="tip">请选择evue文件</div>
</el-upload>
</el-form-item>
<el-form-item>
<el-button @click="uploadFile">开始上传</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
import { postByteCodeFile } from "@/api/app-store";
export default {
name: "ByteCodeFile",
data() {
return {
fileList: [],
};
},
methods: {
createFile(content, filename) {
const a = document.createElement("a");
const blob = new Blob([content]);
const url = window.URL.createObjectURL(blob);
a.href = url;
a.download = filename;
a.click();
window.URL.revokeObjectURL(url);
},
handleUploaded(response) {
if (response.code === 200) {
this.downloadFile(response);
} else {
this.$message.warning(response.message);
}
},
handleUploadFile(file) {
this.fileList.push(file);
},
handleUploadRemove(file, fileList) {
console.log(fileList);
for (let i = 0; i < this.fileList.length; i++) {
if (this.fileList[i].uid == file.uid) {
this.fileList.splice(i, 1);
break;
}
}
},
downloadFile(result) {
const a = document.createElement("a");
a.download = result.data.filename;
a.href = result.data.url;
a.target = "";
a.click();
},
uploadFile() {
this.$refs.upload.submit();
let formData = new FormData();
this.fileList.forEach((item) => {
formData.append("binfile", item.file);
});
postByteCodeFile(formData)
.then((res) => {
if (res.code === 200) {
this.downloadFile(res);
} else {
this.$message.warning(res.message);
}
})
.catch((err) => {
this.$message.error(err.message);
});
},
},
mounted() {},
created() {},
};
</script>
<style lang="scss" scoped>
.app-container {
& > div.page-wrapper {
margin: 10px 0px;
}
}
</style>
<template>
<div class="app-container">
<h3>字体转换工具</h3>
<el-row :gutter="20">
<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
<el-input
type="textarea"
:autosize="{ minRows: 30, maxRows: 30 }"
resize="none"
placeholder="请选择要转换的文本"
v-model="post.text"
></el-input>
</el-col>
<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
<el-form label-position="right" label-width="120px" :model="post">
<el-form-item label="输出bin文件名">
<el-input v-model="post.filename"></el-input>
</el-form-item>
<el-form-item label="文字大小">
<el-input
v-model="post.sizes"
placeholder="可输入多个数值,用英文逗号隔开"
></el-input>
</el-form-item>
<el-form-item label="字库文件">
<el-upload
name="font"
ref="upload"
accept=".eot,.otf,.fon,.font,.ttf,.ttc,.woff"
:limit="1"
:multiple="false"
:data="post"
:action="uploadAction"
:on-success="handleSuccess"
:on-preview="handlePreview"
:on-remove="handleRemove"
:file-list="fileList"
:auto-upload="false"
>
<el-button slot="trigger" size="small" type="primary"
>选取文件</el-button
>
<el-button
style="margin-left: 10px"
size="small"
type="success"
@click="submitUpload"
>开始转换字体</el-button
>
<div slot="tip" class="el-upload__tip">
请选择字库文件,目前只支持如下格式文件:eot,otf,fon,font,ttf,ttc,woff
</div>
</el-upload>
</el-form-item>
<el-form-item>
<el-button @click="loadFont('common')">加载常用字体</el-button>
<el-button @click="loadFont('all')">加载全部字体</el-button>
</el-form-item>
</el-form>
</el-col>
</el-row>
</div>
</template>
<script>
import allFonts from "@/assets/all-fonts.json";
import commonFonts from "@/assets/common-used-fonts.json";
import { generateFont } from "@/api/app-store";
// import { mapTrim } from '@/utils/index'
// 优化:可以取字体差异,POST只发送产生差异的字,比如删除的字、添加的字
export default {
name: "FontTool",
data() {
return {
isLoading: false,
inputString: commonFonts.join(""),
outputString: "",
post: {
sizes: null,
filename: null,
text: commonFonts.join(""),
},
uploadAction: `//${window.location.host}/api/v1/evm_store/system/generateFont`,
fileList: [],
};
},
methods: {
downloadFile(result) {
const a = document.createElement("a");
a.download = result.filename;
a.href = result.url;
a.target = "";
a.click();
},
loadFont(source) {
if (source == "all") this.post.text = allFonts.join("");
else this.post.text = commonFonts.join("");
},
handleUpload() {
let formData = new FormData();
Object.keys(this.post).forEach((k) => {
formData.append(k, this.post[k]);
});
generateFont(formData)
.then((res) => {
console.log(res);
})
.catch((err) => {
console.error(err);
});
},
submitUpload() {
this.$refs.upload.submit();
},
handleSuccess(res) {
if (res.code == 200) {
this.downloadFile(res.data);
}
this.$refs.upload.clearFiles();
},
handleRemove(file, fileList) {
console.log(file, fileList);
},
handlePreview(file) {
console.log(file);
},
},
mounted() {},
created() {},
};
</script>
<style lang="scss" scoped>
.app-container {
& > div.page-wrapper {
margin: 10px 0px;
}
}
</style>
...@@ -87,30 +87,41 @@ ...@@ -87,30 +87,41 @@
min-width="150" min-width="150"
show-overflow-tooltip show-overflow-tooltip
></el-table-column> ></el-table-column>
<el-table-column
prop="path"
label="path"
min-width="150"
show-overflow-tooltip
></el-table-column>
<el-table-column <el-table-column
prop="timestamp" prop="timestamp"
label="timestamp" label="timestamp"
min-width="150" min-width="150"
show-overflow-tooltip show-overflow-tooltip
></el-table-column> ></el-table-column>
<el-table-column label="imei" min-width="150" show-overflow-tooltip>
<template slot-scope="scope">{{ scope.row.imei }}</template>
</el-table-column>
<el-table-column <el-table-column
prop="free_size"
label="free_size" label="free_size"
min-width="100" min-width="150"
show-overflow-tooltip show-overflow-tooltip
> >
<template slot-scope="scope" <template slot-scope="scope"
>{{ scope.row.free_size }}(KB)</template >{{ scope.row.free_size }}(KB)</template
> >
</el-table-column> </el-table-column>
<el-table-column
prop="free_space_size"
label="free_space_size"
min-width="150"
show-overflow-tooltip
>
<template slot-scope="scope"
>{{ scope.row.free_space_size }}(KB)</template
>
</el-table-column>
<el-table-column
label="used_space_size"
min-width="150"
show-overflow-tooltip
>
<template slot-scope="scope"
>{{ scope.row.used_space_size }}(KB)</template
>
</el-table-column>
</el-table> </el-table>
</grid-item> </grid-item>
<grid-item <grid-item
...@@ -350,7 +361,28 @@ ...@@ -350,7 +361,28 @@
<grid-item <grid-item
:x="0" :x="0"
:y="20" :y="20"
:w="12" :w="4"
:h="14"
i="7"
@resize="resizeEvent"
@move="moveEvent"
@resized="resizedEvent"
@container-resized="containerResizedEvent"
@moved="movedEvent"
>
<div>
<p class="item-title">应用大小</p>
<el-table :data="appList" size="mini" style="width: 100%">
<el-table-column prop="appName" label="应用名称" width="180"></el-table-column>
<el-table-column prop="fileSize" label="应用大小(KB)"></el-table-column>
<el-table-column prop="fileCount" label="文件个数" width="100"> </el-table-column>
</el-table>
</div>
</grid-item>
<grid-item
:x="4"
:y="20"
:w="8"
:h="7" :h="7"
i="7" i="7"
@resize="resizeEvent" @resize="resizeEvent"
...@@ -365,11 +397,11 @@ ...@@ -365,11 +397,11 @@
></SystemChart> ></SystemChart>
</grid-item> </grid-item>
<grid-item <grid-item
:x="0" :x="4"
:y="27" :y="27"
:w="12" :w="8"
:h="7" :h="7"
i="7" i="8"
@resize="resizeEvent" @resize="resizeEvent"
@move="moveEvent" @move="moveEvent"
@resized="resizedEvent" @resized="resizedEvent"
...@@ -383,7 +415,7 @@ ...@@ -383,7 +415,7 @@
:y="34" :y="34"
:w="12" :w="12"
:h="7" :h="7"
i="8" i="9"
@resize="resizeEvent" @resize="resizeEvent"
@move="moveEvent" @move="moveEvent"
@resized="resizedEvent" @resized="resizedEvent"
...@@ -544,6 +576,7 @@ export default { ...@@ -544,6 +576,7 @@ export default {
], ],
draggable: true, draggable: true,
resizable: true, resizable: true,
appList: [],
}; };
}, },
components: { components: {
...@@ -576,7 +609,7 @@ export default { ...@@ -576,7 +609,7 @@ export default {
console.error(err.msg); console.error(err.msg);
}); });
wsNotify.eventBus.$emit("exportImg"); wsNotify.eventBus.$emit("export-picture");
monitor monitor
.getAllData((params) => { .getAllData((params) => {
return params.imei && params.imei == this.device; return params.imei && params.imei == this.device;
...@@ -885,14 +918,27 @@ export default { ...@@ -885,14 +918,27 @@ export default {
}); });
} }
}); });
// 处理appList
// 一、统计每个页面有多少个资源文件;二、累加每个资源文件的size;三、以表格形式展示统计信息
if (msg.appList && msg.appList.length) {
this.appList = msg.appList.map(item => {
item.fileCount = item.files.length
item.fileSize = item.files.reduce((total, file) => {
return total + file.size;
}, 0)
item.fileSize = item.fileSize / 1024
return item
})
}
}, },
onSelectChange(res) { onSelectChange(res) {
this.device = res; this.device = res;
// 清空图表数据 // 清空图表数据
wsNotify.eventBus.$emit("clear-system-chart");
wsNotify.eventBus.$emit("clear-evm-chart"); wsNotify.eventBus.$emit("clear-evm-chart");
wsNotify.eventBus.$emit("clear-lvgl-chart"); wsNotify.eventBus.$emit("clear-lvgl-chart");
wsNotify.eventBus.$emit("clear-system-chart");
// 清空各个表格数据 // 清空各个表格数据
this.imageList = []; this.imageList = [];
......
<template>
<div class="app-container">
<el-form :inline="true" :model="form" size="mini">
<el-form-item label="角色名称">
<el-select v-model="form.uuid" filterable placeholder="请输入角色名称">
<el-option v-for="(item, index) in roles" :key="index" :label="item.name" :value="item.uuid"></el-option>
</el-select>
</el-form-item>
<el-form-item><el-button type="primary" @click="onSubmit">查询</el-button></el-form-item>
<el-form-item><el-button @click="onReset">重置</el-button></el-form-item>
<el-form-item><el-button type="warning" @click="onAdd">添加</el-button></el-form-item>
</el-form>
<el-table v-loading="isLoading" element-loading-text="Loading" :data="list" size="mini" border stripe fit highlight-current-row>
<el-table-column prop="name" label="角色名称" align="center" min-width="150" :show-overflow-tooltip="true"></el-table-column>
<el-table-column prop="is_system" label="系统角色" width="80">
<template slot-scope="scope">
<span>{{ scope.row.is_system ? '': '' }}</span>
</template>
</el-table-column>
<el-table-column prop="create_at" label="创建时间" width="150"></el-table-column>
<el-table-column prop="create_by.username" label="创建者" width="150"></el-table-column>
<el-table-column prop="update_at" label="更新时间" width="150"></el-table-column>
<el-table-column prop="update_by.username" label="更新者" width="150"></el-table-column>
<el-table-column label="操作" align="center" width="180" fixed="right">
<template slot-scope="scope">
<el-button size="mini" type="success" :disabled="hasPermission" @click="handleEdit(scope.$index, scope.row)">编辑</el-button>
<el-button size="mini" type="danger" :disabled="scope.row.is_system" @click="handleDelete(scope.$index, scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="page-wrapper">
<el-pagination @current-change="handleCurrentChange" :current-page.sync="form.pagenum" background small :page-size="form.pagesize" :pager-count="5" layout="pager, prev, next, total" :total="total"></el-pagination>
</div>
<el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="45%">
<el-form :model="post" status-icon :rules="rules" :inline="true" ref="post" size="mini" label-width="120px">
<el-form-item label="角色名称" prop="name">
<el-input type="text" v-model="post.name" :disabled="post.is_system" autocomplete="off" placeholder="请输入角色名称"></el-input>
</el-form-item>
<el-divider content-position="left">操作权限</el-divider>
<el-form-item label="基础信息权限" prop="permission">
<el-radio-group v-model="post.permission.basic" size="mini">
<el-radio-button label="可读"></el-radio-button>
<el-radio-button label="可读写"></el-radio-button>
<el-radio-button label="无权限"></el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="流程管理权限" prop="permission">
<el-radio-group v-model="post.permission.flow" size="mini">
<el-radio-button label="可读"></el-radio-button>
<el-radio-button label="可读写"></el-radio-button>
<el-radio-button label="无权限"></el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="回款计划权限" prop="permission">
<el-radio-group v-model="post.permission.paybackPlan" size="mini">
<el-radio-button label="可读"></el-radio-button>
<el-radio-button label="可读写"></el-radio-button>
<el-radio-button label="无权限"></el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="回款进度权限" prop="permission">
<el-radio-group v-model="post.permission.paybackProgress" size="mini">
<el-radio-button label="可读"></el-radio-button>
<el-radio-button label="可读写"></el-radio-button>
<el-radio-button label="无权限"></el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="技术资源库权限" prop="permission">
<el-radio-group v-model="post.permission.techResources" size="mini">
<el-radio-button label="可读"></el-radio-button>
<el-radio-button label="可读写"></el-radio-button>
<el-radio-button label="无权限"></el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="技术日历权限" prop="permission">
<el-radio-group v-model="post.permission.calendar" size="mini">
<el-radio-button label="可读"></el-radio-button>
<el-radio-button label="可读写"></el-radio-button>
<el-radio-button label="无权限"></el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="用户管理权限" prop="permission">
<el-radio-group v-model="post.permission.users" size="mini">
<el-radio-button label="可读"></el-radio-button>
<el-radio-button label="可读写"></el-radio-button>
<el-radio-button label="无权限"></el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="角色管理权限" prop="permission">
<el-radio-group v-model="post.permission.roles" size="mini">
<el-radio-button label="可读"></el-radio-button>
<el-radio-button label="可读写"></el-radio-button>
<el-radio-button label="无权限"></el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="部门管理权限" prop="permission">
<el-radio-group v-model="post.permission.depots" size="mini">
<el-radio-button label="可读"></el-radio-button>
<el-radio-button label="可读写"></el-radio-button>
<el-radio-button label="无权限"></el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="人员资质预警" prop="permission">
<el-radio-group v-model="post.permission.personQualification" size="mini">
<el-radio-button label="可读"></el-radio-button>
<el-radio-button label="可读写"></el-radio-button>
<el-radio-button label="无权限"></el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="设备资质预警" prop="permission">
<el-radio-group v-model="post.permission.equipmentQualification" size="mini">
<el-radio-button label="可读"></el-radio-button>
<el-radio-button label="可读写"></el-radio-button>
<el-radio-button label="无权限"></el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="公司资质预警" prop="permission">
<el-radio-group v-model="post.permission.companyQualification" size="mini">
<el-radio-button label="可读"></el-radio-button>
<el-radio-button label="可读写"></el-radio-button>
<el-radio-button label="无权限"></el-radio-button>
</el-radio-group>
</el-form-item>
<el-divider content-position="left">数据范围</el-divider>
<el-form-item label="项目数据范围" prop="permission">
<el-radio-group v-model="post.permission.dataScope" size="mini">
<el-radio-button label="自己的"></el-radio-button>
<el-radio-button label="部门的"></el-radio-button>
<el-radio-button label="公司的"></el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="预警数据范围" prop="permission">
<el-radio-group v-model="post.permission.warningDataScope" size="mini">
<el-radio-button label="自己的"></el-radio-button>
<el-radio-button label="部门的"></el-radio-button>
<el-radio-button label="公司的"></el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="日历数据范围" prop="permission">
<el-radio-group v-model="post.permission.calendarDataScope" size="mini">
<el-radio-button label="自己的"></el-radio-button>
<el-radio-button label="部门的"></el-radio-button>
<el-radio-button label="公司的"></el-radio-button>
</el-radio-group>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" size="mini" plain @click="submitForm('post')">提交</el-button>
<el-button type="success" size="mini" plain @click="onReset('post')">重置</el-button>
<el-button size="mini" @click="dialogVisible = false">关闭</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { mapState, mapGetters } from "vuex";
import { getRoleList, deleteRole, updateRole, addRole } from '@/api/index'
import checkPermission from '@/utils/permission'
import { mapTrim, compareObjectDiff } from '@/utils/index'
export default {
data() {
return {
total: 0,
list: [],
isLoading: false,
roles: [],
form: {
uuid: null,
name: null,
pagesize: 15,
pagenum: 1
},
dialogTitle: "",
dialogVisible: false,
currentValue: null,
currentIndex: null,
post: {
name: null,
permission: {
basic: '无权限',
flow: '无权限',
users: '无权限',
roles: '无权限',
depots: '无权限',
paybackPlan: '无权限',
paybackProgress: '无权限',
personQualification: "无权限",
equipmentQualification: "无权限",
companyQualification: "无权限",
techResources: "无权限",
calendar: "无权限",
dataScope: "自己的",
warningDataScope: "自己的",
calendarDataScope: "自己的",
},
is_system: false
},
rules: {
name: [
{ type: 'string', required: true, message: '用户名不能为空', trigger: 'blur' },
{ min: 1, max: 20, message: '字符串长度在 1 到 20 之间', trigger: 'blur' }
],
permission: [{ type: 'object', required: true, message: '权限不能为空', trigger: 'blur' }]
}
}
},
computed: {
...mapState("user", [ "avatar", ]),
...mapGetters([ "role", ]),
hasPermission: () => JSON.parse(sessionStorage.getItem("user")).role.name === "超级管理员" ? false : true,
},
methods: {
checkPermission,
fetchData(params) {
this.isLoading = true
getRoleList(Object.assign({
pagenum: this.form.pagenum,
pagesize: this.form.pagesize,
}, params)).then(res => {
this.total = res.count
this.list = res.data
}).catch(err => {
// this.$message.error(err.message)
console.log(err.message)
}).finally(() => {
this.isLoading = false
})
},
fetchSelectData() {
getRoleList({ "scope_type": "list" }).then(res => {
if (res.code == 200) this.roles = res.data
}).catch(err => {
// this.$message.error(err.message)
console.log(err.message)
})
},
handleSizeChange(e) {
this.form.pagesize = e
this.fetchData(mapTrim(this.form))
},
handleCurrentChange(e) {
this.form.pagenum = e
this.fetchData(mapTrim(this.form))
},
handleEdit(index, row) {
if (row.is_system && this.hasPermission) return this.$message.error("系统内置角色,无法修改")
if (row.permission.basic) this.post.permission.basic = row.permission.basic
if (row.permission.dataScope) this.post.permission.dataScope = row.permission.dataScope
if (row.permission.flow) this.post.permission.flow = row.permission.flow
if (row.permission.users) this.post.permission.users = row.permission.users
if (row.permission.roles) this.post.permission.roles = row.permission.roles
if (row.permission.depots) this.post.permission.depots = row.permission.depots
if (row.permission.paybackPlan) this.post.permission.paybackPlan = row.permission.paybackPlan
if (row.permission.paybackProgress) this.post.permission.paybackProgress = row.permission.paybackProgress
if (row.permission.personQualification) this.post.permission.personQualification = row.permission.personQualification
if (row.permission.equipmentQualification) this.post.permission.equipmentQualification = row.permission.equipmentQualification
if (row.permission.companyQualification) this.post.permission.companyQualification = row.permission.companyQualification
if (row.permission.techResources) this.post.permission.techResources = row.permission.techResources
if (row.permission.calendar) this.post.permission.calendar = row.permission.calendar
if (row.permission.calendarDataScope) this.post.permission.calendarDataScope = row.permission.calendarDataScope
if (row.permission.warningDataScope) this.post.permission.warningDataScope = row.permission.warningDataScope
this.post.name = row.name
this.post.is_system = row.is_system
this.currentValue = row
this.currentIndex = index
this.dialogTitle = "编辑"
this.dialogVisible = true
},
handleDelete(index, row) {
if (row.is_system) return this.$message.error("系统内置角色,无法删除")
this.$alert('您确定要删除么?删除操作将不可恢复。如需取消操作,请点击右上角关闭按钮。', '删除提醒', {
confirmButtonText: '确定',
callback: action => {
if (action == 'confirm') deleteRole(row.uuid).then(res => {
console.log(res)
this.total -= 1
this.$delete(this.list, index)
this.$message({ type: 'success', message: `成功删除第${ index }行` })
this.fetchData()
}).catch(err => {
this.$message.error(err.message)
})
}
})
},
submitForm(formName) {
this.$refs[formName].validate((valid) => {
let result = true
if (valid) {
if (this.dialogTitle === '添加') addRole(this.post).then(res => {
console.log(res)
this.$message({ type: 'success', message: '添加成功' })
this.fetchData()
}).catch(err => {
this.$message.error(err.message)
})
else if (this.dialogTitle === '编辑') updateRole(this.currentValue.uuid, compareObjectDiff(this.post, this.currentValue)).then(res => {
console.log(res)
this.$message({ type: 'success', message: '更新成功' })
this.fetchData()
}).catch(err => {
this.$message.error(err.message)
})
} else {
result = false
}
this.dialogVisible = false
return result
})
},
onAdd() {
this.dialogTitle = "添加"
this.dialogVisible = true
},
onSubmit() {
this.form.pagenum = 1
this.form.pagesize = 15
this.fetchData(mapTrim(this.form))
},
onReset(formName) {
this.form = {
account: null,
username: null,
pagesize: 15,
pagenum: 1
}
this.$refs[formName].resetFields()
this.fetchData()
}
},
mounted() {},
created() {
this.fetchData()
this.fetchSelectData()
const user = JSON.parse(sessionStorage.getItem("user"))
if (!user || user.role.permission.roles == "无权限") this.$router.push("/403")
}
}
</script>
<style lang="scss" scoped>
.app-container {
& > div.page-wrapper {
margin: 10px 0px;
}
}
</style>
<template>
<div class="app-container">
<el-form :inline="true" ref="form" :model="form" size="mini">
<el-form-item label="标题" prop="uuid">
<el-select v-model="form.uuid" filterable placeholder="请输入标题">
<el-option v-for="(item, index) in roles" :key="index" :label="item.name" :value="item.uuid"></el-option>
</el-select>
</el-form-item>
<el-form-item><el-button type="primary" @click="onSubmit">查询</el-button></el-form-item>
<el-form-item><el-button @click="onReset">重置</el-button></el-form-item>
<el-form-item><el-button type="warning" @click="onAdd">添加</el-button></el-form-item>
<el-form-item>
<el-popover placement="top-start" width="240" trigger="click">
<el-checkbox-group :min="1" v-model="checkList" @change="onCheckboxChange">
<el-checkbox :label="item" v-for="(item, index) in headerList" :key="index"></el-checkbox>
</el-checkbox-group>
<el-button type="success" slot="reference">表头设置</el-button>
</el-popover>
</el-form-item>
<el-form-item>
<el-button type="info" plain @click="handleDownload">导出当前数据</el-button>
</el-form-item>
</el-form>
<el-table v-loading="isLoading" element-loading-text="Loading" :data="list" size="mini" border stripe fit highlight-current-row>
<el-table-column :prop="item.prop" :label="item.label" :align="item.align" :min-width="item.width" v-for="(item, index) in tableHeader" :key="index"></el-table-column>
<el-table-column prop="create_at" label="创建时间" width="150"></el-table-column>
<el-table-column prop="create_by.username" label="创建者" width="150"></el-table-column>
<el-table-column prop="update_at" label="更新时间" width="150" :show-overflow-tooltip="true"></el-table-column>
<el-table-column prop="update_by.username" label="更新者" width="150"></el-table-column>
<el-table-column label="操作" align="center" width="180" fixed="right">
<template slot-scope="scope">
<el-button size="mini" type="success" @click="handleEdit(scope.$index, scope.row)">编辑</el-button>
<el-button size="mini" type="danger" @click="handleDelete(scope.$index, scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="page-wrapper">
<el-pagination @current-change="handleCurrentChange" :current-page.sync="form.pagenum" background small :page-size="form.pagesize" :pager-count="5" layout="pager, prev, next, total" :total="total"></el-pagination>
</div>
<el-dialog
:title="dialogTitle"
:visible.sync="dialogVisible"
width="50%"
>
<el-form :model="post" status-icon :rules="rules" :inline="true" ref="post" size="mini" label-width="200px">
<el-form-item label="标题" prop="name">
<el-input type="text" v-model="post.name" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="年度调派现场总天数" prop="year_dispatch_site_days">
<el-input type="number" v-model.number="post.year_dispatch_site_days" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="年度监督流失率" prop="year_supervise_churn_rate">
<el-input type="number" v-model.number="post.year_supervise_churn_rate" autocomplete="off"><template slot="append">%</template></el-input>
</el-form-item>
<el-form-item label="年度再认证流失率" prop="year_recert_churn_rate">
<el-input type="number" v-model.number="post.year_recert_churn_rate" autocomplete="off"><template slot="append">%</template></el-input>
</el-form-item>
<el-form-item label="年度顾客满意率" prop="year_satis_churn_rate">
<el-input type="number" v-model.number="post.year_satis_churn_rate" autocomplete="off"><template slot="append">%</template></el-input>
</el-form-item>
<el-form-item label="年度应收款回款率" prop="year_receiv_collection_rate">
<el-input type="number" v-model.number="post.year_receiv_collection_rate" autocomplete="off"><template slot="append">%</template></el-input>
</el-form-item>
<el-form-item label="行业项目比率" prop="indus_project_rate">
<el-input type="number" v-model.number="post.indus_project_rate" autocomplete="off"><template slot="append">%</template></el-input>
</el-form-item>
<el-form-item label="渠道开发项目比率" prop="channel_project_rate">
<el-input type="number" v-model.number="post.channel_project_rate" autocomplete="off"><template slot="append">%</template></el-input>
</el-form-item>
<el-form-item label="年度坏账终止项目数" prop="year_bad_project">
<el-input type="number" v-model.number="post.year_bad_project" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="年度坏账金额" prop="year_bad_debt_amount">
<el-input type="number" v-model.number="post.year_bad_debt_amount" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="行业项目数量" prop="indus_project_count">
<el-input type="number" v-model.number="post.indus_project_count" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="渠道开发项目数量" prop="channel_project_count">
<el-input type="number" v-model.number="post.channel_project_count" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" size="mini" plain @click="submitForm('post')">提交</el-button>
<el-button type="success" size="mini" plain @click="onReset('form')">重置</el-button>
<el-button size="mini" @click="dialogVisible = false">关闭</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { getSummaryList, deleteSummary, addSummary, updateSummary } from '@/api/index'
import { mapTrim } from '@/utils/index'
import { exportJsonToExcel } from "@/utils/excel"
const fieldList = [
{ label: "标题", prop: "name", isShow: true },
{ label: "年度监督流失率", prop: "year_supervise_churn_rate", isShow: true },
{ label: "年度再认证流失率", prop: "year_recert_churn_rate", isShow: true },
{ label: "年度顾客满意率", prop: "year_satis_churn_rate", isShow: true },
{ label: "年度应收款回款率", prop: "year_receiv_collection_rate", isShow: true },
{ label: "行业项目比率", prop: "indus_project_rate", isShow: true },
{ label: "渠道开发项目比率", prop: "channel_project_rate", isShow: true },
{ label: "年度调派现场总天数", prop: "year_dispatch_site_days", isShow: false },
{ label: "年度坏账终止项目数", prop: "year_bad_project", isShow: false },
{ label: "年度坏账金额", prop: "year_bad_debt_amount", isShow: false },
{ label: "行业项目数量", prop: "indus_project_count", isShow: false },
{ label: "渠道开发项目数量", prop: "channel_project_count", isShow: false },
]
const tableHeader = fieldList.filter(item => {
if (item.isShow) return Object.assign(item, { align: "center", width: "150" })
})
export default {
name: "Summary",
data() {
return {
total: 0,
list: [],
isLoading: false,
checkList: tableHeader.map(item => item.label),
headerList: fieldList.map(item => item.label),
tableHeader: tableHeader,
roles: [],
form: {
uuid: null,
name: null,
pagesize: 15,
pagenum: 1
},
currentIndex: 0,
currentValue: null,
dialogTitle: "",
dialogVisible: false,
post: {
name: null,
year_supervise_churn_rate: null,
year_recert_churn_rate: null,
year_satis_churn_rate: null,
year_dispatch_site_days: null,
year_receiv_collection_rate: null,
year_bad_project: null,
year_bad_debt_amount: null,
indus_project_rate: null,
indus_project_count: null,
channel_project_rate: null,
channel_project_count: null,
},
rules: {
year_supervise_churn_rate: [{ type: 'number', required: true, message: '字段不能为空', trigger: 'blur' }],
year_recert_churn_rate: [{ type: 'number', required: true, message: '字段不能为空', trigger: 'blur' }],
year_satis_churn_rate: [{ type: 'number', required: true, message: '字段不能为空', trigger: 'blur' }],
year_dispatch_site_days: [{ type: 'number', required: true, message: '字段不能为空', trigger: 'blur' }],
year_receiv_collection_rate: [{ type: 'number', required: true, message: '字段不能为空', trigger: 'blur' }],
year_bad_project: [{ type: 'number', required: true, message: '字段不能为空', trigger: 'blur' }],
year_bad_debt_amount: [{ type: 'number', required: true, message: '字段不能为空', trigger: 'blur' }],
indus_project_rate: [{ type: 'number', required: true, message: '字段不能为空', trigger: 'blur' }],
indus_project_count: [{ type: 'number', required: true, message: '字段不能为空', trigger: 'blur' }],
channel_project_rate: [{ type: 'number', required: true, message: '字段不能为空', trigger: 'blur' }],
channel_project_count: [{ type: 'number', required: true, message: '字段不能为空', trigger: 'blur' }],
name: [
{ type: 'string', required: true, message: '用户名不能为空', trigger: 'blur' },
{ min: 1, max: 20, message: '字符串长度在 1 到 20 之间', trigger: 'blur' }
]
}
}
},
methods: {
fetchData(params) {
this.isLoading = true
getSummaryList(params).then(res => {
this.total = res.count
this.list = res.data
}).catch(err => {
// this.$message.error(err.message)
console.log(err.message)
}).finally(() => {
this.isLoading = false
})
},
fetchSelectData() {
getSummaryList({ "scope_type": "list" }).then(res => {
if (res.code == 200) this.roles = res.data
}).catch(err => {
// this.$message.error(err.message)
console.log(err.message)
})
},
handleSizeChange(e) {
this.form.pagesize = e
this.fetchData(mapTrim(this.form))
},
handleCurrentChange(e) {
this.form.pagenum = e
this.fetchData(mapTrim(this.form))
},
handleEdit(index, row) {
this.post = Object.assign(row)
this.currentIndex = index
this.currentValue = row
this.dialogTitle = "编辑"
this.dialogVisible = true
},
handleDelete(index, row) {
this.$alert('您确定要删除么?删除操作将不可恢复。如需取消操作,请点击右上角关闭按钮。', '删除提醒', {
confirmButtonText: '确定',
callback: action => {
if (action == 'confirm') deleteSummary(row.uuid).then(res => {
console.log(res)
this.total -= 1
this.$delete(this.list, index)
this.$message({ type: 'success', message: `成功删除第${ index }行` })
}).catch(err => {
this.$message.error(err.message)
})
}
})
},
submitForm(formName) {
this.$refs[formName].validate((valid) => {
let result = true
if (valid) {
if (this.dialogTitle === '添加') addSummary(mapTrim(this.post)).then(res => {
console.log(res)
this.$message({ type: 'success', message: '添加成功' })
this.fetchData(mapTrim(this.form))
}).catch(err => {
this.$message.error(err.message)
})
else if (this.dialogTitle === '编辑') updateSummary(this.currentValue.uuid, this.post).then(res => {
console.log(res)
// this.$set(this.list, this.currentIndex, Object.assign(this.currentValue, tmp))
this.$message({ type: 'success', message: '更新成功' })
this.fetchData(mapTrim(this.form))
}).catch(err => {
this.$message.error(err.message)
})
} else {
result = false
}
this.dialogVisible = false
return result
})
},
handleDownload() {
const loading = this.$loading({
lock: true,
text: 'Loading',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
})
getSummaryList({ "scope_type": "list", "props": this.tableHeader.map(item => item.prop) })
.then((res) => {
exportJsonToExcel({
header: this.tableHeader,
headerLabel: "label",
headerProp: "prop",
jsonData: res.data,
filename: Date.now()
})
})
.catch((err) => {
this.$message.warning(err.message)
}).finally(() => {
loading.close()
})
},
onCheckboxChange(evt) {
let header = []
evt.forEach(f => {
for(let i = 0 ; i < fieldList.length; i++) {
if (fieldList[i].label === f) {
header.push(Object.assign(fieldList[i], { align: "center", width: "150" }))
break
}
}
})
this.tableHeader = header
},
onAdd() {
this.dialogTitle = "添加"
this.dialogVisible = true
},
onSubmit() {
this.form.pagenum = 1
this.form.pagesize = 15
this.fetchData(mapTrim(this.form))
},
onReset(formName) {
this.$refs[formName].resetFields()
this.form.pagesize = 15
this.form.pagenum = 1
this.fetchData(mapTrim(this.form))
}
},
mounted() {},
created() {
this.fetchData(mapTrim(this.form))
this.fetchSelectData()
}
}
</script>
<style lang="scss" scoped>
.app-container {
& > div.page-wrapper {
margin: 10px 0px;
}
}
</style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment