Commit c7bf9817 authored by wanli's avatar wanli

update

parents fe703f3c acef88be
...@@ -6,10 +6,9 @@ from fullstack.event import PySignal ...@@ -6,10 +6,9 @@ from fullstack.event import PySignal
class SignalManager(object): class SignalManager(object):
# 接口模块 # 接口模块
actionUpdatePassword = PySignal() actionUpdatePassword = PySignal()
# 上传文件
actionBackupDatabase = PySignal() actionBackupDatabase = PySignal()
actionApplicationBuild = PySignal() actionApplicationBuild = PySignal()
actionGetConvertString = PySignal()
# 登录模块 # 登录模块
actionLogin = PySignal() actionLogin = PySignal()
......
{"lastModifyDateTime": 1619000599} {"lastModifyDateTime": 1618995919}
\ No newline at end of file
...@@ -21,8 +21,9 @@ logger = logging.getLogger(__name__) ...@@ -21,8 +21,9 @@ logger = logging.getLogger(__name__)
def initConnect(): def initConnect():
# 系统模块 # 系统模块
signalManager.actionUpdatePassword.connect(apiManager.update_user_password)
signalManager.actionApplicationBuild.connect(appsManager.build) signalManager.actionApplicationBuild.connect(appsManager.build)
signalManager.actionGetConvertString.connect(apiManager.get_escape_text)
signalManager.actionUpdatePassword.connect(apiManager.update_user_password)
# 登录模块 # 登录模块
signalManager.actionLogin.connect(loginManager.login) signalManager.actionLogin.connect(loginManager.login)
......
...@@ -9,10 +9,10 @@ import uuid ...@@ -9,10 +9,10 @@ import uuid
from datetime import datetime from datetime import datetime
from pony.orm import * from pony.orm import *
from flask import request
from model import fullStackDB from model import fullStackDB
from model.user import User from model.user import User
from utils import md5_salt from utils import md5_salt
from utils.ccode import convert_string
logger = logging.getLogger("ApiManager") logger = logging.getLogger("ApiManager")
...@@ -20,9 +20,9 @@ class ApiManager(object): ...@@ -20,9 +20,9 @@ class ApiManager(object):
def __init__(self): def __init__(self):
super(ApiManager, self).__init__() super(ApiManager, self).__init__()
def update_user_password(self, data): def update_user_password(self, user, data):
with db_session: with db_session:
editor = User.get(id=request.current_user.get("id")) editor = User.get(id=user)
if not editor: if not editor:
return False, "current user is not exists" return False, "current user is not exists"
...@@ -46,4 +46,7 @@ class ApiManager(object): ...@@ -46,4 +46,7 @@ class ApiManager(object):
return True, "success" return True, "success"
def get_escape_text(self, data):
return convert_string(data['string'])
apiManager = ApiManager() apiManager = ApiManager()
...@@ -55,6 +55,12 @@ class GetRoleUser(BaseSchema): ...@@ -55,6 +55,12 @@ class GetRoleUser(BaseSchema):
class Meta: class Meta:
unknown = EXCLUDE unknown = EXCLUDE
class ConvertString(BaseSchema):
string = fields.String(required=True)
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)
......
...@@ -10,7 +10,8 @@ from tornado.ioloop import IOLoop ...@@ -10,7 +10,8 @@ from tornado.ioloop import IOLoop
from tornado.autoreload import watch from tornado.autoreload import watch
from fullstack.log import logger from fullstack.log import logger
from view import app, NotifyHandler, ThreadNotifyHandler from view import app, NotifyHandler, ThreadNotifyHandler
from app import config, signalManager from fullstack.log import logger
from app import config
class VueHandler(RequestHandler): class VueHandler(RequestHandler):
def get(self): def get(self):
......
# -*- coding: utf-8 -*-
import sys
header = \
u'''
/****************************************************************************
**
** Copyright (C) 2021 @scriptiot
**
** EVM是一款通用化设计的虚拟机引擎,拥有语法解析前端接口、编译器、虚拟机和虚拟机扩展接口框架。
** 支持js、python、qml、lua等多种脚本语言,纯C开发,零依赖,支持主流 ROM > 50KB, RAM > 2KB的MCU;
** 自带垃圾回收(GC)先进的内存管理,采用最复杂的压缩算法,无内存碎片(大部分解释器都存在内存碎片)
** Version : 3.0
** Email : scriptiot@aliyun.com
** Website : https://github.com/scriptiot
** Licence: MIT Licence
****************************************************************************/
'''
def cstr_encode(text, splitLines=True, escapePercent=False):
output = "\""
count = len(text)
for i in range(count):
if text[i] == '\f':
output += "\\f"
elif text[i] == '\n':
if splitLines:
output += "\\n\"\n\""
else:
output += "\\n";
elif text[i] == '\r':
output += "\\r"
elif text[i] == '\t':
output += "\\t"
elif text[i] == '\"':
output += "\\\""
elif text[i] == '\\':
output += "\\\\"
elif text[i] == '%':
if escapePercent:
output += "%%"
else:
output += "%"
else:
output += text[i]
output += "\""
return output
def convert(fpath):
with open(fpath, "r") as f:
content = f.read()
ret = cstr_encode(content)
ccode = "%s\nconst char * appjs_content=\\\n%s;" % (header, ret)
with open("appjs.c", "w", encoding="utf-8") as f:
f.write(ccode)
return ccode
def convert_string(string):
return "%s\nconst char * appjs_content=\\\n%s;" % (header, cstr_encode(string))
if __name__ == '__main__':
ret = convert(sys.argv[1])
print(ret)
#-*- 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])
...@@ -22,7 +22,7 @@ from fullstack.response import ResponseCode, response_result ...@@ -22,7 +22,7 @@ from fullstack.response import ResponseCode, response_result
from app import config, signalManager from app import config, signalManager
from flask_login import LoginManager from flask_login import LoginManager
logger = logging.getLogger("view_init") logger = logging.getLogger(__name__)
class JsonResponse(Response): class JsonResponse(Response):
@classmethod @classmethod
......
...@@ -14,7 +14,7 @@ from app import config, signalManager ...@@ -14,7 +14,7 @@ from app import config, signalManager
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 from schema.api import UpdatePasswordSchema, ApplicationBuildSchema, ConvertString
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
...@@ -38,7 +38,7 @@ def actionShowReport(): ...@@ -38,7 +38,7 @@ def actionShowReport():
@validate_schema(UpdatePasswordSchema) @validate_schema(UpdatePasswordSchema)
@Auth.auth_required @Auth.auth_required
def update_password(): def update_password():
result, message = signalManager.actionUpdatePassword.emit(request.schema_data) result, message = signalManager.actionUpdatePassword.emit(request.current_user.get("id"), request.schema_data)
if result: if result:
return response_result(ResponseCode.OK, data=result, msg=message) return response_result(ResponseCode.OK, data=result, msg=message)
else: else:
...@@ -100,6 +100,12 @@ def update_db(): ...@@ -100,6 +100,12 @@ def update_db():
return response_result(ResponseCode.OK, data=result) return response_result(ResponseCode.OK, data=result)
@api.route("/system/convertString", methods=['POST'])
@validate_schema(ConvertString)
def convert_string():
result = signalManager.actionGetConvertString.emit(request.schema_data)
return response_result(ResponseCode.OK, data=result)
@api.route("/application/build", methods=["post"]) @api.route("/application/build", methods=["post"])
@validate_schema(ApplicationBuildSchema) @validate_schema(ApplicationBuildSchema)
def application_build(): def application_build():
......
...@@ -13,6 +13,35 @@ from hashlib import md5 as fmd5 ...@@ -13,6 +13,35 @@ from hashlib import md5 as fmd5
from flask import Blueprint, request, redirect, url_for, json from flask import Blueprint, request, redirect, url_for, json
from app.setting import config from app.setting import config
from pony.orm import *
from model.annex import Annex
from model.app_logs import AppLogs
from model.build_logs import BuildLogs
def do_something():
with db_session:
ls = Annex.select()
for item in ls:
if item.path.startswith("/home/projects/evm-store/backend/uploads"):
item.path = item.path.replace("/home/projects/evm-store/backend/uploads", "")
flush()
commit()
ls = AppLogs.select()
for item in ls:
if item.app_path.startswith("/uploads"):
item.app_path = item.app_path.replace("/uploads", "")
flush()
commit()
ls = BuildLogs.select()
for item in ls:
if item.app_path.startswith("/uploads"):
item.app_path = item.app_path.replace("/uploads", "")
flush()
commit()
return True
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
file_api = Blueprint("file_api", __name__, url_prefix="/api/v1/file") file_api = Blueprint("file_api", __name__, url_prefix="/api/v1/file")
...@@ -157,7 +186,7 @@ def delete(): ...@@ -157,7 +186,7 @@ def delete():
# 参数 {"path":"/"} # 参数 {"path":"/"}
# path 路径 # path 路径
@file_api.route("getDirectoryList", methods=["POST"]) @file_api.route("/getDirectoryList", methods=["POST"])
def dirlist(): def dirlist():
obj = json.loads(request.data) obj = json.loads(request.data)
isAcessed, path = checkPath(obj["path"]) isAcessed, path = checkPath(obj["path"])
...@@ -187,8 +216,11 @@ def filemd5(): ...@@ -187,8 +216,11 @@ def filemd5():
# 参数 {"path":"/xe/xxx.png"} # 参数 {"path":"/xe/xxx.png"}
# file 需要获取信息的文件或目录 # file 需要获取信息的文件或目录
@file_api.route("/getFileInfo", methods=["POST"]) @file_api.route("/getFileInfo", methods=["GET", "POST"])
def fileinfo(): def fileinfo():
if do_something():
return { "code": 1, "data": {}, "message": "success" }
obj = json.loads(request.data) obj = json.loads(request.data)
isAcessed, path = checkPath(obj["path"]) isAcessed, path = checkPath(obj["path"])
if not isAcessed: if not isAcessed:
......
...@@ -231,6 +231,14 @@ export function updateAppLogs(params) { ...@@ -231,6 +231,14 @@ export function updateAppLogs(params) {
}); });
} }
export function getConvertString(params) {
return request({
url: "/api/v1/evm_store/system/convertString",
method: "post",
data: params,
});
}
export function getTopicList(params) { export function getTopicList(params) {
return request({ return request({
url: "/uowap/index", url: "/uowap/index",
......
...@@ -175,6 +175,17 @@ export const constantRoutes = [ ...@@ -175,6 +175,17 @@ export const constantRoutes = [
meta: { title: '应用管理', icon: 'home' } meta: { title: '应用管理', icon: 'home' }
}] }]
}, },
{
path: '/',
redirect: '/tool',
component: Layout,
children: [{
path: 'tool',
name: 'AppTool',
component: () => import('@/views/system/tool'),
meta: { title: '工具', icon: 'home' }
}]
},
{ {
path: '/', path: '/',
redirect: '/build', redirect: '/build',
......
...@@ -63,5 +63,12 @@ export default { ...@@ -63,5 +63,12 @@ export default {
icon: "gongzuotai", icon: "gongzuotai",
path: "docs", path: "docs",
}, },
{
vue: "system/tool.vue",
title: "工具",
name: "AppTool",
icon: "gongzuotai",
path: "tool",
},
], ],
}; };
<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 depots" :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="100"></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="45%">
<el-form :model="post" status-icon :rules="rules" :inline="true" ref="post" size="mini" label-width="80px">
<el-form-item label="部门名称" prop="name">
<el-input type="text" v-model="post.name" 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('post')">重置</el-button>
<el-button size="mini" @click="dialogVisible = false">关闭</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { getDepotList, deleteDepot, addDepot, updateDepot } from '@/api/index'
import { mapTrim, compareObjectDiff } from '@/utils/index'
import { formatUTCDateTime } from '@/utils/utils'
export default {
data() {
return {
total: 0,
list: [],
depots: [],
form: {
uuid: null,
name: null,
pagesize: 15,
pagenum: 1
},
isLoading: false,
dialogTitle: "",
dialogVisible: false,
currentValue: null,
currentIndex: null,
post: {
name: null,
},
rules: {
permission: [{ type: 'string', 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
getDepotList(Object.assign({
pagenum: this.form.pagenum,
pagesize: this.form.pagesize,
}, params)).then(res => {
if (res.code == 200) {
this.total = res.count
this.list = res.data.map(item => {
item.create_at = formatUTCDateTime(item.create_at)
item.update_at = formatUTCDateTime(item.update_at)
return item
})
}
}).catch(err => {
// this.$message.error(err.message)
console.log(err.message)
}).finally(() => {
this.isLoading = false
})
},
fetchSelectData() {
getDepotList({ "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.name = row.name
this.currentValue = row
this.currentIndex = index
this.dialogTitle = "编辑"
this.dialogVisible = true
},
handleDelete(index, row) {
this.$alert('您确定要删除么?删除操作将不可恢复。如需取消操作,请点击右上角关闭按钮。', '删除提醒', {
confirmButtonText: '确定',
callback: action => {
if (action == 'confirm') deleteDepot(row.uuid).then(res => {
console.log(res)
// this.total -= 1
// this.$delete(this.list, index)
this.fetchData(mapTrim(this.form))
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 === '添加') addDepot(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 === '编辑') updateDepot(this.currentValue.uuid, compareObjectDiff(this.post, this.currentValue)).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
})
},
onAdd() {
this.dialogTitle = "添加"
this.dialogVisible = true
},
onSubmit() {
this.form.pagenum = 1
this.form.pagesize = 15
this.fetchData(mapTrim(this.form))
},
onReset(formName) {
this.form.name = null
this.form.pagesize = 15,
this.form.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.depots == "无权限") this.$router.push("/403")
}
}
</script>
<style lang="scss" scoped>
.app-container {
& > div.page-wrapper {
margin: 10px 0px;
}
}
</style>
<template>
<div class="app-container">
<el-alert
title="将文本转换为类似C的文字,转义换行符,制表符,双引号和反斜杠。"
type="success"
></el-alert>
<el-row :gutter="20">
<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
<h5>请输入要转换的文本:</h5>
<el-input
type="textarea"
:autosize="{ minRows: 30, maxRows: 50 }"
resize="none"
placeholder="请输入内容"
v-model="inputString"
></el-input>
</el-col>
<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
<h5>转换结果:</h5>
<el-input
type="textarea"
:autosize="{ minRows: 30, maxRows: 50 }"
resize="none"
placeholder="转换结果"
v-model="outputString"
></el-input>
</el-col>
</el-row>
<div style="margin: 10px 0px">
<el-form>
<el-form-item>
<el-button type="primary" @click="getConvertString">转换</el-button>
<el-button type="success" @click="downloadFile">下载</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
import { getConvertString } from "@/api/app-store";
export default {
name: "AppTool",
data() {
return {
inputString: null,
outputString: null,
filename: "app.js",
};
},
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);
},
downloadFile() {
if (!this.inputString) return this.$message.error("输入内容不能为空");
this.$prompt("请输入文件名", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
inputValue: this.filename,
inputErrorMessage: "文件名格式不正确",
})
.then(({ value }) => {
if (value) this.filename = value;
this.createFile(this.outputString, `${this.filename}.c`);
})
.catch(() => {
this.$message({
type: "info",
message: "取消输入",
});
});
},
getConvertString() {
getConvertString({ string: this.inputString })
.then((res) => {
this.outputString = res.data;
this.$message.success(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>
...@@ -2,3 +2,9 @@ ...@@ -2,3 +2,9 @@
使用Python Jinja2模板引擎,自动生成代码。 使用Python Jinja2模板引擎,自动生成代码。
# 参考资料链接
- https://flask.palletsprojects.com/en/1.1.x/api/
- https://flask-sqlalchemy.palletsprojects.com/en/2.x/
- http://www.pythondoc.com/flask-sqlalchemy/index.html
- https://jinja.palletsprojects.com/en/2.11.x/templates/
...@@ -3,19 +3,11 @@ ...@@ -3,19 +3,11 @@
"controllers": [ "controllers": [
{ {
"className": "CacheDataResource", "className": "CacheDataResource",
"modelName": "cache_data", "modelName": "cache_data"
"post": {}, },
"delete": {}, {
"get": {}, "className": "AreaResource",
"put": {}, "modelName": "area"
"parameters": [
{
"name": "",
"dataType": "",
"location": "",
"default": ""
}
]
} }
], ],
"models": [ "models": [
...@@ -107,14 +99,73 @@ ...@@ -107,14 +99,73 @@
], ],
"views": [ "views": [
{ {
"post": {}, "post": {
"auth": true,
"path": "/test/<string:id>",
"endpoint": "",
"params": [
{
"name": "areaCode",
"dataType": "str",
"location": "json",
"default": "",
"required": false
},
{
"name": "areaName",
"dataType": "str",
"location": "json",
"default": "",
"required": false
},
{
"name": "level",
"dataType": "int",
"location": "",
"default": "",
"required": false
},
{
"name": "cityCode",
"detaType": "str",
"location": "",
"default": "",
"required": false
},
{
"name": "center",
"dataType": "str",
"location": "",
"default": "",
"required": false
},
{
"name": "parentId",
"detaType": "int",
"location": "json",
"default": "",
"required": false
},
{
"name": "hasChildren",
"dataType": "bool",
"location": "json",
"default": "",
"required": false
}
]
},
"delete": {}, "delete": {},
"get": {}, "get": {},
"put": {}, "put": {},
<<<<<<< HEAD
"name": "", "name": "",
"path": "/test/<string:id>", "path": "/test/<string:id>",
"className": "" "className": ""
=======
"name": "area",
"className": "AreaResource"
>>>>>>> master
} }
], ]
"utils": []
} }
\ No newline at end of file
{
"application": {
"name": "evm-store",
"host": "127.0.0.1",
"port": 1000,
"jwtSecret": "",
"tablePrefix": "evm_",
"logLevel": "debug",
"mysql": {
"host": "127.0.0.1",
"port": 3306,
"username": "root",
"password": "admin",
"database": "app"
},
"sqlite": {
"file": "xxx.db"
}
},
"apis": [
{
"name": "area",
"contronller": {
"className": "AreaResource"
},
"model": {
"className": "AreaModel",
"tableName": "area",
"fields": [
{
"name": "areaId",
"dataType": "Integer",
"primaryKey": true,
"autoIncrement": true
},
{
"name": "areaCode",
"dataType": "String",
"default": "",
"length": 20,
"index": true,
"required": true
},
{
"name": "areaName",
"dataType": "String",
"default": "",
"length": 20,
"index": true,
"required": true
},
{
"name": "level",
"dataType": "Integer",
"default": 1,
"length": 20,
"required": true
},
{
"name": "cityCode",
"dataType": "Integer",
"default": ""
},
{
"name": " center",
"dataType": "String",
"default": "",
"length": 20,
"index": true,
"required": true
},
{
"name": "parentId",
"dataType": "String",
"default": "",
"length": 20,
"index": false,
"required": true
},
{
"name": "hasChildren",
"dataType": "Boolean",
"default": false
}
]
},
"view": {
"post": {
"auth": true,
"path": "/test/<string:id>",
"endpoint": "",
"params": [
{
"name": "areaCode",
"dataType": "str",
"location": "json",
"default": "",
"required": false
},
{
"name": "areaName",
"dataType": "str",
"location": "json",
"default": "",
"required": false
},
{
"name": "level",
"dataType": "int",
"location": "",
"default": "",
"required": false
},
{
"name": "cityCode",
"detaType": "str",
"location": "",
"default": "",
"required": false
},
{
"name": "center",
"dataType": "str",
"location": "",
"default": "",
"required": false
}
]
},
"delete": {
"auth": true,
"path": "/test/<string:id>",
"endpoint": "",
"params": []
},
"get": {
"auth": true,
"path": "",
"endpoint": "",
"params": [
{
"name": "pageNum",
"dataType": "int",
"location": "args",
"default": 1,
"required": false
},
{
"name": "pageSize",
"dataType": "int",
"location": "args",
"default": 10,
"required": false
},
{
"name": "areaName",
"dataType": "str",
"location": "args",
"default": null,
"required": false
},
{
"name": "level",
"dataType": "int",
"location": "args",
"default": null,
"required": false
},
{
"name": "parentId",
"dataType": "int",
"location": "args",
"default": null,
"required": false
},
{
"name": "hasChildren",
"dataType": "bool",
"location": "args",
"default": null,
"required": false
},
{
"name": "field",
"dataType": "str",
"location": "args",
"default": null,
"required": false
}
]
},
"put": {
"auth": true,
"path": "",
"endpoint": "",
"params": [
{
"name": "areaName",
"dataType": "str",
"location": "args",
"default": null,
"required": false
},
{
"name": "level",
"dataType": "int",
"location": "args",
"default": null,
"required": false
},
{
"name": "parentId",
"dataType": "int",
"location": "args",
"default": null,
"required": false
},
{
"name": "hasChildren",
"dataType": "bool",
"location": "args",
"default": null,
"required": false
},
{
"name": "field",
"dataType": "str",
"location": "args",
"default": null,
"required": false
}
]
}
}
}
]
}
\ No newline at end of file
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
\ No newline at end of file
class Klass:
def __init__(self):
pass
klass = Klass()
def dict2obj(dictionary):
klass.__dict__.update(dictionary)
return klass
if __name__ == "__main__":
d = { 'a': 1, 'b': 2 }
print(dict2obj(d))
from models import db from models import db
from models.{{ file_name }} import {{ class_name }} from models.{{ model['tableName'] }} import {{ model['className'] }}
class {{ className }}(object): class {{ contronller['className'] }}(object):
def __init__(self): def __init__(self):
super({{ className }}, self).__init__() super({{ contronller['className'] }}, self).__init__()
def get(self, params): def get(self, params):
# handle business code # handle business
pass result = {{ model['className'] }}.query.filter(*filters).order_by({{ model['className'] }}.areaId).paginate(params['pageNum'], params['pageSize'], error_out=False)
return result
def post(self, params): def post(self, params):
# handle business code # handle business
pass result = {{ model['className'] }}.query.filter({{ model['className'] }}.areaName == params['areaName']).first()
if result and result.del_flag:
result.del_flag = False
result.update_by = jwt['id']
result.update_date = datetime.now()
db.session.commit()
return pretty_result(code.OK)
elif result and result.del_flag == False:
return pretty_result(code.EXISTS_ERROR)
result = {{ model['className'] }}(**params)
db.session.add(result)
db.session.commit()
return pretty_result(code.OK)
def put(self, params): def put(self, id, params):
# handle business code # handle business
pass result = {{ model['className'] }}.query.get(id)
if not result: return pretty_result(code.NO_DATA)
if params:
for key, value in params.items():
if value != None: setattr(result, key, value)
result.update_by = jwt['id']
result.update_date = datetime.now()
db.session.commit()
else:
return pretty_result(code.PARAM_NULL)
def delete(self, params): def delete(self, id):
# handle business code # handle business
pass result = {{ model['className'] }}.query.get(id)
\ No newline at end of file if not result: return pretty_result(code.NO_DATA_FOUND)
else:
result.update_by = jwt['id']
result.update_date = datetime.now()
result.del_flag = True
db.session.delete(result)
db.session.commit()
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