最近学了一下前端框架layui,感觉layui作者风格和aardio作者风格一样,都是”简洁+实用“。下面是练习的作品,没有什么技术含量,也没写权限管理和日志(大家有兴趣有时间可以完善),界面看上去还算顺眼,颜值主要靠layui(真是省了大把html+css代码)长脸了,代码写的不好,希望大家多提意见。
import win.ui;
/*DSG{{*/
winform = win.form(text="简易WEB文件服务器";right=570;bottom=183;border="dialog frame";max=false)
winform.add(
btnOpenFolder={cls="button";text="...";left=491;top=46;right=531;bottom=78;z=5};
btnStart={cls="button";text="启动服务器";left=44;top=100;right=193;bottom=142;font=LOGFONT(h=-13);z=1};
edit={cls="edit";left=107;top=46;right=483;bottom=77;dl=1;dr=1;dt=1;edge=1;z=2};
static1={cls="static";text="共享目录:";left=35;top=46;right=107;bottom=78;center=1;font=LOGFONT(h=-13);transparent=1;z=3};
weblink={cls="syslink";text="网站未运行";left=214;top=115;right=518;bottom=139;dr=1;dt=1;transparent=1;z=4}
)
/*}}*/
import gdip.bitmap;
import win.image;
import fsys.stream; //上面三个库主要用于保存favicon.ico
import fsys;
import fsys.info; //用来获取文件图标
import fsys.dlg.dir;
import inet.http;
//配置网页及网页标题等信息
winform.root = io._exedir;
winform.title = "在线文件管理系统";
winform.admin = "Mr_MAO";
winform.html = inet.http.get("https://aardio.online/attach-download-145.htm");//加载附件"web.html"
//配置服务器
import wsock.tcp.simpleHttpServer;
namespace wsock.tcp.simpleHttpServer{
startIp = "0.0.0.0";
//startPort = 8080;
threadGlobal = { winform = ..winform };
documentRoot = ..winform.root;
}
//获取文件图标,生成缩略图
winform.getfileIcon = function(path){
var sfi = fsys.info.get(path, 0x100/*_SHGFI_ICON*/ | 0x4000/*_SHGFI_SYSICONINDEX*/);
var bmp = ..gdip.bitmap(sfi.hIcon,1/*_IMAGE_ICON*/);
if(sfi.hIcon)::DestroyIcon(sfi.hIcon);
if(bmp) return bmp.saveToBuffer(".png");
}
winform.btnStart.oncommand = function(id,event){
if(string.trim(owner.text)=="启动服务器"){
if(winform.edit.text=="") winform.edit.text = winform.root;
//检查 favicon.ico
if(not io.exist(winform.root + "favicon.ico")){
var hIcon = win.image.extractIcon(io._exepath,,false)
var bmp = gdip.bitmap(hIcon,1);
var stream = fsys.stream()
bmp.saveToStream(stream, "*.png")
string.save(winform.root + "/favicon.ico", stream.readAll() )
::DestroyIcon(hIcon)
}
//检查 logo.png
if(not io.exist(winform.root +"logo.png")){
var hIcon = win.image.extractIcon(io._exepath,,false)
var bmp = gdip.bitmap(hIcon,1);
bmp.save(winform.root +"logo.png")
::DestroyIcon(hIcon)
}
//检查 回收站文件夹
var recyclefolder = winform.root + "回收站"
if(!io.exist(recyclefolder)){
fsys.createDir(recyclefolder)
fsys.attrib(recyclefolder,,2/*_FILE_ATTRIBUTE_HIDDEN*/)
}
//启动simpleHttpServer服务器
url = wsock.tcp.simpleHttpServer.startUrl(
function(response,request,session){
import fsys;
import web.json;
import thread.table; //线程表
//主页
if(request.path == "/main.aardio"){
var path = request.query("folderpath")
if(!path || path=="/"){ //主页请求
html = string.loadcode(winform.html,
//利用模板语法初始化其它一些网站参数
{title=winform.title;admin=winform.admin;nav="<a><cite>根目录</cite></a>";currDir="/";table_url="/"})
}else { //面包屑请求
//将url参数分解为数组,并组装为breadcrumb路径
path=string.trimright(path,'/')
var tab = string.split(path,'/')
var temp = ""
var breadcrumb_str=""
for(k,v in tab){
temp += v +"/"
if(k<#tab){
if(v==""){
v="根目录";
breadcrumb_str += "<a href='/'>" + v + "</a>";
}else{
breadcrumb_str += "<a href='/?folderpath=" + temp + "'>" + v + "</a>";
}
}else {
breadcrumb_str += "<a><cite>"+ v + "</cite></a>";
}
}
html = string.loadcode(winform.html,
{title=winform.title;admin=winform.admin;nav=breadcrumb_str;currDir=path;table_url=path})
}
response.contentType = "text/html";
response.write(html)
return;
}
//返回指定目录内的文件列表
if(request.path == "/getfolder"){
var path = request.query("folderpath")
var serverPath = io.joinpath(request.documentRoot, path)
//检索对应的本地目录
if( fsys.isDir(serverPath) ){
var templist = {}
fsys.enum( serverPath, "*.*",
function(dir,filename,fullpath,findData){
if(findData.dwFileAttributes & 2/*_FILE_ATTRIBUTE_HIDDEN*/) return; //不显示隐藏目录&文件
if(filename){ //文件
var size = math.size64(findData.nFileSizeLow,findData.nFileSizeHigh).format()
var mdftime = tostring(fsys.fromFileTime(findData.ftLastWriteTime),"%Y-%m-%d %H:%M:%S");//utc时间
var webPath = string.right(fullpath,-#request.documentRoot)
webPath = string.replace(webPath,"@\","/")
table.push(templist,
{["name"]=filename,["size"]=size,["time"]=mdftime;["path"]=webPath;["type"]=0}) //设定type=0为文件
}else{ //目录
var mdftime = tostring(fsys.fromFileTime(findData.ftLastWriteTime),"%Y-%m-%d %H:%M:%S");
var webPath = string.right(fullpath,-#request.documentRoot)
webPath = string.replace(webPath,"@\","/")
table.push(templist,
{["name"]=dir,["size"]="/",["time"]=mdftime;["path"]=webPath;["type"]=1}) //设定type=1为目录
}
}
,0/*不包括子目录*/
);
var retlist = {}
if(#templist>0){
retlist = table.mix({},{"code"=0; "msg"="success"; "count"=#templist; "data"=templist} )
}else{
retlist = {"code"=1; "msg"="该目录为空";} //空目录
}
//返回json
var json = web.json.stringify(retlist,true)
response.contentType = "text/json"
response.write(json)
}else{
response.contentType = "text/json"
var retJson = '{ "code": 1, "msg": "错误,找不到你指定的目录"}'
response.write(retJson)
}
return;
}
//返回缩略图
if(string.startWith(request.path,"/thumbnail",true) ){
var path = string.right(request.path,-#"/thumbnail/")
var serverPath = io.joinpath(request.documentRoot, path)
if(io.exist(serverPath)){
if(fsys.isDir(serverPath)){
if(!thread.table("iconlist")["folder"]){
thread.table("iconlist")["folder"] = winform.getfileIcon(io._exedir)
}
response.contentType = "image/png";
response.write( thread.table("iconlist")["folder"] ) //发送文件夹图标
}else{
var ext = fsys.getExtensionName(serverPath) //exe (没有.)
if(ext=='exe'){
response.contentType = "image/png";
response.write( winform.getfileIcon(serverPath) )
}else{
//在iconlist中找
if(!thread.table("iconlist")["."+ ext]){
thread.table("iconlist")["."+ ext] = winform.getfileIcon(serverPath)
}
response.contentType = "image/png";
response.write( thread.table("iconlist")["."+ ext] ) //发送文件夹图标
}
}
}else{
//返回一个默认的图片
}
return;
}
//返回搜索结果(全站搜索,较慢)
if(request.path == "/search"){
var keyword = request.query("keywords")
if(keyword){
var templist = {}
fsys.enum( request.documentRoot, "*.*",
function(dir,filename,fullpath,findData){
if(findData.dwFileAttributes & 2/*_FILE_ATTRIBUTE_HIDDEN*/) return; //不搜索隐藏文件
if(filename){
if( string.find(filename,"@"++keyword) ){
var size = math.size64(findData.nFileSizeLow,findData.nFileSizeHigh).format()
var mdftime = tostring(fsys.fromFileTime(findData.ftLastWriteTime),"%Y-%m-%d %H:%M:%S");
var webPath = string.right(fullpath,-#request.documentRoot)
webPath = string.replace(webPath,"@\","/")
table.push(templist,
{["name"]=filename,["size"]=size,["time"]=mdftime;["path"]=webPath;["type"]=0})
}
}
else{
if(string.find(dir,"@"++keyword)){
var mdftime = tostring(fsys.fromFileTime(findData.ftLastWriteTime),"%Y-%m-%d %H:%M:%S");
var webPath = string.right(fullpath,-#request.documentRoot)
webPath = string.replace(webPath,"@\","/")
table.push(templist,
{["name"]=dir,["size"]="/",["time"]=mdftime;["path"]=webPath;["type"]=1}) //设定type=1为目录
}
}
} ,true
);
var retlist = {}
if(#templist>0){
retlist = table.mix({},{"code"=0; "msg"="success"; "count"=#templist; "data"=templist} )
}else{
retlist = {"code"=2; "msg"="没有找到包含关键字的文件或目录";} //空目录
}
var json = web.json.stringify(retlist,true)
response.contentType = "text/json"
response.write(json)
return;
}
}
//响应客户端-新建文件夹
if(request.path == "/createfolder"){
var path = request.post["fatherdir"]
var newname = request.post["foldername"]
var serverPath = io.joinpath(request.documentRoot, path)
if(io.exist(serverPath)){
if(io.exist(io.joinpath(serverPath,newname))) {
response.errorStatus(417, "已存在同名文件夹!")
return;
} else{
if( fsys.createDir(io.joinpath(serverPath,newname)) ){
response.contentType = "text/json"
response.write('{"success":true}')
return;
}
}
}
response.errorStatus(404, "目录路径不正确")
return;
}
//响应客户端-改名
if(request.path == "/rename"){
var path = request.post["path"]
var newname = request.post["newname"]
var serverPath = io.joinpath(request.documentRoot, path)
var newpath = fsys.getParentDir(serverPath) + newname
if(io.exist(serverPath)){
if(fsys.rename(serverPath,newpath)){
response.contentType = "text/json"
response.write('{"success":true}')
return;
}
}
response.errorStatus(404, "File not found!")
return;
}
//响应客户端-删除
if(request.path == "/delete"){
var path = request.post["path"]
var serverPath = io.joinpath(request.documentRoot, path)
var recyclefolder = request.documentRoot + "回收站"
if(fsys.isDir(serverPath)){//如果要删除的是文件夹 (设为隐藏属性即可)
fsys.attrib(serverPath,,2/*_FILE_ATTRIBUTE_HIDDEN*/)
fsys.rename(serverPath,serverPath+"-已删除")
response.contentType = "text/json"
response.write('{"success":true}')
return;
}else {//如果要删除的是文件(移到回收站)
if(io.exist(serverPath)){ //文件要真实存在
var newdir = fsys.getParentDir( recyclefolder + io.joinpath(path) )
if(!io.exist(newdir)) fsys.createDir(newdir)
if(fsys.move(serverPath,recyclefolder + io.joinpath(path),0x614/*_FOF_NO_UI*/)){
response.contentType = "text/json"
response.write('{"success":true}')
return;
}
}
}
response.errorStatus(404, "未找到指定的文件")
return;
}
//响应客户端-文件下载
if(request.path == "/download/main.aardio"){
var filePath = request.query("filepath")
var serverPath = io.joinpath(request.documentRoot, filePath)
if(io.exist(serverPath)){
var file = io.open(serverPath,"rb");
response.contentType = "application/octet-stream";
response.headers["Content-Disposition"] = "attachment; filename="+ fsys.getFileName(serverPath);
response.headers["Content-Length"] = file.size();
var buffer = raw.buffer(1024 *100);
while(var readsize = file.readBuffer(buffer)){
response.writeBuffer(buffer,readsize)
}
file.close()
}else {
response.errorStatus(404, "File not found!")
}
return;
}
//响应客户端-文件上传
if(request.path == "/updatefile"){
var fileData = request.postFileData(); //获取上传的文件
if(fileData){
var filename = fileData["file"].filename
var path = fileData["dirpath"].value() //取layui上传文件的data附加数据
var serverfolder = io.joinpath(request.documentRoot, path)
//保存文件到指定位置
fileData["file"].save(serverfolder + "\" + filename);
//layui-upload组件要求上传成功后,必须返回的json
response.contentType = "text/json"
var retJson = '{ "code": 0, "msg": "' ++ filename ++ '"}'
response.write(retJson)
return;
}
response.contentType = "text/json"
response.write('{ "code": 1, "msg": "未知错误"}')
return;
}
//响应其他格式的文件请求
//response.headers["Access-Control-Allow-Origin"] = "*" //允许跨域(如在线打开office文件)
response.loadcode( request.path );
}
);
winform.edit.disabled = true
winform.btnOpenFolder.disabled = true
winform.btnStart.text = "停止服务器";
winform.weblink.text = `网站已运行 (主页: <a href="` ++ url ++ `">` ++ url ++ "</a> )"
}else{
//停止服务器
//(如需反复重启,需要修改wsock.tcp.wsock.tcp.simpleHttpServer源码第806行
//if(serverMain) serverMain.stop();
//为:if(serverMain) serverMain.stop(); serverMain=null;
//)
wsock.tcp.simpleHttpServer.stopUrl()
winform.edit.disabled = false
winform.btnOpenFolder.disabled = false
winform.weblink.text = "网站未运行"
winform.btnStart.text = "启动服务器";
}
}
//在浏览器打开网页
winform.weblink.onHyperlinkClick = function(nmSysLink,url,id){
thread.invoke(
function(url){
import process;
process.execute(url);
},url
);
}
//设置共享文件夹
winform.btnOpenFolder.oncommand = function(id,event){
var folderPath = fsys.dlg.dir()
if(folderPath){
if(string.endWith(folderPath,"\")==false) folderPath+= "\"
winform.edit.text = folderPath;
winform.root = folderPath;
//设置为网站根目录
wsock.tcp.simpleHttpServer.documentRoot = folderPath ;
}
}
winform.show();
win.loopMessage();