Compare commits

...

675 Commits

Author SHA1 Message Date
isummer e12779d654 修复容器部署失败问题,重新编写本地部署文档 2 years ago
isummer ac590563a7 修复超级签共享用户下载文件失败问题 2 years ago
isummer 8fc1d353c9 管理后台增加重置密码功能 2 years ago
isummer 35b64d74de 修复flyapps容器构建失败问题,优化部署文档 2 years ago
isummer a064988f56 修复flyapps容器构建失败问题,优化部署文档 2 years ago
isummer adff361c11 修复非苹果设备导致余额不足问题 2 years ago
isummer 419e39eaaa 修复非苹果设备导致余额不足问题 2 years ago
isummer 9d9cb3f2cb Merge remote-tracking branch 'origin/master' 2 years ago
isummer dd802dccbb 优化代码 2 years ago
isummer 1262bff671 优化代码 2 years ago
isummer 289737ed00 修复异常,优化代码 2 years ago
isummer dc7b491534 修复新苹果,新应用无法设置专属签名问题 2 years ago
isummer eed0f5194c 增加苹果设备类型区分,优化苹果设备注册量及展示 2 years ago
isummer e0599585be 修复前端应用超级签名展示异常问题 2 years ago
isummer 42451f2cb0 修复超级签权限问题 2 years ago
isummer 646162593e 增加打包时间 2 years ago
isummer 200494fcf3 增加打包时间 2 years ago
isummer fe5a7605f0 增加打包时间 2 years ago
isummer f70351d8e5 修复容器启动异常问题 2 years ago
isummer 9e2f40383a 优化代码,增加邀请码配置,修改极验弹窗模式 2 years ago
isummer debe95791e 优化容器部署 2 years ago
isummer a3887825c9 更新依赖包,支持python39环境 2 years ago
isummer 8a8f9ef7fe 升级python环境为python39 2 years ago
isummer 8e325e6cde 优化容器启停异常 2 years ago
isummer 92961cfa61 flyapps-cli增加容器访问 2 years ago
isummer 8c25aab63c flyapps-cli增加容器访问 2 years ago
isummer 0cc5084390 修复授权绑定设备添加重复问题 2 years ago
isummer 4d98981485 容器部署支持管理后台访问 2 years ago
isummer a7a1472533 苹果应用授权码支持添加绑定设备 2 years ago
isummer 332d12bddf 容器部署优化 2 years ago
isummer 6439824468 优化docker部署方式 2 years ago
isummer 42478f21d9 1.修复授权码为一次,超级签苹果包下载失败问题 2 years ago
isummer 2c67305f8a 增加通过命令给用户充值次数 2 years ago
isummer 79037d5248 修复应用上传超级签检测问题 2 years ago
isummer 525ec097d7 更新readme 2 years ago
isummer a35ca0b087 更新配置文件信息 2 years ago
isummer d9ac93ccc1 no message 2 years ago
isummer 1ff3da6896 修复管理页面预览展示 2 years ago
isummer cbad06e95d 应用时间更新修复 2 years ago
isummer b093d7133b 页面底部信息配置迁移 2 years ago
isummer 7aa0471ba9 增加应用当天下载次数展示 2 years ago
isummer 2224ce27c7 优化代码 2 years ago
isummer d8b124c1a7 用户下载页私有配置功能 2 years ago
isummer d1a5d69ac8 增加客户端独立部署功能 2 years ago
isummer 8a8d2f2400 增加预览下载页路由模式 2 years ago
isummer 49832ca702 修复新注册用户 默认域名绑定问题 2 years ago
isummer 7075bc7ed6 修改存储添加失败问题 2 years ago
MMXX 7d70f381a1 geetest 增加代理访问 2 years ago
MMXX 15a506450c 增加管理后台应用当天下载次数展示 2 years ago
isummer 93c13fa776 日志增加function名称 2 years ago
MMXX c8f02465d0 修复异常注册问题 2 years ago
isummer 2e240735dc 优化下载次数展示 2 years ago
I夏 ec908f0dea 代码优化,增加缓存函数提前失效参数 3 years ago
I夏 47abaf61f5 订单展示格式化 3 years ago
I夏 31fe8664a9 修复注册赠送下载数异常 3 years ago
nineven f4ca8d48f9 修復转换异常问题 3 years ago
nineven e2b9b12613 修復转换异常问题 3 years ago
nineven f772d65765 存储扩容功能 3 years ago
nineven 3ad5e03504 存储扩容功能 3 years ago
nineven 5f967a9b52 修复存储切换下载token过期问题 3 years ago
nineven e7858a840e 服务器需要部署阿里云,服务器和oss存储内网互通 3 years ago
nineven b191cbae6b 优化代码,增加存储迁移锁解除功能 3 years ago
nineven c36ab08f35 优化存储逻辑和展示页面 3 years ago
nineven a5b73c3695 增加存储共享功能,增加应用历史版本设置,修复设备共享查询问题,优化存储切换逻辑 3 years ago
nineven 0c6b61327a 修复域名绑定获取最小错误返回 3 years ago
nineven 92c0345341 优化代码展示 3 years ago
nineven 25c2ea4c7a 优化代码展示 3 years ago
nineven dfcf213bed 优化代码 3 years ago
nineven 2b29e0e3bd 优化代码 3 years ago
nineven a9bbdd40bd 修复读模式获取开发者发送失败通知 3 years ago
nineven 97349e758f 代码更新 3 years ago
nineven 156bf67c1c 优化代码 3 years ago
nineven 1d75c8ed23 优化异常注册逻辑,修复设置设备状态返回异常问题 3 years ago
nineven ef243feb9f 优化查询状态 3 years ago
nineven 58472fb9e4 修改文件下载失败问题 3 years ago
nineven 6c25f6a932 优化签名开发者查询逻辑 3 years ago
nineven 2d21ee9150 优化签名开发者查询逻辑 3 years ago
nineven 04ba947219 修复链接存在密码情况下,跳转密码丢失问题 3 years ago
nineven 884d6a47e8 大意失荆州啊 3 years ago
nineven 0a64689902 修复 bytesio 导致uwsgi 不识别问题 3 years ago
nineven 5ca5b0eb34 优化错误信息展示 3 years ago
nineven 3bbabdafdb 1.增加异常设备和设备黑名单功能 3 years ago
nineven 4cd0dc7586 设备异常 3 years ago
nineven 5eb947843e 优化啦 3 years ago
nineven 17ab6e6efd 修复前端页面时间显示问题 3 years ago
nineven 94bc5cc1db 优化代码 3 years ago
nineven 584f50ba20 优化页面 3 years ago
nineven df38944eab 优化页面 3 years ago
nineven fe880b27b7 优化下载方式 3 years ago
nineven 8316a52595 下载授权码和设备绑定功能,下载页面优化 3 years ago
nineven 747d2b3dfa 优化通知提醒,增加批量设置开发者账户自动检测,定时任务修改为 【0,1,3,7】自动提醒,同步设备支持条件 3 years ago
nineven 04ae8cccc4 增加应用下载授权token, 增加超级签名多重安全验证,优化本地下载逻辑 3 years ago
nineven 3b8134aafd 优化代码 3 years ago
nineven bb9bdf8891 邮件通知模板优化 3 years ago
nineven bc0cee937d 修复定时任务多线程数据共享异常 3 years ago
nineven d1a41a179b 优化代码,增加苹果签名错误操作记录 3 years ago
nineven 3ff322849a 优化设备错误展示 3 years ago
nineven 4184f2ad1c 问题修复 3 years ago
nineven 22a9b8d816 优化代码 3 years ago
nineven 2390397f1b 微信web登录跳转优化 3 years ago
nineven ae9dfae6a3 微信web登录跳转修改,定时通知逻辑优化 3 years ago
nineven d7e3186f9d 修复配置名重复添加失败问题 3 years ago
nineven 2bfd694f23 重要,微信登录 大版本更新,上一个版本更新 3 years ago
nineven 63e09c1925 增加微信登录多账户功能 3 years ago
nineven 391e4987de 优化消息提醒 3 years ago
nineven 88745550d4 增加消息提醒功能,下载余额,签名余额不足自动检测,发送邮件或微信通知功能 3 years ago
nineven 59e73fa83e 增加消息提醒功能,下载余额,签名余额不足自动检测,发送邮件或微信通知功能 3 years ago
nineven 5eca01278b 优化代码,增加余额不足微信模板消息 3 years ago
nineven 5edf7cd65a 优化代码,增加证书信息展示功能,增加包重签功能 3 years ago
nineven cf9d9eeaf8 优化代码 3 years ago
nineven c4a4db2c7e 优化定时任务设备消耗展示 3 years ago
nineven 24a8307164 优化设备消耗展示 3 years ago
nineven 05669b8d3e 苹果设备状态异常,导致注册失败【苹果设备状态还可能为 INELIGIBLE 和 PROCESSING】,当设备存在该状态,则该开发者将无法注册新设备号,需要禁用该开发者 3 years ago
nineven 32c3058d57 优化账户激活检测代码 3 years ago
nineven 4bbae93933 优化代码 3 years ago
nineven f94184551a 优化代码 3 years ago
nineven dd73441bdd 优化代码 3 years ago
nineven 4e7927a332 优化代码,修复定时任务检测证书获取异常并清理问题 3 years ago
MMXX fc1963c8a9 优化代码 3 years ago
MMXX d15b583804 优化代码 3 years ago
MMXX d930603919 优化代码 3 years ago
MMXX 9b9be3fcf9 版本更新 3 years ago
MMXX 378912944f 优化代码 3 years ago
MMXX 75c7d365a3 优化代码 3 years ago
MMXX 1dec3b7de2 Merge branch 'xsign' of https://github.com/nineaiyu/FlyApps into xsign 3 years ago
MMXX eeba5b409a 优化代码展示 3 years ago
nineven 684a407f97 优化代码,增加设备同步详细日志【有时候会删除该开发者下所有签名数据,很诡异】 3 years ago
nineven 5901d63f3e 优化代码,增加设备同步详细日志【有时候会删除该开发者下所有签名数据,很诡异】 3 years ago
MMXX cf14dcb0a5 代码优化,苹果开发者账户展示优化 3 years ago
MMXX e780a2597e 增加共享设备一键清理功能 3 years ago
MMXX 02f908e3de 增加共享设备一键清理功能 3 years ago
MMXX 7ceb9c83c1 优化代码,修改共享撤回问题 3 years ago
MMXX 77d97fd1d2 优化签名包下载逻辑 3 years ago
nineven 98fe1d5f61 优化代码 3 years ago
nineven fb77c251c3 优化代码 3 years ago
nineven c765658fb5 微信支付,微信web登录功能优化 3 years ago
nineven dd1fb29ba0 优化微信登录和获取任务长轮询请求方式 3 years ago
nineven d571b399d7 代码优化 3 years ago
nineven 115d1c95df 信号优化 3 years ago
nineven e54f6c1286 验证码优化 3 years ago
nineven 75fecbca10 超级签名重签功能 3 years ago
nineven 96295132d9 应用上传黑白名单 3 years ago
nineven ec327598a2 优化代码结构 3 years ago
nineven 81db86b9ef 优化代码结构 3 years ago
nineven 6076659bf1 Merge branch 'master' into xsign 3 years ago
nineven 4b90ce682b 问题修复 3 years ago
nineven f00135a6a4 xsign 模块 3 years ago
nineven 8ce3b14475 Merge branch 'master' into xsign 3 years ago
nineven 25d09e8cf1 修复小问题 3 years ago
nineven c6e78a6eab 优化代码 3 years ago
nineven e9c6cadeb6 重新迁移数据文件 3 years ago
nineven 153f800b91 代码结构优化 3 years ago
nineven 5e380fa09e 优化代码 3 years ago
nineven 42bab0739b 优化代码目录结构 3 years ago
nineven 518fc3101e 优化配置文件读取,支持文件数据库配置模板变量使用 3 years ago
nineven 875a3a4305 设备转移之后,匹配异常问题 3 years ago
nineven 6051f443c1 优化代码,配置文件内部支持template语法,修复新设备注册异常的问题 3 years ago
nineven c4fd9aa793 修复json配置读取失败的问题 3 years ago
nineven 9ba02e449d 大版本更新,签名逻辑更改 3 years ago
nineven cb841b5cf7 大版本更新,签名逻辑更改 3 years ago
nineven 9353abc8a9 配置文件迁移更新 3 years ago
nineven 06bace9f66 配置文件迁移更新 3 years ago
nineven ce31dd5621 优化域名绑定功能 3 years ago
nineven 91e042ea1d 優化代碼 3 years ago
nineven f02eb026de 开发者账号支持自定义自动检测 3 years ago
nineven 44cfd03cee 设置配置缓存过期时间30天 3 years ago
nineven 14f60d4f8d 部分配置信息迁移到数据库,方便直接修改数据库生效 3 years ago
nineven 614db12422 设备共享逻辑及前端页面书写 3 years ago
nineven 10ab90a104 修复清理开发者脏数据失败问题 3 years ago
nineven f5ffc3632f 签名账户设备转移功能 3 years ago
nineven adc71de160 优化上传p8key文件 3 years ago
nineven 6f959fa4a9 优化上传p8key文件 3 years ago
nineven 3d2ce3b73d 优化添加苹果开发者账号逻辑 3 years ago
nineven 192d4cadc0 优化代码 3 years ago
nineven 9f2fea094d 优化代码 3 years ago
nineven 32bdc4ba9e 优化代码 3 years ago
nineven fdd0abb07e 增加添加开发者账号检测功能 3 years ago
nineven a580dddd83 优化下载页 3 years ago
nineven 2f32b71b2b 优化下载页 3 years ago
MMXX 03a6202ee2 优化后台管理api 3 years ago
MMXX 7e15211fd2 清理签名临时数据 3 years ago
MMXX ae58a71ee4 修复签名异常导致死锁问题 3 years ago
MMXX b270d8e5c6 修复域名配置异常问题 3 years ago
MMXX 32ca967d07 优化代码,修改cors逻辑 3 years ago
MMXX 878183dbce 修改日志存储时间 3 years ago
MMXX bebc8417eb 优化应用域名展示 3 years ago
MMXX de511bf90c 状态展示优化 3 years ago
MMXX a8c1df58ee 优化代码,增加设备删除控制,增加设备被封状态 3 years ago
MMXX ef335e118a 优化代码 3 years ago
MMXX 03f66df7b9 优化代码,修复多个开发者,下载不是最新签名包问题,增加批量修改开发者状态 3 years ago
MMXX 4d4ee64a65 优化显示异常提示 3 years ago
MMXX 04ccfe77a3 优化代码,增加苹果账户备注查询功能 3 years ago
MMXX d085d86a26 苹果超级签名优化 3 years ago
MMXX 8a60be6f4f 优化代码 3 years ago
MMXX 869d5ee7bb 优化代码 3 years ago
MMXX 9572382a9e 优化代码 3 years ago
MMXX 7ad5bc8161 优化签名代码逻辑 3 years ago
MMXX 59d7d905d3 优化代码 3 years ago
MMXX c361d740bf 优化代码 3 years ago
MMXX 17c1f0612a 优化缓存代码 3 years ago
MMXX 2b5325ff32 优化缓存代码 3 years ago
MMXX 09257733f8 更新苹果api接口 3 years ago
MMXX 5dd1dd0681 后端更新下载码逻辑 3 years ago
MMXX 979b6f0386 更新前端页面 3 years ago
MMXX e8e6ea962a 修复已知问题 3 years ago
MMXX c50005e7c7 修复激活问题 3 years ago
MMXX 465aea9744 修复页面udid展示不全问题 3 years ago
MMXX 7c2a29b86d 优化代码 3 years ago
MMXX f8418f6414 增加签名应用限额 3 years ago
youngS def6c9dfc8 优化代码 3 years ago
youngS 205505cb0e 优化超级签 获取开发者账户逻辑,增加微信删除必须输入密码限制 3 years ago
youngS 106ae636a2 优化代码 3 years ago
youngS 2e96183c06 修复展示问题 3 years ago
youngS 216bc367c4 优化代码 3 years ago
youngS e559267de3 增加苹果开发者备注显示信息 3 years ago
youngS f04c4411c7 修复已知问题,修正 专属账户,其他应用禁止使用 3 years ago
youngS a60a7d6011 优化代码 3 years ago
youngS d3fc7327a6 增加应用专属开发者功能 3 years ago
youngS 4decc14bf8 优化代码 3 years ago
nineven d657c709f6 优化代码 3 years ago
nineven 73d783b97d 优化代码 3 years ago
nineven b18dfa7a14 优化代码 3 years ago
youngS 0d26e5ac7b 优化代码 3 years ago
youngS bda9cf994d 优化代码 3 years ago
youngS 9d0d36ca63 优化api请求时间 3 years ago
youngS 26e6efeaf4 优化代码,增加苹果api访问代理 3 years ago
youngS 49c35275b6 修复设备消耗查询问题 3 years ago
youngS 92ba4fc258 增加下载码展示 3 years ago
youngS c8a69acb84 增加下载码展示 3 years ago
youngS 7932dde3b4 修复bug 3 years ago
youngS 55f5f65e15 修复已知问题,增加设备消化统计 3 years ago
youngS fd43dcfea4 优化代码 3 years ago
youngS 4c41efa46f 修改 查询开发者策略 按照最小注册设备数进行查找 3 years ago
youngS d3e0c53b8f 修复数据存储异常问题 3 years ago
youngS bd77da66b7 修复自定义id名 3 years ago
youngS ebed9b1aa4 修复只有一个证书激活失败的问题 3 years ago
youngS 0c5c4a6ce7 修复异常问题 3 years ago
youngS b3899d4a97 修复异常问题 3 years ago
youngS 27b8a21556 数据库优化 3 years ago
youngS bbf9664fc7 修复异常问题 3 years ago
youngS 86467ef2fd 优化展示 3 years ago
youngS 2aedb458ee 优化前端展示 3 years ago
youngS 2e491db16c 代码bug修复 3 years ago
youngS 8a59b8d329 代码bug修复 3 years ago
youngS fce8a09d5e 优化代码 3 years ago
fxC 29328d293b 修复mac环境下启动服务失败 3 years ago
fxC 2ec7fb05eb 修复已知问题 3 years ago
youngS 341cf21367 签名优化 3 years ago
youngS 6412e36d0b 优化代码 3 years ago
youngS 8bf925e9df 优化代码 3 years ago
youngS d550d20998 管理后台增加超级签充值功能,前端页面增加udid展示 3 years ago
youngS c170086609 签名余额限制,开发者账户加锁,修复账单数量统计错误问题 3 years ago
youngS bd8c8d00cc 超级签名并发优化,签名余额还未限制,下个版本限制 3 years ago
youngS a2c5d1bd3f 超级签名并发优化,签名余额还未限制,下个版本限制 3 years ago
youngS 169347ca16 下载页举报按钮优化 3 years ago
youngS 372455bcb3 下载页举报按钮优化 3 years ago
youngS d943b5527d 修复已知问题 3 years ago
youngS 5316ed83c1 优化日志保存记录 3 years ago
youngS c173262a0b 修复微信绑定bug 3 years ago
fxC 5be7115e91 兼容老API接口 3 years ago
youngS f30aafb5d9 优化代码 3 years ago
fxC 34971b792a fix some bug 3 years ago
youngS f49c067015 前端代码格式化 3 years ago
youngS 002c90d5e3 优化代码,修改已知问题 3 years ago
youngS 4c29d32d67 下载页面增加举报功能 3 years ago
youngS 819c9a7017 管理后台增加举报信息 3 years ago
youngS 479abff102 下载页面增加举报功能 3 years ago
youngS 20ac8eadda 优化代码 3 years ago
youngS 1cc05645ec 优化代码 3 years ago
youngS 2ee4352544 证书导出功能优化 3 years ago
youngS 7702fa5209 开发者keyid和存储secert加密存储处理 3 years ago
youngS 50da6044a4 增加设备消化账单 3 years ago
youngS 7d781de388 优化代码 3 years ago
youngS ab52639caf 优化代码 3 years ago
youngS 5232ba5fe6 优化代码 3 years ago
youngS 47861511fc 优化单用户签名流程 3 years ago
fxC 0a20226dd7 reformat code and import 3 years ago
fxC cb4fc0b827 no message 3 years ago
youngS 674bf66827 共有池 3 years ago
fxC abd2db398d 一些优化 3 years ago
youngS 9d3b5c582e 共有池 3 years ago
youngS abbe709d27 共有池 3 years ago
fxC b3637c6844 签名共有池实现 3 years ago
youngS 9b7590146a 优化下载页跳转 3 years ago
youngS 7309eaf9b5 修复绑定异常问题 3 years ago
youngS edd603b8e9 下载域名权限问题 3 years ago
youngS 9b69021337 优化cli.py 上传脚本 3 years ago
youngS e7d4df5941 修复新应用短连接重复异常上传问题 3 years ago
youngS b772d2921e 优化代码下载 3 years ago
youngS dd5d0ed0ed 优化代码下载 3 years ago
youngS dc2fa091cb 增加自定义广告功能 3 years ago
youngS d34073301b 增加自定义广告功能 3 years ago
youngS fac7eccc05 优化代码下载 3 years ago
youngS 4533e04850 修复域名下载问题 3 years ago
youngS 0e2578738f 优化docker部署 3 years ago
youngS 08c6b7b87f 优化代码 3 years ago
youngS 7c5ab20dd9 优化uwsgi 启动服务 3 years ago
youngS 1a9cae8cb7 优化uwsgi 启动服务 3 years ago
youngS e34ca43cfc 签名逻辑优化 3 years ago
youngS 75d5a5df76 增加状态描述文件下载状态 3 years ago
youngS ac8614b54c 服务启动方式被manage.py托管 3 years ago
youngS 1e1385da84 服务启动方式被manage.py托管 3 years ago
youngS 0bac3e55f4 优化微信消息推送模板,管理后台增加微信绑定功能 3 years ago
youngS 820e1df84e 优化代码 3 years ago
youngS 08ffa72eab 管理后台增加应用类型展示 3 years ago
youngS 6861c65b83 管理后台增加应用原包下载功能 3 years ago
youngS 439db9788a 管理后台增加应用原包下载功能 3 years ago
youngS 2feda8800c 管理后台增加域名功能 3 years ago
youngS b10a40d177 下载域名统一管理 3 years ago
youngS 3325814c03 增加域名访问权限控制,用户绑定的域名只能允许本用户应用访问 3 years ago
youngS f6918011ca 增加域名下载码绑定功能,权限大于1的可以使用该功能 3 years ago
youngS d7a31c62b3 优化代码 3 years ago
youngS d154381895 优化代码,增加cli.py 上传进度条,修复签名相关问题 3 years ago
youngS 13a67be0ff 修复超级签名,老包未及时清理问题 3 years ago
youngS b815950f7d 优化代码 3 years ago
youngS 4316398d82 修复存储迁移失败的问题 3 years ago
youngS 749d72b513 优化代码展示 3 years ago
youngS bfb3738d69 优化代码,修复新用户注册一直绑定同一个系统域名问题 3 years ago
youngS 3c80635d5f 增加微信登录开启关闭配置 3 years ago
youngS ed05083bbe 修改异常bug 3 years ago
youngS 31677fb1fd 优化代码 3 years ago
youngS cf1267deb2 增加用户名控制登录 3 years ago
youngS 5988e0e1a9 描述文件bug 3 years ago
youngS 81f1f75fb1 描述文件bug 3 years ago
youngS 08e7eb3476 优化代码 3 years ago
youngS 0148905071 优化获取token逻辑 3 years ago
youngS bab6e083bf 优化代码 3 years ago
youngS adaf7af866 优化代码,增加查询udid的服务器逻辑 3 years ago
youngS e8931df00f 优化描述文件签名逻辑,修复清理临时文件bug 3 years ago
youngS 1dc6e84ba7 下载页面增加udid展示 3 years ago
youngS cac1703957 优化开发者账户同步逻辑 3 years ago
youngS dfcf878416 优化代码,修复bug 3 years ago
youngS 45978aae73 修复设备id不存在返回异常 3 years ago
youngS e84f47170a 修改bug 3 years ago
youngS 69c699aebb 修改只能注册两个用户bug 3 years ago
youngS 19709c7da3 优化获取微信token代码 3 years ago
youngS dc8de286c5 优化获取微信token代码 3 years ago
youngS 9b8412304f 增加微信公众号绑定扫码登录功能 3 years ago
youngS d6ce64c3b6 优化苹果开发者激活检测方式 3 years ago
youngS 4f0c8a302c 优化下载次数统计代码 3 years ago
youngS 3ade1efadb 优化页面展示 3 years ago
youngS 90dceee1c5 修复开发者账户认证键值异常 3 years ago
youngS d460da0024 优化重置密码逻辑 3 years ago
youngS 10297e1616 修复清理临时文件失败的问题 3 years ago
youngS 37df9f4a5d 支持短信找回密码功能 3 years ago
youngS a8e8402eff 修复本地文件连接异常问题 3 years ago
youngS dd218fe745 优化上传失败 3 years ago
youngS 42cb1bfc88 增加js版本展示 3 years ago
youngS d8b02a74ab 优化阿里云oss上传失败重试 3 years ago
youngS 7599e5f3a2 代码优化 3 years ago
youngS 4501b5dc2a 前端页面增加应用上传速度展示 3 years ago
youngS 58e7f8fa6a 实名认证照片存放到服务器默认存储 3 years ago
youngS 436e26af37 前端页面增加批量应用上传功能 3 years ago
youngS cb3738f4de 管理后台 存储和超级签权限修改 3 years ago
youngS aa83de23b5 优化代码 3 years ago
youngS 5169c8a477 超级签自定义名字不能为空 3 years ago
youngS 83509a79de 增加容器部署 3 years ago
youngS 9abdc5f5ae 下载页展示优化 3 years ago
youngS a95a2fb22f 修复超级签密码访问未校验问题,增加post接收速率限制 3 years ago
youngS 1bd0f08a4b 优化代码 3 years ago
youngS cdf778d3f3 苹果开发者过期时间限制 3 years ago
youngS bb5d5829df 优化代码 3 years ago
youngS a5a79867f1 cdn NGINX获取真实ip 3 years ago
youngS 8c1ca01532 优化代码 3 years ago
youngS 4e3af4de35 修复解除合并,未清理cache问题 3 years ago
youngS 586136729a 优化下载页展示 3 years ago
youngS 3c4e5aa6e3 修改下载页面,第三方应用不自动跳转问题 3 years ago
youngS cad1a77f8f 增加服务操作脚本 3 years ago
youngS f7f0896893 优化下载页展示 3 years ago
youngS f3349ecc5b 修复当miniOSversion不存在引发的异常 3 years ago
youngS 7fba632390 修复当miniOSversion不存在引发的异常 3 years ago
youngS aa33e5640b 优化代码 3 years ago
youngS 45d813cca3 优化代码 3 years ago
youngS 95b4b45da8 修复开发者不存在导致签名失败bug 3 years ago
youngS 00032239b0 优化证书检测 3 years ago
youngS 86d5623437 修改p12 证书导入逻辑 3 years ago
youngS d4e4e9b278 修改p12 证书导入逻辑 3 years ago
youngS a6f0cb0174 增加支持p12 证书导入 3 years ago
youngS b40f93a16c 增加支持p12 证书导入 3 years ago
youngS e6f8b2f628 修改超级签方式,isign 部分包无法签名,使用zsign 进行签名 3 years ago
youngS ed841bc8fb 优化实名认证逻辑 4 years ago
youngS a59958e1af 管理后台增加超级签开发展示 4 years ago
youngS 5835b4d6e1 优化代码 4 years ago
youngS 5bac330551 优化代码 4 years ago
youngS 1cc239698b 优化代码,增加超级签密钥证书获取教程 4 years ago
youngS 56cd35565f 超级签默认启动 4 years ago
youngS 30db4882b4 修改前端页面 4 years ago
youngS 19b82de65f 优化首页代码 4 years ago
youngS 179f46b2b3 更新Django版本,增加celery定时任务 4 years ago
youngS 2cb0f1a8f5 超级签下载次数消化更换 4 years ago
youngS 04df14d919 超级签下载次数消化更换 4 years ago
youngS a39e3f623d 优化阿里云浏览器上传授权 4 years ago
youngS 04fe7a2965 修复管理员迁移失败问题 4 years ago
youngS 0df8cf68be 修改超级签名使用任务队列进行签名 4 years ago
youngS 8b0fab87b5 优化代码 4 years ago
youngS fd56fcd88b 删除超级签名,用户和密码添加方式 4 years ago
youngS 2c557a5b12 set default storage cache 4 years ago
youngS 19ba89eec7 超级签下载文件到服务器通过内网通信 4 years ago
youngS 96785fec31 超级签下载文件到服务器通过内网通信 4 years ago
youngS bb422ee67d 超级签下载文件到服务器通过内网通信 4 years ago
youngS 0baaaedc67 修改代码 4 years ago
youngS e53e0843a3 优化代码,增加域名默认数据 4 years ago
nineven 10e9f80067 优化代码 4 years ago
nineven 7a4e73fc2b 优化代码 4 years ago
nineven af21dd2129 优化上传展示 4 years ago
youngS 7c5b2b7270 优化业务支持第三方域名https跳转 4 years ago
youngS 0ac35618e2 reset db install ........... 4 years ago
youngS 76bde18c5a 增加重置密码页面和逻辑 4 years ago
youngS 50d877f2f3 增加域名绑定功能 4 years ago
youngS 710de8432d 增加域名绑定功能 4 years ago
youngS 4a8de02afa 增加域名绑定功能 4 years ago
youngS 250c07c1a6 增加域名绑定功能 4 years ago
youngS a82f2a3ec7 增加域名绑定页面展示 4 years ago
youngS 3da097f6e5 增加默认日志路径 4 years ago
youngS 875445bc09 封禁应用无法下载 4 years ago
youngS a57143f732 增加app 历史版本可查看更多 4 years ago
youngS 9727534b91 vue.config settings 4 years ago
youngS 7100febed9 增加geetest 加载动画展示 4 years ago
youngS a320bd9165 发送邮件支持 ssl 465端口 4 years ago
youngS 2980131dd3 修复oss上传失败bug 4 years ago
youngS 49ce167ce6 修复超级签按钮展示 4 years ago
youngS 0416bf5e15 优化代码 4 years ago
youngS ed18398563 优化前端展示界面 4 years ago
youngS 23f0d90c50 优化前端展示界面 4 years ago
youngS f96fc79822 修复超级签bug 4 years ago
youngS c93df04b18 优化充值问题 4 years ago
youngS 25fb257a53 vue 打包命令修改 4 years ago
youngS 9157a9b43f 优化前端展示界面 4 years ago
youngS e1a34c1fa8 实名认证问题 4 years ago
youngS 227501d89c 优化前端展示界面 4 years ago
youngS 6c0cde3b7f 优化前端展示界面 4 years ago
youngS a22d72e4d8 优化前端页面展示 4 years ago
youngS 056b30bc82 增加个人信息修改验证 4 years ago
youngS 35e6ac8e39 绑定域名之后,自动关闭微信访问简易模式 4 years ago
youngS 02e5eedc82 优化前端代码 4 years ago
youngS e357168fcd 优化前端代码 4 years ago
youngS 3623b36247 优化前端代码 4 years ago
youngS 54e9de66b6 订单页面展示 4 years ago
youngS 87ae640c51 管理后台存储迁移逻辑处理 4 years ago
youngS e25046df93 管理后台存储选择页面展示 4 years ago
youngS ef5d434c40 优化代码,修复未实名认证导致存储无法修改问题 4 years ago
youngS ac77e8b36a 存储参数修改 4 years ago
youngS d133d0ec7b 管理后台 实名认证页面添加 4 years ago
youngS 7a0c8bfce3 优化代码,修复认证之后,免费下载次数不变问题 4 years ago
youngS 2e21465a1e 支持支付宝和微信支付 4 years ago
youngS c7e77ad46b 增加微信之后后端逻辑 4 years ago
youngS 07dc141b29 微信支付提交中 4 years ago
youngS 75630183c6 增加下载每超过100M消耗一次下载次数 4 years ago
youngS cad5906404 订单逻辑优化 4 years ago
youngS e2d8f60640 增加支付宝充值 4 years ago
youngS cae0715e7a 增加管理后台应用版本历史记录功能 4 years ago
youngS 23a215d980 增加应用展示页面 4 years ago
nineven c8f3126a85 管理后台初始化 4 years ago
nineven cdf43a7f41 实名认证显示优化 4 years ago
nineven cfc31fc9d8 优化代码 4 years ago
nineven 30e7e69ff8 优化代码 4 years ago
nineven 00f70627ae 优化页面展示 4 years ago
nineven c67b0d48ec format code 4 years ago
youngS 270e47999c 修复bug 4 years ago
youngS 6c1137afdc 修复bug 4 years ago
youngS ea6e2fab44 优化界面展示 4 years ago
youngS de7b3f26aa 优化界面展示 4 years ago
youngS ed3cc532d6 优化界面展示 4 years ago
youngS c45aeed34e 增加实人认证界面 4 years ago
youngS fbb4d41934 增加实名认证数据表 4 years ago
youngS 5fd3df9095 优化页面展示 4 years ago
youngS 8b7dd30adb 优化页面展示 4 years ago
youngS d5f5e8ca34 修复一个bug 4 years ago
youngS 946e77b0bc 增加订单功能 4 years ago
youngS fb973da90e 增加订单功能 4 years ago
youngS 1fcf10575d 优化前端页面展示 4 years ago
youngS 7ff34ef43d 修改安卓包读取图标失败问题 4 years ago
youngS 0f3b7c5049 增加前端购买次数页面展示 4 years ago
youngS 4d7ce27ff5 代码优化,超级签需要消化两个下载次数 4 years ago
youngS 4b2a3c7508 增加注册登录 geetest 验证,增加免费次数下载,增加速率限制功能 4 years ago
youngS c2ecb1aa3e 修复用户名修改失败未返回错误状态问题 4 years ago
youngS 2cad11ba32 修复绑定域名上传失败问题 4 years ago
youngS b8d737e08b 优化展示 4 years ago
youngS 5433d2f463 优化下载页显示 4 years ago
youngS 2d057d46ae 修复应用截图删除,存储未清理问题 4 years ago
youngS 0dbea33ff3 优化下载页显示 4 years ago
youngS 74127bac08 优化下载页显示 4 years ago
youngS fbb5c85fcd 优化下载页显示 4 years ago
youngS 930a8e3cbf 下载页显示超级签帮助 4 years ago
youngS 5f9ffcd9f9 下载页显示超级签帮助 4 years ago
youngS a8d0162c6f 下载页显示应用截屏 4 years ago
youngS 0d9eb758a0 下载页显示应用截屏 4 years ago
youngS ecadd2a030 增加应用截图上传 4 years ago
youngS 68c7de7374 增加苹果包 企业签显示企业名称 4 years ago
youngS ab5034d898 修复bug 4 years ago
youngS 0c11effbe6 修改已知bug 4 years ago
youngS d8f16e04c4 优化代码 4 years ago
youngS a5388cb9e7 开启cdn,导致二维码生成失败,需要在阿里云cdn 添加自定义头 4 years ago
youngS c8465522f0 优化下载码跨域显示 4 years ago
youngS 291dd950d5 优化代码,修复已知Bug,增加本地存储支持阿里云cdn URL鉴权访问 4 years ago
youngS 504b27831d 修改前端存储路由 4 years ago
nineven 65fadc2718 单个应用超级签加锁单线程执行;更新描述文件;迁移存储,清理头像缓存 4 years ago
nineven 51020ed73e 增加 存储切换 自动迁移数据功能 4 years ago
nineven 641b7643de 修复bug,后端增加 存储迁移和清理方法 4 years ago
youngS f902020079 存储切换,迁移头像数据 4 years ago
youngS 4d856bf5c0 优化存储代码 4 years ago
youngS d1ea31cdba 优化代码 4 years ago
youngS d5ccb336a1 优化代码 4 years ago
youngS a2ceeccdef 优化代码 4 years ago
youngS b6f5210fe7 优化代码 4 years ago
youngS ef8c0c3472 优化代码 4 years ago
youngS 5a85eb20d6 增加应用签名限额 4 years ago
youngS 348c6a16f5 超级签 支持自定义bundleid 和 签名类型 4 years ago
nineven a263d3cf46 修复APP删除之后,缓存未清理 4 years ago
nineven b02563a377 修复APP删除之后,缓存未清理 4 years ago
nineven f2d8619083 修复APP删除之后,缓存未清理 4 years ago
nineven 9446559dbc 修复APP删除之后,缓存未清理 4 years ago
nineven e7eb8f59c8 修复APP删除之后,缓存未清理 4 years ago
nineven 3de5b56584 优化代码 4 years ago
nineven a3bc31a0f9 修复超级签已知问题 4 years ago
nineven 308faf76b6 format code 4 years ago
nineven 81717de958 定时任务日志级别修改为error 4 years ago
nineven 23016487fe 优化代码 4 years ago
nineven 664c79dedf 修复bug 4 years ago
nineven 46acd9c391 修复bug 4 years ago
nineven b4a1cb47ae 苹果开发账户仅同步enable设备 4 years ago
nineven 21fe5665e2 苹果开发账户仅同步enable设备 4 years ago
nineven a5dd4c7759 优化代码 4 years ago
nineven a3cbc7354b 优化超级签名速度,把一下数据信息存放到数据库内 4 years ago
nineven 24754db152 修复页面刷新 按钮被禁用 4 years ago
nineven aeb6460946 超级签支持udid显示跳转 4 years ago
nineven 9e19f93ffb 修复bug 4 years ago
nineven d5f1ff07df fix cli.py 4 years ago
nineven 8222ad2df5 关闭检查苹果开发者账户是否激活定时任务 4 years ago
nineven 0c0e32bb23 优化代码 4 years ago
nineven 46a89416bc 开启邮箱tls支持 4 years ago
nineven 97b5a23dba fix a bug 4 years ago
nineven 7c292f85a4 超级签应用更新自动进行签名 4 years ago
nineven 0d42223af2 formcat code 4 years ago
nineven d7a3506230 优化代码,修复bug 4 years ago
nineven a39f7348b3 fix some bugs 4 years ago
nineven a2d0bdd3b0 add requirements 4 years ago
nineven 8a080a5ed3 自动创建证书功能 4 years ago
nineven 082b56121f 自动创建证书功能 4 years ago
nineven dcdf2aac5c 优化超级签逻辑 4 years ago
nineven a41f6335bc 优化超级签逻辑 4 years ago
nineven 5b7e6a3869 增加p8key 秘钥支持签名功能 4 years ago
nineven 69d5979ff8 增加p8key 秘钥支持签名功能 4 years ago
nineven 4da62f86b9 前端页面增加苹果开发者p8key 用户添加 4 years ago
nineven 068561ae99 FORMAT CODE 4 years ago
nineven aed955c657 修复手机端应用未找到不显示错误信息 4 years ago
nineven 0f1b7c39b4 增加应用专属域名功能 4 years ago
nineven 6e66592ba2 增加APP下载码保存本地功能 4 years ago
nineven fad08e4be2 增加APP下载码保存本地功能 4 years ago
nineven 65bae2d9c8 fix a bug 4 years ago
youngS ccc9a176f4 增加设置类型判断,修复设备同步只增不减的问题 4 years ago
youngS 95a96e5dc5 修复应用不存在的问题 4 years ago
youngS 9f178f5c7f format code 4 years ago
youngS a0dba04bf2 增加验证码开启关闭配置 4 years ago
youngS d5c42cc769 add api cli 4 years ago
youngS 1683f27792 增加nginx直接读取资源配置,一般用于使用本地存储,并通过cdn访问 4 years ago
xiaoyu e2eaa14da5 优化前端页面展示 4 years ago
xiaoyu d135f4bcc0 优化前端页面展示 4 years ago
xiaoyu cb71d238bc 修复超级签失败,导致下载的包为老包 4 years ago
xiaoyu c66c304e81 增加登录注册 回车事件 4 years ago
xiaoyu d72faa2a46 no message 4 years ago
xiaoyu 386a395f80 fix a bug 4 years ago
xiaoyu 62c204a300 增加footer 页面 4 years ago
xiaoyu 21ffdea520 fix a bug 4 years ago
xiaoyu 04e51c8d3c fix a bug 4 years ago
xiaoyu b45d16cfe0 增加ios开发账户定时检测 4 years ago
xiaoyu eee1685361 no message 4 years ago
xiaoyu b0abdfa8d2 增加存储和超级签权限管理 4 years ago
xiaoyu 97cb1f08bc 增加邮箱和手机号登录 4 years ago
xiaoyu 94754fe2dc 增加邮箱和手机号登录 4 years ago
xiaoyu d805283ef2 增加邮箱和手机号登录 4 years ago
xiaoyu d5c8a09ce6 增加邮箱和手机号登录 4 years ago
xiaoyu d02a7a74b8 增加邮箱和手机号注册 4 years ago
xiaoyu cad199394b 增加前端打包参数 4 years ago
xiaoyu 3861b0a84f 优化前端显示代码 4 years ago
xiaoyu 0521f0c6a0 fix some bugs 4 years ago
xiaoyu 11810cd6ca add register function 4 years ago
xiaoyu a9b5e320c0 Merge branch 'super_signature' 4 years ago
xiaoyu b4bf20f960 fix a bug 4 years ago
xiaoyu 58b1fd06ac fix a bug 4 years ago
xiaoyu bbdb6bb1d4 Merge branch 'super_signature' 4 years ago
xiaoyu ffcc4efd89 优化代码 4 years ago
xiaoyu 474f2d9eee Merge branch 'super_signature' 4 years ago
xiaoyu 4af2212c9e fix a bug 4 years ago
xiaoyu 03a07f01f4 Merge branch 'super_signature' 4 years ago
xiaoyu b9679c586a fix a bug 4 years ago
xiaoyu dc64563c55 Merge branch 'super_signature' 4 years ago
xiaoyu d0700522ee 增加苹果企业签名,下载描述文件之后,自动跳转到描述文件安装设置 4 years ago
xiaoyu 49f8f1c0ca Merge branch 'super_signature' 4 years ago
xiaoyu ce6a0e8dcc 增加苹果超级签名,下载描述文件之后,自动跳转到描述文件安装设置 4 years ago
xiaoyu ff1c45946f Merge branch 'super_signature' 4 years ago
xiaoyu 1fe5d51143 优化代码 4 years ago
xiaoyu 1af07cc2cb Merge branch 'super_signature' 4 years ago
xiaoyu 0dc9577913 修复删除最后一个release 版本,如果是超级签名,不清理问题 4 years ago
xiaoyu 5f58e88ebb Merge branch 'super_signature' 4 years ago
xiaoyu 66e8969cc2 增加苹果描述文件签名 4 years ago
xiaoyu a121bfddad Merge branch 'super_signature' 4 years ago
xiaoyu c0a8ad6415 fix a bug 4 years ago
nineven e5d4fcb4f2 update readme 4 years ago
nineven a06822ee37 fix a bug 5 years ago
nineven 863c4d2fe6 fix a bug 5 years ago
nineven 96394cbece 修复设置域名bug 5 years ago
nineven c0296619cc 增加本地存储上传域名配置 5 years ago
nineven e035f40d86 优化代码 5 years ago
nineven 060f6991d6 修复bug 5 years ago
nineven 02cd05eb7e 修复存储修改失败 却保存数据的问题 5 years ago
nineven c46bbc6f75 优化代码,增加添加oss存储 校验功能 5 years ago
nineven b32a12a597 优化代码 5 years ago
nineven 33e16c9284 增加应用微信内访问限制 5 years ago
nineven 5161f04fae 修复添加密码,导致下载源文件失败 5 years ago
nineven d7fb8480c5 fix web download release_bug 5 years ago
nineven a879fea15c 微信防封,可能会防封成功 5 years ago
nineven 0a1cefa2ad 修复前端搜素支持模糊匹配 5 years ago
nineven 539ff8b10d 修复ios 微信下没有引导,关联应用设置密码,下载不显示密码框 5 years ago
nineven c5ddfd5e33 修复关联应用,修改操作,未清理缓存导致异常 5 years ago
nineven a1167f6303 增加日志逻辑 5 years ago
nineven 9f21a2f51e 优化代码结构 5 years ago
nineven d9b0d3718c 增加登录验证码操作,登录失败超过限制次数,锁定24小时 5 years ago
nineven fb99233ce5 修复自动清理临时文件 由于缓存时间不足,导致任务失效 5 years ago
nineven 1dac608843 fix some bugs 增加清理临时上传文件 5 years ago
nineven 47e79acf42 fix a bug 5 years ago
nineven 0c61cd4398 fix a bug 5 years ago
nineven f588a860df 修复添加存储字段不校验问题 5 years ago
nineven 7821d10929 fix a bug 5 years ago
nineven ff81f62d95 优化代码 5 years ago
nineven a4e9579236 fix some bugs 5 years ago
nineven b3610913e2 fix a bug 5 years ago
nineven 42de66927f 或许修复了下载token失效问题 5 years ago
nineven 9d8a28ff9a fix a bug 5 years ago
nineven a341fbc647 fix a bug 5 years ago
nineven 96cd18e405 修复获取默认存储的问题 5 years ago
nineven 9299e4af05 fix a bug 5 years ago
nineven 9679d1d7fc 修复超级签同一个udid下载,次数不增加问题 5 years ago
nineven 19ea47a65c fix a bug 5 years ago
nineven 616e959978 fix a bug 5 years ago
nineven 4180b82311 fix a bug 5 years ago
nineven ebfa2126a6 fix some bugs 5 years ago
nineven 68eceea99f 修复超级签包更新,重签bug 5 years ago
nineven 28ec622347 fix a bug 5 years ago
nineven bd213e2c0b fix some bugs 5 years ago
nineven b9a646f521 fix some bugs 5 years ago
nineven b8ebd2b8d9 rename download html 5 years ago
nineven 03c59c4fcf 修复开发者账户使用量显示 5 years ago
nineven 695c1c9ad1 修复超级签下载次数bug 5 years ago
nineven 9cdc609eb5 fix some bugs 5 years ago
nineven 72d8ebcfd8 超级签功能优化 5 years ago
nineven 85a1982129 add new functions 5 years ago
nineven 870646daeb fix bugs 5 years ago
nineven 4e60166ecc add a new fun 5 years ago
nineven de4285a46a fix some bugs 5 years ago
nineven 789b9a0c58 实现超级签名方法 5 years ago
nineven 8de6e4a87d 管理员默认存储配置 5 years ago
nineven 15e88b9b59 修复切换存储,缓存数据未删除 5 years ago
nineven 60b514fc0c fix a bug 5 years ago
nineven cb32a2226e 新增用户存储设置 5 years ago
nineven 1027110786 增加存储配置 5 years ago
nineven 8d18692809 修复release版本下载缓存bug 5 years ago
nineven 47f2f534c7 增加下载权限控制 5 years ago
nineven 68c8db9339 优化第三方下载显示 5 years ago
nineven 31c075a3f8 修复苹果版本显示问题 5 years ago
nineven 8a39c3d100 fix a bug 5 years ago
nineven 003c39aae6 增加下载次数统计 5 years ago
nineven 917ed49f74 缓存优化 5 years ago
nineven eaa98f49d6 修复双重缓存过期不一致 5 years ago
nineven 870b6a2424 fix a download bug 5 years ago
nineven 7421d1a38d 优化访问速度 5 years ago
nineven a8b5d4dbbe 优化下载次数统计,放到缓存里面,每10秒同步到数据库 5 years ago
nineven 5f7873c29f 优化下载流程 5 years ago
nineven f72be06618 add uwsgi start ; add mysql database ;add nginx vhost 5 years ago
nineven 1513cb4ca9 add short cache 5 years ago
nineven d8e4702632 add download_url cache 5 years ago
nineven 986e179bba fix thread url download 5 years ago
nineven 45708d3fc3 upload fir_download 5 years ago
nineven bdacda6a64 fix some bugs 5 years ago
nineven f308de1aeb fix ios download 5 years ago
  1. 12
      .gitignore
  2. 74
      README.md
  3. 102
      doc/docker.md
  4. BIN
      doc/images/img_1.png
  5. BIN
      doc/images/img_10.png
  6. BIN
      doc/images/img_11.png
  7. BIN
      doc/images/img_2.png
  8. BIN
      doc/images/img_3.png
  9. BIN
      doc/images/img_4.png
  10. BIN
      doc/images/img_5.png
  11. BIN
      doc/images/img_6.png
  12. BIN
      doc/images/img_7.png
  13. BIN
      doc/images/img_8.png
  14. BIN
      doc/images/img_9.png
  15. 166
      doc/local.md
  16. 67
      docker/build/docker-compose.yml
  17. 31
      docker/flyapps/docker-compose.only.yml
  18. 48
      docker/flyapps/docker-compose.yml
  19. 7
      docker/init/clean.sh
  20. 10
      docker/init/download.images
  21. 24
      docker/init/init.sh
  22. 1
      docker/init/timezone
  23. 43
      docker/mariadb/docker-compose.yml
  24. 108
      docker/mariadb/server.cnf
  25. 25
      docker/redis/docker-compose.yml
  26. 6
      docker/scripts/build.sh
  27. 9
      docker/scripts/start_all.sh
  28. 10
      docker/scripts/stop_all.sh
  29. 14
      fir_admin/.editorconfig
  30. 6
      fir_admin/.env.development
  31. 6
      fir_admin/.env.production
  32. 8
      fir_admin/.env.staging
  33. 4
      fir_admin/.eslintignore
  34. 198
      fir_admin/.eslintrc.js
  35. 16
      fir_admin/.gitignore
  36. 5
      fir_admin/.travis.yml
  37. 21
      fir_admin/LICENSE
  38. 102
      fir_admin/README-zh.md
  39. 91
      fir_admin/README.md
  40. 14
      fir_admin/babel.config.js
  41. 35
      fir_admin/build/index.js
  42. 24
      fir_admin/jest.config.js
  43. 9
      fir_admin/jsconfig.json
  44. 57
      fir_admin/mock/index.js
  45. 81
      fir_admin/mock/mock-server.js
  46. 29
      fir_admin/mock/table.js
  47. 84
      fir_admin/mock/user.js
  48. 25
      fir_admin/mock/utils.js
  49. 63
      fir_admin/package.json
  50. 8
      fir_admin/postcss.config.js
  51. BIN
      fir_admin/public/favicon.ico
  52. 17
      fir_admin/public/index.html
  53. 11
      fir_admin/src/App.vue
  54. 61
      fir_admin/src/api/app.js
  55. 54
      fir_admin/src/api/developer.js
  56. 10
      fir_admin/src/api/devices.js
  57. 31
      fir_admin/src/api/domain.js
  58. 38
      fir_admin/src/api/order.js
  59. 8
      fir_admin/src/api/qiniu.js
  60. 31
      fir_admin/src/api/report.js
  61. 32
      fir_admin/src/api/storage.js
  62. 9
      fir_admin/src/api/table.js
  63. 63
      fir_admin/src/api/user.js
  64. 31
      fir_admin/src/api/wxbind.js
  65. BIN
      fir_admin/src/assets/404_images/404.png
  66. BIN
      fir_admin/src/assets/404_images/404_cloud.png
  67. BIN
      fir_admin/src/assets/logo.png
  68. 78
      fir_admin/src/components/Breadcrumb/index.vue
  69. 44
      fir_admin/src/components/Hamburger/index.vue
  70. 101
      fir_admin/src/components/Pagination/index.vue
  71. 91
      fir_admin/src/components/Sticky/index.vue
  72. 62
      fir_admin/src/components/SvgIcon/index.vue
  73. 111
      fir_admin/src/components/Tinymce/components/EditorImage.vue
  74. 59
      fir_admin/src/components/Tinymce/dynamicLoadScript.js
  75. 250
      fir_admin/src/components/Tinymce/index.vue
  76. 7
      fir_admin/src/components/Tinymce/plugins.js
  77. 6
      fir_admin/src/components/Tinymce/toolbar.js
  78. 134
      fir_admin/src/components/Upload/SingleImage.vue
  79. 130
      fir_admin/src/components/Upload/SingleImage2.vue
  80. 157
      fir_admin/src/components/Upload/SingleImage3.vue
  81. 49
      fir_admin/src/directive/clipboard/clipboard.js
  82. 13
      fir_admin/src/directive/clipboard/index.js
  83. 77
      fir_admin/src/directive/el-drag-dialog/drag.js
  84. 13
      fir_admin/src/directive/el-drag-dialog/index.js
  85. 41
      fir_admin/src/directive/el-table/adaptive.js
  86. 13
      fir_admin/src/directive/el-table/index.js
  87. 13
      fir_admin/src/directive/permission/index.js
  88. 31
      fir_admin/src/directive/permission/permission.js
  89. 91
      fir_admin/src/directive/sticky.js
  90. 13
      fir_admin/src/directive/waves/index.js
  91. 26
      fir_admin/src/directive/waves/waves.css
  92. 72
      fir_admin/src/directive/waves/waves.js
  93. 9
      fir_admin/src/icons/index.js
  94. 1
      fir_admin/src/icons/svg/dashboard.svg
  95. 1
      fir_admin/src/icons/svg/example.svg
  96. 1
      fir_admin/src/icons/svg/eye-open.svg
  97. 1
      fir_admin/src/icons/svg/eye.svg
  98. 1
      fir_admin/src/icons/svg/form.svg
  99. 1
      fir_admin/src/icons/svg/link.svg
  100. 1
      fir_admin/src/icons/svg/nested.svg
  101. Some files were not shown because too many files have changed in this diff Show More

12
.gitignore vendored

@ -1,6 +1,16 @@
fir_ser/.idea/
fir_ser/db.sqlite3
*.pyc
fir_ser/files/
fir_ser/venv/
fir_client/.idea
fir_admin/.idea/.gitignore
fir_admin/.idea/
fir_client/yarn.lock
fir_download/package-lock.json
fir_client/src/assets/down_left.png
fir_client/src/assets/down_right.png
mailhtml/build/
mailhtml/node_modules/
mailhtml/.idea/
fir_client/dist_index/
fir_client/dist_short/

@ -1,17 +1,63 @@
# FlyApps
### 用与应用分发,苹果超级签名
#### 部署前准备
- 备案域名【至少需要一个域名,以下可通过子域名部署】
- API域名
- 前端web域名
- 下载页域名
- 下载页域名可配置多个
- 存储域名(使用阿里云oss存储)
- ssl证书
- API域名证书
- 存储域名证书(使用阿里云oss存储)
- 前端web域名证书(可选)
- Centos8Stream 服务器
- 如果使用oss存储,则带宽为1M,若使用本地存储,则带宽越大越好
- 如果使用超级签,最低配置为2cpu 4G内存,若干不使用签名,则1cpu2G就行
- 阿里云短信或极光短信服务【可选一个,主要用与注册,重置密码】
- 阿里云短信
- 极光短信
- 邮箱服务【可选,用与注册,重置密码,通知信息】
- 阿里云OSS存储【可选】
- [sts授权配置](https://help.aliyun.com/document_detail/100624.html)
- 阿里云CDN【可选,用与加速访问】
- 极验验证【可选,滑动验证服务】
- 微信公众号【可选,用与微信扫描登录】
- 阿里云支付【可选,用与购买下载次数】
- 微信支付【可选,用与购买下载次数】
## install
```
yum install -y npm
npm install -g n
n latest
#### 自用搭建建议
- 阿里云服务器需要1cpu 2G内存,无需系统盘,如果使用超级签,可以适当增加配置
- 需要阿里云OSS存储和阿里云CDN,并且OSS存储和阿里云服务器部署同一个地区
- 可以申请一个极验进行滑动验证,或者开启验证码验证
- 阿里云备案域名:api和前端可以使用一个域名,下载页单独域名
npm install -g yarn
```
#### 部署必备资料
- 域名证书
- web域名和证书
- api域名和证书
- 下载页域名(可配置证书)
- 存储域名和证书
- 本地存储,则该域名和证书可以和api域名证书一致
- 阿里云oss存储
- 开启cdn,需要新域名和证书
- 不开启,无需域名和证书
- Centos8Stream 服务器
## build
```
cd ./fir_client
yarn install
yarn build
```
## 部署方式
### 1.[Docker 部署](./doc/docker.md) 【推荐】
### 2.[本地部署](./doc/local.md)
### 功能预览
![img_1.png](./doc/images/img_1.png)
![img_2.png](./doc/images/img_2.png)
![img_3.png](./doc/images/img_3.png)
![img_4.png](./doc/images/img_4.png)
![img_5.png](./doc/images/img_5.png)
![img_6.png](./doc/images/img_6.png)
![img_7.png](./doc/images/img_7.png)
![img_8.png](./doc/images/img_8.png)
![img_9.png](./doc/images/img_9.png)
![img_10.png](./doc/images/img_10.png)
![img_11.png](./doc/images/img_11.png)

@ -0,0 +1,102 @@
### Docker最小化部署前准备,如果使用超级签和云存储,需要使用阿里云的服务器
系统|Centos 8 Stream 纯净系统 [2cpu 4G内存]
----|----
域名|```app.hehelucky.cn```
域名SSL证书| nginx 格式证书 [阿里云和腾讯云都可以申请免费ssl证书]
数据路径| ```/data```
### 开始部署
##### 1.从git上面下载源码
```
cd /data/
dnf install git -y
git clone https://github.com/nineaiyu/flyapps
```
## 注意,下面展示的相对路径,都是以```/data/flyapps```为相对目录
#### 2.docker环境安装
```
cd /data/flyapps/docker/init
sh init.sh
```
#### 3.配置域名和证书,如果有cdn或者oss,也要进行配置
a.将域名证书通过```sftp软件```或者```rz命令```复制到```/data/flyapps/nginx.conf.d```目录中
b.将域名证书分别重命名为 ```域名.pem``` 和 ```域名.key``` .本次使用的域名是 ```app.hehelucky.cn``` ,因此,证书名称类似如下
```shell script
nginx.conf.d/app.hehelucky.cn.key
nginx.conf.d/app.hehelucky.cn.pem
```
c.修改NGINX配置文件```nginx.conf.d/flyapps-vhost.conf```,将```server_name```字段修改为域名,将```ssl_certificate```和
```ssl_certificate_key```修改为对应证书路径,修改之后,对应字段如下
```shell
server_name app.hehelucky.cn;
ssl_certificate /etc/nginx/conf.d/app.hehelucky.cn.pem;
ssl_certificate_key /etc/nginx/conf.d/app.hehelucky.cn.key;
```
#### 4.配置api服务需要修改api和web域名,如果有需求,还可以配置 短信,邮箱,geetest,存储等信息
##### fir_ser配置文件 ```fir_ser/config.py```
```python
class DOMAINCONF(object):
API_DOMAIN = "https://app.hehelucky.cn" # 用与开启本地存储,上传应用配置
WEB_DOMAIN = "https://app.hehelucky.cn" # 用于超级签跳转配置,该域名一般为前端页面域名
```
##### fir_client配置文件 ```fir_client/vue.confjg.js```
```javascript
const pro_base_env = {
baseUrl: '/', //该选项可以填写web-api的域名,类似 https://api.xxx.com/
index_static: '/', //若配置cdn等加速,可以填写cdn加速域名
baseShortUrl: '/', //该选项可以填写short-api的域名,也可以和web-api域名一样,类似 https://api.xxx.com/
short_static: '/short/', //若配置cdn等加速,可以填写cdn加速域名
version: version,
};
```
##### 构建静态资源
```
cd /data/flyapps/docker/scripts
sh build.sh
```
##### 启动所有服务
```
cd /data/flyapps/docker/scripts
sh start_all.sh
```
##### 关闭所有服务
```
cd /data/flyapps/docker/scripts
sh stop_all.sh
```
##### 根据提示创建默认管理用户,用与访问管理后台
```shell
docker exec -it flyapps python manage.py createsuperuser
```
##### 测试访问
- 在浏览器输入自己配置的域名 https://app.hehelucky.cn/ 进行访问
- 管理后台访问 https://app.hehelucky.cn:3448/ 进行访问
##### 如果要使用本地的数据库和redis,api服务使用容器,需要修改文件```/data/flyapps/docker/flyapps/docker-compose.yml```
```shell
external_links:
- mariadb:mariadb
- redis:redis
```
修改为
```shell
extra_hosts:
- "mariadb:172.31.31.1"
- "redis:172.31.31.1"
```
并将```nginx:```下面的配置注释掉
同时还需要修改mariadb和redis授权

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

@ -0,0 +1,166 @@
### 本地部署前准备
系统 | Centos 8 Stream [2cpu 4G内存]
----|----
域名|```app.hehelucky.cn```
域名SSL证书| nginx 格式证书 [阿里云和腾讯云都可以申请免费ssl证书]
数据路径| ```/data```
##### 从git上面下载源码
```shell
cd /data/
dnf install git gcc zip unzip -y
git clone https://github.com/nineaiyu/flyapps
```
### flyapps 本地部署 [python3 环境]
##### 搭建python env 环境
```shell
dnf install python39 python39-devel redis mariadb-server mariadb-devel -y
python3.9 -m venv py39
source py39/bin/activate
```
###### 安装pip包
```shell
cd /data/flyapps/fir_ser/
pip install -U setuptools pip -i https://pypi.tuna.tsinghua.edu.cn/simple/
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple/
```
#### 配置数据库
##### 启动mariadb数据库
```shell
systemctl restart mariadb
systemctl enable mariadb
```
##### 创建mysql数据库
```shell
mysql
```
执行下面mysql命令
```mariadb
create database flyapps default character set utf8 COLLATE utf8_general_ci;
grant all on flyapps.* to flyuser@'127.0.0.1' identified by 'KGzKjZpWBp4R4RSa';
```
##### 启动redis数据库
```shell
echo 'requirepass nineven' >> /etc/redis.conf # 配置授权密码
systemctl restart redis
systemctl enable redis
```
### flyapps zsign ipa重签名工具安装
```shell
dnf install openssl-devel -y
dnf install gcc-c++ gcc -y
cd /data/flyapps/fir_ser/
tar xvf zsign-1.1.2.tar.gz
cd zsign-1.1.2/
g++ *.cpp common/*.cpp -lcrypto -O3 -std=c++11 -o /usr/bin/zsign
```
#### 配置api服务需要修改api和web域名,如果有需求,还可以配置 短信,邮箱,geetest,存储等信息
##### fir_ser配置文件 ```fir_ser/config.py```
```python
class DOMAINCONF(object):
API_DOMAIN = "https://app.hehelucky.cn" # 用与开启本地存储,上传应用配置
WEB_DOMAIN = "https://app.hehelucky.cn" # 用于超级签跳转配置,该域名一般为前端页面域名
```
##### fir_client配置文件 ```fir_client/vue.confjg.js```
```javascript
const pro_base_env = {
baseUrl: '/', //该选项可以填写web-api的域名,类似 https://api.xxx.com/
index_static: '/', //若配置cdn等加速,可以填写cdn加速域名
baseShortUrl: '/', //该选项可以填写short-api的域名,也可以和web-api域名一样,类似 https://api.xxx.com/
short_static: '/short/', //若配置cdn等加速,可以填写cdn加速域名
version: version,
};
```
### flyapps web端搭建
###### npm编译环境
```shell
dnf install npm -y
npm install -g n
n 12.13 # 安装12版本的node或者14版本 ,最新版本会有问题
npm install -g yarn
```
###### 编译web端和下载页
```shell
cd /data/flyapps/fir_client/
vim vue.config.js #修改api接口地址
# pro_base_env 正式环境信息
# dev_base_env 开发环境信息
yarn install
yarn build index # 前端打包,输出目录 dist_index
yarn build short # 下载页打包,输出目录 dist_short
```
###### 编译web管理后台
```shell
cd /data/flyapps/fir_admin/
yarn install
yarn build:prod # 下载页打包,输出目录 dist
```
### nginx配置
##### 安装nginx
```shell
dnf install nginx -y
```
##### 将域名ssl证书解压到```/etc/nginx/conf.d/``` 目录中,并重命名为```域名.pem```,```域名.key```格式
##### 拷贝虚拟主机配置文件
```shell
cp /data/flyapps/nginx.conf.d/flyapps-vhost.conf /etc/nginx/conf.d/
```
1.创建web目录,并将打包好的web复制该目录
```shell
mkdir -pv /data/{fir_client/short,fir_admin}
cp -a /data/flyapps/fir_client/dist_index/* /data/fir_client/
cp -a /data/flyapps/fir_client/dist_short/* /data/fir_client/short/
cp -a /data/flyapps/fir_admin/dist/* /data/fir_admin/
chown nginx.nginx -R /data/{fir_client,fir_admin}
```
2.启动nginx服务
```shell
nginx -t
systemctl restart nginx
systemctl enable nginx
```
##### 添加redis和mariadb uwsgi本地解析
```shell
echo '127.0.0.1 mariadb redis flyapps' >> /etc/hosts
```
###### 迁移数据库
```shell
cd /data/flyapps/fir_ser/
python manage.py makemigrations
python manage.py migrate
```
#### 启动api服务
```shell
echo 'net.core.somaxconn=1024' >> /etc/sysctl.conf
sysctl -p
cd /data/flyapps/fir_ser/
python manage.py start all -u nginx -usm 1 -d
```
##### 根据提示创建默认管理用户,用与访问管理后台
```shell
python manage.py createsuperuser
```
- 需要输入用户名,邮箱和密码
- 用户名和密码用与登录管理后台
- 邮箱和密码用与登录前端web

@ -0,0 +1,67 @@
version: '3.2'
services:
buildflyapps:
image: 'flyapps'
build:
context: ../../fir_ser
dockerfile: Dockerfile
command:
- echo
- success
buildclient:
container_name: buildclient
image: 'node:14.17.3'
working_dir: /fir_client
volumes:
- /etc/localtime:/etc/localtime:ro
- ../../fir_client:/fir_client
- ../../data/web/:/web
command:
- bash
- -c
- yarn config set registry https://registry.npm.taobao.org && yarn install && yarn build index && yarn build short && ([ ! -e /web/fir_client ] && \cp -a dist_index /web/fir_client || \cp -a dist_index/* /web/fir_client/) && ([ ! -e /web/fir_client/short ] && \cp -a dist_short /web/fir_client/short || \cp -a dist_short/* /web/fir_client/short/) && echo build success
buildindex:
container_name: buildindex
image: 'node:14.17.3'
working_dir: /fir_client
volumes:
- /etc/localtime:/etc/localtime:ro
- ../../fir_client:/fir_client
- ../../data/web/:/web
command:
- bash
- -c
- yarn config set registry https://registry.npm.taobao.org && yarn install && yarn build index && ([ ! -e /web/fir_index ] && \cp -a dist_index /web/fir_index || \cp -a dist_index/* /web/fir_index/) && echo build success
buildshort:
container_name: buildshort
image: 'node:14.17.3'
working_dir: /fir_client
volumes:
- /etc/localtime:/etc/localtime:ro
- ../../fir_client:/fir_client
- ../../data/web/:/web
command:
- sh
- -c
- yarn config set registry https://registry.npm.taobao.org && yarn install && yarn build short && ([ ! -e /web/fir_short ] && \cp -a dist_short /web/fir_short || \cp -a dist_short/* /web/fir_short/) && echo build success
buildadmin:
container_name: buildadmin
image: 'node:14.17.3'
working_dir: /fir_admin
volumes:
- /etc/localtime:/etc/localtime:ro
- ../../fir_admin:/fir_admin
- ../../data/web/:/web
command:
- sh
- -c
- yarn config set registry https://registry.npm.taobao.org && yarn install && yarn build:prod && ([ ! -e /web/fir_admin ] && \cp -a dist /web/fir_admin || \cp -a dist/* /web/fir_admin/) && echo build success

@ -0,0 +1,31 @@
version: '3'
networks:
flyapps:
external: true
name: flyapps
services:
flyapps:
container_name: flyapps
restart: always
image: 'nineven/flyapps'
working_dir: /data/fir_ser
volumes:
- /etc/localtime:/etc/localtime:ro
- ../../fir_ser:/data/fir_ser
- ../../data/flyapps/files:/data/fir_ser/files
- ../../data/logs/flyapps/:/data/fir_ser/logs
- ../../data/flyapps/supersign/:/data/fir_ser/supersign
- ../../nginx.conf.d:/data/cert
networks:
flyapps:
ipv4_address: 172.31.31.100
external_links:
- mariadb:mariadb
- redis:redis
sysctls:
- net.core.somaxconn=4096
extra_hosts:
- "mariadb:172.31.31.1"
- "redis:172.31.31.1"

@ -0,0 +1,48 @@
version: '3'
networks:
flyapps:
external: true
name: flyapps
services:
flyapps:
container_name: flyapps
restart: always
image: 'nineven/flyapps'
working_dir: /data/fir_ser
volumes:
- /etc/localtime:/etc/localtime:ro
- ../../fir_ser:/data/fir_ser
- ../../data/flyapps/files:/data/fir_ser/files
- ../../data/logs/flyapps/:/data/fir_ser/logs
- ../../data/flyapps/supersign/:/data/fir_ser/supersign
- ../../nginx.conf.d:/data/cert
networks:
flyapps:
ipv4_address: 172.31.31.100
external_links:
- mariadb:mariadb
- redis:redis
sysctls:
- net.core.somaxconn=4096
nginx:
container_name: nginx
restart: always
image: 'nginx:1.21.3'
volumes:
- /etc/localtime:/etc/localtime:ro
- ../../data/web:/data
- ../../nginx.conf.d:/etc/nginx/conf.d
- ../../data/logs/nginx:/var/log/nginx
networks:
flyapps:
ipv4_address: 172.31.31.200
ports:
- 80:80
- 443:443
- 3448:3448
external_links:
- flyapps:flyapps
depends_on:
- flyapps

@ -0,0 +1,7 @@
#!/bin/bash
#
#
for i in nginx flyapps mariadb redis buildclient buildshort buildadmin ;do echo $i;docker rm -f $i;done
docker network rm flyapps

@ -0,0 +1,10 @@
#!/bin/bash
#
#
docker pull 'bitnami/mariadb:10.7.3'
docker pull 'bitnami/redis:6.2.7'
docker pull 'nginx:1.21.3'
docker pull 'nineven/flyapps:latest'
docker pull 'node:14.17.3'

@ -0,0 +1,24 @@
#!/bin/bash
#
#
which dockerd
if [ $? -ne 0 ];then
dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo
dnf install docker-ce -y
fi
#which docker-compose
#if [ $? -ne 0 ];then
# curl -L https://get.daocloud.io/docker/compose/releases/download/v2.5.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
# chmod +x /usr/local/bin/docker-compose
#fi
data_path="$(dirname $(dirname `pwd`))/data"
mkdir -pv ${data_path}/{flyapps/files,web,mariadb,redis,logs/{mariadb,nginx,flyapps}}
\cp $(dirname $(dirname `pwd`))/fir_ser/files/head_img.jpeg ${data_path}/flyapps/files/
chown 1001.1001 -R ${data_path}/{flyapps,web,mariadb,redis,logs/{mariadb,nginx,flyapps}}
chown 101.101 -R ${data_path}/{flyapps,logs/flyapps}
systemctl start docker && docker network create flyapps --driver bridge --subnet=172.31.31.0/24 --gateway=172.31.31.1
systemctl enable docker
systemctl status docker

@ -0,0 +1 @@
Asia/Shanghai

@ -0,0 +1,43 @@
version: '3.2'
networks:
flyapps:
external: true
name: flyapps
services:
mariadb:
image: bitnami/mariadb:10.7.3
container_name: mariadb
restart: always
environment:
- MARIADB_ROOT_PASSWORD=rootIPD.xx2.19
- MARIADB_DATABASE=flyapps
- MARIADB_USER=flyuser
- MARIADB_PASSWORD=KGzKjZpWBp4R4RSa
#- ALLOW_EMPTY_PASSWORD=yes
- MARIADB_ENABLE_SLOW_QUERY=1
- MARIADB_LONG_QUERY_TIME=3
- MARIADB_SKIP_TEST_DB=yes
- MARIADB_EXTRA_FLAGS=--max-connect-errors=3000 --max_connections=30000
ports:
- 3306:3306
networks:
flyapps:
ipv4_address: 172.31.31.90
volumes:
- ../init/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
- ../../data/mariadb:/bitnami/mariadb/data
- ../../data/logs/mariadb:/data/logs/mariadb
- ./server.cnf:/opt/bitnami/mariadb/conf/my_custom.cnf:ro
# adminer:
# image: adminer
# ports:
# - 8080:8080
# networks:
# - fungame

@ -0,0 +1,108 @@
#
# These groups are read by MariaDB server.
# Use it for options that only the server (but not clients) should see
#
# See the examples of server my.cnf files in /usr/share/mysql/
#
# this is only for the mysqld standalone daemon
[mysqld]
binlog_cache_size = 192K
thread_stack = 384K
join_buffer_size = 4096K
query_cache_type = 1
max_heap_table_size = 1024M
default_storage_engine = InnoDB
performance_schema_max_table_instances = 400
table_definition_cache = 400
skip-external-locking
key_buffer_size = 512M
max_allowed_packet = 1G
table_open_cache = 1024
sort_buffer_size = 2048K
net_buffer_length = 4K
read_buffer_size = 2048K
read_rnd_buffer_size = 1024K
myisam_sort_buffer_size = 16M
thread_cache_size = 192
query_cache_size = 256M
tmp_table_size = 1024M
sql-mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
max_connections = 30000
max_connect_errors = 1000
open_files_limit = 65535
expire_logs_days = 10
#log_queries_not_using_indexes=on
character-set-client-handshake = FALSE
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci
init_connect='SET NAMES utf8mb4'
#character-set-server=utf8
skip_name_resolve
event_scheduler=1
#skip-grant-tables
#innodb_data_home_dir = /var/lib/mysql/
#innodb_data_file_path = ibdata1:10M:autoextend
#innodb_log_group_home_dir = /var/lib/mysql/
#innodb_buffer_pool_size = 1024M
#innodb_log_file_size = 128M
#innodb_log_buffer_size = 32M
#innodb_flush_log_at_trx_commit = 1
#innodb_lock_wait_timeout = 50
#innodb_max_dirty_pages_pct = 90
#innodb_read_io_threads = 4
#innodb_write_io_threads = 4
#
# Allow server to accept connections on all interfaces.
#
#bind-address=0.0.0.0
#
# this is only for embedded server
# This group is only read by MariaDB servers, not by MySQL.
# If you use the same .cnf file for MySQL and MariaDB,
# you can put MariaDB-only options here
[mariadb]
#autoset_open_files_limit
#enable_slow_query_log
#audit
plugin_load_add=server_audit
server_audit_logging=on
server_audit_events=connect,query
server_audit=force_plus_permanent
server_audit_events=QUERY_DDL,QUERY_DML,CONNECT
server_audit_output_type=file
server_audit_file_rotate_now=on
server_audit_file_rotations=9
server_audit_file_rotate_size=1G
server_audit_file_path=/data/logs/mariadb
log_error=/data/logs/mariadb/mariadb.err.log
log_output=FILE
slow_query_log
long_query_time=3
slow_query_log_file=/data/logs/mariadb/mariadb-slow.log
log_queries_not_using_indexes=ON #Logging Queries That Don't Use Indexes
#server_id=2
log-bin=/data/logs/mariadb/mysql-bin
# This group is only read by MariaDB-10.5 servers.
# If you use the same .cnf file for MariaDB of different versions,
# use this group for options that older servers don't understand

@ -0,0 +1,25 @@
version: '3.2'
networks:
flyapps:
external: true
name: flyapps
services:
redis:
image: 'bitnami/redis:6.2.7'
container_name: redis
restart: always
volumes:
- ../init/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
- ../../data/redis:/bitnami/redis/data
environment:
#- REDIS_REPLICATION_MODE=master
#- ALLOW_EMPTY_PASSWORD=yes
- REDIS_PASSWORD=nineven
networks:
- flyapps
#ports:
# - 6379:6379

@ -0,0 +1,6 @@
#!/bin/bash
#
#
cd ../build/
docker compose up buildclient buildadmin

@ -0,0 +1,9 @@
#!/bin/bash
#
#
cd ../mariadb/ && docker compose up -d
cd ../redis/ && docker compose up -d
cd ../flyapps/ && docker compose up -d
docker logs -f flyapps

@ -0,0 +1,10 @@
#!/bin/bash
#
#
cd ../flyapps/ && docker compose down
cd ../redis/ && docker compose down
cd ../mariadb/ && docker compose down

@ -0,0 +1,14 @@
# http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false

@ -0,0 +1,6 @@
# just a flag
ENV = 'development'
# base api
VUE_APP_BASE_API = 'https://flyapps.cn/api/v3/fir/server'
#VUE_APP_BASE_API = 'https://app.hehelucky.cn/api/v3/fir/server'

@ -0,0 +1,6 @@
# just a flag
ENV = 'production'
# base api
VUE_APP_BASE_API = '/api/v3/fir/server'

@ -0,0 +1,8 @@
NODE_ENV = production
# just a flag
ENV = 'staging'
# base api
VUE_APP_BASE_API = '/stage-api'

@ -0,0 +1,4 @@
build/*.js
src/assets
public
dist

@ -0,0 +1,198 @@
module.exports = {
root: true,
parserOptions: {
parser: 'babel-eslint',
sourceType: 'module'
},
env: {
browser: true,
node: true,
es6: true,
},
extends: ['plugin:vue/recommended', 'eslint:recommended'],
// add your custom rules here
//it is base on https://github.com/vuejs/eslint-config-vue
rules: {
"vue/max-attributes-per-line": [2, {
"singleline": 10,
"multiline": {
"max": 1,
"allowFirstLine": false
}
}],
"vue/singleline-html-element-content-newline": "off",
"vue/multiline-html-element-content-newline":"off",
"vue/name-property-casing": ["error", "PascalCase"],
"vue/no-v-html": "off",
'accessor-pairs': 2,
'arrow-spacing': [2, {
'before': true,
'after': true
}],
'block-spacing': [2, 'always'],
'brace-style': [2, '1tbs', {
'allowSingleLine': true
}],
'camelcase': [0, {
'properties': 'always'
}],
'comma-dangle': [2, 'never'],
'comma-spacing': [2, {
'before': false,
'after': true
}],
'comma-style': [2, 'last'],
'constructor-super': 2,
'curly': [2, 'multi-line'],
'dot-location': [2, 'property'],
'eol-last': 2,
'eqeqeq': ["error", "always", {"null": "ignore"}],
'generator-star-spacing': [2, {
'before': true,
'after': true
}],
'handle-callback-err': [2, '^(err|error)$'],
'indent': [2, 2, {
'SwitchCase': 1
}],
'jsx-quotes': [2, 'prefer-single'],
'key-spacing': [2, {
'beforeColon': false,
'afterColon': true
}],
'keyword-spacing': [2, {
'before': true,
'after': true
}],
'new-cap': [2, {
'newIsCap': true,
'capIsNew': false
}],
'new-parens': 2,
'no-array-constructor': 2,
'no-caller': 2,
'no-console': 'off',
'no-class-assign': 2,
'no-cond-assign': 2,
'no-const-assign': 2,
'no-control-regex': 0,
'no-delete-var': 2,
'no-dupe-args': 2,
'no-dupe-class-members': 2,
'no-dupe-keys': 2,
'no-duplicate-case': 2,
'no-empty-character-class': 2,
'no-empty-pattern': 2,
'no-eval': 2,
'no-ex-assign': 2,
'no-extend-native': 2,
'no-extra-bind': 2,
'no-extra-boolean-cast': 2,
'no-extra-parens': [2, 'functions'],
'no-fallthrough': 2,
'no-floating-decimal': 2,
'no-func-assign': 2,
'no-implied-eval': 2,
'no-inner-declarations': [2, 'functions'],
'no-invalid-regexp': 2,
'no-irregular-whitespace': 2,
'no-iterator': 2,
'no-label-var': 2,
'no-labels': [2, {
'allowLoop': false,
'allowSwitch': false
}],
'no-lone-blocks': 2,
'no-mixed-spaces-and-tabs': 2,
'no-multi-spaces': 2,
'no-multi-str': 2,
'no-multiple-empty-lines': [2, {
'max': 1
}],
'no-native-reassign': 2,
'no-negated-in-lhs': 2,
'no-new-object': 2,
'no-new-require': 2,
'no-new-symbol': 2,
'no-new-wrappers': 2,
'no-obj-calls': 2,
'no-octal': 2,
'no-octal-escape': 2,
'no-path-concat': 2,
'no-proto': 2,
'no-redeclare': 2,
'no-regex-spaces': 2,
'no-return-assign': [2, 'except-parens'],
'no-self-assign': 2,
'no-self-compare': 2,
'no-sequences': 2,
'no-shadow-restricted-names': 2,
'no-spaced-func': 2,
'no-sparse-arrays': 2,
'no-this-before-super': 2,
'no-throw-literal': 2,
'no-trailing-spaces': 2,
'no-undef': 2,
'no-undef-init': 2,
'no-unexpected-multiline': 2,
'no-unmodified-loop-condition': 2,
'no-unneeded-ternary': [2, {
'defaultAssignment': false
}],
'no-unreachable': 2,
'no-unsafe-finally': 2,
'no-unused-vars': [2, {
'vars': 'all',
'args': 'none'
}],
'no-useless-call': 2,
'no-useless-computed-key': 2,
'no-useless-constructor': 2,
'no-useless-escape': 0,
'no-whitespace-before-property': 2,
'no-with': 2,
'one-var': [2, {
'initialized': 'never'
}],
'operator-linebreak': [2, 'after', {
'overrides': {
'?': 'before',
':': 'before'
}
}],
'padded-blocks': [2, 'never'],
'quotes': [2, 'single', {
'avoidEscape': true,
'allowTemplateLiterals': true
}],
'semi': [2, 'never'],
'semi-spacing': [2, {
'before': false,
'after': true
}],
'space-before-blocks': [2, 'always'],
'space-before-function-paren': [2, 'never'],
'space-in-parens': [2, 'never'],
'space-infix-ops': 2,
'space-unary-ops': [2, {
'words': true,
'nonwords': false
}],
'spaced-comment': [2, 'always', {
'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
}],
'template-curly-spacing': [2, 'never'],
'use-isnan': 2,
'valid-typeof': 2,
'wrap-iife': [2, 'any'],
'yield-star-spacing': [2, 'both'],
'yoda': [2, 'never'],
'prefer-const': 2,
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
'object-curly-spacing': [2, 'always', {
objectsInObjects: false
}],
'array-bracket-spacing': [2, 'never']
}
}

@ -0,0 +1,16 @@
.DS_Store
node_modules/
dist/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
package-lock.json
tests/**/coverage/
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln

@ -0,0 +1,5 @@
language: node_js
node_js: 10
script: npm run test
notifications:
email: false

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017-present PanJiaChen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -0,0 +1,102 @@
# vue-admin-template
> 这是一个极简的 vue admin 管理后台。它只包含了 Element UI & axios & iconfont & permission control & lint,这些搭建后台必要的东西。
[线上地址](http://panjiachen.github.io/vue-admin-template)
[国内访问](https://panjiachen.gitee.io/vue-admin-template)
目前版本为 `v4.0+` 基于 `vue-cli` 进行构建,若你想使用旧版本,可以切换分支到[tag/3.11.0](https://github.com/PanJiaChen/vue-admin-template/tree/tag/3.11.0),它不依赖 `vue-cli`
## Extra
如果你想要根据用户角色来动态生成侧边栏和 router,你可以使用该分支[permission-control](https://github.com/PanJiaChen/vue-admin-template/tree/permission-control)
## 相关项目
- [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)
- [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
- [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template)
- [awesome-project](https://github.com/PanJiaChen/vue-element-admin/issues/2312)
写了一个系列的教程配套文章,如何从零构建后一个完整的后台项目:
- [手摸手,带你用 vue 撸后台 系列一(基础篇)](https://juejin.im/post/59097cd7a22b9d0065fb61d2)
- [手摸手,带你用 vue 撸后台 系列二(登录权限篇)](https://juejin.im/post/591aa14f570c35006961acac)
- [手摸手,带你用 vue 撸后台 系列三 (实战篇)](https://juejin.im/post/593121aa0ce4630057f70d35)
- [手摸手,带你用 vue 撸后台 系列四(vueAdmin 一个极简的后台基础模板,专门针对本项目的文章,算作是一篇文档)](https://juejin.im/post/595b4d776fb9a06bbe7dba56)
- [手摸手,带你封装一个 vue component](https://segmentfault.com/a/1190000009090836)
## Build Setup
```bash
# 克隆项目
git clone https://github.com/PanJiaChen/vue-admin-template.git
# 进入项目目录
cd vue-admin-template
# 安装依赖
npm install
# 建议不要直接使用 cnpm 安装以来,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题
npm install --registry=https://registry.npm.taobao.org
# 启动服务
npm run dev
```
浏览器访问 [http://localhost:9528](http://localhost:9528)
## 发布
```bash
# 构建测试环境
npm run build:stage
# 构建生产环境
npm run build:prod
```
## 其它
```bash
# 预览发布环境效果
npm run preview
# 预览发布环境效果 + 静态资源分析
npm run preview -- --report
# 代码格式检查
npm run lint
# 代码格式检查并自动修复
npm run lint -- --fix
```
更多信息请参考 [使用文档](https://panjiachen.github.io/vue-element-admin-site/zh/)
## 购买贴纸
你也可以通过 购买[官方授权的贴纸](https://smallsticker.com/product/vue-element-admin) 的方式来支持 vue-element-admin - 每售出一张贴纸,我们将获得 2 元的捐赠。
## Demo
![demo](https://github.com/PanJiaChen/PanJiaChen.github.io/blob/master/images/demo.gif)
## Browsers support
Modern browsers and Internet Explorer 10+.
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari |
| --------- | --------- | --------- | --------- |
| IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions
## License
[MIT](https://github.com/PanJiaChen/vue-admin-template/blob/master/LICENSE) license.
Copyright (c) 2017-present PanJiaChen

@ -0,0 +1,91 @@
# vue-admin-template
English | [简体中文](./README-zh.md)
> A minimal vue admin template with Element UI & axios & iconfont & permission control & lint
**Live demo:** http://panjiachen.github.io/vue-admin-template
**The current version is `v4.0+` build on `vue-cli`. If you want to use the old version , you can switch branch to [tag/3.11.0](https://github.com/PanJiaChen/vue-admin-template/tree/tag/3.11.0), it does not rely on `vue-cli`**
## Build Setup
```bash
# clone the project
git clone https://github.com/PanJiaChen/vue-admin-template.git
# enter the project directory
cd vue-admin-template
# install dependency
npm install
# develop
npm run dev
```
This will automatically open http://localhost:9528
## Build
```bash
# build for test environment
npm run build:stage
# build for production environment
npm run build:prod
```
## Advanced
```bash
# preview the release environment effect
npm run preview
# preview the release environment effect + static resource analysis
npm run preview -- --report
# code format check
npm run lint
# code format check and auto fix
npm run lint -- --fix
```
Refer to [Documentation](https://panjiachen.github.io/vue-element-admin-site/guide/essentials/deploy.html) for more information
## Demo
![demo](https://github.com/PanJiaChen/PanJiaChen.github.io/blob/master/images/demo.gif)
## Extra
If you want router permission && generate menu by user roles , you can use this branch [permission-control](https://github.com/PanJiaChen/vue-admin-template/tree/permission-control)
For `typescript` version, you can use [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) (Credits: [@Armour](https://github.com/Armour))
## Related Project
- [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)
- [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
- [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template)
- [awesome-project](https://github.com/PanJiaChen/vue-element-admin/issues/2312)
## Browsers support
Modern browsers and Internet Explorer 10+.
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari |
| --------- | --------- | --------- | --------- |
| IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions
## License
[MIT](https://github.com/PanJiaChen/vue-admin-template/blob/master/LICENSE) license.
Copyright (c) 2017-present PanJiaChen

@ -0,0 +1,14 @@
module.exports = {
presets: [
// https://github.com/vuejs/vue-cli/tree/master/packages/@vue/babel-preset-app
'@vue/cli-plugin-babel/preset'
],
'env': {
'development': {
// babel-plugin-dynamic-import-node plugin only does one thing by converting all import() to require().
// This plugin can significantly increase the speed of hot updates, when you have a large number of pages.
// https://panjiachen.github.io/vue-element-admin-site/guide/advanced/lazy-loading.html
'plugins': ['dynamic-import-node']
}
}
}

@ -0,0 +1,35 @@
const { run } = require('runjs')
const chalk = require('chalk')
const config = require('../vue.config.js')
const rawArgv = process.argv.slice(2)
const args = rawArgv.join(' ')
if (process.env.npm_config_preview || rawArgv.includes('--preview')) {
const report = rawArgv.includes('--report')
run(`vue-cli-service build ${args}`)
const port = 9526
const publicPath = config.publicPath
var connect = require('connect')
var serveStatic = require('serve-static')
const app = connect()
app.use(
publicPath,
serveStatic('./dist', {
index: ['index.html', '/']
})
)
app.listen(port, function () {
console.log(chalk.green(`> Preview at http://localhost:${port}${publicPath}`))
if (report) {
console.log(chalk.green(`> Report at http://localhost:${port}${publicPath}report.html`))
}
})
} else {
run(`vue-cli-service build ${args}`)
}

@ -0,0 +1,24 @@
module.exports = {
moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
transform: {
'^.+\\.vue$': 'vue-jest',
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$':
'jest-transform-stub',
'^.+\\.jsx?$': 'babel-jest'
},
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1'
},
snapshotSerializers: ['jest-serializer-vue'],
testMatch: [
'**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
],
collectCoverageFrom: ['src/utils/**/*.{js,vue}', '!src/utils/auth.js', '!src/utils/request.js', 'src/components/**/*.{js,vue}'],
coverageDirectory: '<rootDir>/tests/unit/coverage',
// 'collectCoverage': true,
'coverageReporters': [
'lcov',
'text-summary'
],
testURL: 'http://localhost/'
}

@ -0,0 +1,9 @@
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
}
},
"exclude": ["node_modules", "dist"]
}

@ -0,0 +1,57 @@
const Mock = require('mockjs')
const { param2Obj } = require('./utils')
const user = require('./user')
const table = require('./table')
const mocks = [
...user,
...table
]
// for front mock
// please use it cautiously, it will redefine XMLHttpRequest,
// which will cause many of your third-party libraries to be invalidated(like progress event).
function mockXHR() {
// mock patch
// https://github.com/nuysoft/Mock/issues/300
Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send
Mock.XHR.prototype.send = function() {
if (this.custom.xhr) {
this.custom.xhr.withCredentials = this.withCredentials || false
if (this.responseType) {
this.custom.xhr.responseType = this.responseType
}
}
this.proxy_send(...arguments)
}
function XHR2ExpressReqWrap(respond) {
return function(options) {
let result = null
if (respond instanceof Function) {
const { body, type, url } = options
// https://expressjs.com/en/4x/api.html#req
result = respond({
method: type,
body: JSON.parse(body),
query: param2Obj(url)
})
} else {
result = respond
}
return Mock.mock(result)
}
}
for (const i of mocks) {
Mock.mock(new RegExp(i.url), i.type || 'get', XHR2ExpressReqWrap(i.response))
}
}
module.exports = {
mocks,
mockXHR
}

@ -0,0 +1,81 @@
const chokidar = require('chokidar')
const bodyParser = require('body-parser')
const chalk = require('chalk')
const path = require('path')
const Mock = require('mockjs')
const mockDir = path.join(process.cwd(), 'mock')
function registerRoutes(app) {
let mockLastIndex
const { mocks } = require('./index.js')
const mocksForServer = mocks.map(route => {
return responseFake(route.url, route.type, route.response)
})
for (const mock of mocksForServer) {
app[mock.type](mock.url, mock.response)
mockLastIndex = app._router.stack.length
}
const mockRoutesLength = Object.keys(mocksForServer).length
return {
mockRoutesLength: mockRoutesLength,
mockStartIndex: mockLastIndex - mockRoutesLength
}
}
function unregisterRoutes() {
Object.keys(require.cache).forEach(i => {
if (i.includes(mockDir)) {
delete require.cache[require.resolve(i)]
}
})
}
// for mock server
const responseFake = (url, type, respond) => {
return {
url: new RegExp(`${process.env.VUE_APP_BASE_API}${url}`),
type: type || 'get',
response(req, res) {
console.log('request invoke:' + req.path)
res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond))
}
}
}
module.exports = app => {
// parse app.body
// https://expressjs.com/en/4x/api.html#req.body
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
extended: true
}))
const mockRoutes = registerRoutes(app)
var mockRoutesLength = mockRoutes.mockRoutesLength
var mockStartIndex = mockRoutes.mockStartIndex
// watch files, hot reload mock server
chokidar.watch(mockDir, {
ignored: /mock-server/,
ignoreInitial: true
}).on('all', (event, path) => {
if (event === 'change' || event === 'add') {
try {
// remove mock routes stack
app._router.stack.splice(mockStartIndex, mockRoutesLength)
// clear routes cache
unregisterRoutes()
const mockRoutes = registerRoutes(app)
mockRoutesLength = mockRoutes.mockRoutesLength
mockStartIndex = mockRoutes.mockStartIndex
console.log(chalk.magentaBright(`\n > Mock Server hot reload success! changed ${path}`))
} catch (error) {
console.log(chalk.redBright(error))
}
}
})
}

@ -0,0 +1,29 @@
const Mock = require('mockjs')
const data = Mock.mock({
'items|30': [{
id: '@id',
title: '@sentence(10, 20)',
'status|1': ['published', 'draft', 'deleted'],
author: 'name',
display_time: '@datetime',
pageviews: '@integer(300, 5000)'
}]
})
module.exports = [
{
url: '/vue-admin-template/table/list',
type: 'get',
response: config => {
const items = data.items
return {
code: 20000,
data: {
total: items.length,
items: items
}
}
}
}
]

@ -0,0 +1,84 @@
const tokens = {
admin: {
token: 'admin-token'
},
editor: {
token: 'editor-token'
}
}
const users = {
'admin-token': {
roles: ['admin'],
introduction: 'I am a super administrator',
avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
name: 'Super Admin'
},
'editor-token': {
roles: ['editor'],
introduction: 'I am an editor',
avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
name: 'Normal Editor'
}
}
module.exports = [
// user login
{
url: '/vue-admin-template/user/login',
type: 'post',
response: config => {
const { username } = config.body
const token = tokens[username]
// mock error
if (!token) {
return {
code: 60204,
message: 'Account and password are incorrect.'
}
}
return {
code: 20000,
data: token
}
}
},
// get user info
{
url: '/vue-admin-template/user/info\.*',
type: 'get',
response: config => {
const { token } = config.query
const info = users[token]
// mock error
if (!info) {
return {
code: 50008,
message: 'Login failed, unable to get user details.'
}
}
return {
code: 20000,
data: info
}
}
},
// user logout
{
url: '/vue-admin-template/user/logout',
type: 'post',
response: _ => {
return {
code: 20000,
data: 'success'
}
}
}
]

@ -0,0 +1,25 @@
/**
* @param {string} url
* @returns {Object}
*/
function param2Obj(url) {
const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
if (!search) {
return {}
}
const obj = {}
const searchArr = search.split('&')
searchArr.forEach(v => {
const index = v.indexOf('=')
if (index !== -1) {
const name = v.substring(0, index)
const val = v.substring(index + 1, v.length)
obj[name] = val
}
})
return obj
}
module.exports = {
param2Obj
}

@ -0,0 +1,63 @@
{
"name": "fir_admin",
"version": "1.1.0",
"description": "fir admin",
"author": "nineven@qq.com",
"scripts": {
"dev": "vue-cli-service serve",
"build:prod": "vue-cli-service build",
"build:stage": "vue-cli-service build --mode staging",
"preview": "node build/index.js --preview",
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml",
"lint": "eslint --ext .js,.vue src",
"test:unit": "jest --clearCache && vue-cli-service test:unit",
"test:ci": "npm run lint && npm run test:unit"
},
"dependencies": {
"axios": "0.18.1",
"core-js": "3.6.5",
"element-ui": "2.13.2",
"js-base64": "2.5.2",
"js-cookie": "2.2.0",
"normalize.css": "7.0.0",
"nprogress": "0.2.0",
"path-to-regexp": "2.4.0",
"vue": "2.6.10",
"vue-router": "3.0.6",
"vuex": "3.1.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "4.4.4",
"@vue/cli-plugin-eslint": "4.4.4",
"@vue/cli-plugin-unit-jest": "4.4.4",
"@vue/cli-service": "4.4.4",
"@vue/test-utils": "1.0.0-beta.29",
"autoprefixer": "9.5.1",
"babel-eslint": "10.1.0",
"babel-jest": "23.6.0",
"babel-plugin-dynamic-import-node": "2.3.3",
"chalk": "2.4.2",
"connect": "3.6.6",
"eslint": "6.7.2",
"eslint-plugin-vue": "6.2.2",
"html-webpack-plugin": "3.2.0",
"mockjs": "1.0.1-beta3",
"runjs": "4.3.2",
"sass": "1.26.8",
"sass-loader": "8.0.2",
"script-ext-html-webpack-plugin": "2.1.3",
"serve-static": "1.13.2",
"svg-sprite-loader": "4.1.3",
"svgo": "1.2.2",
"vue-template-compiler": "2.6.10"
},
"browserslist": [
"> 1%",
"last 2 versions"
],
"engines": {
"node": ">=8.9",
"npm": ">= 3.0.0"
},
"license": "MIT"
}

@ -0,0 +1,8 @@
// https://github.com/michael-ciniawsky/postcss-load-config
module.exports = {
'plugins': {
// to edit target browsers: use "browserslist" field in package.json
'autoprefixer': {}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= webpackConfig.name %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= webpackConfig.name %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

@ -0,0 +1,11 @@
<template>
<div id="app">
<router-view />
</div>
</template>
<script>
export default {
name: 'App'
}
</script>

@ -0,0 +1,61 @@
import request from '@/utils/request'
export function getAppList(query) {
return request({
url: '/app/info',
method: 'get',
params: query
})
}
export function getAppInfos(pk) {
return request({
url: '/app/info/' + pk,
method: 'get'
})
}
export function updateAppInfo(pk, data) {
return request({
url: '/app/info/' + pk,
method: 'put',
data
})
}
export function deleteApp(pk) {
return request({
url: '/app/info/' + pk,
method: 'delete'
})
}
export function getAppReleaseList(query) {
return request({
url: '/app/release/info',
method: 'get',
params: query
})
}
export function getAppReleaseInfos(pk) {
return request({
url: '/app/release/info/' + pk,
method: 'get'
})
}
export function updateReleaseAppInfo(pk, data) {
return request({
url: '/app/release/info/' + pk,
method: 'put',
data
})
}
export function downloadAppReleaseInfos(data) {
return request({
url: '/app/release/info',
method: 'post',
data
})
}

@ -0,0 +1,54 @@
import request from '@/utils/request'
export function getDeveloperList(query) {
return request({
url: '/developer/info',
method: 'get',
params: query
})
}
export function getDeveloperInfo(pk) {
return request({
url: '/developer/info/' + pk,
method: 'get'
})
}
export function updatedeveloperInfo(pk, data) {
return request({
url: '/developer/info/' + pk,
method: 'put',
data
})
}
export function getBillList(query) {
return request({
url: '/bill/info',
method: 'get',
params: query
})
}
export function addBillInfo(data) {
return request({
url: '/bill/info',
method: 'post',
data
})
}
export function delBillInfo(pk) {
return request({
url: '/bill/info/' + pk,
method: 'delete'
})
}
export function getUserBillInfo(query) {
return request({
url: '/bill/userinfo',
method: 'get',
params: query
})
}

@ -0,0 +1,10 @@
import request from '@/utils/request'
export function getDevicesList(query) {
return request({
url: '/devices/info',
method: 'get',
params: query
})
}

@ -0,0 +1,31 @@
import request from '@/utils/request'
export function getDomainList(query) {
return request({
url: '/domain/info',
method: 'get',
params: query
})
}
export function getDomainInfos(pk) {
return request({
url: '/domain/info/' + pk,
method: 'get'
})
}
export function updateDomainInfo(pk, data) {
return request({
url: '/domain/info/' + pk,
method: 'put',
data
})
}
export function deleteDomain(pk) {
return request({
url: '/domain/info/' + pk,
method: 'delete'
})
}

@ -0,0 +1,38 @@
import request from '@/utils/request'
export function getOrderList(query) {
return request({
url: '/order/info',
method: 'get',
params: query
})
}
export function getOrderInfo(pk) {
return request({
url: '/order/info/' + pk,
method: 'get'
})
}
export function updateOrderInfo(pk, data) {
return request({
url: '/order/info/' + pk,
method: 'put',
data
})
}
export function deleteOrderInfo(pk) {
return request({
url: '/order/info/' + pk,
method: 'delete'
})
}
export function createOrderInfo(data) {
return request({
url: '/order/info',
method: 'post',
data
})
}

@ -0,0 +1,8 @@
import request from '@/utils/request'
export function getToken() {
return request({
url: '/qiniu/upload/token', // 假地址 自行替换
method: 'get'
})
}

@ -0,0 +1,31 @@
import request from '@/utils/request'
export function getAppReportList(query) {
return request({
url: '/report/info',
method: 'get',
params: query
})
}
export function getAppReportIfo(pk) {
return request({
url: '/report/info/' + pk,
method: 'get'
})
}
export function updateAppReportIfo(pk, data) {
return request({
url: '/report/info/' + pk,
method: 'put',
data
})
}
export function deleteAppReportIfo(pk) {
return request({
url: '/report/info/' + pk,
method: 'delete'
})
}

@ -0,0 +1,32 @@
import request from '@/utils/request'
export function getStorageList(query) {
return request({
url: '/storage/info',
method: 'get',
params: query
})
}
export function getStorageInfo(pk) {
return request({
url: '/storage/info/' + pk,
method: 'get'
})
}
export function updateStorageInfo(pk, data) {
return request({
url: '/storage/info/' + pk,
method: 'put',
data
})
}
export function changeStorageInfo(data) {
return request({
url: '/storage/change',
method: 'put',
data
})
}

@ -0,0 +1,9 @@
import request from '@/utils/request'
export function getList(params) {
return request({
url: '/vue-admin-template/table/list',
method: 'get',
params
})
}

@ -0,0 +1,63 @@
import request from '@/utils/request'
export function login(data) {
return request({
url: '/login',
method: 'post',
data
})
}
export function getInfo(token) {
return request({
url: '/user/info',
method: 'get',
params: { token }
})
}
export function logout() {
return request({
url: '/user/logout',
method: 'post'
})
}
export function getUserInfos(query) {
return request({
url: '/userinfo',
method: 'get',
params: query
})
}
export function updateUserInfo(data) {
return request({
url: '/userinfo',
method: 'put',
data
})
}
export function getCertificationInfo(query) {
return request({
url: '/certification/info',
method: 'get',
params: query
})
}
export function updateCertificationInfo(data) {
return request({
url: '/certification/info',
method: 'put',
data
})
}
export function resetPassword(data) {
return request({
url: '/user/info',
method: 'post',
data
})
}

@ -0,0 +1,31 @@
import request from '@/utils/request'
export function getWxBindList(query) {
return request({
url: '/wxbind/info',
method: 'get',
params: query
})
}
export function getWxBindInfos(pk) {
return request({
url: '/wxbind/info/' + pk,
method: 'get'
})
}
export function updateWxBindInfo(pk,data) {
return request({
url: '/wxbind/info/' + pk,
method: 'put',
data
})
}
export function deleteWxBind(pk) {
return request({
url: '/wxbind/info/' + pk,
method: 'delete'
})
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

@ -0,0 +1,78 @@
<template>
<el-breadcrumb class="app-breadcrumb" separator="/">
<transition-group name="breadcrumb">
<el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
<span v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect">{{ item.meta.title }}</span>
<a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
</el-breadcrumb-item>
</transition-group>
</el-breadcrumb>
</template>
<script>
import pathToRegexp from 'path-to-regexp'
export default {
data() {
return {
levelList: null
}
},
watch: {
$route() {
this.getBreadcrumb()
}
},
created() {
this.getBreadcrumb()
},
methods: {
getBreadcrumb() {
// only show routes with meta.title
let matched = this.$route.matched.filter(item => item.meta && item.meta.title)
const first = matched[0]
if (!this.isDashboard(first)) {
matched = [{ path: '/dashboard', meta: { title: 'Dashboard' }}].concat(matched)
}
this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
},
isDashboard(route) {
const name = route && route.name
if (!name) {
return false
}
return name.trim().toLocaleLowerCase() === 'Dashboard'.toLocaleLowerCase()
},
pathCompile(path) {
// To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561
const { params } = this.$route
var toPath = pathToRegexp.compile(path)
return toPath(params)
},
handleLink(item) {
const { redirect, path } = item
if (redirect) {
this.$router.push(redirect)
return
}
this.$router.push(this.pathCompile(path))
}
}
}
</script>
<style lang="scss" scoped>
.app-breadcrumb.el-breadcrumb {
display: inline-block;
font-size: 14px;
line-height: 50px;
margin-left: 8px;
.no-redirect {
color: #97a8be;
cursor: text;
}
}
</style>

@ -0,0 +1,44 @@
<template>
<div style="padding: 0 15px;" @click="toggleClick">
<svg
:class="{'is-active':isActive}"
class="hamburger"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
width="64"
height="64"
>
<path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" />
</svg>
</div>
</template>
<script>
export default {
name: 'Hamburger',
props: {
isActive: {
type: Boolean,
default: false
}
},
methods: {
toggleClick() {
this.$emit('toggleClick')
}
}
}
</script>
<style scoped>
.hamburger {
display: inline-block;
vertical-align: middle;
width: 20px;
height: 20px;
}
.hamburger.is-active {
transform: rotate(180deg);
}
</style>

@ -0,0 +1,101 @@
<template>
<div :class="{'hidden':hidden}" class="pagination-container">
<el-pagination
:background="background"
:current-page.sync="currentPage"
:page-size.sync="pageSize"
:layout="layout"
:page-sizes="pageSizes"
:total="total"
v-bind="$attrs"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</template>
<script>
import { scrollTo } from '@/utils/scroll-to'
export default {
name: 'Pagination',
props: {
total: {
required: true,
type: Number
},
page: {
type: Number,
default: 1
},
limit: {
type: Number,
default: 20
},
pageSizes: {
type: Array,
default() {
return [10, 20, 30, 50]
}
},
layout: {
type: String,
default: 'total, sizes, prev, pager, next, jumper'
},
background: {
type: Boolean,
default: true
},
autoScroll: {
type: Boolean,
default: true
},
hidden: {
type: Boolean,
default: false
}
},
computed: {
currentPage: {
get() {
return this.page
},
set(val) {
this.$emit('update:page', val)
}
},
pageSize: {
get() {
return this.limit
},
set(val) {
this.$emit('update:limit', val)
}
}
},
methods: {
handleSizeChange(val) {
this.$emit('pagination', { page: this.currentPage, limit: val })
if (this.autoScroll) {
scrollTo(0, 800)
}
},
handleCurrentChange(val) {
this.$emit('pagination', { page: val, limit: this.pageSize })
if (this.autoScroll) {
scrollTo(0, 800)
}
}
}
}
</script>
<style scoped>
.pagination-container {
background: #fff;
padding: 32px 16px;
}
.pagination-container.hidden {
display: none;
}
</style>

@ -0,0 +1,91 @@
<template>
<div :style="{height:height+'px',zIndex:zIndex}">
<div
:class="className"
:style="{top:(isSticky ? stickyTop +'px' : ''),zIndex:zIndex,position:position,width:width,height:height+'px'}"
>
<slot>
<div>sticky</div>
</slot>
</div>
</div>
</template>
<script>
export default {
name: 'Sticky',
props: {
stickyTop: {
type: Number,
default: 0
},
zIndex: {
type: Number,
default: 1
},
className: {
type: String,
default: ''
}
},
data() {
return {
active: false,
position: '',
width: undefined,
height: undefined,
isSticky: false
}
},
mounted() {
this.height = this.$el.getBoundingClientRect().height
window.addEventListener('scroll', this.handleScroll)
window.addEventListener('resize', this.handleResize)
},
activated() {
this.handleScroll()
},
destroyed() {
window.removeEventListener('scroll', this.handleScroll)
window.removeEventListener('resize', this.handleResize)
},
methods: {
sticky() {
if (this.active) {
return
}
this.position = 'fixed'
this.active = true
this.width = this.width + 'px'
this.isSticky = true
},
handleReset() {
if (!this.active) {
return
}
this.reset()
},
reset() {
this.position = ''
this.width = 'auto'
this.active = false
this.isSticky = false
},
handleScroll() {
const width = this.$el.getBoundingClientRect().width
this.width = width || 'auto'
const offsetTop = this.$el.getBoundingClientRect().top
if (offsetTop < this.stickyTop) {
this.sticky()
return
}
this.handleReset()
},
handleResize() {
if (this.isSticky) {
this.width = this.$el.getBoundingClientRect().width + 'px'
}
}
}
}
</script>

@ -0,0 +1,62 @@
<template>
<div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
<svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
<use :xlink:href="iconName" />
</svg>
</template>
<script>
// doc: https://panjiachen.github.io/vue-element-admin-site/feature/component/svg-icon.html#usage
import { isExternal } from '@/utils/validate'
export default {
name: 'SvgIcon',
props: {
iconClass: {
type: String,
required: true
},
className: {
type: String,
default: ''
}
},
computed: {
isExternal() {
return isExternal(this.iconClass)
},
iconName() {
return `#icon-${this.iconClass}`
},
svgClass() {
if (this.className) {
return 'svg-icon ' + this.className
} else {
return 'svg-icon'
}
},
styleExternalIcon() {
return {
mask: `url(${this.iconClass}) no-repeat 50% 50%`,
'-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
}
}
}
}
</script>
<style scoped>
.svg-icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
.svg-external-icon {
background-color: currentColor;
mask-size: cover!important;
display: inline-block;
}
</style>

@ -0,0 +1,111 @@
<template>
<div class="upload-container">
<el-button :style="{background:color,borderColor:color}" icon="el-icon-upload" size="mini" type="primary" @click=" dialogVisible=true">
upload
</el-button>
<el-dialog :visible.sync="dialogVisible">
<el-upload
:multiple="true"
:file-list="fileList"
:show-file-list="true"
:on-remove="handleRemove"
:on-success="handleSuccess"
:before-upload="beforeUpload"
class="editor-slide-upload"
action="https://httpbin.org/post"
list-type="picture-card"
>
<el-button size="small" type="primary">
Click upload
</el-button>
</el-upload>
<el-button @click="dialogVisible = false">
Cancel
</el-button>
<el-button type="primary" @click="handleSubmit">
Confirm
</el-button>
</el-dialog>
</div>
</template>
<script>
// import { getToken } from 'api/qiniu'
export default {
name: 'EditorSlideUpload',
props: {
color: {
type: String,
default: '#1890ff'
}
},
data() {
return {
dialogVisible: false,
listObj: {},
fileList: []
}
},
methods: {
checkAllSuccess() {
return Object.keys(this.listObj).every(item => this.listObj[item].hasSuccess)
},
handleSubmit() {
const arr = Object.keys(this.listObj).map(v => this.listObj[v])
if (!this.checkAllSuccess()) {
this.$message('Please wait for all images to be uploaded successfully. If there is a network problem, please refresh the page and upload again!')
return
}
this.$emit('successCBK', arr)
this.listObj = {}
this.fileList = []
this.dialogVisible = false
},
handleSuccess(response, file) {
const uid = file.uid
const objKeyArr = Object.keys(this.listObj)
for (let i = 0, len = objKeyArr.length; i < len; i++) {
if (this.listObj[objKeyArr[i]].uid === uid) {
this.listObj[objKeyArr[i]].url = response.files.file
this.listObj[objKeyArr[i]].hasSuccess = true
return
}
}
},
handleRemove(file) {
const uid = file.uid
const objKeyArr = Object.keys(this.listObj)
for (let i = 0, len = objKeyArr.length; i < len; i++) {
if (this.listObj[objKeyArr[i]].uid === uid) {
delete this.listObj[objKeyArr[i]]
return
}
}
},
beforeUpload(file) {
const _self = this
const _URL = window.URL || window.webkitURL
const fileName = file.uid
this.listObj[fileName] = {}
return new Promise((resolve, reject) => {
const img = new Image()
img.src = _URL.createObjectURL(file)
img.onload = function() {
_self.listObj[fileName] = { hasSuccess: false, uid: file.uid, width: this.width, height: this.height }
}
resolve(true)
})
}
}
}
</script>
<style lang="scss" scoped>
.editor-slide-upload {
margin-bottom: 20px;
::v-deep .el-upload--picture-card {
width: 100%;
}
}
</style>

@ -0,0 +1,59 @@
let callbacks = []
function loadedTinymce() {
// to fixed https://github.com/PanJiaChen/vue-element-admin/issues/2144
// check is successfully downloaded script
return window.tinymce
}
const dynamicLoadScript = (src, callback) => {
const existingScript = document.getElementById(src)
const cb = callback || function() {}
if (!existingScript) {
const script = document.createElement('script')
script.src = src // src url for the third-party library being loaded.
script.id = src
document.body.appendChild(script)
callbacks.push(cb)
const onEnd = 'onload' in script ? stdOnEnd : ieOnEnd
onEnd(script)
}
if (existingScript && cb) {
if (loadedTinymce()) {
cb(null, existingScript)
} else {
callbacks.push(cb)
}
}
function stdOnEnd(script) {
script.onload = function() {
// this.onload = null here is necessary
// because even IE9 works not like others
this.onerror = this.onload = null
for (const cb of callbacks) {
cb(null, script)
}
callbacks = null
}
script.onerror = function() {
this.onerror = this.onload = null
cb(new Error('Failed to load ' + src), script)
}
}
function ieOnEnd(script) {
script.onreadystatechange = function() {
if (this.readyState !== 'complete' && this.readyState !== 'loaded') return
this.onreadystatechange = null
for (const cb of callbacks) {
cb(null, script) // there is no way to catch loading errors in IE8
}
callbacks = null
}
}
}
export default dynamicLoadScript

@ -0,0 +1,250 @@
<template>
<div :class="{fullscreen:fullscreen}" class="tinymce-container" :style="{width:containerWidth}">
<textarea :id="tinymceId" class="tinymce-textarea" />
<div class="editor-custom-btn-container">
<editorImage color="#1890ff" class="editor-upload-btn" @successCBK="imageSuccessCBK" />
</div>
</div>
</template>
<script>
/**
* docs:
* https://panjiachen.github.io/vue-element-admin-site/feature/component/rich-editor.html#tinymce
*/
import editorImage from './components/EditorImage'
import plugins from './plugins'
import toolbar from './toolbar'
import load from './dynamicLoadScript'
// why use this cdn, detail see https://github.com/PanJiaChen/tinymce-all-in-one
const tinymceCDN = 'https://cdn.jsdelivr.net/npm/tinymce-all-in-one@4.9.3/tinymce.min.js'
export default {
name: 'Tinymce',
components: { editorImage },
props: {
id: {
type: String,
default: function() {
return 'vue-tinymce-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '')
}
},
value: {
type: String,
default: ''
},
toolbar: {
type: Array,
required: false,
default() {
return []
}
},
menubar: {
type: String,
default: 'file edit insert view format table'
},
height: {
type: [Number, String],
required: false,
default: 360
},
width: {
type: [Number, String],
required: false,
default: 'auto'
}
},
data() {
return {
hasChange: false,
hasInit: false,
tinymceId: this.id,
fullscreen: false,
languageTypeList: {
'en': 'en',
'zh': 'zh_CN',
'es': 'es_MX',
'ja': 'ja'
}
}
},
computed: {
containerWidth() {
const width = this.width
if (/^[\d]+(\.[\d]+)?$/.test(width)) { // matches `100`, `'100'`
return `${width}px`
}
return width
}
},
watch: {
value(val) {
if (!this.hasChange && this.hasInit) {
this.$nextTick(() =>
window.tinymce.get(this.tinymceId).setContent(val || ''))
}
}
},
mounted() {
this.init()
},
activated() {
if (window.tinymce) {
this.initTinymce()
}
},
deactivated() {
this.destroyTinymce()
},
destroyed() {
this.destroyTinymce()
},
methods: {
init() {
// dynamic load tinymce from cdn
load(tinymceCDN, (err) => {
if (err) {
this.$message.error(err.message)
return
}
this.initTinymce()
})
},
initTinymce() {
const _this = this
window.tinymce.init({
selector: `#${this.tinymceId}`,
language: this.languageTypeList['en'],
height: this.height,
body_class: 'panel-body ',
object_resizing: false,
toolbar: this.toolbar.length > 0 ? this.toolbar : toolbar,
menubar: this.menubar,
plugins: plugins,
end_container_on_empty_block: true,
powerpaste_word_import: 'clean',
code_dialog_height: 450,
code_dialog_width: 1000,
advlist_bullet_styles: 'square',
advlist_number_styles: 'default',
imagetools_cors_hosts: ['www.tinymce.com', 'codepen.io'],
default_link_target: '_blank',
link_title: false,
nonbreaking_force_tab: true, // inserting nonbreaking space &nbsp; need Nonbreaking Space Plugin
init_instance_callback: editor => {
if (_this.value) {
editor.setContent(_this.value)
}
_this.hasInit = true
editor.on('NodeChange Change KeyUp SetContent', () => {
this.hasChange = true
this.$emit('input', editor.getContent())
})
},
setup(editor) {
editor.on('FullscreenStateChanged', (e) => {
_this.fullscreen = e.state
})
},
// it will try to keep these URLs intact
// https://www.tiny.cloud/docs-3x/reference/configuration/Configuration3x@convert_urls/
// https://stackoverflow.com/questions/5196205/disable-tinymce-absolute-to-relative-url-conversions
convert_urls: false
//
// images_dataimg_filter(img) {
// setTimeout(() => {
// const $image = $(img);
// $image.removeAttr('width');
// $image.removeAttr('height');
// if ($image[0].height && $image[0].width) {
// $image.attr('data-wscntype', 'image');
// $image.attr('data-wscnh', $image[0].height);
// $image.attr('data-wscnw', $image[0].width);
// $image.addClass('wscnph');
// }
// }, 0);
// return img
// },
// images_upload_handler(blobInfo, success, failure, progress) {
// progress(0);
// const token = _this.$store.getters.token;
// getToken(token).then(response => {
// const url = response.data.qiniu_url;
// const formData = new FormData();
// formData.append('token', response.data.qiniu_token);
// formData.append('key', response.data.qiniu_key);
// formData.append('file', blobInfo.blob(), url);
// upload(formData).then(() => {
// success(url);
// progress(100);
// })
// }).catch(err => {
// failure('')
// console.log(err);
// });
// },
})
},
destroyTinymce() {
const tinymce = window.tinymce.get(this.tinymceId)
if (this.fullscreen) {
tinymce.execCommand('mceFullScreen')
}
if (tinymce) {
tinymce.destroy()
}
},
setContent(value) {
window.tinymce.get(this.tinymceId).setContent(value)
},
getContent() {
window.tinymce.get(this.tinymceId).getContent()
},
imageSuccessCBK(arr) {
const _this = this
arr.forEach(v => {
window.tinymce.get(_this.tinymceId).insertContent(`<img class="wscnph" src="${v.url}" >`)
})
}
}
}
</script>
<style lang="scss" scoped>
.tinymce-container {
position: relative;
line-height: normal;
}
.tinymce-container {
::v-deep {
.mce-fullscreen {
z-index: 10000;
}
}
}
.tinymce-textarea {
visibility: hidden;
z-index: -1;
}
.editor-custom-btn-container {
position: absolute;
right: 4px;
top: 4px;
/*z-index: 2005;*/
}
.fullscreen .editor-custom-btn-container {
z-index: 10000;
position: fixed;
}
.editor-upload-btn {
display: inline-block;
}
</style>

@ -0,0 +1,7 @@
// Any plugins you want to use has to be imported
// Detail plugins list see https://www.tinymce.com/docs/plugins/
// Custom builds see https://www.tinymce.com/download/custom-builds/
const plugins = ['advlist anchor autolink autosave code codesample colorpicker colorpicker contextmenu directionality emoticons fullscreen hr image imagetools insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textcolor textpattern visualblocks visualchars wordcount']
export default plugins

@ -0,0 +1,6 @@
// Here is a list of the toolbar
// Detail list see https://www.tinymce.com/docs/advanced/editor-control-identifiers/#toolbarcontrols
const toolbar = ['searchreplace bold italic underline strikethrough alignleft aligncenter alignright outdent indent blockquote undo redo removeformat subscript superscript code codesample', 'hr bullist numlist link image charmap preview anchor pagebreak insertdatetime media table emoticons forecolor backcolor fullscreen']
export default toolbar

@ -0,0 +1,134 @@
<template>
<div class="upload-container">
<el-upload
:data="dataObj"
:multiple="false"
:show-file-list="false"
:on-success="handleImageSuccess"
class="image-uploader"
drag
action="https://httpbin.org/post"
>
<i class="el-icon-upload" />
<div class="el-upload__text">
将文件拖到此处<em>点击上传</em>
</div>
</el-upload>
<div class="image-preview">
<div v-show="imageUrl.length>1" class="image-preview-wrapper">
<img :src="imageUrl+'?imageView2/1/w/200/h/200'">
<div class="image-preview-action">
<i class="el-icon-delete" @click="rmImage" />
</div>
</div>
</div>
</div>
</template>
<script>
import { getToken } from '@/api/qiniu'
export default {
name: 'SingleImageUpload',
props: {
value: {
type: String,
default: ''
}
},
data() {
return {
tempUrl: '',
dataObj: { token: '', key: '' }
}
},
computed: {
imageUrl() {
return this.value
}
},
methods: {
rmImage() {
this.emitInput('')
},
emitInput(val) {
this.$emit('input', val)
},
handleImageSuccess() {
this.emitInput(this.tempUrl)
},
beforeUpload() {
const _self = this
return new Promise((resolve, reject) => {
getToken().then(response => {
const key = response.data.qiniu_key
const token = response.data.qiniu_token
_self._data.dataObj.token = token
_self._data.dataObj.key = key
this.tempUrl = response.data.qiniu_url
resolve(true)
}).catch(err => {
console.log(err)
reject(false)
})
})
}
}
}
</script>
<style lang="scss" scoped>
@import "~@/styles/mixin.scss";
.upload-container {
width: 100%;
position: relative;
@include clearfix;
.image-uploader {
width: 60%;
float: left;
}
.image-preview {
width: 200px;
height: 200px;
position: relative;
border: 1px dashed #d9d9d9;
float: left;
margin-left: 50px;
.image-preview-wrapper {
position: relative;
width: 100%;
height: 100%;
img {
width: 100%;
height: 100%;
}
}
.image-preview-action {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
cursor: default;
text-align: center;
color: #fff;
opacity: 0;
font-size: 20px;
background-color: rgba(0, 0, 0, .5);
transition: opacity .3s;
cursor: pointer;
text-align: center;
line-height: 200px;
.el-icon-delete {
font-size: 36px;
}
}
&:hover {
.image-preview-action {
opacity: 1;
}
}
}
}
</style>

@ -0,0 +1,130 @@
<template>
<div class="singleImageUpload2 upload-container">
<el-upload
:data="dataObj"
:multiple="false"
:show-file-list="false"
:on-success="handleImageSuccess"
class="image-uploader"
drag
action="https://httpbin.org/post"
>
<i class="el-icon-upload" />
<div class="el-upload__text">
Drag或<em>点击上传</em>
</div>
</el-upload>
<div v-show="imageUrl.length>0" class="image-preview">
<div v-show="imageUrl.length>1" class="image-preview-wrapper">
<img :src="imageUrl">
<div class="image-preview-action">
<i class="el-icon-delete" @click="rmImage" />
</div>
</div>
</div>
</div>
</template>
<script>
import { getToken } from '@/api/qiniu'
export default {
name: 'SingleImageUpload2',
props: {
value: {
type: String,
default: ''
}
},
data() {
return {
tempUrl: '',
dataObj: { token: '', key: '' }
}
},
computed: {
imageUrl() {
return this.value
}
},
methods: {
rmImage() {
this.emitInput('')
},
emitInput(val) {
this.$emit('input', val)
},
handleImageSuccess() {
this.emitInput(this.tempUrl)
},
beforeUpload() {
const _self = this
return new Promise((resolve, reject) => {
getToken().then(response => {
const key = response.data.qiniu_key
const token = response.data.qiniu_token
_self._data.dataObj.token = token
_self._data.dataObj.key = key
this.tempUrl = response.data.qiniu_url
resolve(true)
}).catch(() => {
reject(false)
})
})
}
}
}
</script>
<style lang="scss" scoped>
.upload-container {
width: 100%;
height: 100%;
position: relative;
.image-uploader {
height: 100%;
}
.image-preview {
width: 100%;
height: 100%;
position: absolute;
left: 0px;
top: 0px;
border: 1px dashed #d9d9d9;
.image-preview-wrapper {
position: relative;
width: 100%;
height: 100%;
img {
width: 100%;
height: 100%;
}
}
.image-preview-action {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
cursor: default;
text-align: center;
color: #fff;
opacity: 0;
font-size: 20px;
background-color: rgba(0, 0, 0, .5);
transition: opacity .3s;
cursor: pointer;
text-align: center;
line-height: 200px;
.el-icon-delete {
font-size: 36px;
}
}
&:hover {
.image-preview-action {
opacity: 1;
}
}
}
}
</style>

@ -0,0 +1,157 @@
<template>
<div class="upload-container">
<el-upload
:data="dataObj"
:multiple="false"
:show-file-list="false"
:on-success="handleImageSuccess"
class="image-uploader"
drag
action="https://httpbin.org/post"
>
<i class="el-icon-upload" />
<div class="el-upload__text">
将文件拖到此处<em>点击上传</em>
</div>
</el-upload>
<div class="image-preview image-app-preview">
<div v-show="imageUrl.length>1" class="image-preview-wrapper">
<img :src="imageUrl">
<div class="image-preview-action">
<i class="el-icon-delete" @click="rmImage" />
</div>
</div>
</div>
<div class="image-preview">
<div v-show="imageUrl.length>1" class="image-preview-wrapper">
<img :src="imageUrl">
<div class="image-preview-action">
<i class="el-icon-delete" @click="rmImage" />
</div>
</div>
</div>
</div>
</template>
<script>
import { getToken } from '@/api/qiniu'
export default {
name: 'SingleImageUpload3',
props: {
value: {
type: String,
default: ''
}
},
data() {
return {
tempUrl: '',
dataObj: { token: '', key: '' }
}
},
computed: {
imageUrl() {
return this.value
}
},
methods: {
rmImage() {
this.emitInput('')
},
emitInput(val) {
this.$emit('input', val)
},
handleImageSuccess(file) {
this.emitInput(file.files.file)
},
beforeUpload() {
const _self = this
return new Promise((resolve, reject) => {
getToken().then(response => {
const key = response.data.qiniu_key
const token = response.data.qiniu_token
_self._data.dataObj.token = token
_self._data.dataObj.key = key
this.tempUrl = response.data.qiniu_url
resolve(true)
}).catch(err => {
console.log(err)
reject(false)
})
})
}
}
}
</script>
<style lang="scss" scoped>
@import "~@/styles/mixin.scss";
.upload-container {
width: 100%;
position: relative;
@include clearfix;
.image-uploader {
width: 35%;
float: left;
}
.image-preview {
width: 200px;
height: 200px;
position: relative;
border: 1px dashed #d9d9d9;
float: left;
margin-left: 50px;
.image-preview-wrapper {
position: relative;
width: 100%;
height: 100%;
img {
width: 100%;
height: 100%;
}
}
.image-preview-action {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
cursor: default;
text-align: center;
color: #fff;
opacity: 0;
font-size: 20px;
background-color: rgba(0, 0, 0, .5);
transition: opacity .3s;
cursor: pointer;
text-align: center;
line-height: 200px;
.el-icon-delete {
font-size: 36px;
}
}
&:hover {
.image-preview-action {
opacity: 1;
}
}
}
.image-app-preview {
width: 320px;
height: 180px;
position: relative;
border: 1px dashed #d9d9d9;
float: left;
margin-left: 50px;
.app-fake-conver {
height: 44px;
position: absolute;
width: 100%; // background: rgba(0, 0, 0, .1);
text-align: center;
line-height: 64px;
color: #fff;
}
}
}
</style>

@ -0,0 +1,49 @@
// Inspired by https://github.com/Inndy/vue-clipboard2
const Clipboard = require('clipboard')
if (!Clipboard) {
throw new Error('you should npm install `clipboard` --save at first ')
}
export default {
bind(el, binding) {
if (binding.arg === 'success') {
el._v_clipboard_success = binding.value
} else if (binding.arg === 'error') {
el._v_clipboard_error = binding.value
} else {
const clipboard = new Clipboard(el, {
text() { return binding.value },
action() { return binding.arg === 'cut' ? 'cut' : 'copy' }
})
clipboard.on('success', e => {
const callback = el._v_clipboard_success
callback && callback(e) // eslint-disable-line
})
clipboard.on('error', e => {
const callback = el._v_clipboard_error
callback && callback(e) // eslint-disable-line
})
el._v_clipboard = clipboard
}
},
update(el, binding) {
if (binding.arg === 'success') {
el._v_clipboard_success = binding.value
} else if (binding.arg === 'error') {
el._v_clipboard_error = binding.value
} else {
el._v_clipboard.text = function() { return binding.value }
el._v_clipboard.action = function() { return binding.arg === 'cut' ? 'cut' : 'copy' }
}
},
unbind(el, binding) {
if (binding.arg === 'success') {
delete el._v_clipboard_success
} else if (binding.arg === 'error') {
delete el._v_clipboard_error
} else {
el._v_clipboard.destroy()
delete el._v_clipboard
}
}
}

@ -0,0 +1,13 @@
import Clipboard from './clipboard'
const install = function(Vue) {
Vue.directive('Clipboard', Clipboard)
}
if (window.Vue) {
window.clipboard = Clipboard
Vue.use(install); // eslint-disable-line
}
Clipboard.install = install
export default Clipboard

@ -0,0 +1,77 @@
export default {
bind(el, binding, vnode) {
const dialogHeaderEl = el.querySelector('.el-dialog__header')
const dragDom = el.querySelector('.el-dialog')
dialogHeaderEl.style.cssText += ';cursor:move;'
dragDom.style.cssText += ';top:0px;'
// 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
const getStyle = (function() {
if (window.document.currentStyle) {
return (dom, attr) => dom.currentStyle[attr]
} else {
return (dom, attr) => getComputedStyle(dom, false)[attr]
}
})()
dialogHeaderEl.onmousedown = (e) => {
// 鼠标按下,计算当前元素距离可视区的距离
const disX = e.clientX - dialogHeaderEl.offsetLeft
const disY = e.clientY - dialogHeaderEl.offsetTop
const dragDomWidth = dragDom.offsetWidth
const dragDomHeight = dragDom.offsetHeight
const screenWidth = document.body.clientWidth
const screenHeight = document.body.clientHeight
const minDragDomLeft = dragDom.offsetLeft
const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth
const minDragDomTop = dragDom.offsetTop
const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomHeight
// 获取到的值带px 正则匹配替换
let styL = getStyle(dragDom, 'left')
let styT = getStyle(dragDom, 'top')
if (styL.includes('%')) {
styL = +document.body.clientWidth * (+styL.replace(/\%/g, '') / 100)
styT = +document.body.clientHeight * (+styT.replace(/\%/g, '') / 100)
} else {
styL = +styL.replace(/\px/g, '')
styT = +styT.replace(/\px/g, '')
}
document.onmousemove = function(e) {
// 通过事件委托,计算移动的距离
let left = e.clientX - disX
let top = e.clientY - disY
// 边界处理
if (-(left) > minDragDomLeft) {
left = -minDragDomLeft
} else if (left > maxDragDomLeft) {
left = maxDragDomLeft
}
if (-(top) > minDragDomTop) {
top = -minDragDomTop
} else if (top > maxDragDomTop) {
top = maxDragDomTop
}
// 移动当前元素
dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`
// emit onDrag event
vnode.child.$emit('dragDialog')
}
document.onmouseup = function(e) {
document.onmousemove = null
document.onmouseup = null
}
}
}
}

@ -0,0 +1,13 @@
import drag from './drag'
const install = function(Vue) {
Vue.directive('el-drag-dialog', drag)
}
if (window.Vue) {
window['el-drag-dialog'] = drag
Vue.use(install); // eslint-disable-line
}
drag.install = install
export default drag

@ -0,0 +1,41 @@
import { addResizeListener, removeResizeListener } from 'element-ui/src/utils/resize-event'
/**
* How to use
* <el-table height="100px" v-el-height-adaptive-table="{bottomOffset: 30}">...</el-table>
* el-table height is must be set
* bottomOffset: 30(default) // The height of the table from the bottom of the page.
*/
const doResize = (el, binding, vnode) => {
const { componentInstance: $table } = vnode
const { value } = binding
if (!$table.height) {
throw new Error(`el-$table must set the height. Such as height='100px'`)
}
const bottomOffset = (value && value.bottomOffset) || 30
if (!$table) return
const height = window.innerHeight - el.getBoundingClientRect().top - bottomOffset
$table.layout.setHeight(height)
$table.doLayout()
}
export default {
bind(el, binding, vnode) {
el.resizeListener = () => {
doResize(el, binding, vnode)
}
// parameter 1 is must be "Element" type
addResizeListener(window.document.body, el.resizeListener)
},
inserted(el, binding, vnode) {
doResize(el, binding, vnode)
},
unbind(el) {
removeResizeListener(window.document.body, el.resizeListener)
}
}

@ -0,0 +1,13 @@
import adaptive from './adaptive'
const install = function(Vue) {
Vue.directive('el-height-adaptive-table', adaptive)
}
if (window.Vue) {
window['el-height-adaptive-table'] = adaptive
Vue.use(install); // eslint-disable-line
}
adaptive.install = install
export default adaptive

@ -0,0 +1,13 @@
import permission from './permission'
const install = function(Vue) {
Vue.directive('permission', permission)
}
if (window.Vue) {
window['permission'] = permission
Vue.use(install); // eslint-disable-line
}
permission.install = install
export default permission

@ -0,0 +1,31 @@
import store from '@/store'
function checkPermission(el, binding) {
const { value } = binding
const roles = store.getters && store.getters.roles
if (value && value instanceof Array) {
if (value.length > 0) {
const permissionRoles = value
const hasPermission = roles.some(role => {
return permissionRoles.includes(role)
})
if (!hasPermission) {
el.parentNode && el.parentNode.removeChild(el)
}
}
} else {
throw new Error(`need roles! Like v-permission="['admin','editor']"`)
}
}
export default {
inserted(el, binding) {
checkPermission(el, binding)
},
update(el, binding) {
checkPermission(el, binding)
}
}

@ -0,0 +1,91 @@
const vueSticky = {}
let listenAction
vueSticky.install = Vue => {
Vue.directive('sticky', {
inserted(el, binding) {
const params = binding.value || {}
const stickyTop = params.stickyTop || 0
const zIndex = params.zIndex || 1000
const elStyle = el.style
elStyle.position = '-webkit-sticky'
elStyle.position = 'sticky'
// if the browser support css sticky(Currently Safari, Firefox and Chrome Canary)
// if (~elStyle.position.indexOf('sticky')) {
// elStyle.top = `${stickyTop}px`;
// elStyle.zIndex = zIndex;
// return
// }
const elHeight = el.getBoundingClientRect().height
const elWidth = el.getBoundingClientRect().width
elStyle.cssText = `top: ${stickyTop}px; z-index: ${zIndex}`
const parentElm = el.parentNode || document.documentElement
const placeholder = document.createElement('div')
placeholder.style.display = 'none'
placeholder.style.width = `${elWidth}px`
placeholder.style.height = `${elHeight}px`
parentElm.insertBefore(placeholder, el)
let active = false
const getScroll = (target, top) => {
const prop = top ? 'pageYOffset' : 'pageXOffset'
const method = top ? 'scrollTop' : 'scrollLeft'
let ret = target[prop]
if (typeof ret !== 'number') {
ret = window.document.documentElement[method]
}
return ret
}
const sticky = () => {
if (active) {
return
}
if (!elStyle.height) {
elStyle.height = `${el.offsetHeight}px`
}
elStyle.position = 'fixed'
elStyle.width = `${elWidth}px`
placeholder.style.display = 'inline-block'
active = true
}
const reset = () => {
if (!active) {
return
}
elStyle.position = ''
placeholder.style.display = 'none'
active = false
}
const check = () => {
const scrollTop = getScroll(window, true)
const offsetTop = el.getBoundingClientRect().top
if (offsetTop < stickyTop) {
sticky()
} else {
if (scrollTop < elHeight + stickyTop) {
reset()
}
}
}
listenAction = () => {
check()
}
window.addEventListener('scroll', listenAction)
},
unbind() {
window.removeEventListener('scroll', listenAction)
}
})
}
export default vueSticky

@ -0,0 +1,13 @@
import waves from './waves'
const install = function(Vue) {
Vue.directive('waves', waves)
}
if (window.Vue) {
window.waves = waves
Vue.use(install); // eslint-disable-line
}
waves.install = install
export default waves

@ -0,0 +1,26 @@
.waves-ripple {
position: absolute;
border-radius: 100%;
background-color: rgba(0, 0, 0, 0.15);
background-clip: padding-box;
pointer-events: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-transform: scale(0);
-ms-transform: scale(0);
transform: scale(0);
opacity: 1;
}
.waves-ripple.z-active {
opacity: 0;
-webkit-transform: scale(2);
-ms-transform: scale(2);
transform: scale(2);
-webkit-transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
transition: opacity 1.2s ease-out, transform 0.6s ease-out;
transition: opacity 1.2s ease-out, transform 0.6s ease-out, -webkit-transform 0.6s ease-out;
}

@ -0,0 +1,72 @@
import './waves.css'
const context = '@@wavesContext'
function handleClick(el, binding) {
function handle(e) {
const customOpts = Object.assign({}, binding.value)
const opts = Object.assign({
ele: el, // 波纹作用元素
type: 'hit', // hit 点击位置扩散 center中心点扩展
color: 'rgba(0, 0, 0, 0.15)' // 波纹颜色
},
customOpts
)
const target = opts.ele
if (target) {
target.style.position = 'relative'
target.style.overflow = 'hidden'
const rect = target.getBoundingClientRect()
let ripple = target.querySelector('.waves-ripple')
if (!ripple) {
ripple = document.createElement('span')
ripple.className = 'waves-ripple'
ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px'
target.appendChild(ripple)
} else {
ripple.className = 'waves-ripple'
}
switch (opts.type) {
case 'center':
ripple.style.top = rect.height / 2 - ripple.offsetHeight / 2 + 'px'
ripple.style.left = rect.width / 2 - ripple.offsetWidth / 2 + 'px'
break
default:
ripple.style.top =
(e.pageY - rect.top - ripple.offsetHeight / 2 - document.documentElement.scrollTop ||
document.body.scrollTop) + 'px'
ripple.style.left =
(e.pageX - rect.left - ripple.offsetWidth / 2 - document.documentElement.scrollLeft ||
document.body.scrollLeft) + 'px'
}
ripple.style.backgroundColor = opts.color
ripple.className = 'waves-ripple z-active'
return false
}
}
if (!el[context]) {
el[context] = {
removeHandle: handle
}
} else {
el[context].removeHandle = handle
}
return handle
}
export default {
bind(el, binding) {
el.addEventListener('click', handleClick(el, binding), false)
},
update(el, binding) {
el.removeEventListener('click', el[context].removeHandle, false)
el.addEventListener('click', handleClick(el, binding), false)
},
unbind(el) {
el.removeEventListener('click', el[context].removeHandle, false)
el[context] = null
delete el[context]
}
}

@ -0,0 +1,9 @@
import Vue from 'vue'
import SvgIcon from '@/components/SvgIcon'// svg component
// register globally
Vue.component('svg-icon', SvgIcon)
const req = require.context('./svg', false, /\.svg$/)
const requireAll = requireContext => requireContext.keys().map(requireContext)
requireAll(req)

@ -0,0 +1 @@
<svg width="128" height="100" xmlns="http://www.w3.org/2000/svg"><path d="M27.429 63.638c0-2.508-.893-4.65-2.679-6.424-1.786-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.465 2.662-1.785 1.774-2.678 3.916-2.678 6.424 0 2.508.893 4.65 2.678 6.424 1.786 1.775 3.94 2.662 6.465 2.662 2.524 0 4.678-.887 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zm13.714-31.801c0-2.508-.893-4.65-2.679-6.424-1.785-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zM71.714 65.98l7.215-27.116c.285-1.23.107-2.378-.536-3.443-.643-1.064-1.56-1.762-2.75-2.094-1.19-.33-2.333-.177-3.429.462-1.095.639-1.81 1.573-2.143 2.804l-7.214 27.116c-2.857.237-5.405 1.266-7.643 3.088-2.238 1.822-3.738 4.152-4.5 6.992-.952 3.644-.476 7.098 1.429 10.364 1.905 3.265 4.69 5.37 8.357 6.317 3.667.947 7.143.474 10.429-1.42 3.285-1.892 5.404-4.66 6.357-8.305.762-2.84.619-5.607-.429-8.305-1.047-2.697-2.762-4.85-5.143-6.46zm47.143-2.342c0-2.508-.893-4.65-2.678-6.424-1.786-1.775-3.94-2.662-6.465-2.662-2.524 0-4.678.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.786 1.775 3.94 2.662 6.464 2.662 2.524 0 4.679-.887 6.465-2.662 1.785-1.775 2.678-3.916 2.678-6.424zm-45.714-45.43c0-2.509-.893-4.65-2.679-6.425C68.68 10.01 66.524 9.122 64 9.122c-2.524 0-4.679.887-6.464 2.661-1.786 1.775-2.679 3.916-2.679 6.425 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zm32 13.629c0-2.508-.893-4.65-2.679-6.424-1.785-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zM128 63.638c0 12.351-3.357 23.78-10.071 34.286-.905 1.372-2.19 2.058-3.858 2.058H13.93c-1.667 0-2.953-.686-3.858-2.058C3.357 87.465 0 76.037 0 63.638c0-8.613 1.69-16.847 5.071-24.703C8.452 31.08 13 24.312 18.714 18.634c5.715-5.68 12.524-10.199 20.429-13.559C47.048 1.715 55.333.035 64 .035c8.667 0 16.952 1.68 24.857 5.04 7.905 3.36 14.714 7.88 20.429 13.559 5.714 5.678 10.262 12.446 13.643 20.301 3.38 7.856 5.071 16.09 5.071 24.703z"/></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

@ -0,0 +1 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M96.258 57.462h31.421C124.794 27.323 100.426 2.956 70.287.07v31.422a32.856 32.856 0 0 1 25.971 25.97zm-38.796-25.97V.07C27.323 2.956 2.956 27.323.07 57.462h31.422a32.856 32.856 0 0 1 25.97-25.97zm12.825 64.766v31.421c30.46-2.885 54.507-27.253 57.713-57.712H96.579c-2.886 13.466-13.146 23.726-26.292 26.291zM31.492 70.287H.07c2.886 30.46 27.253 54.507 57.713 57.713V96.579c-13.466-2.886-23.726-13.146-26.291-26.292z"/></svg>

After

Width:  |  Height:  |  Size: 497 B

@ -0,0 +1 @@
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="128" height="128"><defs><style/></defs><path d="M512 128q69.675 0 135.51 21.163t115.498 54.997 93.483 74.837 73.685 82.006 51.67 74.837 32.17 54.827L1024 512q-2.347 4.992-6.315 13.483T998.87 560.17t-31.658 51.669-44.331 59.99-56.832 64.34-69.504 60.16-82.347 51.5-94.848 34.687T512 896q-69.675 0-135.51-21.163t-115.498-54.826-93.483-74.326-73.685-81.493-51.67-74.496-32.17-54.997L0 513.707q2.347-4.992 6.315-13.483t18.816-34.816 31.658-51.84 44.331-60.33 56.832-64.683 69.504-60.331 82.347-51.84 94.848-34.816T512 128.085zm0 85.333q-46.677 0-91.648 12.331t-81.152 31.83-70.656 47.146-59.648 54.485-48.853 57.686-37.675 52.821-26.325 43.99q12.33 21.674 26.325 43.52t37.675 52.351 48.853 57.003 59.648 53.845T339.2 767.02t81.152 31.488T512 810.667t91.648-12.331 81.152-31.659 70.656-46.848 59.648-54.186 48.853-57.344 37.675-52.651T927.957 512q-12.33-21.675-26.325-43.648t-37.675-52.65-48.853-57.345-59.648-54.186-70.656-46.848-81.152-31.659T512 213.334zm0 128q70.656 0 120.661 50.006T682.667 512 632.66 632.661 512 682.667 391.339 632.66 341.333 512t50.006-120.661T512 341.333zm0 85.334q-35.328 0-60.33 25.002T426.666 512t25.002 60.33T512 597.334t60.33-25.002T597.334 512t-25.002-60.33T512 426.666z"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -0,0 +1 @@
<svg width="128" height="64" xmlns="http://www.w3.org/2000/svg"><path d="M127.072 7.994c1.37-2.208.914-5.152-.914-6.87-2.056-1.717-4.797-1.226-6.396.982-.229.245-25.586 32.382-55.74 32.382-29.24 0-55.74-32.382-55.968-32.627-1.6-1.963-4.57-2.208-6.397-.49C-.17 3.086-.399 6.275 1.2 8.238c.457.736 5.94 7.36 14.62 14.72L4.17 35.96c-1.828 1.963-1.6 5.152.228 6.87.457.98 1.6 1.471 2.742 1.471s2.284-.49 3.198-1.472l12.564-13.983c5.94 4.416 13.021 8.587 20.788 11.53l-4.797 17.418c-.685 2.699.686 5.397 3.198 6.133h1.37c2.057 0 3.884-1.472 4.341-3.68L52.6 42.83c3.655.736 7.538 1.227 11.422 1.227 3.883 0 7.767-.49 11.422-1.227l4.797 17.173c.457 2.208 2.513 3.68 4.34 3.68.457 0 .914 0 1.143-.246 2.513-.736 3.883-3.434 3.198-6.133l-4.797-17.172c7.767-2.944 14.848-7.114 20.788-11.53l12.336 13.738c.913.981 2.056 1.472 3.198 1.472s2.284-.49 3.198-1.472c1.828-1.963 1.828-4.906.228-6.87l-11.65-13.001c9.366-7.36 14.849-14.474 14.849-14.474z"/></svg>

After

Width:  |  Height:  |  Size: 944 B

@ -0,0 +1 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M84.068 23.784c-1.02 0-1.877-.32-2.572-.96a8.588 8.588 0 0 1-1.738-2.237 11.524 11.524 0 0 1-1.042-2.621c-.232-.895-.348-1.641-.348-2.238V0h.278c.834 0 1.622.085 2.363.256.742.17 1.645.575 2.711 1.214 1.066.64 2.363 1.535 3.892 2.686 1.53 1.15 3.453 2.664 5.77 4.54 2.502 2.045 4.494 3.771 5.977 5.178 1.483 1.406 2.618 2.6 3.406 3.58.787.98 1.274 1.812 1.46 2.494.185.682.277 1.278.277 1.79v2.046H84.068zM127.3 84.01c.278.682.464 1.535.556 2.558.093 1.023-.37 2.003-1.39 2.94-.463.427-.88.832-1.25 1.215-.372.384-.696.704-.974.96a6.69 6.69 0 0 1-.973.767l-11.816-10.741a44.331 44.331 0 0 0 1.877-1.535 31.028 31.028 0 0 1 1.737-1.406c1.112-.938 2.317-1.343 3.615-1.215 1.297.128 2.363.405 3.197.83.927.427 1.923 1.173 2.989 2.239 1.065 1.065 1.876 2.195 2.432 3.388zM78.23 95.902c2.038 0 3.752-.511 5.143-1.534l-26.969 25.83H18.037c-1.761 0-3.684-.47-5.77-1.407a24.549 24.549 0 0 1-5.838-3.709 21.373 21.373 0 0 1-4.518-5.306c-1.204-2.003-1.807-4.07-1.807-6.202V16.495c0-1.79.44-3.665 1.32-5.626A18.41 18.41 0 0 1 5.04 5.562a21.798 21.798 0 0 1 5.213-3.964C12.198.533 14.237 0 16.37 0h53.24v15.984c0 1.62.278 3.367.834 5.242a16.704 16.704 0 0 0 2.572 5.179c1.159 1.577 2.665 2.898 4.518 3.964 1.853 1.066 4.078 1.598 6.673 1.598h20.295v42.325L85.458 92.45c1.02-1.364 1.529-2.856 1.529-4.476 0-2.216-.857-4.113-2.572-5.69-1.714-1.577-3.776-2.366-6.186-2.366H26.1c-2.409 0-4.448.789-6.116 2.366-1.668 1.577-2.502 3.474-2.502 5.69 0 2.217.834 4.092 2.502 5.626 1.668 1.535 3.707 2.302 6.117 2.302h52.13zM26.1 47.951c-2.41 0-4.449.789-6.117 2.366-1.668 1.577-2.502 3.473-2.502 5.69 0 2.216.834 4.092 2.502 5.626 1.668 1.534 3.707 2.302 6.117 2.302h52.13c2.409 0 4.47-.768 6.185-2.302 1.715-1.534 2.572-3.41 2.572-5.626 0-2.217-.857-4.113-2.572-5.69-1.714-1.577-3.776-2.366-6.186-2.366H26.1zm52.407 64.063l1.807-1.663 3.476-3.196a479.75 479.75 0 0 0 4.587-4.284 500.757 500.757 0 0 1 5.004-4.667c3.985-3.666 8.48-7.758 13.485-12.276l11.677 10.741-13.485 12.404-5.004 4.603-4.587 4.22a179.46 179.46 0 0 0-3.267 3.068c-.88.853-1.367 1.322-1.46 1.407-.463.341-.973.703-1.529 1.087-.556.383-1.112.703-1.668.959-.556.256-1.413.575-2.572.959a83.5 83.5 0 0 1-3.545 1.087 72.2 72.2 0 0 1-3.475.895c-1.112.256-1.946.426-2.502.511-1.112.17-1.854.043-2.224-.383-.371-.426-.464-1.151-.278-2.174.092-.511.278-1.279.556-2.302.278-1.023.602-2.067.973-3.132l1.042-3.005c.325-.938.58-1.577.765-1.918a10.157 10.157 0 0 1 2.224-2.941z"/></svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

@ -0,0 +1 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M115.625 127.937H.063V12.375h57.781v12.374H12.438v90.813h90.813V70.156h12.374z"/><path d="M116.426 2.821l8.753 8.753-56.734 56.734-8.753-8.745z"/><path d="M127.893 37.982h-12.375V12.375H88.706V0h39.187z"/></svg>

After

Width:  |  Height:  |  Size: 285 B

@ -0,0 +1 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M.002 9.2c0 5.044 3.58 9.133 7.998 9.133 4.417 0 7.997-4.089 7.997-9.133 0-5.043-3.58-9.132-7.997-9.132S.002 4.157.002 9.2zM31.997.066h95.981V18.33H31.997V.066zm0 45.669c0 5.044 3.58 9.132 7.998 9.132 4.417 0 7.997-4.088 7.997-9.132 0-3.263-1.524-6.278-3.998-7.91-2.475-1.63-5.524-1.63-7.998 0-2.475 1.632-4 4.647-4 7.91zM63.992 36.6h63.986v18.265H63.992V36.6zm-31.995 82.2c0 5.043 3.58 9.132 7.998 9.132 4.417 0 7.997-4.089 7.997-9.132 0-5.044-3.58-9.133-7.997-9.133s-7.998 4.089-7.998 9.133zm31.995-9.131h63.986v18.265H63.992V109.67zm0-27.404c0 5.044 3.58 9.133 7.998 9.133 4.417 0 7.997-4.089 7.997-9.133 0-3.263-1.524-6.277-3.998-7.909-2.475-1.631-5.524-1.631-7.998 0-2.475 1.632-4 4.646-4 7.91zm31.995-9.13h31.991V91.4H95.987V73.135z"/></svg>

After

Width:  |  Height:  |  Size: 821 B

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save