diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..692a38f --- /dev/null +++ b/.dockerignore @@ -0,0 +1,6 @@ +node_modules/ +cache/ +log/ +.vscode/ +.git +.gitigonre \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a35f343 --- /dev/null +++ b/.gitignore @@ -0,0 +1,36 @@ +Thunbs.db +*.exe +*.pdb +*.user +*.aps +*.pch +*.vspscc +*_i.c +*_p.c +*.ncb +*.suo +*.tlb +*.tlh +*.bak +*.cache +*.ilk +*.log +[Dd]ebug*/ +*.lib +*.sbr +*.refresh +*.suo +*.yml +*.key +obj/ +[Rr]elease*/ +_ReSharper*/ +.svn +*.cache +.DS_Store + +/node_modules +/log +/static/upload + +package-lock.json \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d264419 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM node:16.15.0 + +ADD . /gpclub + +WORKDIR /gpclub + +RUN npm install + +EXPOSE 10129 + +CMD ["npm", "run", "prod"] + diff --git a/DockerfileYZ b/DockerfileYZ new file mode 100644 index 0000000..85a72f9 --- /dev/null +++ b/DockerfileYZ @@ -0,0 +1,12 @@ +FROM node:16.15.0 + +ADD . /gpclub + +WORKDIR /gpclub + +RUN npm install + +EXPOSE 10129 + +CMD ["npm", "run", "yz"] + diff --git a/DockerfileYZdebug b/DockerfileYZdebug new file mode 100644 index 0000000..638df90 --- /dev/null +++ b/DockerfileYZdebug @@ -0,0 +1,11 @@ +FROM node:16.15.0 + +ADD . /gpclub + +WORKDIR /gpclub + +RUN npm install + +EXPOSE 10129 + +CMD ["npm", "run", "debugyz"] \ No newline at end of file diff --git a/English-learning.me b/English-learning.me new file mode 100644 index 0000000..77f81e0 --- /dev/null +++ b/English-learning.me @@ -0,0 +1,65 @@ +n. 名称 +v. 包含vi和vt +vi. 不及物动词 +vt. 及物动词 +adj. 形容词 + +Resume 简历 +Contracts 合同 +Clents 客户,客户端 +Escow : 固定价格工作的第三方担保,类似于支付宝,托管; +Milestone:里程碑,大额固定价格工作通常设置为多个里程碑,阶段性完成工作,阶段性交付 ; +Bonus : 奖金/小费,在完成工作酬金之余,客户另外给的小费。这个小费平台也会收取佣金 ; +Profile:简历,指的是在Upwork平台上的个人履历,优秀的简历会被客户搜索到,并有大量邀请工作的机会; +Connects:竞标豆,Upwork平台上用来申请工作的一种点数。申请一个工作一般消耗两个竞标豆,邀请工作不消耗竞标豆 ; + +Bid:竞标/出价,在看到合适的工作时,进行竞标或者出价申请; + +Chat 聊天 vi 【chat with sb about sth】 +Withdraw 提款vt 退出 vi +Freelancer 自由职业者 +Proposal : 提案,竞标工作时提出的方案,一般包含 Bid Price(竞标价),Cover Letter(竞标方案),Period(项目周期),Hourly Rate(时薪)等; +Feedback :客户评价 +JSS: Job Success Score -工作完成率评分,反应了 自由职业者在平台上的工作完成率,一般在完成5-8个工作后,会显示该该分数;取最近6个月,12个月,24个月 的最高值。 + +Rasing Talent : 潜力天才,Upwork平台会自动针对自由者的简历进行评级,如果经过评测简历,认为有丰富的从业经验,但是在Upwork工作还不丰富的话(一般约5个工作以下,还没有JSS之前)就会给予 Rising Talent ; +Top Rated : Upwork 最高评级 , 需要满足三个条件: + +Upwork Fixed Payment Protection : 固定价格工作保护政策,此政策用来保障自由职业者在做 固定价格工作 时的合法权益。 + +Upwork Hourly Payment Protection : 小时计费工作保护政策,此政策用来保障自由职业者在做按 小时计费工作 时的合法权益。 + +most recent :最近的 + +browse:浏览 + +order by most relevant:按照最相关的排序 + +revelant:相关的 + +stats:统计数据 +transaction 交易 + +statement 清单 报告 报表 +period 阶段,时期,一段时间 + +criteria [kraɪ'tɪəriə] 标准 准则 +disputes [dɪˈspjuːts] 纠纷 + + +Referral 送交 转送(到能提供专门帮助的人或地方那里) n. +Declining 拒绝 减少 +Invitation 邀请 +referr 推荐人 +achived 取得的 adj. 取得 v. +interview 面试 +Agency:机构/团队,指的是在Upwork组团接活的组织; +Enterprise Client:企业客户 +Budget : 预算 + + + + +fill one's job 完成某人的工作 +Lead to 导致,通向 +help sb succeed 帮助某人成功|帮助某人实现目标 \ No newline at end of file diff --git "a/OSI\346\250\241\345\236\213.png" "b/OSI\346\250\241\345\236\213.png" new file mode 100644 index 0000000..eee736f Binary files /dev/null and "b/OSI\346\250\241\345\236\213.png" differ diff --git a/README.md b/README.md new file mode 100644 index 0000000..8cd73e2 --- /dev/null +++ b/README.md @@ -0,0 +1,278 @@ +# Node 后端模版说明 + + +项目发布原理: + 1.如果static项目的dll文件内的框架有变动,需要npm run dll-prod + 2.static项目执行npm run prod + 3.把static项目下的dist文件夹内的所有文件,拷贝到node项目下的static文件夹里面的latest里面,同时再创建一个当日发布的文件加,比如2022-08-21文件夹, + latest里面表示最新的静态文件,也是线上的文件,2022-08-21文件夹是发布的版本的拷贝,用于记录发布的历史版本,如果线上出问题,就回滚到之前的日期的文件夹【只需要修改config文件加内的prod的staticServer即可】 + 只需要修改config.js文件中的prod.staticPath,重置前端静态文件的路径,就可以实现前端静态资源的回滚【js,css,html等所有前端静态资源】 + 4.在node项目执行npm run prod,就启动了node服务,在服务器启动node,就等于发布了整个站点,因为前后端代码都在一个站点里面。 + 5.昨晚上面的3步,然后把第四步node启动+mongo数据库启动,都封装到docker里面,实现容器部署,这样就很轻松地实现了整个webapp的容器化部署发布,方便在各个服务器之间实现迁移 + docker容器化的好处是,容器里面包含了node版本,mongo版本等所有需要的环境基础,0成本迁移服务器,迁移的时候只需要考虑服务器的操作系统是否和docker兼容即可,docker在所有服务器下的命令都一样,一次部署,随意迁移 + +本地发布流程【模仿线上】: + 1.如果static项目的dll文件内的框架有变动,需要npm run dll-prod + 2.static项目执行npm run prod + 3.把static项目下的dist文件夹内的所有文件,拷贝到node项目下的static文件夹里面的latest里面,同时再创建一个当日发布的文件加,比如2022-08-21文件夹, + 4.本地启动都开docker,删除所有容器,删除node项目所对应的镜像【数据库镜像gp-database和数据库管理镜像mongo-express不需要删除】 + 5.到node项目下,执行docker-compose up -d执行镜像构建和容器生成【一键完成】,然后在localhost/recommend/home下就可以访问了【目前数据库访问出错,因为线上的数据库帐号密码和本地的数据库帐号密码不一样】 + 所以需要在本地构建一个yz环境,模仿线上,yz环境的数据库帐号和密码也必须正确,不然就会访问出错 + +上线发布流程: + 1.如果static项目的dll文件内的框架有变动,需要npm run dll-prod + 2.static项目执行npm run prod + 3.把static项目下的dist文件夹内的所有文件,拷贝到node项目下的static文件夹里面的latest里面,同时再创建一个当日发布的文件加,比如2022-08-21文件夹, + 4.打开putty.exe,选择VCN over SSH,点击load,加载出远程服务器地址43.143.25.248和远程端口22,点击连接【需要输入ssh连接远程服务器的帐号和密码,这样就建立了ssh连接】 + + //下面是命令行的发布流程 + 5.进入koa-node目录,git pull 拉最新代码 + 6.如果是第一次构建发布, + 1.执行“mongo.readme文件中的数据库集群配置和数据库管理员;就是执行mongo.readme文中“创建副本集步骤”下面的内容 + 2.docker-compose up -d来创建或更新容器 + 如果是后续发布: + 1.sudo docker-compose build web :该操作把服务器git上的最新代码部署到最新的镜像;因为数据库和mongo-express没有修改,所以不需要用docker-compose pulll来拉区最新的镜像 + 2.docker-compose up -d来创建或更新容器 + + //下面是linux界面的发布流程 + 5.打开VCN-VIEW软件,用这个软件实现服务器远程登录控制,因为putty软件已经设置了来拦截,所以VCN-VIEW的请求会通过putty软件的ssh加密通道来登录,保证了远程登录的安全 + 6.接下来,就是服务器的发布流程了,之前1-3是本地代码更新,4-5是连接服务器,这一步就是在服务器上发布了,先在服务器拉最新的git代码 + 7.网站第一次发布,执行docker-compose up -d即可【先进入koa-node目录下,执行sudo su root获得root权限,不然执行目录可能被拒绝】:腾讯那边可以设置自动执行的命令,把这三个命令统一放到一键执行的命令里面: + 如果不是第一次发布,那么先执行sudo docker-compose build web来获取最新的web服务的镜像【知识镜像变了,容器还是没变】,然后再执行docker-compose up -d生成最新的容器 + 如果用docker-compose down 删除了所有的容器,那么数据库容器也会被删除,就得重新设置数据库帐号密码以及集群配置,所以千万别执行docker-compose down ,一旦执行了docker-compose down + 就要重新按照mongo.readme里面的步骤重新配置数据库 + + //相关命令 + docker-compose down :删除所有容器,连数据库都会被删除,千万别执行这个 + docker-compose pull :更新镜像内容 :如果遇到通过dockerfile构建的镜像,需要自己docker-compose buld service名称来手动执行构建镜像【根据yml的对应service的名称下的内容来构建】 + docker-compose up -d:根据镜像创建容器,第一次启动还会自动构建镜像,然后再根据镜像创建容器 + + + +难点:dev出错调试很容易,难的是dev正确,qa和yz环境下出错,因为qa和yz都在docker下运行,这样去调试显然不适合,需要在本地模仿qa和yz的开发环境来调试 + 1.先确定前端静态资源已经正确发布,很多时候是静态资源压根没发上去,或者服务器缓存,反正就是静态资源不对 + 2.如果静态资源正常发布了,接下来从node,前端,数据库3个方向排查 + 3.运行npm run debugyz:先仿造可调式的node端的yz环境,排查node端是否有问题; + 4.一般如果是前端的问题,直接对比request和respose基本就可以得出结论,如果还是没法找出错误按照下面步骤执行 + 用fiddler拦截js,把压缩的js换成dev的js,如果dev环境的js没问题但压缩的文件出问题,就检查压缩文件是否是新的代码,或者压缩过程中代码被压缩坏了 + 不用fiddler,也可以暂时修改前端打包,把压缩改成未压缩,然后调试 + + + + + +//开发的时候特别要注意,在npm run debug-node的调试环境下,任何非node端请求的相关js文件, + 修改都无法同步到调试环境,需要重启node才能获得最新代码; + +node启动命令:npm start +node调试命令:npm run debug-node 【前提是chorme下的node调试环境已经配置好】 +node 服务器重新启动调试命令:npm run debugs 【前提是chorme下的node调试环境已经配置好】 + 调试流程: + 1.执行上面的npm run debug-node或者npm run debugs + 2.在chrome中输入地址 chrome://inspect/#devices + 3.点击浏览器页面内部的Devices下的Remote Target下面的inspect,就自动进入node调试界面 + +npm run debug-node和npm run debugs区别: + npm run debug-node用于服务端请求相关的node端js代码的调试 + npm run debugs用于服务端的初始化相关的node端js代码的调试 + npm run debug-node是用于服务端node请求的调试,也就是node端的node页面或ajax相关的js有修改 + 可以用这个命令调试,这个命令启动之后,按照上面的调试流程到第三步点击inspect,等于调试环境启动成功 + 接下来修改node端的页面请求和ajax请求相关js,然后只要在前端刷新页面或者请求ajax + 就会执行最新的后端代码,非常方便,但是涉及到node服务端初始化的相关js,就无法在这里调试 + 因为这个调试命令只是和node服务请求相关,不涉及node服务器的初始化的相关代码; + + 而npm run debugs,是弥补上面的调试的缺陷,如果调试的代码涉及到node端启动的js代码, + 如果用npm run debug-node来调试,那每次修改node端启动的代码,首先要停止当前的node服务 + 然后再重新执行上面的“调试流程1,2,3”步,才能看到最新的node端启动代码,而过用npm run debugs + 那么每次修改node端的启动代码,只要点击“调试流程”中的第三步的inspect,就进入了最新代码的调试环节 + 但npm run debugs的坏处在于,它调试服务端的node请求【非node端启动】的js代码比较费劲, + 就是每次修改代码,都要点击inspect,然后执行完node初始化js后,再刷新页面,接下来才能执行正常的页面内部的node请求调试。 + + +npm run debug-node执行以后,关于页面请求和ajax请求的后端代码修改,是可以直接同步的,很方便调试 + 但是服务器启动的代码无法重新调试,因为浏览器只能是关于node端的请求代码,而非node端启动代码 + + +如何在docker容器里面执行调试node:!!! +1.在yml文件里面对应构建node项目用到的docker文件里面,添加调试命令,例如把dockerfile文件的最后一行CMD ["npm", "run", "prod"] 改为CMD ["npm", "run", "debugyz"],debugyz就是那个调试命令 +2.在package.json文件里面设置调试命令debugyz,具体如下"debugyz": "NODE_ENV='yz' nodemon --inspect-brk=0.0.0.0 app.js", 和本地node调试基本没啥变化,只是inspect-brk后面添加了=0.0.0.0而已 +3.因为要调试docker,所以在yml文件的ports下面需要额外添加一个端口用于调试,比如本来- 80:10129用于端口映射,那么在下面再随意添加一个端口,比如- 9229:9229 ,这个9229端口就专门用于调试 +4.最关键的一部来了,因为第2步中添加了0.0.0.0监控,docker的端口也添加了9229,所以再浏览器的chrome://inspect/#devices页面里面,需要给Discover network targets添加以一个0.0.0.0:9229的监控 + 这样一来,docker容器运行,chorme的inspect插件就可以通过0.0.0.0:9229来监控node,调试方法还是和本地调试一样 + + + + + + +服务器启动流程: + 1.执行app.js,使用koa框架创建app + 2.进入middleware的index.js,注册所有中间件:用app.use注册中间件 + 3.使用http或https的createServer方法,传入koa框架产生的那个app.callback(),并添加监听:例如http.createServer(app.callback()).listen(端口,服务器地址); + +客户端请求node服务器的流程:比如浏览器输入http://localhost:10129/recommend/home请求,传送到node端服务器,就会执行下面的大概流程 + 1.根据middleware的index.js里面的中间件的注册顺序,依次执行每一个中间件,最后肯定会执行到router这个路由中间件 + 2.跳转到路由中间件router>index.js从function* getController这个函数开始,执行路由的划分,跳转到对应的controlls文件夹下的js文件 + 3.执行controlls下的对应js文件里面和页面名称对应的js函数【例如home】,js函数里面会调用render函数 + 4.这个render函数其实也是在router文件夹下的index.js里面定义的【包括其他ajax的render,jsonp的render等,我把这些render函数都写在这里】 + 5.render函数里面用到了“co-views”这个模板渲染引擎,放入对应的参数,就能去找views文件夹下对应的页面的html + 6.到这里基本流程都结束了,总体流程是依次执行中间件,执行到路由中间件的时候,执行个人设置的mvc,就是从路由跳转到controller,controll中写业务逻辑和对model的调用 + 获取到页面所有需要的数据后,controller再用render函数来跳转到view来编译html模板,最后把生成的文件或数据发送给客户端浏览器 + + + + +关于dev,qa,yz,prod的环境部署问题: +1.所有环境相关的变量,都统一放在config.js文件里面,不要东一块西一块导致修改环境的时候出bug +2.qa,yz,环境都是用docker发布和访问,所以必须有各自对应的dockerfile;本地执行npm run qa|yz|prod访问的是,node虽然启动了,但是对应的数据库环境是docker环境,所以本地执行npm run prod|yz|qa毫无意义 + 反而容易把docker环境的dockerfile里面执行的npm run prod|yz|qa 搞混,本地调试qa,yz环境,不是本地执行npm run qa|yz ;而是创建docker容器,在本地从dock容器访问【最好是有qa和yz服务器,通过服务器访问】 +3.如果所有的静态资源都是在同一个服务器,那么qa和yz的静态资源就没必要添加host前缀,直接可以用相对地址,这样保证了除了数据库数据,其他qa,yz,prod的所有数据都是一样的 + + + + + + +直接参考项目根目录下的Dockerfile。 + + + +nodemom:用于后端系统重启,但如果后端系统崩溃了,那就需要另一个软件让nodemon自动重启,这个软件就是forever,这样才会有安全稳定可访问的线上环境,即使站点崩溃了,也可以马上重启 + nodemon.json文件中设置相关项,手动重启是rs;只要修改的node端的文件,nodemon都会自动刷新,然后用户刷新页面,就是最新的文件了。 + 所以在nodemon执行的环境下,任何修改都等于实时发布,修改完,用户就能获取最新的业务代码,但后端不能随意修改,还是要走一个正常的测试发布流程,最后把所有文件批量覆盖线上的文件 + 这样就做到了瞬间发布大批功能。 + + nodemon修改后自动重启,重启的只是服务器,html不会刷新,所以html的刷新,需要自己手动; + + + +//文件目录结构说明 +.cert:站点安全证书 +.dockerignore : 后端站点构建镜像的时候,有些文件不需要打在镜像里面,在这里设置哪些不需要打进去的文件 +.gitignore:git提交忽略的文件 +Dockerfile : dockerfike快速创建自定义的Docker镜像 :https://blog.csdn.net/mozf881/article/details/55798811 +nodemon.js:nodemon本地调试配置 +package.json:项目文件 +webpack-assets.json:static站点和node站点的静态文件匹配(prod环境才用到,dev环境不用) +errorPages:公共错误页面 +node_modules:node插件集合 +log:日志 +config.js:node站点资源配置文件!! +models:node请求的model !! +views:node返回用的html文件 !! +app.js:node执行命令入口文件!! +controllers:mvc的controller!! +lib:公用文件 !! + middleware文件夹:node中间件 + app.js:中间件入口 + util.js:站点通用js + + + + + + +//启动流程和用户请求流程 +1.本地启动:app.js > lib(中间件加载:包括路由,鉴权,渲染模板等) +2.用户发送url请求:routes/index.js > controllers > views :最终返回用户数据 +主要关注!!的文件夹即可 + + + + + +!!!!!!!!环境安装!!!!!!! +chrome下node调试环境配置要求:使用方法见https://github.com/node-inspector/node-inspector + +1.chrome版本要55+ + +2.node版本要7+:别用7以下的版本,会出各种问题,因为下载的node-inspector是最新的版本,和老版本的node结合使用,将是灾难;要么用老版本的node-inspector和node@6.10.0 + 而且老版本的命令和新版本也不一样,要区分 + +3.安装用:npm install -g node-inspector + +4.如果还不行,就是缺少软件包,全局安装 node-gyp和node-pre-gyp + +5.如果还不行,去https://dotnet.microsoft.com/download/visual-studio-sdks这个地址下载安装包4.6.2 ,然后再npm install --global --production windows-build-tools@4.0.0 + +6.最后,一定要注意,使用的命令必须是node --inspect-brk app.js【app.js是启动文件名,和package.json同目录下】 + node-debug;node --debug等已经被废弃了,一旦使用就会报错,怎么解决都解决不了的 + + + + +!!!!!!!!!!调试!!!!!!!!!!!!!!! +1.node --inspect-brk app.js 【会出现监控地址和端口,例如127.0.0.1:8080,看cmd框中的内容即可】 +2.打开chrome://inspect/#devices,设置configure,添加刚才cmd中出现的地址,例如(127.0.0.1:8080),后面的uuid不用拷贝进去 +3.点击下面出现的inspect,就会自动到debugger的地方【有的时候不灵,多试几遍】 + +//如何调试node页面 +1. 同上面一摸一样,先调试app.js,执行完app.js,这个时候服务器已经启动了 +2.前在对应的js处打断点即可,刷新对应的node页面,例如刷新,http://localhost:10129/recommend/list;就自动会进入node页面的后端执行流程,就能执行到断点处 + + +3.node端开发,遇到出错,复杂的问题,用inspect调试;如果页面没有错误,只是业务上想看一些后端的数据,可以在nodmon启动后,直接在后端代码处添加console.log(数据),就可以直接在命令行出现;如果用inspect调试,那么打console.log会直接报错 + +4.后端如何调试: + 1.如果不需要在浏览器中调试,启动npm start 后,直接在页面里面打console.log(),命令行出现最新的打印内容 + 2.如果需要在浏览器中调试单次调试,用npm run debug-node:打开调试界面输入地址,点击inspect, + 执行服务器初始化,然后再刷新html页面,就会进入正常的服务器页面请求流程的调试,经过所有middlle, + 包括rout流程; + 3. 如果需要热替换调试,就执行npm run debugs,修改后端代码,然后不需要重启node,直接点击inspect, + 就进入了服务器初始化的node流程,再点刷新页面或者点击页面的功能,就会自动进入最新代码的node端请求流程 + + + + + + + + + + + +//通用后端功能: +1. 路由 :koa-router +2. body解析:koa-bodyparser +3. http头相关安全防范:koa-helmet +4. 缓存:koa-conditional-get加koa-etag +5. 静态资源服务器【如果前后端分离,就可以不用,静态资源单独单间一个站点,启动独立静态资源服务器,而不是用koa-static在node端并行搞一个静态资源服务器】:koa-static +6. 发布版本管理插件,用于发布的静态资源文件管理,去缓存:自己写逻辑 +7. 登录,验权:自己写逻辑 +8. 错误日志管理:自己写逻辑,也可以找通用的错误日志管理插件 +9. 数据埋点:自己写,用于统计用户数据和行为习惯,以便于网站的优化 + + + + + +1.npm start ,查看代码是否报错; +2.用chrome调试app.js,看代码是否有遗漏,整个流程是否跑通【如何调试本地Nodejs.txt文件】 +3.npm start ,启动访问对应的浏览器地址,例如http://localhost:10129/recomment/index,查看页面的网络反馈,只要存在html文件,那就是node端的路由时没问题,正常访问到了那个页面 + 3.1那接下来就是再那个页面对应的controller中打debugger,调试页面的代码逻辑问题 + +4.如果访问页面网络反馈的时404,啥都没有,这个时最难办的,错误可能时url不对;更糟糕的可能时app.js文件中执行的流程有疏漏, + 但不管怎么样,只要host和端口没错,浏览器中输入任意地址,例如http://localhost:10129/recommend/list + 都会经过如下流程:【所以首先看是否使用了rout中间件,没用的话,压根就没路由,没法执行到controller,反馈肯定是404】 + 1.middleware插件之前注册过,所以每个middleware插件都会执行:这个是核心,网站的页面渲染,缓存,保护,所有的业务和安全,全在这个里面执行 + 2.如果middleware插件中用了route插件,就实现了路由功能,不管输入的网址对不对,都会执行如下流程 + 1. *controller函数 + 2. 对应的controller函数【一般这个函数里肯定会有render的调用】 + 3. 因为上一步调用了render,所以会进入*render + 4. *render里面调用了view,view里面执行具体的页面内容设置,包括body,请求头,等信息 + + + + + + + +完整的流程如下: + 首先初始化的时候require了route.js,执行了里面的router文件夹里面的index.js,因为route.js对所有的页面都执行了一边请求,所以每个页面都执行到了router里面的index.js文件里面的getController之前【有个yield】;下一次客户端请求,就会根据路由,继续执行里面对应的controller【每个页面的controller平时都处于监听状态,只要由请求发过来,就继续执行】, + 最后再controller里面执行业务逻辑,执行render,这个render是router文件夹下index.js里面的render, + 而这个render又用到了lib下的views.js + + + + +服务端压缩:gzip,需要在html的header设置服务端输出的压缩类型,这样浏览器会获取到资源就能识别 diff --git a/app.js b/app.js new file mode 100644 index 0000000..dc0cac5 --- /dev/null +++ b/app.js @@ -0,0 +1,49 @@ +const config = require("./config") +const http = require("http") +const https = require("https") +const fs = require("fs") +const Koa = require("koa") +const middleware = require("./lib/middleware") +const app = new Koa() +const path = require("path"); +require("./routes/mapping.js");//引入路由,给每一个路由路径的页面设置回调函数,初始化路由 + + +/*这个里面用app.use来录入路由中间件,启动路由,这样每次访问页面, +都会经过路由,因为每次请求,都会把所有录入的中间件执行一遍*/ +middleware(app); + +app.on("error", (err, ctx) => { + if (ctx && !ctx.headerSent && ctx.status < 500) {//ctx.headerSent:检查 response header 是否已经发送,用于在发生错误时检查客户端是否被通知。 + console.log("ctx") + // console.log(ctx) + console.log(err) + ctx.status = 500; + } + if (ctx && ctx.log && ctx.log.error) { + if (!ctx.state.logged) { + ctx.log.error(err.stack); + } + } +}); + + + +const { + PORT, + HTTPS_PORT, + HOST_ADDRESS +} = config +const host = app.callback() + +http.createServer(host).listen(PORT, HOST_ADDRESS); +console.log(`app start at: http://${HOST_ADDRESS}:${PORT}`); + +if (config.enableHTTPS) { + const httpsOptions = { + key: fs.readFileSync('cert/server.key'), + cert: fs.readFileSync('cert/server.crt') + } + https.createServer(httpsOptions, host).listen(HTTPS_PORT, HOST_ADDRESS); + console.log(`app start https at: https://${HOST_ADDRESS}:${HTTPS_PORT}`); +} \ No newline at end of file diff --git a/cert/server.crt b/cert/server.crt new file mode 100644 index 0000000..e69de29 diff --git a/config.js b/config.js new file mode 100644 index 0000000..889ceaa --- /dev/null +++ b/config.js @@ -0,0 +1,105 @@ +// config文件的原则是,把所有环境相关和全局用到的静态数据,放到里面,主要是为了配置不同环境的切换 +//目前只有dev环境和yz环境以及prod,qa没用到,因为个人站点不需要,yz模仿线上测试,yz环境的所有node配置和线上都相同,只有数据库是yz的数据库;如果走正常的公司发布,那还需要给yz设置特定的静态资源的url +// 但目前yz环境是再本地开发地址下检测,所以yz要和prod保持所有的数据都相同,只有数据库不同 +var env = process.env,pkg = require("./package.json"); +var NODE_ENV = env.NODE_ENV || 'prod',path = require("path"); + +var combine={ + dev:{ + enableHTTPS: false,//是否启用https + logFilePath: './log/main.log',//设置日志存储路径 + staticPath: "/static/latest",//这个是静态资源的重置路径,dev环境用不到,dev下放这个变量只是为了防止js报错 + staticServer: "//localhost:8080"//dev环境静态资源服务器 + }, + qa:{ + staticPath: "/static/latest",//这个是静态资源的重置路径 + staticServer: "//qares.jeffrey.cn" + }, + yz:{ + staticPath: "/static/latest",//这个是静态资源的重置路径 + staticServer: "" + }, + prod:{ + staticPath: "/static/latest",//这个是静态资源的重置路径,通过修改这个,修改这里可以实现线上的前端代码的回滚,在staticResourceMappingPath变量和middleware的index中都有用到 + staticServer: ""//因为静态资源和node在同一个服务器,所以用相对路径,不需要重新设置,staticServer用于html文件里面的静态资源的mapping替换时候的前缀 + } +} + +var config={ + "PORT": env.PORT || "10129",//应用的HTTP服务端口 + "HTTPS_PORT": env.HTTPS_PORT || "4124",//应用的HTTPS服务端口 + "HOST_ADDRESS": env.HOST_ADDRESS || (NODE_ENV=="dev"?"localhost":"0.0.0.0"),//服务器机器名,dock下不能用localhost,要用0.0.0.0表示服务器,否则会导致浏览其无法访问docker中的node程序 + "NODE_ENV": NODE_ENV,//当前的环境,分为 dev qa yz prod(production) + enableHTTPS: false,//是否启用https + enableHTMLCompress: env.ENABLE_HTTP_COMPRESS || true,//是否启用压缩的HTTP内容。 采用html-minifier组件进行压缩 + warning: {//设置API的报警阀值为200ms, 意思是当调用API获取数据的时候,超出了200ms,则会写入warning日志 + api: 200 + }, + logFilePath: '/home/logs/' + pkg.name + '/logstash/logstash.log',//设置日志存储路径 + staticResourceMappingPath: env.STATIC_RESOURCE_MAPPING_PATH || path.resolve(__dirname, "."+combine.prod.staticPath+"/assets-mapping.json"),//设置静态资源映射文件的路径。 + host: env.HOST,//环境的host + apiServer: '',//node端请求java的api基础地址,在proxy中用到,用于处理跨域问题 + auth: { + key: "",//服务端动态码,给未登录游客的, + secret: "jeffreychen",//jwt的密钥,用于token数据的加签和解签,jwt不是加密,所以不能放私密数据; + deviceId: "", + shaKey:"jeffrey"//sha256加密的key,不允许修改,一旦修改,数据库的密码就会全部对不上号,其实也没必要修改,sha256加密是不可逆的,就算别人知道了这个key,也没用 + }, + + /* + desc:数据库连接和超时设置 + local数据库,从名字可以看出,它只会在本地存储数据,即local数据库里的内容不会同步到副本集里其他节点上去;目前local数据库主要存储副本集的配置信息、oplog信息,这些信息是每个Mongod进程独有的,不需要同步到副本集种其他节点。 + 在使用MongoDB时,重要的数据千万不要存储在local数据库中,否则当一个节点故障时,存储在local里的数据就会丢失。 + + 集群只有一台数据库服务器的时候,那一台会自动变成secondary[次要],没有primary服务器,无法解决数据请求 + 集群有超2台数据库服务器,就会自动选一台作为iprimary,任何一台坏了,其他的自动接替primary角色 + 任意一台数据改变,其他数据库服务器都会自动同步 + mongodb的数据库连接URI规则:mongodb://[username:password@]host1[:port1][,...hostN[:portN]]][/[database][?options]] + retryWrites=false必须设置,否则数据写入会失败; + replicaSet=mySet表示集群uri,mySet是集群的名称,可以在集群中执行rs.status()查看集群详细信息 + */ + db:{ + dev:{ + dbURI:"mongodb://127.0.0.1:27017,127.0.0.1:27001,127.0.0.1:27002/gpclubs?retryWrites=false&replicaSet=mySet", + timeout:3000 + }, + qa:{ + dbURI:"mongodb://0.0.0.0:27017,0.0.0.0:27001,0.0.0.0:27002/gpclubs?retryWrites=false&replicaSet=mySet", + timeout:3000 + }, + yz:{ + dbURI:"mongodb://gpyz:123456@database:27017/gpclubs?retryWrites=false", + timeout:3000 + }, + prod:{//生产环境连接的是docker,docker默认访问网址是0.0.0.0,这样才能和docker外面的数据库通信 + // dbURI:"mongodb://gp:Z103496out@192.168.101.10:27017/gpclubs?retryWrites=false",//因为docker容器中我用了bridge的网络模式,每个容器都有一个ip,需要通过ip访问【前提是ip要设置静态ip】 + // dbURI:"mongodb://127.0.0.1:27017/gpclubs?compressors=disabled&gssapiServiceName=mongodb", + + // dbURI:"mongodb://gp:Z103496out@database:27017/gpclubs?retryWrites=false",//因为docker容器中我用了bridge的网络模式,每个容器都有一个ip,需要通过ip访问,但ip是动态的,所以改用yml中的services的名称来访问database + dbURI:"mongodb://gp:Z103496out@database:27017,database:27018,database:27019/gpclubs?retryWrites=false&replicaSet=mongoset",//因为docker容器中我用了bridge的网络模式,每个容器都有一个ip,需要通过ip访问,但ip是动态的,所以改用yml中的services的名称来访问database + // dbURI:"mongodb://gpyz:123456@database:27017/gpclubs?retryWrites=false", + timeout:3000 + } + }, + + + session: {//服务端发送html给客户端的时候,将session的key和对应的value保存在cookie中一起发出 + key: 'sessionId', //cookie key (default is koa:sess), + maxAge: 86400000, // cookie的过期时间 maxAge in ms (default is 1 days) + overwrite: true, //是否可以overwrite (默认default true) + autoCommit: true, // (boolean) automatically commit headers (default true) + httpOnly: false, //cookie是否只有服务器端可以访问 httpOnly or not (default true);客户端js无法访问 + signed: false, //签名默认true : 这个是天坑,设置signed: true后,它就会寻找req.secret(一个秘钥字符串),进行加密 allen返回浏览器;,最后导致cookie代码中的keys报错 + //解决办法:需要在middleware的index.js中,设置app.keys = ['密钥'];跳过cookie中的密钥相关逻辑 + rolling: false, //在每次请求时强行设置cookie,这将重置cookie过期时间(默认:false) + renew: false, //(boolean) renew session when session is nearly expired, + // secure: true,//只有https请求才能访问获取这个cookie,如果时http就无法访问这个cookie + + // 设置了Strict或Lax以后,基本就杜绝了 CSRF 攻击。当然,前提是用户浏览器支持 SameSite 属性。 + sameSite: "Lax"//Strict:防止CSRF 攻击,完全禁止第三方 Cookie,跨站点时,任何情况下都不会发送 Cookie,但用户体验不好。换言之,只有当前网页的 URL 与请求目标一致,才会带上 Cookie + //strict的话,从本地的a链接跳转到其他站点,这个站点用户本来就已经登陆过了,从你这边跳过去,还得重新登录;但cookie有多个,有的可以带有的可不带,登录的cookie必须用Strict + // Lax:则稍稍放宽,大多数情况也是不发送第三方 Cookie,但是导航到目标网址的 Get 请求除外。 + } +} + +module.exports = Object.assign({}, config, combine[NODE_ENV]); \ No newline at end of file diff --git a/controllers/ajax.js b/controllers/ajax.js new file mode 100644 index 0000000..6bc173c --- /dev/null +++ b/controllers/ajax.js @@ -0,0 +1,763 @@ + +const KidsClassService=require("../models/index.js");//获取公共地址信息(全国的省,市,区)【目前只在node请求省的信息,市和区放在客户端请求】 +const paramsUtil = require("../lib/util.js"); +const config = require("../config"); +const svgCaptcha = require('svg-captcha'); +const uuid = require('uuid/v4'); //不会重复,业内通用 +const requestIp = require('request-ip'); +const jsonwebtoken = require('jsonwebtoken'); +const auth=require("../lib/middleware/auth.js"); +let Model = require("../models/index.js"); +let pModel = require("../models/personal.js"); +const base64url = require('base64url'); +const formidable = require('formidable');//图片上传插件 +const fs = require("fs"); +const path = require("path"); +const utilJs= require("../lib/util.js"); + +/*后台权限验证: + 1.是否登录:登录态验证 + 2.是否是私人资料:验证修改的资料在登录态用户的名下 + 3.数据是否有独立的权限系统:某些数据设置独立的可访问白名单,名单之外的任何人都无法访问这个数据【作者除外】*/ +module.exports = { + + //添加文章的标签或删除标签:这个有个概念特别重要,需要验证后台登录态的uid和前端传过来的资源的id关联 + //以确保被操做的数据是“当前登录态的用户”的私人资料,只验证一个登录态,那我知道了别人文章的id, + // 然后直接操作别人的文章下的内容或标签,就越权了。 + // add_article_tag:function *(scope) { + // if(scope.isLogin){ + // var uid=scope.jwtData.id;//后端登录态的下的用户的uid + // var model = new Model(); + // var {articleId,isAdd,inputValue,tagId=null}= this.request.body; + // var JSONData={}; + // yield model.verifyArticleRight.bind(this)({uid,articleId} ,scope); + // if(scope.status&&scope.mongoData&&scope.mongoData.length){ + // yield model.setArticleTag.bind(this)({articleId,isAdd,inputValue,tagId} ,scope); + + // if(scope.status&&scope.mongoData){ + // JSONData = {data:"",state:1,status:200,msg:""}; + // }else{ + // JSONData = {data:"",state:0,status:200,msg:"操作标签失败"}; + // } + // }else{ + // JSONData = {data:"",state:0,status:200,msg:"您没有操作权限"}; + // } + + // }else{ + // JSONData = {data:"",state:0,status:200,msg:"请先登录"}; + // } + + // yield this.renderJSON(JSONData);//响应ajax请求,就是把数据放到response.body上 + // }, + + //修改密码 + modify_pwd:function *(scope) { + var model = new pModel(); + var {oldPwd,newPwd,id}= this.request.body; + id=id?base64url.decode(decodeURIComponent(id)):null; + var JSONData={}; + var isSelf=(id==scope.jwtData.id)?true:false; + var IP = requestIp.getClientIp(this.req); + var ua = this.header["user-agent"]; + var phoneNum; + if(scope.isLogin&&isSelf){ + yield model.changePassward.bind(this)({oldPwd,newPwd,id} ,scope); + + if(scope.status){ + JSONData = {data:"",state:1,status:200,msg:"修改密码成功"}; + phoneNum=scope.mongoData?scope.mongoData.phone:""; + auth.addToken.bind(this)({phoneNum , IP , ua , id});//更新token + }else{ + JSONData = {data:"",state:0,status:200,msg:scope.errorMsg}; + } + }else{ + JSONData = {data:"",state:0,status:200,msg:"修改失败,请重新登录再修改密码"}; + } + + + yield this.renderJSON(JSONData);//响应ajax请求,就是把数据放到response.body上 + }, + + article_tag_info:function *(scope) { + // var uid=scope.jwtData.id;//后端登录态的下的用户的uid + var model = new Model(); + var {articleId}= this.request.body; + var JSONData={}; + var rstArr=[]; + yield model.getArticleTag.bind(this)({articleId} ,scope); + if(scope.status&&scope.mongoData){ + (scope.mongoData||[]).forEach(function({_id,content}) { + rstArr.push({_id,content}); + }) + JSONData = {data:{tags:rstArr},state:1,status:200,msg:""}; + }else{ + JSONData = {data:"",state:0,status:200,msg:scope.errorMsg||"获取标签失败"}; + } + + yield this.renderJSON(JSONData);//响应ajax请求,就是把数据放到response.body上 + }, + + //收藏或取消收藏文章 + add_article_collect:function *(scope) { + if(scope.isLogin){ + var model = new Model(); + var {articleId,uid,isAdd} = this.request.body; + uid=uid?base64url.decode(decodeURIComponent(uid)):null; + var JSONData={}; + yield model.setArticleCollect.bind(this)({articleId,uid,isAdd} ,scope); + + if(scope.status&&scope.mongoData){ + var {collect}=scope.mongoData.linkUser; + JSONData = {data:{collect},state:1,status:200,msg:""}; + }else{ + JSONData = {data:"",state:0,status:200,msg:scope.errorMsg||"收藏文章失败"}; + } + }else{ + JSONData = {data:"",state:0,status:200,msg:"请先登录"}; + } + + yield this.renderJSON(JSONData);//响应ajax请求,就是把数据放到response.body上 + }, + + //添加文章点赞或取消点赞 + add_article_fav:function *(scope) { + if(scope.isLogin){ + var model = new Model(); + var {articleId,uid,isAdd} = this.request.body; + uid=uid?base64url.decode(decodeURIComponent(uid)):null; + var JSONData={}; + yield model.setArticleFav.bind(this)({articleId,uid,isAdd} ,scope); + + if(scope.status&&scope.mongoData){ + var {fav}=scope.mongoData.linkUser; + JSONData = {data:{fav},state:1,status:200,msg:""}; + }else{ + JSONData = {data:"",state:0,status:200,msg:scope.errorMsg||"点赞失败"}; + } + }else{ + JSONData = {data:"",state:0,status:200,msg:"请先登录"}; + } + + yield this.renderJSON(JSONData);//响应ajax请求,就是把数据放到response.body上 + }, + + //关注某人 + add_user_attention:function *(scope) { + + if(scope.isLogin){ + var model = new Model(); + var {authorId,uid,isAdd} = this.request.body; + uid=uid?base64url.decode(decodeURIComponent(uid)):null; + var JSONData={}; + yield model.setUserAttention.bind(this)({authorId,uid,isAdd} ,scope); + if(scope.status&&scope.mongoData){ + var {linkUser}=scope.mongoData; + JSONData = {data:{linkUser},state:1,status:200,msg:""}; + }else{ + JSONData = {data:{},state:0,status:200,msg:scope.errorMsg||"关注失败"}; + } + }else{ + JSONData= {status:200,msg:"请先登录",data:{},state:0}; + } + + + + + yield this.renderJSON(JSONData);//响应ajax请求,就是把数据放到response.body上 + }, + + //搜索 + search:function *(scope) { + var model = new Model(); + var {uid,searchInfo} = this.request.body; + uid=uid?base64url.decode(decodeURIComponent(uid)):null; + var JSONData={},rstArr=[]; + var {type,val}=searchInfo; + var rstData={}; + yield model.searchInfoList.bind(this)({uid,searchInfo} ,scope); + + if(scope.status&&scope.mongoData&&scope.mongoData.length){ + rstArr=scope.mongoData; + if(type=="user"){ + rstData={user:rstArr}; + }else if(type=="article"){ + rstData={article:rstArr[0],articleInTags:rstArr[1]}; + }else if(type=="all"){ + rstData={user:rstArr[0],article:rstArr[1],articleInTags:rstArr[2]}; + } + JSONData = {data:rstData,state:1,status:200,msg:""}; + }else{ + JSONData = {data:[],state:0,status:200,msg:scope.errorMsg||"没查到相关人或相关信息"}; + } + + yield this.renderJSON(JSONData);//响应ajax请求,就是把数据放到response.body上 + }, + + //评论点赞 + add_comment_fav:function *(scope) { + if(scope.isLogin){ + var model = new Model(); + var {cid,uid,isAdd} = this.request.body; + uid=uid?base64url.decode(decodeURIComponent(uid)):null; + var JSONData={}; + yield model.setCommentFav.bind(this)({cid,uid,isAdd} ,scope); + + if(scope.status&&scope.mongoData){ + var _id=scope.mongoData._id; + var {fav}=scope.mongoData.linkUser; + JSONData = {data:{fav,_id},state:1,status:200,msg:""}; + }else{ + JSONData = {data:[],state:0,status:200,msg:scope.errorMsg||"点赞失败"}; + } + }else{ + JSONData = {data:[],state:0,status:200,msg:"请先登录"}; + } + + yield this.renderJSON(JSONData);//响应ajax请求,就是把数据放到response.body上 + }, + + + //单独文章查询:有个权限设置linkUser.accessViewUser可查看人员; + // linkUser.accessCommentUser:可评论人员 + //如果没有uid且isLogin为false,那就是未登录,就不需要做uid的逻辑 + article_info:function *(scope) { + var model = new Model(); + var {id,uid,needAccess=false} = this.request.body; + uid=uid?base64url.decode(decodeURIComponent(uid)):null; + var JSONData={}; + yield model.getArticleListById.bind(this)({id,uid,needAccess} ,scope); + var articleData=scope.mongoData?scope.mongoData[0]:null; + scope.mongoData=null; + + if(articleData){ + var {_id,time,title,content,tag,linkUser,linkComment,category,level,personInfo}=articleData; + var commentList=[]; + //寻找这个和这个文章id关联,且categroy为2的comment + yield model.getCommentListByOrigin.bind(this)({_id:_id,category:"2"} ,scope); + if(scope.mongoData){//存在关联comment + commentList=scope.mongoData; + } + id=_id.toString(); + + /* + commentList中每一条,都包含repliedUserInfo:结构如下 + { id:1, + time:1, + content:1, + level:1, + linkUser:1, + linkOther:1, + linkOrigin:1, + personInfo:1, + repliedUserInfo:1 + } + */ + JSONData = {data:{id,time,title,content,tag,linkUser,linkComment,category,level,personInfo,commentList},state:1,status:200,msg:""}; + + }else{ + JSONData = {data:null,state:1,status:200,msg:scope.errorMsg||"未找对应文章"}; + } + + yield this.renderJSON(JSONData);//响应ajax请求,就是把数据放到response.body上 + }, + + + //添加文章评论 + add_article_comment:function *(scope) { + if(scope.isLogin){ + var model = new Model(); + var {uid,content,linkOrigin,linkOther} = this.request.body;//category,targetId,origin + uid=uid?base64url.decode(decodeURIComponent(uid)):""; + var JSONData={}; + + yield model.addComment.bind(this)({uid,content,linkOrigin,linkOther} ,scope); + + if(scope.mongoData&&scope.mongoData.length){ + var data=scope.mongoData; + var rstArr=[]; + data.forEach(function(item,idx) { + var {_id,time,content,level,linkUser,linkOther,linkOrigin,personInfo,repliedUserInfo}=item; + var id=_id; + //ObjectId在传给前端之前会自动调用toString()转成字符串 + rstArr.push({id,time,content,level,linkUser,linkOther,linkOrigin,personInfo,repliedUserInfo}); + }); + JSONData = {data:rstArr,state:1,status:200,msg:""}; + }else{ + JSONData = {data:"",state:0,status:200,msg:scope.errorMsg||"评论失败"}; + } + }else{ + JSONData = {data:"",state:0,status:200,msg:"请先登录再评论"}; + } + yield this.renderJSON(JSONData);//响应ajax请求,就是把数据放到response.body上 + }, + + //个人文章list请求 + person_article_list:function *(scope) { + var model = new Model(); + var {id,isPassVerify=0} = this.request.body; + id=base64url.decode(decodeURIComponent(id)); + var JSONData={}; + if(scope.isLogin||isPassVerify){//isPassVerify字段表示不需要鉴权,直接通过;因为在别人的个人中心查看对方文章的时候,是不需要验证登录态的 + yield model.getUserArticleList.bind(this)({id} ,scope); + if(scope.mongoData&&scope.mongoData.length){ + var data=scope.mongoData; + var rstArr=[]; + data.forEach(function(item,idx) { + var {id,time,title,content,tag,linkUser,linkComment,categroy,level}=item; + rstArr.push({id,time,title,content,tag,linkUser,linkComment,categroy,level}); + }); + + JSONData = {data:rstArr,state:1,status:200,msg:""}; + }else{ + JSONData = {data:[],state:1,status:200,msg:scope.errorMsg||"未找到您的文章"}; + } + }else{ + JSONData= {status:200,msg:"请先登录",data:[],state:0}; + } + + yield this.renderJSON(JSONData);//响应ajax请求,就是把数据放到response.body上 + }, + + //个人收藏文章列表 + person_collection_list:function *(scope) { + var model = new pModel(); + var {id} = this.request.body; + var uid=scope.jwtData.id; + id=base64url.decode(decodeURIComponent(id)); + var JSONData={}; + if(id==uid){ + if(scope.isLogin){ + yield model.getUserCollectionList.bind(this)({id} ,scope); + if(scope.mongoData&&scope.mongoData.length){ + rstArr=scope.mongoData; + JSONData = {data:rstArr,state:1,status:200,msg:rstArr.length?"":"您还没收藏过文章"}; + }else{ + JSONData = {data:[],state:1,status:200,msg:scope.errorMsg||"未找到您的文章"}; + } + }else{ + JSONData= {status:200,msg:"请先登录",data:[],state:0}; + } + }else{//这里做权限处理,收藏列表是否设置个人隐私权限,后续在做,设置字段 + JSONData= {status:200,msg:"该用户关闭了他收藏文章的展示",data:[],state:0}; + } + yield this.renderJSON(JSONData);//响应ajax请求,就是把数据放到response.body上 + }, + + //用户粉丝列表 + person_fans_list:function *(scope) { + var model = new pModel(); + var {id,isPassVerify=0} = this.request.body; + id=base64url.decode(decodeURIComponent(id)); + var JSONData={}; + var isSelf; + if(scope.isLogin||isPassVerify){ + var uid=scope.jwtData?scope.jwtData.id:null;//如果请求的是别人页面,用id,如果请求的是自己的页面,用scope.jwtData.id + + //如果传过来的id是自己的id,就是查看自己的信息, + //如果是是别人的id,就是查看别人的信息;如果是查看别人的信息,得有权限筛选 + isSelf=(uid==id)?true:false; + yield model.getUserFansList.bind(this)({id} ,scope); + + if(scope.mongoData&&scope.mongoData&&scope.mongoData.length){ + var data=scope.mongoData[0].personInfo; + var rstArr=[]; + data&&data.forEach(function(item,idx) { + var {_id,userName,name,phone,userPic,linkUser,time}=item; + if(isSelf){ + rstArr.push({_id,userName,name,phone,userPic,linkUser,time}); + }else{ + rstArr.push({_id,userName,name,phone,userPic,linkUser,time}); + } + }); + JSONData = {data:rstArr,state:1,status:200,msg:""}; + }else{ + JSONData = {data:[],state:1,status:200,msg:scope.errorMsg||"您还没有粉丝"}; + } + }else{ + JSONData= {status:200,msg:"请先登录",data:[],state:0}; + } + + yield this.renderJSON(JSONData);//响应ajax请求,就是把数据放到response.body上 + }, + + //关注列表 + person_attention_list:function *(scope) { + var model = new pModel(); + var {id,isPassVerify=0} = this.request.body; + id=base64url.decode(decodeURIComponent(id)); + var JSONData={}; + var isSelf; + if(scope.isLogin||isPassVerify){ + var uid=scope.jwtData?scope.jwtData.id:null;//后端登录态的下的用户的uid + + //如果传过来的id是自己的id,就是查看自己的信息, + //如果是是别人的id,就是查看别人的信息;如果是查看别人的信息,得有权限筛选 + isSelf=(uid==id)?true:false; + yield model.getUserAttentionList.bind(this)({id} ,scope); + + if(scope.mongoData&&scope.mongoData&&scope.mongoData.length){ + var data=scope.mongoData[0].personInfo; + var rstArr=[]; + data&&data.forEach(function(item,idx) { + var {_id,userName,name,phone,userPic,linkUser,time}=item; + if(isSelf){ + rstArr.push({_id,userName,name,phone,userPic,linkUser,time}); + }else{ + rstArr.push({_id,userName,name,phone,userPic,linkUser,time}); + } + }); + JSONData = {data:rstArr,state:1,status:200,msg:""}; + }else{ + JSONData = {data:[],state:1,status:200,msg:scope.errorMsg||"您还没有关注别人"}; + } + }else{ + JSONData= {status:200,msg:"请先登录",data:[],state:0}; + } + + yield this.renderJSON(JSONData);//响应ajax请求,就是把数据放到response.body上 + }, + + //node端做的事情:1.路由,2.鉴权,3.请求webapi数据保存到html,4.seo相关页面的html得在node端做同构 + reigst_user: function *(scope) {//this.header中有请求头的所有数据 + var IP = requestIp.getClientIp(this.req); + var ua = this.header["user-agent"]; + var {phoneNum,passward,nickName} = this.request.body; + var tgObj={}; + if(nickName&&nickName.trim()){ + tgObj={passward:passward,phone:phoneNum,userName:nickName}; + }else{ + tgObj={passward:passward,phone:phoneNum,userName:uuid()}; + } + + tgObj=auth.xssEncode(tgObj);//防止xss攻击,把对应数据中的危险标签转译掉,服务端加密数据的防御 + //服务端未加密数据,直接在页面通用路径上用auth.xssEncode防御过了 + + var JSONData,repeatObj={},msg=""; + + model = new KidsClassService(); + + yield model.registUser(tgObj,scope); + + // scope.mongoData的数据结构[{id,_id,phone,userName,.......},...]数组, + // 或者{id,_id,phone,userName....}单一对象,所以要注意逻辑区分 + //其中id是字符串,_id是symbol对象,是数据库内真正的主键,所以查找的时候 + if(scope.status){//注册成功 + var {id,phone,userName,userPic}=scope.mongoData; + + JSONData= {status:200,msg:"注册成功",data:{id,phone,userName,userPic},state:1}; + + //设置jwt的token, + auth.addToken.bind(this)({phoneNum , IP , ua , id}); + + }else{//注册失败 + if(scope.mongoData){//因为手机号或者昵称重复 + var isNickNameRepeat=scope.mongoData.some(function(item) { + return item.userName==nickName + }); + var isPhoneRepeat=scope.mongoData.some(function(item) { + return item.phone==phoneNum + }); + msg=scope.errorMsg; + repeatObj={phone:(isPhoneRepeat?1:0),userName:(isNickNameRepeat?1:0)}; + repeatObj.userNameMsg=isNickNameRepeat?"昵称已被别人注册,不能重复;":""; + repeatObj.phoneMsg=isPhoneRepeat?"该手机号已经被注册过,不能重复":""; + JSONData= {status:200,msg:msg,data:repeatObj,state:0}; + }else{//其他数据库错误 + JSONData= {status:500,msg:scope.errorMsg,data:"",state:0}; + } + } + + + // this.json(JSONData); + //通过renderJSON插件已经把这个方法挂载到context上了 + yield this.renderJSON(JSONData);//响应ajax请求,就是把数据放到response.body上 + }, + + login: function *(scope) { + var model = new Model(); + var {phoneNum,passward,nickName,timeStamp} = this.request.body; + + yield model.checkUserInfo.bind(this)({phone:phoneNum,passward,timeStamp} ,scope); + if(scope.mongoData&&scope.mongoData.length){ + var data=scope.mongoData[0]||{}; + var {userName,name,phone,id,userPic,linkUser}=data; + var IP = requestIp.getClientIp(this.req); + var ua = this.header["user-agent"]; + var isLogin=true; + + //设置jwt的token, + auth.addToken.bind(this)({phoneNum , IP , ua ,id }); + yield this.renderJSON({data:{userName,name,phone,isLogin,userPic,linkUser},state:1,status:200,msg:"登录成功"}); + }else{ + yield this.renderJSON({data:{},state:1,status:501,msg:scope.errorMsg}); + } + + }, + + logout: function *(scope) { + var model = new Model(); + var {id} = this.request.body; + scope.isLogin=false; + this.cookies.set("u","",{maxAge:0}); + this.cookies.set("token","",{maxAge:0}); + yield this.renderJSON({data:{isLogin:scope.isLogin},state:1,status:200,msg:scope.errorMsg}); + + }, + + create_article: function *(scope) { + var model = new Model(); + var {title,content,id,tags} = this.request.body; + + if(scope.isLogin){//token验证通过 + yield model.addArticle.bind(this)({title,content,id,tags} ,scope); + if(scope.mongoData){ + var uid=id;//用户id保存到uid里面,后面用到的id是文章的id + var data=scope.mongoData||{}; + var {time,title,content,id}=data; + var isLogin=true; + var tagsBackData=scope.tagsData||[]; + if(scope.needTagsStatus&&scope.tagsStatus||scope.tagsStatus==false){//标签请求也成功 + yield this.renderJSON({data:{time,title,content,id,uid,isLogin,tags:tagsBackData},state:1,status:200,msg:"提交成功"}); + }else{//标签请求失败 + yield this.renderJSON({data:{time,title,content,id,uid,isLogin,tags:tagsBackData},state:2,status:200,msg:"文章提交成功,但文章标签添加失败"}); + } + }else{ + yield this.renderJSON({data:{},state:1,status:501,msg:scope.errorMsg||"提交失败"}); + } + }else{ + yield this.renderJSON({data:{isLogin:false},state:0,status:200,msg:"登陆状态过期,请重新登录"}); + } + + }, + + //获取个人信息 + user_info:function *(scope) { + var model = new Model(); + var {id} = this.request.body; + id=base64url.decode(decodeURIComponent(id)); + var JSONData={}; + var isSelf=(scope.jwtData&&(id==scope.jwtData.id))?true:false; + var JSONData={}; + if(scope.isLogin){ + if(isSelf){ + yield model.getUserInfo.bind(this)({_id:id},scope); + if(scope.mongoData&&scope.mongoData.length){ + var data=scope.mongoData[0]||{}; + var {_id,userName,name,phone,sex,age,userPic,linkUser,time,categroy}=data; + var isLogin=scope.isLogin; + JSONData={data:{_id,userName,name,phone,sex,age,userPic,categroy,linkUser,time,isLogin},state:1,status:200,msg:""} + }else{ + JSONData={data:null,state:1,status:501,msg:scope.errorMsg||"未获取到用户信息"} + } + }else{ + JSONData={data:null,state:0,status:200,msg:"不能获取他人的信息"} + } + }else{ + JSONData={data:null,state:0,status:200,msg:"请登录,如找不到右上角的登录按钮,请刷新页面"} + } + yield this.renderJSON(JSONData);//ajax请求都不用缓存 + }, + + //更新个人信息 + update_user_info:function *(scope) { + var model = new pModel(); + var {id,age,sex,phone,name,userName} = this.request.body; + id=id?base64url.decode(decodeURIComponent(id)):null; + var JSONData={}; + var isSelf=(id==scope.jwtData.id)?true:false; + if(scope.isLogin){ + if(isSelf){ + var tempObj={_id:id}; + if(age){ + tempObj.age=age; + } + if(sex){ + tempObj.sex=sex; + } + if(phone){ + tempObj.phone=phone; + } + if(name){ + tempObj.name=name; + } + if(userName){ + tempObj.userName=userName; + } + yield model.setUserInfo.bind(this)(tempObj,scope); + + if(scope.mongoData){ + var data=scope.mongoData||{}; + var {_id,userName,name,age,sex,phone,userPic,linkUser,time}=data; + JSONData={data:{_id,userName,name,age,sex,phone,userPic,linkUser,time},state:1,status:200,msg:""} + }else{ + JSONData={data:null,state:1,status:501,msg:scope.errorMsg||"更新失败,未查找到用户"} + } + }else{ + JSONData={data:null,state:0,status:200,msg:"不能获取他人的信息"} + } + }else{ + JSONData={data:null,state:0,status:200,msg:"请登录,如找不到右上角的登录按钮,请刷新页面"} + } + yield this.renderJSON(JSONData); + }, + + //登录用的动态码,双ajax来防止登录的重播攻击中的动态码ajax环节 + dynomic_code: function *(scope) { + var model = new Model(); + var {phoneNum} = this.request.body; + yield model.getUserInfo.bind(this)({phone:phoneNum},scope); + + if(scope.mongoData&&scope.mongoData.length){ + var data=scope.mongoData[0]||{}; + var {timeStamp}=data; + + yield this.renderJSON({data:{timeStamp},state:1,status:200,msg:"动态码获取成功"}); + }else{ + yield this.renderJSON({data:{},state:1,status:501,msg:scope.errorMsg||"登录失败"}); + } + + }, + + //请求方式:get + jsonp: function *(scope) { + let JSONPData= {status:200,msg:"JSONP成功",data:{}}; + let url=this.request.url; + let arr = url.match(/callback=([\w]{1,})/); + let callback=arr.length>1?arr[1]:""; + + yield this.renderJSONP(JSONPData,callback); + }, + + //svg图片验证码的ajax请求,图片中直接请求这个ajax地址,就可以返回对应的图片数据 + //请求方式:get + captcha: function *(scope) { + var captcha = svgCaptcha.create({ + inverse: false,// 翻转颜色 + fontSize: 36,// 字体大小 + noise: 2,// 噪声线条数 + width: 80,// 宽度 + height: 30// 高度 + }); + this.cookies.set("captcha",base64url.encode(captcha.text.toLowerCase()),Object.assign({},config.session,{sameSite:"",httpOnly:false})); + let data=String(captcha.data); + yield this.renderPicture(data); + }, + + //文件上传:黑名单【文件名包含特殊字符】+白名单验证【文件扩展名+MIME类型】;目录验证【不能用客户端变量设置目录路径,因为上传变量容易作弊;修改文件名和文件路径,不用前端传的变量】;检测文件内容[不用做,文件后缀名修改,就无法执行];size限制 + //包含木马的图片文件下载后,还需要在客户端用对应js执行解析,否则图片里面有木马,也没法执行 + //详见:https://www.cnblogs.com/bmjoker/p/8970006.html + //上传过程肯定是不会执行脚本的,所以只要把上传目录的权限拿掉,同时不用前端变量来设置保存路径,统一保存到那个没有权限的文件夹,这样服务端安全就可以保证,但是客户端那边下载文件就无法保证安全了,很麻烦 + // 漏洞的核心原因就是:文件的后缀名可以随意改,无法真正通过后缀去区分,文件内容检测首先是太麻烦,其次就是木马内容千变万化根本无法过滤干净 + // 最牛的木马植入:首先拿一张正常图片,然后植入木马,然后用00方式截断上传,比如文件名称为1.php.0x00.jpg,服务端获取到它是jpg类型文件,图片内容也是正常图片【其实里面植入了木马】, + /*很多服务器有截断漏洞,遇到到0x00,直接会忽略后面的字段【包括0X00】,所以获取文件的时候,文件名自动变成了1.php,是可执行文件,这一步,直接用截断绕过后缀检测,植入图片绕过图片内容检测 + 然后就是通过文件名的设置,把文件放到具有执行权限且浏览器可访问的文件夹下,那么接下来就可以通过访问浏览器来访问服务端,访问服务端的时候就触发服务端的那个植入的可执行文件,最终黑掉服务器。 + “0x00” 和 “%00”最终都是同一个原理,都代表着 chr(0) ,即空字符*/ + + upload: function *(scope) { + var isOverSize=true,msg="",isInWhiteList=false,isInBlackList=true; + var uid=scope.jwtData.id;//后端登录态的下的用户的uid + var pic,ext,match; + var ctx=this; + var regExp=/[\d\D]*\.([\w]{3,4})/g; + var promise,JSONData,state; + const whiteList=[["image/png","png"],["image/jpg","jpg"],["image/gif","gif"],["image/jpeg","jpeg"]]; + const blackList=[".php",".jsp",".net",".asp",".aspx",".js","eval(","0x00","%00"]; + const maxSize=512000; + var dirPath="../static/upload/"+uid; + var transPath=path.join(__dirname,dirPath); + var rstFileName=""; + var isExist=fs.existsSync(transPath); + if(!isExist){ + fs.mkdirSync(transPath,"0644");//0777是读写和执行权限 + + // 0755->即用户具有读/写/执行权限,组用户和其它用户具有读写权限; + // 0644->即用户具有读写权限,组用户和其它用户具有只读权限; + // 0666->即用户,组用户和其它用户具有读写权限; + // 0777->即用户,组用户和其它用户具有读/写/执行权限; + } + // else{ + // // var tempPath=path.join(__dirname,dirPath+"/user_image.jpeg"); + // // if(fs.existsSync(tempPath)){ + // // fs.rmSync(tempPath); + // // } + // } + + //uploadDir是相对于文件更目录的,目录千万别写错了 + const form = formidable({uploadDir:"./static/upload/"+uid, keepExtensions: true,maxFileSize: maxSize,filter:function({originalFilename,mimetype,size}) { + match=regExp.exec(originalFilename); + ext=(match&&match.length==2)?match[1]:null; + + isInWhiteList=ext&&whiteList.some(function(item) { + return (item[0]==mimetype)&&(item[1]==ext) + }); + isInBlackList=ext&&blackList.some(function(item) { + return originalFilename.indexOf(item)!==-1 + }); + + if(isInWhiteList&&!isInBlackList){ + msg="" + }else{ + if(!isInWhiteList){ + msg="只能上传'png,jpg,gif,jpeg'类型的图片"; + } + if(isInBlackList){ + msg="图片名称中不能包含.php .jsp .asp .aspx .js 0x00 %00 eval(之类的字符"; + } + } + if(msg){ + return false; + }else{ + return true; + } + },filename:function({originalFilename,mimetype,size}){ + ext=(match&&match.length==2)?match[1]:null; + rstFileName=Date.now()+"user_image."+ext; + return rstFileName + }});//放到用户个人资料静态文件夹下 + + //解析form,把图片存放到uploadDir文件夹 + var promise=new Promise(function(resolve,reject) { + form.parse(ctx.req,function(err,fields,files) { + if(err){ + reject(err); + }else{ + var regp=/default\.png/g; + var tempOriginPicPath=path.join(__dirname,"../static"+fields.originImagUrl); + if(fs.existsSync(tempOriginPicPath)&&!regp.test(tempOriginPicPath)){ + fs.rm(tempOriginPicPath,{force:true},function(err){}); + } + resolve(fields,files) + } + }); + return + }) + yield promise.then(function(fields,files) { + },function(err) { + msg="图片解析失败" + }); + + var model = new pModel(); + var tempPicPath=`/upload/${uid}/${rstFileName}`; + yield model.setUserInfo.bind(this)({_id:uid,userPic:tempPicPath},scope); + + if(scope.mongoData){ + + var {userPic}=scope.mongoData||{}; + if(userPic){ + msg=""; + state=1; + }else{ + msg="图片上传失败" + state=0; + } + }else{ + state=0; + msg="图片上传失败"; + } + + JSONData={data:{userPic},state:state,status:200,msg:msg}; + yield this.renderJSON(JSONData); + + } + +}; \ No newline at end of file diff --git a/controllers/recommend.js b/controllers/recommend.js new file mode 100644 index 0000000..d18bd11 --- /dev/null +++ b/controllers/recommend.js @@ -0,0 +1,123 @@ +/* + @desc:所有html页面请求 + */ + +let paramsUtil = require("../lib/util.js"); +let Model = require("../models/index.js");//获取公共地址信息(全国的省,市,区)【目前只在node请求省的信息,市和区放在客户端请求】 +const base64url = require('base64url'); + +module.exports = { + + //node端做的事情:1.路由,2.鉴权,3.请求webapi数据保存到html,4.seo相关页面的html得在node端做同构 + react_demo: function* (scope) { + // paramsUtil.ensureAuthrized(scope, this);//鉴权,是否登录,未登录就跳转到登录页 + // let code = paramsUtil.getUrlParam(scope.url, 'code');//通过url后面的参数,解析成对应的param + // let cityInfo = yield new model(this).getCityInfo(code);//发送对应的node端请求,获取对应数据 + var cityInfo={}; + scope.outputWindowInfo = paramsUtil.outputWindowInfo({//把最终获取的数据,保存到scope + 'user': scope.userInfo, + cityInfo + }); + + yield this.render("react_demo");//渲染页面,跳转到views文件去渲染对应页面 + + }, + redux_demo: function* (scope) { + yield this.render("redux_demo"); + }, + + //scope挂在context.state下面,这里的this就是context,,所以this.state.scope=参数scope + home:function*(scope) { + var isLogin=false; + if(scope.isLogin){ + var {phoneNum , IP , ua}=scope.jwtData; + var data; + + model = new Model(); + + yield model.getUserInfo.bind(this)({phone:phoneNum},scope); + data=scope.errorMsg?{}:(scope.mongoData[0]||{}); + isLogin=(scope.mongoData&&scope.mongoData.length)?true:false; + var {userName,name,age,phone,sex,categroy,userPic,linkUser,linkChart,linkArticle,linkComment}=data; + scope.outputWindowInfo = paramsUtil.outputWindowInfo({//这个是页面登录态传送给前端的数据,不用再ajax获取 + userName,name,phone,isLogin,linkUser,userPic + });//用JSON.stringify转成字符串,这样输入到html页面,前端那边直接就能拿到对象 + + //xss攻击案例: + // scope.outputWindowInfo = paramsUtil.outputWindowInfo('` + }, + + + //所有页面的初始化数据输出函数 + outPutPublicInfo(obj){ + var transStr=encodeURIComponent(JSON.stringify(obj)); + return `` + }, + + deepColne(obj){ + + } + + +} + +// fs.exists:是否存在 +// fs.stat:检测是文件还是目录(目录 文件是否存在) + +// fs.mkdir:创建目录 (创建之前先判断是否存在) + +// fs.writeFile:写入文件(文件不存在就创建,但不能创建目录) + +// fs.appendFile:写入追加文件 + +// fs.readFile:读取文件 + +// fs.readdir:读取目录 + +// fs.rename:重命名 + +// fs.rmdir:删除目录 + +// fs.unlink:删除文件 \ No newline at end of file diff --git a/linux.readme b/linux.readme new file mode 100644 index 0000000..fe2f577 --- /dev/null +++ b/linux.readme @@ -0,0 +1,231 @@ +• ls: 列出目录 +• cd:切换目录 +• pwd:显示目前的目录 +• mkdir:创建一个新的目录 +• rmdir:删除一个空的目录 +• cp: 复制文件或目录 +• rm: 移除文件或目录 +• mv: 移动文件与目录、文件重命名 + +sudo +apt-get +netstat +kill +chmod +查询某个文件: find / |grep 文件包含的字母 + + + +vi/vim:用于新建,编辑,删除文本文件 +:q用于退出编辑,exit用于退出容器编辑 +yum:用于安装linux系统下的其他软件【是一个shell前端软件包管理器,类似于npm】 +• 1.列出所有可更新的软件清单命令:yum check-update +• 2.更新所有软件命令:yum update +• 3.仅安装指定的软件命令:yum install +• 4.仅更新指定的软件命令:yum update +• 5.列出所有可安裝的软件清单命令:yum list +• 6.删除软件包命令:yum remove +• 7.查找软件包 命令:yum search +• 8.清除缓存命令: +o yum clean packages: 清除缓存目录下的软件包 +o yum clean headers: 清除缓存目录下的 headers +o yum clean oldheaders: 清除缓存目录下旧的 headers +o yum clean, yum clean all (= yum clean packages; yum clean oldheaders) :清除缓存目录下的软件包及旧的headers + +学习资料:https://www.w3cschool.cn/linux/linux-shell.html +Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁 +Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务 +Shell 脚本(shell script),是一种为 shell 编写的脚本程序。 +Shell 编程跟 java、php 编程一样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了 +• Linux的shell种类众多,一般用Bourne Again Shell(/bin/bash),由于易用和免费,Bash 在日常工作中被广泛使用。同时,Bash 也是大多数 Linux 系统默认的 Shell。 +• Shell脚本可以用vim创建,后缀名是sh,就是shell的意思【但扩展名sh并不影响脚本的执行】 +• #!/bin/bash +echo "Hello World !" +• 第一行告诉系统用什么解释器来执行下面的代码,echo表示向窗口输出内容 + + + +Ubuntu下的相关命令:【我用腾讯云的版本是ubuntu 20.04 64-bit】 +curl:curl命令是个功能强大的网络工具,支持通过http、ftp等方式下载文件、上传文件。还可以用来抓取网页、网络监控等方面的开发,解决开发过程中遇到的问题 + curl命令参数很多,这里只列出我曾经用过、特别是在shell脚本中用到过的那些。 +-v/--verbose 小写的v参数,用于打印更多信息,包括发送的请求信息,这在调试脚本是特别有用。 +-m/--max-time 指定处理的最大时长 +-H/--header 指定请求头参数 +-s/--slient 减少输出的信息,比如进度 +--connect-timeout 指定尝试连接的最大时长 +-x/--proxy 指定代理服务器地址和端口,端口默认为1080 +-T/--upload-file 指定上传文件路径 +-o/--output 指定输出文件名称 +-d/--data/--data-ascii 指定POST的内容 +--retry 指定重试次数 +-e/--referer 指定引用地址 +-I/--head 仅返回头部信息,使用HEAD请求 + +apt-get:获取软件 + + +如何查看ubuntu的gnome-shell版本:gnome-shell –version 【gnome在3.28的版本之前有内存泄露问题】 + + + +查看端口占用情况:netstat -anp | grep 27017 +找到进程id后直接删除:sudo kill 进程号 +查看所有进程:ps -ef +查找名称包含某些字母的进程: ps -ef | grep 名称 +查找名称步包含某些字母的进程: ps -ef | grep -v 名称 +多重筛选,比如查找名称中不包含root和ubuntu的进程:ps -ef | grep -v root | grep -v ubuntu +查看当前用户:who或user或w +查看所有用户信息:grep bash /etc/passwd + + + + + + + + + +//----------------------linux权限问题 start------------------------- + +sudo su root进入root权限,输入exit退出 + + +详见:https://blog.csdn.net/A18373279153/article/details/78604174 + +可读、可写、可执行,分别用字母r、w、x表示;若该文件为目录则用d标志,否则用-标志。 + +ubuntu下查看权限的命令为: +ls -l filename +ls -ld folder +chmod 777 文件路径/文件名 :修改文件权限为777 +chmod -R 777 文件路径/文件名:修改文件权限以及这个文件下的所有子文件的权限都为777 + + + +所有的权限数字详见:https://blog.csdn.net/Yang_yangyang/article/details/120904833 +-r--------(400):所有制也只有只读权限 +-rw------- (600) 只有所有者才有读和写的权限 +-rw-r--r-- (644) 只有所有者才有读和写的权限,组群和其他人只有读的权限 +-rwx------ (700) 只有所有者才有读,写,执行的权限 +-rwxr-xr-x (755) 只有所有者才有读,写,执行的权限,组群和其他人只有读和执行的权限 +-rwx--x--x (711) 只有所有者才有读,写,执行的权限,组群和其他人只有执行的权限 +-rw-rw-rw- (666) 每个人都有读写的权限 +-rwxrwxrwx (777) 每个人都有读写和执行的权限 + +sudo chmod 600 ××× (只有所有者有读和写的权限) + +sudo chmod 644 ××× (所有者有读和写的权限,组用户只有读的权限) + +sudo chmod 700 ××× (只有所有者有读和写以及执行的权限) + +sudo chmod 666 ××× (每个人都有读和写的权限) + +sudo chmod 777 ××× (每个人都有读和写以及执行的权限) + +//----------------------linux权限问题 end------------------------- + + + + + +//-----------------------linux的图形界面安装 start---------------------- + + +Ubuntu在腾讯云安装图形界面【用ubuntu18.04版本,别用20版本,因为该系统软件不够用,同时会有各种软件不兼容的问题】: +//下面4步安装完后重启,就成功安装了ubuntu界面了,可以去web的vnc上登录查看,已经可以进入UI界面了【sudo su root进入root权限,因为有时候安装软件连sudo权限都不够】 +sudo apt-get update +sudo apt-get install xinit +sudo apt-get install gdm3 +sudo apt-get install ubuntu-desktop + +//接下来是修改配置文件 +修改ubuntu.conf配置文件,在文件尾加入两行: + +vi /usr/share/lightdm/lightdm.conf.d/50-ubuntu.conf + +[Seat:*] + +user-session=ubuntu + +greeter-show-manual-login=true + +allow-guest=false + +3.修改pam文件,分别注释/etc/pam.d/gdm-autologin跟/etc/pam.d/gdm-password中的两行内容 + +vi /etc/pam.d/gdm-autologin + +#%PAM-1.0 +auth requisite pam_nologin.so +#auth required pam_succeed_if.so user != root quiet_success + +vi /etc/pam.d/gdm-password + +#%PAM-1.0 + +auth requisite pam_nologin.so + +#auth required pam_succeed_if.so user != root quiet_success + +4.修改profile文件,修改最后一行 + +vi /root/.profile + +…… + +tty -s && mesg n || true + + +接下来是vnc界面搜索x11,安装X11VNC Server,然后launch,设置端口,设置连接帐号:注意,X1NVC Server是最容易装的,其他的vncserver,tightVnc什么的,网上没一个教程是对的,垃圾得要死 +设置好X11VNC Server的端口以后,不能勾选后面的ssl和listen on localhost;点击ok +然后又会出现一个勾选列表,必须要勾选Accept Connections,否则无法连接!!! +通过浏览器的vnc界面登录,然后安装X11VNC-server,设置好端口,这个端口必须在腾讯云的防火墙那边放行。 + +13、去https://www.realvnc.com/en/connect/download/viewer/下载realVNC软件,是一个exe文件,点开就可以用,不需要安装 +14、在 VNC Viewer 软件中,输入 云服务器的 IP 地址:5900,按 Enter,按步骤操作就可以访问了 + + + + +//通过上面的步骤,可以用在window上用VNC view来访问ubuntu的X11VNC Server软件,实现windows下远程访问ubuntu界面,但是没有加密,在上面的基础上,做一些修改,实现用putty软件的ssh访问X11VNC Server,从而实现ssh安全通道,保证数据安全 +详见:具体步骤https://blog.csdn.net/lakeside1/article/details/78350022 +前提: +1. ubuntu的ssh必须是开启的,最好先安装apt-get install openssh-server,然后执行/etc/init.d/ssh start来启动ssh服务【这个不一定有用,但是我是做了这个操作】 +2. X11VNC Server软件需要额外勾选listen on localhost,且端口和putty的Tunnels里面的端口保持一致,这里的 listen on localhost和端口号,和putty的Tunnels的数据保持一致,构建ssh通道; +Putty软件的Tunnels里面的destionation是127.0.0.1:5901是表示本地的监听地址,也就是本地vnc view软件访问这个地址,会直接映射到服务器地址;映射的服务器端口是Tunnels里面的Source port,映射的服务器地址是最上面的session里面的Host Name +Session里面的Host Name后面的port是ubuntu服务器端口,只是用于传递数据【这个端口必须是ubuntu防火墙允许的端口】,这个port和映射没有关系,只需要保证能让数据通过 +3. 本地的127.0.0.1:5901和127.0.0.1:1都可以访问到服务器,具体的访问流程是: +本地vncviewer访问127.0.0.1:5901 --> putty拦截127.0.0.1:5901-->本地putty通过Host Name :Tunnel和服务器构建ssh通道 --> VNCServers所在服务器的ssh通道接受数据然后转化解密数据--> VNCServer因为设置了监听localhost的5901端口,(127.0.0.1:5901),所以能第一时间获取解密数据 + + + +//-----------------------linux的图形界面安装 end---------------------- + +一般只需要用putty软件远程访问ubuntu【命令行界面,不是图形界面】,因为命令行界面占用内存只有600M,图形界面内存要多1G,我的服务器内存才2G +设置很简单,打开软件,session栏目【默认进入的就是这个界面】,输入远程的ip和22端口号【腾讯运上的防火墙开了22端口用于ssh远程访问】,点击open即可,输入帐号和密码 + + + + + + +一开始时打中介电话,对方说有房子,我不想表现得自己很急,所以就说过2天后去看,然后中介的套路来了,说有2个的商铺,一个已经被人交了定金没法看了,还剩一个商铺,次日早上也有人看, +因为我之前去踩过点,知道那边空出来的商铺很少,就一个勉强满意,但还没决定拿下,中介突然说出现一个新的房源,次日又有人去看,我当时就有点急了,因为如果不去,一旦对方说得是真的 +那么这个房子就真的可能没了,因为当时我也不知道那个房子的具体位置,要去了才知道,所以没法子,当天下午就火急火燎去了,知道很大概率是套路,但没法子。 +到了以后,我看了下感觉马马虎虎,但我爸觉得很不错,我妈看了也说只能拿下了,因为没有别的位子了,我对做生意也不了解,少数服从多数,那就定下来那个房子,接下来就是看怎么谈价格了, +然后接下来的坑开始了,因为这个中介基本是和商铺的房东联合在一起的,或者说这个中介太嫩了,被那个房东牵着鼻子走,我们决定和房东谈下,房东却和我们说他那边人不太方便过来,反转一堆借口, +这个时候我还没意识到中介和房东是联合在一起的,但现在想起来,当时他们就是联合在一起的,我们当天下午急着过去,如果中介没有和房东说的话,那房东就不会知道我们有点急,所以就不会用不方便这种借口来轻微地试探我们, +当时我们来都来了,再不去的话,每天有人看房,万一定了就很麻烦,所以冒着雨打车去了房东那边,到这里,已经错了两次了,第一个错误是当天下午过去,显得急切,第二个错误就是明明是房东应该过来,结果他却推脱让我们过去 +就是试探我们,我和我爸都被套路了,接下来到了房东那边,真正的套路开始了,房东说自己是开公司的老总,这边好几个产业都是他的,包括当时我们和他谈的那个场地也是他的,说网上可以查,这个的确没错,他的确是开着几家公司 +也是不缺钱的主,然后他说平时这些小事情都是他手下去办的,今天是中介来说,就当面和我们谈,然后中介也说的确是这个样子,中介和他合作好多次了,因为基于对正规的中介公司的信任,我也是看了下他的相关资料和个人详细, +基本上说得都没问题,但是一开始这么说,他的目的就是一个,侧面的意思就是提醒我们“合同的安全性没问题,我不差钱,我也很忙,你们要是太难搞我就不和你们扯了”,遇到这样的,我们就更加被动了,同时因为急着拿下来 +当时真的是昏了头了,脑子一热就定下来了,还交了一万的意向金,同时还约定了后续签合同,需要给转让费,押金,同时还得给中介一个月的服务费,虽然房租不贵,但是杂七杂八的费用太多了,然后再看到他的店铺还需要装修, +算上装修的钱以及装修期间不能营业的房租,那么出去房租,额外的费用高达20来万,回来以后我好纠结,主要还是我来拿主意,但是我真的对这种找商铺不在行,经验明显欠缺,我爸妈也是,一旦判断出错,就是起码30万以上的损失 +有人已经和我爸妈说过去那边做生意亏了60来万,当时就想着,签合同之前再讨价还价一下,能把转让费去掉,就直接签,否则就算了,意向金一万没了也就没了,总体下来感觉风险太大不值得冒险。 +当时和中介说,转让费免除,我们就可以签,让中介去和房东说,结果中介和房东沟通下来,说让我们直接过去,当面谈,因为之前毕竟已经说好了,的确是我们理亏,当时没想清楚,后来细细一想感觉不太好做, +但我们也有一万的押金作为成本,所以真正意义上也谈不上什么理亏,对方不同意我们也会失去押金 + + + + + diff --git a/models/baseModel.js b/models/baseModel.js new file mode 100644 index 0000000..3b7e400 --- /dev/null +++ b/models/baseModel.js @@ -0,0 +1,42 @@ +//mongoose是基于mongodb基础上的封装 +const sch= require('./schema.js'); +const hostUtil = require("../lib/util.js"); + +var {tagSchema,userSchema,articleSchema,commentSchema,chartSchema,defaultUser,defaultArticle,defaultComment,defaultChart,defaultTag}= sch; + +class BaseModel{ + + constructor(opts) { + this.opts = opts; + } + + //通过代理去获取中台的数据,这里已经不用了 + * fnClassJeffrey(param, origin) { + + //添加origin,为了让node支持自定义域名,一般不需要,但是测试环境下,后端接口还没开发完成,只能调用公共那边接口的时候,就需要这个参数 + let classJeffrey = origin || hostUtil.getClassJeffreyHost(this.ctx.request.header.host); + + if (param.url) { + param.url = `${classJeffrey}${param.url}`; + } else { + param = { url: `${classJeffrey}${param}` }; + } + + return yield this.ctx.proxy(param); + } + +} + +//静态属性 +BaseModel.UserSchema=userSchema; +BaseModel.ArticleSchema=articleSchema; +BaseModel.CommentSchema=commentSchema; +BaseModel.ChartSchema=chartSchema; +BaseModel.TagSchema=tagSchema; +BaseModel.defaultUser=defaultUser; +BaseModel.defaultArticle=defaultArticle; +BaseModel.defaultComment=defaultComment; +BaseModel.defaultChart=defaultChart; +BaseModel.defaultTag=defaultTag; + +module.exports = BaseModel; diff --git a/models/dbExample.js b/models/dbExample.js new file mode 100644 index 0000000..15a55ae --- /dev/null +++ b/models/dbExample.js @@ -0,0 +1,33 @@ +//初始化的时候,如何在docker中创建mongo的管理员 +1.docker exec -it gp-database mongo admin //数据库用户创建相关案例,在docker中进入容器后,执行下面命令可以创建对应的数据库管理帐号 +2.db.auth("jeffreychen","out103496") //[这个帐号密码是在yml文件中设置的auth帐号密码,需要db.auth()登录,才能添加管理员] +3.db.createUser({//创建超级管理员:clusterAdmin是超级管理员角色,readAnyDatabase是访问出了config和local数据库以外的所数据库的角色 + user: 'jeffreyadmin', + pwd: 'out103496Z', + roles: [{ + role: 'clusterAdmin', + db: 'admin' + },{ + role: 'readAnyDatabase',//出了local和config仓库,对其他任何仓库都有查看的权限【没有修改其他仓库的权限】 + db: 'admin' + },{ + role : 'readWrite', + db : 'config' + },{ + role : 'readWrite', + db : 'local' + }] +}) + +//注意,创建gpclubs下的管理员,必须要切到gpclubs下,否则这个帐号对gpclubs就是无效的;还有一点就是,use gpclubs切换到gpclubs,如果没有auth登录,还是无法创建, +//必须在admin仓库下用db.auth("jeffreychen","out103496")验证,然后再use gpclubs 进入gpclubs 仓库,然后再创建这个仓库的管理员 +use gpclubs + +db.createUser({ + user: 'gp', + pwd: 'Z103496out', + roles: [{ + role: 'readWrite', + db: 'gpclubs' + }] +}) \ No newline at end of file diff --git a/models/index.js b/models/index.js new file mode 100644 index 0000000..d3aacb8 --- /dev/null +++ b/models/index.js @@ -0,0 +1,1078 @@ +/* + @desc:首页的所有model请求,从数据库获取数据 + */ + +const BaseModel = require('./baseModel'); +const auth=require("../lib/middleware/auth.js"); +const mongoose=require("mongoose");//基于"mongodb"的封装,使用更加方便 +const util=require("../lib/util.js"); +// const affair=require("./affair.js"); +const Transaction = require("mongoose-transactions"); +const transaction = new Transaction(); +let session = null; +let config=require("../config.js"); +let envObj=config.db[config.NODE_ENV]; +let {dbURI,timeout}=envObj; +let timeOut={ + serverSelectionTimeoutMS: timeout//数据库连接超时设置,5000ms +}; + +//自定义,支持 findAndModify + + +/*@desc: + articleRecommend:默认推荐文章的评论数 + userRecommend:默认推荐的用户的粉丝数 + article:搜索关键词时,如果文章评论数超对应的值,就在里面搜索是否包含关键词,其他都不搜索,基数太大,需要筛选出热门的再去搜索 + comment:搜索关键词时,如果评论的回复数超对应的值,就在里面搜索是否包含关键词,其他都不搜索,基数太大,需要筛选出热门的再去搜索 +*/ +const hotDefine={article:0,comment:2,articleRecommend:1,userRecommend:1}; + + +//字符串转ObjectId: mongoose.Types.ObjectId(id); +//ObjectId转字符串:mongoose.Types.ObjectId(id).toString() +//mongodb数据库返回的id,默认就是_id的字符串,就是默认调用id=mongoose.Types.ObjectId(_id).toString() + + +//用JSON.parse(mongodb的_id);得到一个24位的字符串id:时间戳【8位】 机器id【6位】 进程id【4位】 计数器【6位】 +//mongodb返回的数据结构中_id就是唯一的id,而id就是_id的字符串格式,所以只需要用ObjectID(data._id)反序列化即可 +//用ObjectID(序列化的字符串):来实时ObjectId的反序列化 +//一般的序列化和反序列化,只要用js自带的JSON.stringify和JSON.parse即可 + + +//link相关字段下的很很多id,都需要用mongoose.Types.ObjectId转成ObjectId +//为了关联表级联的时候通过id来级联 + +class KidsClassService extends BaseModel{ + + constructor(self) { + super(); + this.ctx = self; + } + + + //搜索热门文章【综合推荐】:地下评论数超某个值,以这个位筛选条件,然后排序, + //优质复盘和优质技术贴,是在综合推荐的基础上,找出满足对于tag标签|关键词的文章 + * getHotArticle({articleId},scope) { + // let db=mongoose.connect(dbURI,timeOut); + // yield db.then(function(data) { + // articleId=articleId?mongoose.Types.ObjectId(articleId):articleId; + // //如果linkArticle数组里面的元素是对象,那么得用{$elemMatch:{key:value}}的格式,key表示对象里面需要满足条件的key;value就是key对应的value + // //使用promise,无法筛选字段,所以["_id","content"]或"_id ["_id","content"]"或{_id:1,content:1}都无法过滤字段 + // return BaseModel.TagSchema.find({linkArticle:{$elemMatch:{$eq:articleId}}},["_id","content"]); + + // },function(err){ + // scope.mongoData=null; + // scope.status=false; + // }).then(function(data) { + // scope.mongoData=data; + // scope.status=true; + // },function(err) { + // scope.mongoData=null; + // scope.status=false; + // }) + } + + + * getArticleTag({articleId},scope) { + let db=mongoose.connect(dbURI,timeOut); + yield db.then(function(data) { + articleId=articleId?mongoose.Types.ObjectId(articleId):articleId; + //使用promise,无法筛选字段,所以["_id","content"]或"_id ["_id","content"]"或{_id:1,content:1}都无法过滤字段 + + //如果linkArticle数组里面的元素是对象,那么得用{$elemMatch:{key:value}}的格式,key表示对象里面需要满足条件的key;value就是key对应的value + return BaseModel.TagSchema.find({linkArticle:{$elemMatch:{$eq:articleId}}},["_id","content"]); + + },function(err){ + scope.errorMsg="数据库连接出错"; + scope.mongoData=null; + scope.status=false; + }).then(function(data) { + if(scope.errorMsg){return} + scope.mongoData=data; + scope.status=true; + },function(err) { + scope.errorMsg="获取标签出错"; + scope.mongoData=null; + scope.status=false; + }) + } + + + + + //校验登录态用户是否有操作文章的权限【修改文章内容,标签,删除文章下的其他人的评论,删除文章等操作之前,需要校验】 + * verifyArticleRight({uid,articleId},scope) { + let db=mongoose.connect(dbURI,timeOut); + yield db.then(function(data) { + uid=uid?mongoose.Types.ObjectId(uid):uid; + articleId=articleId?mongoose.Types.ObjectId(articleId):articleId; + // {$push:{"linkUser.fav":uid}}表示向 linkUser.fav字段的数组中添加uid,如果是$addToSet表示添加唯一值 + //new设置为true,数据库更新后会返回最新的值 + //updateOne不会默认返回更新数据或元数据,要用 findOneAndUpdate 才能返回更新数据或原数据 + return BaseModel.ArticleSchema.find({_id:articleId,"linkUser.uid":uid}); + + // mongoose提供的findOneAndUpdate,默认返回原始的数据,需要将new属性设置为true,返回更新后的数据 + // mongoose中没有findAndModify方法. + },function(err){ + scope.errorMsg="数据库连接出错"; + scope.mongoData=null; + scope.status=false; + }).then(function(data) { + if(scope.errorMsg){return} + scope.mongoData=data; + scope.status=true; + },function(err) { + scope.errorMsg="查询文章内容出错"; + scope.mongoData=null; + scope.status=false; + }) + } + + + //收藏文章或取消收藏 + * setArticleCollect({articleId,uid,isAdd},scope) { + let db=mongoose.connect(dbURI,timeOut); + yield db.then(function(data) { + uid=uid?mongoose.Types.ObjectId(uid):uid; + articleId=articleId?mongoose.Types.ObjectId(articleId):articleId; + // {$push:{"linkUser.fav":uid}}表示向 linkUser.fav字段的数组中添加uid,如果是$addToSet表示添加唯一值 + //new设置为true,数据库更新后会返回最新的值 + //updateOne不会默认返回更新数据或元数据,要用 findOneAndUpdate 才能返回更新数据或原数据 + if(isAdd){ + return BaseModel.ArticleSchema.findOneAndUpdate({_id:articleId},{$addToSet:{"linkUser.collect":uid}},{new:true}); + }else{ + return BaseModel.ArticleSchema.findOneAndUpdate({_id:articleId},{$pull:{"linkUser.collect":uid}},{new:true}); + } + + // mongoose提供的findOneAndUpdate、findAndModify的两个方法,默认返回原始的数据,需要将new属性设置为true,返回更新后的数据 + },function(err){ + scope.errorMsg="数据库连接出错"; + scope.mongoData=null; + scope.status=false; + }).then(function(data) { + if(scope.errorMsg){return} + scope.mongoData=data; + scope.status=true; + },function(err) { + scope.errorMsg="收藏或取消收藏出错"; + scope.mongoData=null; + scope.status=false; + }) + } + + + //添加文章点赞或取消 + * setArticleFav({articleId,uid,isAdd},scope) { + let db=mongoose.connect(dbURI,timeOut); + yield db.then(function(data) { + uid=uid?mongoose.Types.ObjectId(uid):uid; + articleId=articleId?mongoose.Types.ObjectId(articleId):articleId; + // {$push:{"linkUser.fav":uid}}表示向 linkUser.fav字段的数组中添加uid,如果是$addToSet表示添加唯一值 + //new设置为true,数据库更新后会返回最新的值 + //updateOne不会默认返回更新数据或元数据,要用 findOneAndUpdate 才能返回更新数据或原数据 + if(isAdd){ + return BaseModel.ArticleSchema.findOneAndUpdate({_id:articleId},{$addToSet:{"linkUser.fav":uid}},{new:true}); + }else{ + return BaseModel.ArticleSchema.findOneAndUpdate({_id:articleId},{$pull:{"linkUser.fav":uid}},{new:true}); + } + + // mongoose提供的findOneAndUpdate、findAndModify的两个方法,默认返回原始的数据,需要将new属性设置为true,返回更新后的数据 + },function(err){ + scope.errorMsg="数据库连接出错"; + scope.mongoData=null; + scope.status=false; + }).then(function(data) { + if(scope.errorMsg){return} + scope.mongoData=data; + scope.status=true; + },function(err) { + scope.errorMsg="点赞或取消点赞出错"; + scope.mongoData=null; + scope.status=false; + }) + } + + //关注某人 + * setUserAttention({authorId,uid,isAdd},scope) { + let db=mongoose.connect(dbURI,timeOut); + yield db.then(() => mongoose.startSession()).then(function(_session ) { + session=_session; + uid=uid?mongoose.Types.ObjectId(uid):uid;//主动关注的那个人 + authorId=authorId?mongoose.Types.ObjectId(authorId):authorId;//被关注的那个人 + + session.startTransaction(); + scope.tempParam={uid,authorId,isAdd}; + + + if(scope.tempParam.isAdd){ + return BaseModel.UserSchema.findOneAndUpdate({_id:scope.tempParam.authorId},{$addToSet:{"linkUser.fans":scope.tempParam.uid}},{new:true,session:session}); + }else{ + return BaseModel.UserSchema.findOneAndUpdate({_id:scope.tempParam.authorId},{$pull:{"linkUser.fans":scope.tempParam.uid}},{new:true,session:session}); + } + + + // mongoose提供的findOneAndUpdate、findAndModify的两个方法,默认返回原始的数据,需要将new属性设置为true,返回更新后的数据 + },function(err){ + scope.errorMsg="数据库连接出错"; + scope.mongoData=null; + scope.status=false; + }).then(function(data) { + if(scope.errorMsg){return} + scope.transStatus="success"; + if(scope.tempParam.isAdd){ + return BaseModel.UserSchema.findOneAndUpdate({_id:scope.tempParam.uid},{$addToSet:{"linkUser.attention":scope.tempParam.authorId}},{new:true,session:session}); + }else{ + return BaseModel.UserSchema.findOneAndUpdate({_id:scope.tempParam.uid},{$pull:{"linkUser.attention":scope.tempParam.authorId}},{new:true,session:session}); + } + },function(err) { + scope.transStatus="error"; + scope.mongoData=null; + scope.status=false; + }).then(function(data) { + if(scope.transStatus=="success"){ + scope.transStatus="success"; + scope.mongoData=data; + scope.status=true; + return session.commitTransaction(); + }else{ + scope.mongoData=null; + scope.status=false; + scope.transStatus="error"; + return session.abortTransaction(); + } + },function(err) { + scope.mongoData=null; + scope.status=false; + scope.transStatus="error"; + scope.errorMsg="关注失败"; + return session.abortTransaction(); + }).then(function(data) { + return session.endSession(); + }); + } + + static getSearchFilter(val){ + var regExpVal,tagFilter,userFilter,commentFilter,articleFilter; + var dynomicCommentKey=`linkUser.comment.${hotDefine.comment}`;//评论的回复数量超 hotDefine.comment + var dynomicArticleKey=`linkUser.comment.${hotDefine.article}`;//文章评论数超 hotDefine.article + + regExpVal=new RegExp(`.*${val}.*`,"gi"); + tagFilter = {content:{$regex: regExpVal}};//标签中是否包含搜索词 + userFilter=[{userName:{$regex: regExpVal}}] ;//作者名称包含搜索词 + // userFilter=[{userName:{$regex: regExpVal}},{phone:{$regex: regExpVal}}] ;//作者名称或者手机号码中包含搜索词 + commentFilter={ + // "linkUser.comment":{$exists:1} + };//评论的回复数量超一定值【评论比较热门】,就搜索该评论内容中是否包含搜索关键词 + + //设置评论数一定的值,才能允许搜索文章内容,否则查询消耗太大 + //这里有一个搜索的bug,因为文章content保存的时候带入了html标签,所以查某些特殊字母是不准的 + //因为标签里面就有这些字母,所以需要前端做进一步的精确筛选,把标签删除后再匹配 + commentFilter[dynomicCommentKey]={$exists:1}; + commentFilter["content"]={$regex:regExpVal}; + + + //文章的评论数量超一定值【评论比较热门】,就搜索该评论内容中是否包含搜索关键词 + articleFilter=[{ + title:{$regex: regExpVal} + },{ + // "linkUser.comment":{$exists:1} + // "content":{$regex: regExpVal} + }]; + articleFilter[1][dynomicArticleKey]={$exists:1};//设置评论数一定的值的文章,才能允许搜索它的内容,否则查询消耗太大 + articleFilter[1]["content"]={$regex:regExpVal}; + + return {tagFilter,userFilter,commentFilter,articleFilter}; + } + + //搜寻后续要加权限验证和黑名单功能unfinish + * searchInfoList(opts,scope) { + let db=mongoose.connect(dbURI,timeOut); + yield db.then(function(data) { + var {searchInfo}=opts; + var uid=opts.uid?mongoose.Types.ObjectId(opts.uid):opts.uid; + var {type,val}=searchInfo; + var dynomicRecommendUserKey=`linkUser.fans.${hotDefine.userRecommend}`;//文章评论数超 hotDefine.article + var dynomicRecommendArticleKey=`linkUser.comment.${hotDefine.articleRecommend}`;//文章评论数超 hotDefine.articleRecommend + var userFilter=[],commentFilter=[],articleFilter=[],valArr=[]; + var userFilterArr=[],commentFilterArr=[],articleFilterArr=[],tagFilterArr=[]; + var initFilter=KidsClassService.getSearchFilter(val); + var tempFilter,tagFilter;//tagFilter千万别设置位数组,因为后面是通过if(tagFilter)来判断的,设置位数组会出错 + + + if(val.trim()){ + + //整体搜索 + tagFilterArr.push(initFilter.tagFilter); + commentFilterArr.push(initFilter.commentFilter); + userFilterArr=userFilterArr.concat(initFilter.userFilter); + articleFilterArr=articleFilter.concat(initFilter.articleFilter); + + //如果中间又空格,再分别搜索 + valArr=val.trim().split(" ").filter(function(item) {return (item||"").trim()}); + if(valArr.length>1){ + valArr.forEach(function(item) { + tempFilter=KidsClassService.getSearchFilter(item.trim()); + userFilterArr=userFilterArr.concat(tempFilter.userFilter); + articleFilterArr=articleFilterArr.concat(tempFilter.articleFilter); + commentFilterArr=commentFilterArr.concat(tempFilter.commentFilter); + tagFilterArr=tagFilterArr.concat(tempFilter.tagFilter); + }); + } + + //获得最终的搜索条件 + userFilter={$or:userFilterArr}; + articleFilter={$or:articleFilterArr}; + commentFilter={$or:commentFilterArr}; + tagFilter={$or:tagFilterArr}; + + + + }else{//查询内容为空,就返回推荐文章和推荐作者 + // userFilter={"linkUser.fans":{$exists:1}}; + userFilter={}; + userFilter[dynomicRecommendUserKey]={$exists:1}; + // articleFilter={"linkUser.comment":{$exists:1}}; + articleFilter={}; + articleFilter[dynomicRecommendArticleKey]={$exists:1}; + } + + + + if(type=="all"){ + + // BaseModel.CommentSchema.aggregate([{ + // $match:commentFilter + // },{ + // $lookup:{ + // from: "users",//需要连接的表名 + // localField: "linkUser.uid",//本表[articles表]需要关联的字段 + // foreignField: "_id",//被连接表需要关联的字段 + // as: "personInfo"//查询出的结果集别名 + // } + // },{ + // $project:{ + // time:1, + // content:1, + // personInfo:1 + // } + // }]), + + var allArr=[ + BaseModel.UserSchema.aggregate([{ + $match:userFilter + },{ + $sort:{level:-1} + },{ + $project:{ + userName:1, + phone:1, + userPic:1, + linkUser:1 + } + }]), + BaseModel.ArticleSchema.aggregate([{ + $match:articleFilter + },{ + $sort:{level:-1} + },{ + $lookup:{ + from: "users",//需要连接的表名 + localField: "linkUser.uid",//本表[articles表]需要关联的字段 + foreignField: "_id",//被连接表需要关联的字段 + as: "personInfo"//查询出的结果集别名 + } + },{ + $project:{ + time:1, + title:1, + content:1, + personInfo:1, + linkUser:1 + } + }]) + ]; + if(tagFilter){ + allArr.push(BaseModel.TagSchema.aggregate([{ + $match:tagFilter + },{ + $lookup:{ + from: "articles",//需要连接的表名 + localField: "linkArticle",//如果是数组,表示里面的每一项和foreignField的key关联 + foreignField: "_id",//被连接表需要关联的字段 + as: "articleInfo"//查询出的结果集别名 + } + },{ + $project:{ + content:1, + linkUser:1, + articleInfo:1 + } + }]) + ); + } + return Promise.all(allArr); + }else if(type=="user"){ + return BaseModel.UserSchema.aggregate([{ + $match:userFilter + },{ + $sort:{level:-1} + },{ + $project:{ + userName:1, + phone:1, + userPic:1, + linkUser:1 + } + }]); + }else if(type=="comment"){//查询回复超10个的评论 + //linkUser.comment存在且长度大于10【linkUser.comment.10表示linkUser.comment[10],如果它存在,那么长度肯定大于10】 + return BaseModel.CommentSchema.aggregate([{ + $match:commentFilter + },{ + $lookup:{ + from: "users",//需要连接的表名 + localField: "linkUser.uid",//本表[articles表]需要关联的字段 + foreignField: "_id",//被连接表需要关联的字段 + as: "personInfo"//查询出的结果集别名 + } + },{ + $project:{ + time:1, + content:1, + personInfo:1, + linkUser:1 + } + }]); + + + }else{//如果传的类型不对,按照文章查询:article + //标题包含查询字符,或者评论超20的文章的内容中包含这个字符 + var allArr=[ + BaseModel.ArticleSchema.aggregate([{ + $match:articleFilter + },{ + $lookup:{ + from: "users",//需要连接的表名 + localField: "linkUser.uid",//本表[articles表]需要关联的字段 + foreignField: "_id",//被连接表需要关联的字段 + as: "personInfo"//查询出的结果集别名 + } + },{ + $project:{ + time:1, + title:1, + content:1, + personInfo:1, + linkUser:1 + } + }]) + ]; + if(tagFilter){ + allArr.push( + BaseModel.TagSchema.aggregate([{ + $match:tagFilter + },{ + $lookup:{ + from: "articles",//需要连接的表名 + localField: "linkArticle",//如果是数组,表示里面的每一项和foreignField的key关联 + foreignField: "_id",//被连接表需要关联的字段 + as: "articleInfo"//查询出的结果集别名 + } + },{ + // $unwind : "$linkArticle" + // },{ + $project:{ + content:1, + linkUser:1, + articleInfo:1 + } + }]) + ); + } + + return Promise.all(allArr); + } + + },function(err){ + scope.errorMsg="数据库连接出错"; + scope.mongoData=null; + scope.status=false; + }).then(function(data) { + if(scope.errorMsg){return} + scope.mongoData=data; + scope.status=true; + },function(err) { + scope.mongoData=null; + scope.status=false; + }) + } + + //添加评论点赞 + * setCommentFav(opts,scope) { + let db=mongoose.connect(dbURI,timeOut); + yield db.then(function(data) { + var uid=opts.uid?mongoose.Types.ObjectId(opts.uid):opts.uid; + var cid=opts.cid?mongoose.Types.ObjectId(opts.cid):opts.cid; + var isAdd=opts.isAdd; + // {$push:{"linkUser.fav":uid}}表示向 linkUser.fav字段的数组中添加uid,如果是$addToSet表示添加唯一值 + //new设置为true,数据库更新后会返回最新的值 + //updateOne不会默认返回更新数据或元数据,要用 findOneAndUpdate 才能返回更新数据或原数据 + if(isAdd){ + return BaseModel.CommentSchema.findOneAndUpdate({_id:cid},{$addToSet:{"linkUser.fav":uid}},{new:true}); + }else{ + return BaseModel.CommentSchema.findOneAndUpdate({_id:cid},{$pull:{"linkUser.fav":uid}},{new:true}); + } + + // mongoose提供的findOneAndUpdate、findAndModify的两个方法,默认返回原始的数据,需要将new属性设置为true,返回更新后的数据 + },function(err){ + scope.mongoData=null; + scope.status=false; + scope.errorMsg="数据库连接出错"; + }).then(function(data) { + if(scope.errorMsg){return} + scope.mongoData=data; + scope.status=true; + },function(err) { + scope.mongoData=null; + scope.status=false; + scope.errorMsg="添加评论点赞出错"; + }) + } + + //通过Origin的category和targetId来寻找关联评论 + //例如传入{category:"2",targetId:文章id};就可以查询和这个文章下的所有评论 + // 具体如何关联,schema.js中看commentSchema的linkOrigin字段的内部解释 + * getCommentListByOrigin(opts,scope) { + let that=this; + let db= mongoose.connect(dbURI,timeOut);//返回promise + yield db.then(function(data) { + var {_id,category}=opts; + + //添加用户级联 + var filter=[{ + $match:{"linkOrigin.targetId":_id} + },{ + //含义:对上面match出的每条文档,去关联users表, + //关联条件是match的文档中linkUser.uid和users表中的_id相同,让文档合并 + // 合并文档以CommentSchema的机构为基础,增加personInfo字段来放关联文档内容 + $lookup:{ + from: "users",//需要连接的表名 + localField: "linkUser.uid",//本表[articles表]需要关联的字段 + foreignField: "_id",//被连接表需要关联的字段 + as: "personInfo"//查询出的结果集别名 + } + },{ + //级联被回复的评论的作者信息 + $lookup:{ + from: "users",//需要连接的表名 + localField: "linkOther.targetUserId",//本表[articles表]需要关联的字段 + foreignField: "_id",//被连接表需要关联的字段 + as: "repliedUserInfo"//查询出的结果集别名 + } + },{ + //这里只是举例,其实没必要,每个字段都会用到 + $project:{//_id是默认自带的,所以不需要添加到里面,其他都需要添加 + id:1, + time:1, + content:1, + level:1, + linkUser:1, + linkOther:1, + linkOrigin:1, + personInfo:1, + repliedUserInfo:1 + } + }]; + + + //用管道和级联 $lookup,实现筛选+多表合并 + return BaseModel.CommentSchema.aggregate(filter); + + + // 每个then里面的第一个function返回promise对象,实现链式调用 + },function(err){ + scope.mongoData=null; + scope.status=false; + scope.errorMsg="数据库连接出错"; + }).then(function(data) { + if(scope.errorMsg){return} + if(data){//索取所有关联到该文章下的评论列表[每条评论级联了对应的评论者信息] + scope.mongoData=data; + scope.status=true; + }else{ + scope.mongoData=null; + scope.status=false; + } + },function(err) { + scope.mongoData=null; + scope.status=false; + scope.errorMsg="获取评论信息出错"; + }) + } + + + + + //添加评论【category的类型不同,评论的类型也不同】 + // 需要同步到其他表,是事务,具有原子性,mongoose的事务插件是mongoose-transactions + //如果category=="2",添加的是文章的评论,同时也产生了点赞者和文章的关联, + // 需要给对应的文章的lingUser.comment添加信息 + * addComment(opts,scope) {//管道操作只用于查询数据和查询结果数据的修改,不涉及数据库修改 + debugger + let that=this; + let db= mongoose.connect(dbURI,timeOut);//返回promise + yield db.then(() => mongoose.startSession()).then(function(_session ) {//category,targetId,origin + debugger + //自己的查询参数和业务逻辑处理 + var {uid,content,linkOther,level="1",linkOrigin}=opts; + linkOther.targetId=linkOther.targetId?mongoose.Types.ObjectId(linkOther.targetId):linkOther.targetId; + linkOther.targetUserId=linkOther.targetUserId?mongoose.Types.ObjectId(linkOther.targetUserId):linkOther.targetUserId; + linkOrigin.targetId=linkOrigin.targetId?mongoose.Types.ObjectId(linkOrigin.targetId):linkOrigin.targetId; + uid=uid?mongoose.Types.ObjectId(uid):uid; + var originParam={ + time:+new Date(), + content:content, + level:level, + linkUser:{ + uid:uid//关联用户的id + }, + linkOther, + linkOrigin + }; + var commentParam=Object.assign({},BaseModel.defaultComment,originParam); + var articleParam=[{//找到_id为linkOther.targetId的文章,添加评论者id + _id:linkOther.targetId + },{ + $push:{"linkUser.comment":uid} + }]; + //因为article和comment的表设计的时候雷同,所以它们的参数一样,但还是得分开写 + var linkCommentParam=[{_id:linkOther.targetId},{$push:{"linkUser.comment":uid}}] + scope.tempParam={originParam,articleParam,linkCommentParam,commentParam}; + + + //使用说明:https://mongoosejs.com/docs/transactions.html + session = _session; + session.startTransaction();//开启 + //session.abortTransaction() 中断 + // session.commitTransaction()提交事务:一旦提交,事务就同步到数据库了 + // session.endSession() 停止 + //传入sesstion,是为了让在接下来的请求中,可以查到你对数据库的临时操作 + //否则的话你插入对数据库的操作都在事务的临时列表中,无法从数据库查到 + //只有commitTransaction以后,你的所有的操作,才会更新到数据库 + return BaseModel.CommentSchema.create([commentParam],{session}); + // new BaseModel.UserSchema({}).save()和BaseModel.UserSchema.create([{}]) + //创建的时候session传入方式和查询不同 + // BaseModel.CommentSchema.create([{ name: 'Test' }], { session: session }); + // return BaseModel.CommentSchema.findOne({ name: 'foo' }).session(session); + + + },function(err){ + scope.mongoData=null; + scope.status=false; + scope.errorMsg="数据库连接出错"; + }).then(function(data) {// + if(scope.errorMsg){return } + scope.transStatus="transCommentSuccess"; + var originParam=scope.tempParam.originParam + if(originParam.linkOther.category=="2"){//给对应文章添加评论人关联 + return BaseModel.ArticleSchema.findOneAndUpdate(scope.tempParam.articleParam[0],scope.tempParam.articleParam[1],{session:session,new:true}); + }else if(originParam.linkOther.category=="4"){//给对应评论添加评论人关联 + return BaseModel.CommentSchema.findOneAndUpdate(scope.tempParam.linkCommentParam[0],scope.tempParam.linkCommentParam[1],{session:session,new:true}); + } + + // return BaseModel.ArticleSchema.aggregate().session(session); + },function(err) { + scope.errorMsg="获取文章或评论信息出错"; + // 出错就终止事务 + scope.transStatus="transCommentError"; + return session.abortTransaction(); + }).then(function(data) { + if(scope.transStatus!="transCommentError"){ + return session.commitTransaction(); + }else{ + return session.abortTransaction(); + } + + },function(err) { + scope.transStatus="transArticleError"; + return session.abortTransaction(); + }).then((data) => { + // if(data.ok!="1"){ + // //事务失败的埋点 + // } + scope.transStatus="transactionSuccess"; + return session.endSession(); + },function(err) { + scope.transStatus="transactionFail"; + return session.endSession(); + }).then(function(data) { + if(scope.transStatus=="transactionSuccess"){//事务成功 + var {targetId}=scope.tempParam.originParam.linkOrigin; + // 如果category是1类型,targetId就是cid,源头是个人的说说 + // 如果category是2类型,targetId就是aid,源头是文章 + // 如果category是3类型,targedid就是uid,源头是别人的留言板 + // 如果category是5类型,targedid就是chartId,源头是图表 + + //用管道和级联 $lookup,实现筛选+多表合并 + return BaseModel.CommentSchema.aggregate([{ + // $match:{"linkOrigin":{targetId:targetId} 这样写是错误的,是全匹配的意思 + $match:{"linkOrigin.targetId":targetId}//指向这篇文章的所有评论 + + },{ + //含义:对上面match出的每条文档,去关联users表, + //关联条件是match的文档中linkUser.uid和users表中的_id相同,让文档合并 + // 合并文档以CommentSchema的机构为基础,增加personInfo字段来放关联文档内容 + $lookup:{ + from: "users",//需要连接的表名 + localField: "linkUser.uid",//本表[articles表]需要关联的字段 + foreignField: "_id",//被连接表需要关联的字段 + as: "personInfo"//查询出的结果集别名 + } + },{ + //级联被回复的评论的作者信息 + $lookup:{ + from: "users",//需要连接的表名 + localField: "linkOther.targetUserId",//本表[articles表]需要关联的字段 + foreignField: "_id",//被连接表需要关联的字段 + as: "repliedUserInfo"//查询出的结果集别名 + } + },{ + //这里只是举例,其实没必要,每个字段都会用到 + $project:{//_id是默认自带的,所以不需要添加到里面,其他都需要添加 + id:1, + time:1, + content:1, + level:1, + linkUser:1, + linkOther:1, + linkOrigin:1, + personInfo:1, + repliedUserInfo:1 + } + } + ]); + + }else{ + scope.mongoData=null; + scope.status=false; + } + + },function(err) { + scope.mongoData=null; + scope.status=false; + scope.errorMsg="添加评论出错"; + }).then(function(data) { + if(scope.errorMsg){return } + if(data&&data.length){//索取所有关联到该文章下的评论列表[每条评论级联了对应的评论者信息] + scope.mongoData=data; + scope.status=true; + }else{ + scope.mongoData=null; + scope.status=false; + } + },function(err) { + scope.mongoData=null; + scope.status=false; + }) + } + + + + + //获取文章列表,登录不登陆无关紧要,关键看文章对那些人有“查看权限和评论权限” + //{$exits:true},注意,这个只能是判断文档的第一级字段,不能判断内部的字段 + * getArticleListById(opts,scope) { + let db=mongoose.connect(dbURI,timeOut); + yield db.then(function(data) { + var{id,uid,needAccess}=opts; + var idObj=(id&&id[0])?mongoose.Types.ObjectId(id[0]):id[0]; + var filter=null; + uid=uid?mongoose.Types.ObjectId(uid):uid;//uid不存在的话,用mongoose.Types.ObjectId会报错,导致无法返回数据,最后导致前端获取不到数据,产生js错误 + if(needAccess){//鉴权功能有待验证,功能开没开发 + var filter1={ + _id:idObj, + linkUser:{//accessViewUser数组中存在all或uid的数据 + accessViewUser:{$elemMatch:{$in:['all',uid]}} + } + // accessViewUser::筛选出accessViewUser数组中包含all的数据 + }; + var filter2={ + _id:idObj, + linkUser:{ + uid:uid + } + } + var rstFilter={$or:[filter1,filter2]} + }else{ + var filter1={ + _id:idObj + }; + var rstFilter=filter1; + } + + let articleModel=BaseModel.ArticleSchema; + + filter=[{ + $match:rstFilter + + },{ + //含义:对上面match出的每条文档,去关联users表, + //关联条件是match的文档中linkUser.uid和users表中的_id相同,让文档合并 + // 合并文档以CommentSchema的机构为基础,增加personInfo字段来放关联文档内容 + $lookup:{//获取文章作者的信息 + from: "users",//需要连接的表名 + localField: "linkUser.uid",//本表[articles表]需要关联的字段 + foreignField: "_id",//被连接表需要关联的字段 + as: "personInfo"//查询出的结果集别名 + } + }]; + + return articleModel.aggregate(filter); + + + + },function(err){ + scope.mongoData=null; + scope.status=false; + scope.errorMsg="数据库连接出错"; + }).then(function(data) { + if(scope.errorMsg){return } + if(data.length){ + scope.mongoData=data; + } + },function(err) { + scope.mongoData=null; + scope.status=false; + scope.errorMsg="获取文章列表出错"; + }); + } + + + //获取个人文章内容:个人登录下才会调用,因为自己的文章,所以不用鉴权 + * getUserArticleList(opts,scope) { + let db=mongoose.connect(dbURI,timeOut); + yield db.then(function(data) { + var uid=opts.id?mongoose.Types.ObjectId(opts.id):opts.id; + // var obj={ + // linkUser:{ + // uid:uid//关联用户的id + // } + // }; + var obj={//上面的对象内嵌套对象,是全匹配的意思,只要某一个属性,得用这种方式 + "linkUser.uid":uid + }; + + let articleModel=BaseModel.ArticleSchema; + return articleModel.find(obj); + },function(err){ + scope.mongoData=null; + scope.status=false; + scope.errorMsg="数据库连接出错"; + }).then(function(data) { + if(scope.errorMsg){return } + if(data.length){ + scope.mongoData=data; + } + },function(err) { + scope.mongoData=null; + scope.status=false; + scope.errorMsg="获取文章内容出错"; + }); + } + + + * getUserInfo(opts,scope) { + let db=mongoose.connect(dbURI,timeOut); + yield db.then(function(data) { + let userModel=BaseModel.UserSchema; + return userModel.find(opts); + },function(err){ + scope.mongoData=null; + scope.status=false; + scope.errorMsg="数据库连接出错"; + }).then(function(data) { + if(scope.errorMsg){return } + if(data&&data.length){ + scope.mongoData=data; + }else{ + scope.mongoData=null; + scope.errorMsg="帐号或密码错误"; + } + },function(err) { + scope.mongoData=null; + scope.status=false; + scope.errorMsg="获取用户信息出错"; + }); + } + + + + * checkUserInfo(opts,scope) { + let db=mongoose.connect(dbURI,timeOut); + yield db.then(function(data) { + let userModel=BaseModel.UserSchema; + opts.passward=auth.hash(opts.passward,config.auth.shaKey);//对密码用sha256不可逆算法加密 + return userModel.find(opts); + },function(err){ + scope.mongoData=null; + scope.status=false; + scope.errorMsg="数据库连接出错"; + }).then(function(data) { + if(scope.errorMsg){return } + if(data&&data.length){ + scope.mongoData=data; + }else{ + scope.errorMsg="账户名或密码错误"; + } + },function(err) { + scope.mongoData=null; + scope.status=false; + scope.errorMsg="获取用户信息出错"; + }); + } + + + + + * registUser(opts,scope) { + let that=this; + let db= mongoose.connect(dbURI,timeOut);//返回promise + yield db.then(function(data) { + let queryArray= [{phone:opts.phone},{userName:opts.userName}]; //或条件,属性要分开写 + let userModel=BaseModel.UserSchema; + return userModel.find({ + $or:queryArray + }); + + // 每个then里面的第一个function返回promise对象,实现链式调用 + },function(err){ + scope.mongoData=null; + scope.status=false; + scope.errorMsg="数据库连接出错"; + }).then(function(data) { + if(scope.errorMsg){return } + + if(!data.length){//save效率低,最号用于修改,别用于插入数据 + opts.passward=auth.hash(opts.passward,config.auth.shaKey);//对密码用sha256不可逆算法加密 + return new BaseModel.UserSchema(Object.assign({},BaseModel.defaultUser,opts)).save();//是个promise + }else{ + scope.mongoData=data; + scope.status=false; + } + },function(err) { + scope.mongoData=null; + scope.status=false; + scope.errorMsg="注册条件查询出错"; + }).then(function(data) { + if(scope.errorMsg){return } + if(!scope.mongoData){ + + scope.mongoData=data; + scope.status=true; + } + },function(err) { + scope.mongoData=null; + scope.status=false; + scope.errorMsg="注册失败"; + }) + } + + + + * addArticle(opts,scope) { + let that=this; + let db= mongoose.connect(dbURI,timeOut);//返回promise + yield db.then(function(data) { + var uid=opts.id?mongoose.Types.ObjectId(opts.id):opts.id; + var {tags=[]}=opts; + var obj={ + title:opts.title, + content:opts.content, + linkUser:{ + uid:uid//关联用户的id + } + }; + scope.tempParam={tags,uid}; + return new BaseModel.ArticleSchema(Object.assign({},BaseModel.defaultArticle,{time:Date.now()},obj)).save();//是个promise + + // 每个then里面的第一个function返回promise对象,实现链式调用 + },function(err){ + scope.mongoData=null; + scope.status=false; + scope.errorMsg="数据库连接出错"; + }).then(function(data) { + if(scope.errorMsg){return;} + if(!data.length){//save效率低,最号用于修改,别用于插入数据 + scope.mongoData=data; + scope.status=true; + scope.tempParam.articleId=data._id; + // scope.tempParam.tags + if(scope.tempParam.tags.length){ + scope.needTagsStatus=true; + scope.tagsStatus=false; + return BaseModel.TagSchema.find({content:{$in:scope.tempParam.tags}});//or和in别搞错 + } + + }else{ + scope.mongoData=null; + scope.status=false; + } + },function(err) { + scope.mongoData=null; + scope.status=false; + scope.errorMsg="文章更新出错"; + }).then(function(data) { + if(scope.errorMsg){return;} + scope.existsTags=[];//标签已经存在,只需要插入articleId的tags + var needBeCreatedTags=scope.tempParam.tags; + if(data&&data.length){//有的标签已存在,需要重新梳理需要新建的标签 + needBeCreatedTags=scope.tempParam.tags.filter(function(item,idx) { + var tempObj=null; + var isExist = (data||[]).some(function(subItem) { + if(subItem.content==item){ + tempObj=subItem; + } + return subItem.content==item + }); + isExist&&scope.existsTags.push(tempObj); + return !isExist + }); + } + + var addTagsOptions=[]; + var updateTagsOptions=[]; + needBeCreatedTags.forEach(function(item) { + addTagsOptions.push(Object.assign({},BaseModel.defaultTag,{"content":item,linkArticle:[scope.tempParam.articleId]})); + }); + scope.existsTags.forEach(function(item) { + updateTagsOptions.push({id:item._id});//别用id,id是字符串,_id才是正确的key + }); + var tm=db.tags; + + // BaseModel.TagSchema.db.collections.tags.findAndModify + return Promise.all([//BaseModel.TagSchema.db是原生db + BaseModel.TagSchema.updateMany({$or:updateTagsOptions},{$addToSet:{"linkArticle":scope.tempParam.articleId}},{new:true}), + BaseModel.TagSchema.create([...addTagsOptions])//{new:true} + ]); + //updateMany不能返回更新后的最新数据,mongoose也没有类似mongodb的findAndModify方法,算了,搞了半天找不到解决方案 + // 直接多查一次得了 + },function(err) { + scope.tagsStatus=false; + scope.tagsData=null; + scope.errorMsg="标签查找出错"; + }).then(function(data=[]) { + if(scope.errorMsg){return;} + scope.tagsStatus=true; + scope.tagsData = data; + + },function(err) { + scope.errorMsg="标签更新或创建出错"; + scope.tagsStatus=false; + scope.tagsData=null; + }) + } +} + + +module.exports = KidsClassService diff --git a/models/personal.js b/models/personal.js new file mode 100644 index 0000000..6eb3ed0 --- /dev/null +++ b/models/personal.js @@ -0,0 +1,240 @@ +/* + @desc:个人中心的model,请求个人中心相关数据 + */ + +const BaseModel = require('./baseModel'); +const auth=require("../lib/middleware/auth.js"); +const mongoose=require("mongoose"); +const util=require("../lib/util.js"); +const Transaction = require("mongoose-transactions"); +const transaction = new Transaction(); +let session = null; +let config=require("../config.js"); +let envObj=config.db[config.NODE_ENV]; +let {dbURI,timeout}=envObj; +let timeOut={ + serverSelectionTimeoutMS: timeout//数据库连接超时设置,5000ms +}; + +/*@desc: + articleRecommend:默认推荐文章的评论数 + userRecommend:默认推荐的用户的粉丝数 + article:搜索关键词时,如果文章评论数超对应的值,就在里面搜索是否包含关键词,其他都不搜索,基数太大,需要筛选出热门的再去搜索 + comment:搜索关键词时,如果评论的回复数超对应的值,就在里面搜索是否包含关键词,其他都不搜索,基数太大,需要筛选出热门的再去搜索 +*/ +const hotDefine={article:20,comment:2,articleRecommend:1,userRecommend:1}; + +class KidsClassService extends BaseModel{ + + constructor(self) { + super(); + this.ctx = self; + } + + + //修改密码:通过原密码来修改密码 + * changePassward({oldPwd,newPwd,id},scope) { + let db=mongoose.connect(dbURI,timeOut); + yield db.then(function(data) { + var uid=id?mongoose.Types.ObjectId(id):id; + // var obj={ + // linkUser:{ + // uid:uid//关联用户的id + // } + // }; + var match={//上面的对象内嵌套对象,是全匹配的意思,只要某一个属性,得用这种方式 + _id:uid, + passward:auth.hash(oldPwd,config.auth.shaKey) + }; + + let userModel=BaseModel.UserSchema; + return userModel.findOneAndUpdate(match,{$set:{passward:auth.hash(newPwd,config.auth.shaKey)}},{new:true}); + },function(err){ + scope.mongoData=null; + scope.status=false; + scope.errorMsg="数据库连接出错"; + }).then(function(data) { + if(data){ + scope.status=true; + scope.mongoData=data; + }else{ + scope.status=false; + scope.errorMsg="原密码错误,修改密码失败"; + } + },function(err) { + scope.mongoData=null; + scope.status=false; + scope.errorMsg="数据库未知错误"; + }); + } + + //获取个人文章内容:个人登录下才会调用,因为自己的文章,所以不用鉴权 + * getUserArticleList(opts,scope) { + let db=mongoose.connect(dbURI,timeOut); + yield db.then(function(data) { + var uid=opts.id?mongoose.Types.ObjectId(opts.id):opts.id; + // var obj={ + // linkUser:{ + // uid:uid//关联用户的id + // } + // }; + var obj={//上面的对象内嵌套对象,是全匹配的意思,只要某一个属性,得用这种方式 + "linkUser.uid":uid + }; + + let articleModel=BaseModel.ArticleSchema; + return articleModel.find(obj); + },function(err){ + scope.mongoData=null; + scope.status=false; + }).then(function(data) { + if(data.length){ + scope.mongoData=data; + } + },function(err) { + scope.mongoData=null; + scope.status=false; + }); + } + + + //个人收藏:搜索太麻烦了,需要遍历所有文章,不过查看收藏的操作不频繁,所以暂时不优化了 + * getUserCollectionList(opts,scope) { + let db=mongoose.connect(dbURI,timeOut); + yield db.then(function(data) { + var uid=opts.id?mongoose.Types.ObjectId(opts.id):opts.id; + var match={$match:{ + "linkUser.collect":{ + $elemMatch:{$eq:uid} + } + }}; + + let articleModel=BaseModel.ArticleSchema; + return articleModel.aggregate([match,{ + $project:{ + time:1, + title:1, + content:1, + tag:1, + linkUser:1, + linkComment:1, + categroy:1, + level:1 + } + }]); + },function(err){ + scope.mongoData=null; + scope.status=false; + }).then(function(data) { + if(data.length){ + scope.mongoData=data; + } + scope.status=true; + },function(err) { + scope.mongoData=null; + scope.status=false; + }); + } + + * getUserFansList({id},scope) { + let db=mongoose.connect(dbURI,timeOut); + yield db.then(function(data) { + var uid=id?mongoose.Types.ObjectId(id):id; + let userModel=BaseModel.UserSchema; + let match={//上面的对象内嵌套对象,是全匹配的意思,只要某一个属性,得用这种方式 + $match:{"_id":uid} + }; + let lookup={ + $lookup:{ + from: "users",//需要连接的表名 + localField: "linkUser.fans",//本表[articles表]需要关联的字段 + foreignField: "_id",//被连接表需要关联的字段 + as: "personInfo"//查询出的结果集别名 + } + }; + + return userModel.aggregate([match,lookup,{ + $project:{ + personInfo:1 + } + }]); + },function(err){ + scope.mongoData=null; + scope.status=false; + }).then(function(data) { + if(data.length){ + scope.mongoData=data; + } + scope.status=true; + },function(err) { + scope.mongoData=null; + scope.status=false; + }); + } + + * getUserAttentionList({id},scope) { + let db=mongoose.connect(dbURI,timeOut); + yield db.then(function(data) { + var uid=id?mongoose.Types.ObjectId(id):id; + let userModel=BaseModel.UserSchema; + let match={//上面的对象内嵌套对象,是全匹配的意思,只要某一个属性,得用这种方式 + $match:{"_id":uid} + }; + let lookup={ + $lookup:{ + from: "users",//需要连接的表名 + localField: "linkUser.attention",//本表[articles表]需要关联的字段 + foreignField: "_id",//被连接表需要关联的字段 + as: "personInfo"//查询出的结果集别名 + } + }; + + return userModel.aggregate([match,lookup,{ + $project:{ + personInfo:1 + } + }]); + },function(err){ + scope.mongoData=null; + scope.status=false; + }).then(function(data) { + if(data.length){ + scope.mongoData=data; + } + scope.status=true; + },function(err) { + scope.mongoData=null; + scope.status=false; + }); + } + + + //修改用户信息 + * setUserInfo(opts,scope) { + let db=mongoose.connect(dbURI,timeOut); + yield db.then(function(data) { + var uid=opts._id?mongoose.Types.ObjectId(opts._id):_id; + let userModel=BaseModel.UserSchema; + delete opts._id; + return userModel.findOneAndUpdate({_id:uid},{$set:opts},{new:true}); + },function(err){ + scope.mongoData=null; + scope.status=false; + }).then(function(data) { + if(data){ + scope.mongoData=data; + }else{ + scope.mongoData=null; + } + },function(err) { + scope.mongoData=null; + scope.status=false; + }); + } + + + +} + + +module.exports = KidsClassService diff --git a/models/schema.js b/models/schema.js new file mode 100644 index 0000000..9f6dc94 --- /dev/null +++ b/models/schema.js @@ -0,0 +1,714 @@ +let mongoose=require("mongoose");//require("mongodb") + +var Schema = mongoose.Schema; + +//最主要的功能尽量能快速1次或2次查询找到,非主要功能尽量碎片化【多集合】,以保证可拓展性 +//主要功能:人,文章,文章评论|说说|留言|回复评论,图标的增删改查 +//数据库最好的逻辑:修改一个实体,这个实体的所有外键关联它的所有信息,只根据外键就可以同步所有,不然东改西改逻辑容易乱!! + +// 所有的操作,都是先获取当前操作实体的id,然后通过它的所有外键,去同步信息: + +/* + 所有的操作,都是以实体为中心,用外键关联来同步到其他实体;这样只要关注1件事情,实体改变,关联实体内信息是否全部同步到位 + 用一个实体作为 +*/ + +// !!!删除操作是最麻烦的,因为实体之间有链接,如果删一个,另外的链接如何关联处理,跟着删肯定不行!!!! +// 删除操作,人不能删,其他实体删除,只打一个disable标签,数据仍然存在,遇到disable实体就做特殊展示,包括关联外键的特殊展示 + + + +// 1.文章: 文章分可修改和不可修改2个类型 +// 增:文章集合内插入;uid和atuid【同步人的信息】; +// 删:文章集合内删除;然后看其他表的关联项里是否涉及到这个数据,有的话就要关联 +// 改:文章集合内修改;然后看其他表的关联项里是否涉及到这个数据,有的话就要关联 +// 查:文章集合通过id|其他外键|标签,找文章;然后根据文章id,关联所有外键【文章下评论串联需要前端自己串】 +// 2.评论:评论不可修改 +// 增:评论类型中插入评论;link>targetId,link>originId,uid,atuid关联同步信息【人和文章的同步,自身同步】 +// 删:~ +// 查和改:都不做 + +// 3.用户:不可删,但可禁用,分权限等级【关联文章操作权限,文章上热搜权限 等各种权限,预留接口】 +// 增:添加用户,默认引导界面添加“外键”关联 +// 删:不需要做,没见过那个网站还能删自己帐号的 +// 改:实体内容+关联外键【一大堆】 +// 查:通过id或者其他属性,查找某个人;然后根据文章id,关联所有外键【文章下评论串联需要前端自己串】 + +// 4.图表:增删改查都是通过先操作图表,然后根据里面的外键,来同步关联实体 + + +// schema里面的属性和字段,数据库是会校验的,C++语言级别的校验, +// 但是用户基数过大,那么大量的增|改操作,以为数据的校验导致性能出问题 + +/* +关键的核心 + 1.每次操作实体,首先修改实体本身,然后列出和自己有关联的其他所有表,看其他表的关联项中是否要更新 + 2.实体与实体之间,一般只要单向关联即可,这样完全可以做到功能的需要; + 单向关联的好处是,操作实体,不需要修改其他关联表;以操作最频繁的表为主,也就是 + 在操作最频繁的那个表中添加关联key,可以减少常用功能对应的操作次数 + 3.表和表之间做了双向关联,有点是查询方便,一张表包括了所有基本信息; + 但缺点也很明显,操作一张表的实体,还需要同步到关联表,而且这个是原子操作 + 也就是必须通过事务来实现双向关联的表 +*/ + + +/*mongodb默认值设置注意事项: + 1.设置了default,就不需要设置required了,因为不管有没有传,因为没传就用default,所以就不存在需要不需要,肯定有值 + 2.如果设置了required,但是没有设置default,也没有传入,那么数据库就会校验报错 + 3.对象里面属性的默认值试了一下,设置是没有效果的,传入就会覆盖;不传入的话数据库也不会自动创建默认值 + 4.表内的unique:true的字段不要轻易删,不然后续添加的会一直报之前删除的哪个键重复,因为每次插入都是空,空值相同 + 解决办法个人猜测时更新”集合“; + 5.如果一个字段设置了unique,那他肯定是require + 6.default的意思是,这个key的数值不放在表里,如果有人请求这个字段,那就从获取默认字段还给他 + 默认字段的货期是动态的,比如设置默认字段值是Date.now(),那么以后每次获取,都是再获取的时候 + 执行Date.now(),然后返回这个值,所以这个压根就不是不变的默认值,所以设置默认值 + 别用动态的js计算,里面有变量的话,每次都不一样 + + deafult值是不能用于find条件查找的,所以要设置条件查找的默认值,还是得用Object.assign(default对象) +*/ + + +/*----------------------------------------user start-------------------------------------------------------*/ +//mongodb支持populate填充设置多表嵌套关联,mongoose用populate实现,前提是表中设置ref +//涉及到改数据库,还是算了,其实;性能上还是$lookup比较好,但是只能双表关联 +var userSchema=new Schema({//用系统自己产生的id,保证唯一性,返回数据的时候带上id + timeStamp:{//时间动态码,每次用户登录,先获取动态码,然后返回管客户端,再次ajax请求 + //通过用户名+密码+动态码校验,正确后就设置最新动态码,修改完后然后执行登录态记录 + type:Number + }, + time:{ + type:Number + }, + passward:{ + type:String, + required:true//require为true的数据,在传入数据库的时候必须要有,如果没有,就会报错 + }, + userName:{//用户名|网名|昵称|花名【唯一,大家网名不能相互重复】:注册时可以不填写,后续添加:因为名称唯一性容易重复导致用户体验下降 + type:String, + unique:true + }, + phone:{ + type:String, + required:true, + unique:true + }, + name:{//真实姓名 + type:String, + default:"" + }, + age:{ + type:String, + default:"" + }, + sex:{ + type:String, + default:"" + }, + + userPic:{ + type:String, + default:"/upload/default.png"//用户没有头像就用默认图片做头像 + }, + + level:{//个人的等级,等级越高,主页展示得越考前:这个等级通过文章的linkUser和linkComment综合评分,得到一个等级 + type:Number, + default:1 + }, + + categroy:{//用户的不同种类,区分不同的权限,后续再设置,默认权限1,正常用户 + // type:[Schema.Types.Integer], + type:String, + default:"1" + }, + + + //关联的所有用户 + linkUser:{ + type:Object, + properties:{ + fans:{//粉丝 不需要,fans和attention只需要一个,不需要双向关联 + type:Array//uid + }, + attention:{//关注哪些人 + type:Array//uid + }, + blackList:{//黑名单 + type:Array//uid + }, + specialAttention:{//特别关注 + type:Array//uid + } + } + } +}); + +/*----------------------------------------user end-------------------------------------------------------*/ + + + + + + +/*----------------------------------------article start-------------------------------------------------------*/ + +//文章【不包含说说,评论,留言板留言等,只是文章】 +var articleSchema=new Schema({ + time:{//文章写的时间 + type:Number, + required:true + }, + title:{//标题 + type:String, + required:true + }, + content:{//内容 + type:String, + required:true + }, + tag:{//标签 + type:Array + }, + + //默认不鉴权,所以筛选条件中不需要添加accessViewUser|accessCommentUser + //一旦用户开启鉴权,需要给accessViewUser|accessCommentUser设置all或者特定的人 + //这样下次访问这篇文章,遇到needAccess为true,才能通过accessViewUser|accessCommentUser + //数组内对应的值来判断是否能让用户访问 + needAccess:{//true表示需要鉴权才能查看,这个参数查询的时候要带过来; + type:Boolean + }, + categroy:{//文章的类型,类型1表示默认文章,无类型;2表示技术分享;3每日复盘;4表示热点讨论 + type:String, + default:"1" + }, + + level:{//文章的等级,等级越高,主页展示得越考前:这个等级通过文章的linkUser和linkComment综合评分,得到一个等级 + type:Number, + default:1 + }, + + //--------------------------下面是关联数据---------------------------------- + + + linkUser:{ + type:Object, + required:true, + properties:{ + uid:{//去关联用户表:谁写的 + type:mongoose.Types.ObjectId,//mongodb的compass中查看 + required:true + }, + + accessViewUser:{//数组中出现"all",表示所有都可以查看, + type:Array + }, + accessCommentUser:{//数组中出现"all",表示所有都可以查看, + type:Array + }, + fav:{//点赞 :uid + type:Array + }, + collect:{//收藏 :uid + type:Array + }, + relay:{//转发 :uid + type:Array + }, + comment:{//评论的人:uid + type:Array + }, + atList:{//评论的@相关人员,atId主动at的人;atedId是被at的人 + type:Array//{atId,atedId,atType:2表示文章的at,4表示评论的at} + } + } + } + +}); + + + + +/*----------------------------------------article end-------------------------------------------------------*/ + + + + + + + +/*----------------------------------------comment start-------------------------------------------------------*/ + + +/*短文:因为这个量非常大,所以需要单独拎出来,不能和文章放在一个集合里面 + 1.“个人说说”:没针对谁,自己发的说说, + 2.“文章评论:针对文章的第一层留言,人与人之间回复不算”, + 3.“留言板留言:针对某个人,是某人留言板下的1级留言,”, + 4.“评论回复”:就是2级+的评论【上面123都是1级评论】 + 5.“图表留言”:针对图表的第一层留言 + + 注意: + 1.这个表的linkOther必须建立索引,查询非常多,量也大,所以需要的索引的内存也很大 + 如果有1亿的数据,索引内存大小是: 2^32 = 4G;【每个用户平均万级别数据条数;1亿用户】 + 所以万亿级别的表就是极限了【到时候看下建立索引需要多大内存】 + 2.人物,文章,图表的删除操作逻辑都不复杂,也好操作; + 但评论的增加和删除,必须有一个复杂,另外一个才好操作; + 新增较多删除少,所以新增做简单,删除做复杂; + 方案1:删除的时候,评论下面所有的评论,要一级一级关联【前端做关联:列出所有下级评论id】; + 最后统一发达数据库做批量删除;这样的话,别人下面的评论不明所以就不见了 + 体验不好 + 方案2:单独删除当前评论,级联下面所有的评论【前端做关联:列出所有下级评论id】, + 统一给下面所有的评论的linkOther添加属性isDelete,告诉它父节点被删除; + 同时数据库每隔一段时间执行删除linkOther.isDelete是true的comment文档 +*/ +var commentSchema=new Schema({//自动产生的id为cid,就是评论id + time:{//文章写的时间 + type:Number + }, + content:{//内容 + type:String, + required:true + }, + + level:{//评论等级,等级越高,文章内展示得越靠前:这个等级通过linkUser和linkOther综合评分,得到一个等级 + type:Number, + default:1 + }, + + //--------------------------下面是关联数据---------------------------------- + + linkUser:{ + type:Object, + required:true, + properties:{ + uid:{//谁写的 + type:mongoose.Types.ObjectId,//mongodb的compass中查看 + required:true + }, + fav:{//点赞 :uid + type:Array + }, + collect:{//收藏 :uid + type:Array + }, + relay:{//转发 :uid + type:Array + }, + comment:{//评论的人:uid + type:Array + }, + atList:{//评论的@相关人员,atId主动at的人的id;atedId是被at的人的id:atId和上面的uid一样,就是作者主动at别人 + type:Array//{atId,atedId,atType:2表示文章的at,4表示评论的at} + } + } + }, + + //链接的父元素节点:一条评论只会有一个外部关联项,也就是只有一个category类型 + // 通过linkOrigin,前端就可以串联出某篇文章下的所有评论数据和关系 + // 前端需要通过遍历树操作,才能把所有评论串起来,前端逻辑比较复杂,但为了数据库的简化+可拓展性,是值得的 + // linkOther改名为linkParent比较恰当,但业务写好了没法改了 + linkOther:{// + type:Object, + required:true, + properties:{ + category:{ + //这条评论自己的类别:[1,2,3,4,5:详细介绍见下面]【注意这个和linkOrigin要区分】 + // 这里的category是评论自身的属性,不是它的关联节点的属性; + // 没有必要知道关联节点的属性 + type:String, + required:true + }, + targetId:{//被回复方【article|comment】的id:针对的哪个目标的“回复|评论” + // 如果category是1类型,targetId就是自己个人的uid;【放自己说说列表】 + // 如果category是2类型,targetId就是aid,放到对应文章下面 + // 如果category是3类型,targedid就是其他人的uid【放对方留言板1级留言】 + // 如果category是4类型,targedid就是cid,放到其他评论的下面 + // 如果category是5类型,targedid就是chartId,放到对应图表下面 + type:mongoose.Types.ObjectId,//mongodb的compass中查看 + required:true + }, + targetUserId:{//被回复方的用户Id + type:mongoose.Types.ObjectId, + required:true + } + } + }, + + //这条评论的源头是哪里:他和linkOther的category字段意义不同,别混淆 + //这个字段是为了方便数据的查找,找到源头就可以找出所有下面的评论,接下来由前端去串联 + //如果没有这个字段,那么评论就要在后台一级一级地串联,非常耗费性能。 + linkOrigin:{// + type:Object, + required:true, + properties:{ + category:{//这条评论的源头的类型:[1,2,3,4,5:详细介绍见下面] + type:String, + required:true + }, + targetId:{//属于的那个源头的id + // 如果category是1类型,targetId就是cid,源头是个人的说说 + // 如果category是2类型,targetId就是aid,源头是文章 + // 如果category是3类型,targedid就是uid,源头是别人的留言板 + // 如果category是5类型,targedid就是chartId,源头是图表 + type:mongoose.Types.ObjectId,//mongodb的compass中查看 + required:true + } + } + } + +}); + + +/*----------------------------------------comment end-------------------------------------------------------*/ + + + +/*----------------------------------------tag start-------------------------------------------------------*/ + +//标签系统:追踪文章类型,当前热搜【热度,和持续时间】 +var tagSchema=new Schema({ + startTime:{//标签新建的时间 + type:Number, + required:true + }, + latestTime:{//标签最新被别人添加的时间 + type:Number, + required:true + }, + content:{//内容 + type:String, + required:true + }, + + categroy:{//文章的类型,类型1表示默认文章,无类型;2表示技术分享;3每日复盘;4表示热点讨论 + type:String, + default:"1" + }, + + level:{//标签等级,等级越高,各种业务展示的优先级越高 + type:Number, + default:1 + }, + + //--------------------------下面是关联数据---------------------------------- + + + linkArticle:{//cid + type:Array + }, + linkUser:{//uid + type:Array + }, + +}); + +/*----------------------------------------tag end-------------------------------------------------------*/ + + + + +/*----------------------------------------chart start-------------------------------------------------------*/ + +//图表:结构和文章基本一样,只是标题非必须 +var chartSchema=new Schema({ + time:{//时间 + type:Number + }, + title:{//图标可以没有标题,也可以有 + type:String, + default:"" + }, + content:{//图表数据内容,转成字符串 + type:String, + required:true + }, + tag:{//标签 + type:Array + }, + categroy:{//文章的类型,类型1表示默认图表【以后可增加各种类型图表】 + type:String, + default:"1" + }, + + level:{//图表的推送等级,等级越高,展示得越靠前:这个等级通过图表的linkUser和linkComment综合评分,得到一个等级 + type:String, + default:"1" + }, + + //--------------------------下面是关联数据---------------------------------- + linkUser:{ + type:Object, + required:true, + properties:{ + uid:{//去关联用户表:谁写的 + type:mongoose.Types.ObjectId,//mongodb的compass中查看 + required:true + }, + fav:{//点赞 :uid + type:Array + }, + collect:{//收藏 :uid + type:Array + }, + relay:{//转发 :uid + type:Array + }, + comment:{//评论的人:uid + type:Array + }, + atList:{//评论的@相关人员,atId主动at的人;atedId是被at的人 + type:Array//{atId,atedId,atType:2表示文章的at,4表示评论的at,5表示图表的at} + } + } + } +}); + + +/*----------------------------------------char end-------------------------------------------------------*/ + + + +/*----------------------------------------热度评分表 不做了,没必要做那么好,又不是靠这个赚钱,只是练习而已 start-------------------------------------------------------*/ + +//热门推荐系统:产生热门作者和热门文章 +//每次点击的时候,都需要操作修改统计表,所以不能放在主表,以免操作过于频繁 +//每次热度值变化,任何点赞,评论,转发,收藏,点击文章,都会涉及文章热度变化,都要查询表 +// 所以必须独立出来,否则对内容表的操作太频繁,容易卡死 + +// var hotArticleSchema=new Schema({ +// aid:"文章id", +// uid:"作者id", +// uv:[{uid:"",pv:[time,time,...]},{uid:"",pv:[time,time,...]}], +// fav:[{uid:"",time:""},{uid:"",time:""}], +// collect:[{uid:"",time:""},{uid:"",time:""}], +// comment:[{uid:"",list:[{cid,time}]},{uid:"",list:[{cid,time}]}], +// cotalHot:"总体热度", +// curHot:"当前热度"//设置最近的某段时间内的累计热度 +// }); + + +// //用户推荐较少,所以依赖于其他表的搜索,内部不添加实体信息;热度逻辑在返回客户端信息后再计算统计 +// var hotUserSchema=new Schema({//计算总分需要查hotArticleSchema表【获取文章评分】+user表【获取粉丝评分】 +// uid:"用户id", +// totalHot:100,//总体热度【粉丝权重可设置】:粉丝+所有文章评分累计 +// curHot:10//最近热度【时间宽度可设置】:最近一段时间粉丝增量+最近一段时间文章评分累计 +// }); + +/*----------------------------------------热度评分表 end-------------------------------------------------------*/ + + + + +//必须的不传会报错,非必须的都给默认值,这样创建的时候就比较方便,用不到defaultUser,因为数据库里设置了 +let defaultUser={//用系统自己产生的id,保证唯一性,返回数据的时候带上id + timeStamp:Date.now(), + time:Date.now()//注册时间 + // passward:"",//必须前端传入 + // userName:"",//必须前端传入 + // phone:"",//必须前端传入 + + // //关联的所有用户 + // linkUser:{ + // fans:[], + // attention:[], + // blackList:[], + // specialAttention:[] + // } +} + + +//新建文章的默认蓝本 +var defaultArticle={//这个是服务器启动时间,不是实时的时间 + time:Date.now() + // title:"",//必须前端传入 + // content:"",//必须前端传入 + // tag:[], + // linkUser:{ + // uid:"",//必须后端传入 + // fav:[], + // collect:[], + // relay:[], + // comment:[], + // atList:[] + // } +}; + + +var defaultComment={ + time:Date.now() + // time:Date.now(), + // content:"",//必须前端传入 + // linkUser:{ + // uid:""//必须前端传入 + // }, + // linkOther:{ + // category:0,//必须前端传入 + // targetId:""//必须前端传入 + // } + // linkOrigin:{ + // category:0,//必须前端传入 + // targetId:""//必须前端传入 + // } +}; + + +//新建图表的时候用到 +var defaultChart={ + time:Date.now() + // time:Date.now(), + // title:"", + // content:"",//必须前端传入 + // tag:[], + // linkUser:{ + // uid:"",//必须前端传入 + // fav:[], + // collect:[], + // relay:[], + // comment:[], + // atList:[] + // } +}; + +var defaultTag={ + startTime:Date.now(), + latestTime:Date.now() + // time:Date.now(), + // title:"", + // content:"",//必须前端传入 + // tag:[], + // linkUser:{ + // uid:"",//必须前端传入 + // fav:[], + // collect:[], + // relay:[], + // comment:[], + // atList:[] + // } +}; + + + +userSchema = mongoose.model('User',userSchema ); +articleSchema = mongoose.model('Article',articleSchema ); +commentSchema = mongoose.model('Comment',commentSchema ); +chartSchema = mongoose.model('Chart',chartSchema ); +tagSchema = mongoose.model('Tag',tagSchema ); + +module.exports= {tagSchema,userSchema,articleSchema,commentSchema,chartSchema,defaultUser,defaultArticle,defaultComment,defaultChart,defaultTag}; + + + + + + + + + + + //关联的所有图表:chart实体中有了,这里没必要做反向关联 + // linkChart:{ + // type:Object, + // properties:{ + // content:{//自己有哪些图表 + // type:Array//图标的chartid的列表 + // }, + // fav:{//点赞的图表 + // type:Array + // }, + // collect:{//收藏的图表 + // type:Array + // }, + // relay:{//转发的图表 + // type:Array + // }, + // atList:{ + // type:Array//自己at别人的图表【文章可以是别人的,也可以是自己的】 + // // 数组内是对象,别人at我的信息是否已读用isRead, + // // 用于用户登录的时候或实时提醒用户浏览“未读信息” + // // {atType:2表示文章的at,4表示评论的at,atId:内容对应的id,isRead:是否已读} + // }, + // atedList:{ + // type:Array//别人at自己的图表【文章可以是别人的,也可以是自己的】 + // } + // } + // }, + + //关联的所有文章:article实体中有了,这里没必要做反向关联 + // linkArticle:{ + // type:Object, + // properties:{ + // content:{ //自己的文章 + // type:Array//aid + // }, + // fav:{ + // type:Array + // }, + // collect:{ + // type:Array + // }, + // relay:{ + // type:Array + // }, + // atList:{ + // type:Array + // }, + // atedList:{ + // type:Array + // } + // } + // }, + + //关联的所有评论:comment实体中有了,这里没必要做反向关联 + // linkComment:{ + // type:Object, + // properties:{ + // content:{//自己写的所有“文章评论|回复评论|说说|留言板评论” + // type:Array//cid + // }, + // fav:{//我收藏点赞的所有评论 + // type:Array + // }, + // collect:{ + // type:Array + // }, + // relay:{ + // type:Array + // }, + // atList:{ + // type:Array + // }, + // atedList:{ + // type:Array + // }, + // msgboard:{//留言板,谁给我留言了 + // type:Array//cid + // } + // } + // } + + + + + + + + + + + + + // //关联评论:没必要做反向关联,评论里面已经包含对应关联文章的id + // linkComment:{ + // type:Array//[{type:2|4,contentId:aid|cid}],type=2表示文章的1级评论,type=4表示评论回复 + // } + + + + + + + + + + //关联评论:图表下的所有评论:没必要反向关联,comment中已经有关联项了 + // linkComment:{ + // type:Array//[{type:2|4,contentId:aid|cid}],type=5表示图表的1级评论,type=4表示评论回复 + // } diff --git a/mongo.readme b/mongo.readme new file mode 100644 index 0000000..eb8feab --- /dev/null +++ b/mongo.readme @@ -0,0 +1,187 @@ +//数据库数据导出 +如果是容器内导出,需要先进入容器:docker exec -it 6f5212068289 /bin/bash +mongoexport -d 数据库名 -c 集合名 -o 导出的文件路径【例如e:\DingData.json】 +最后把导出的文件从容器中拷贝出来 + + +//数据数据如何导入 +然后使用cp命令将主机文件拷贝到docker容器中 +docker cp b.json 6f5212068289:/ + +然后进入容器 +docker exec -it 6f5212068289 /bin/bash + +然后执行导入命令 +mongoimport -h 127.0.0.1 -d DB_NAME -c COLLECTION_NAME b.json -u=对应的那个数据库的帐号 -p=对应的那个数据库的密码 + + + + + +//集群的安全:https://www.cnblogs.com/hahaha111122222/p/13965196.html +1.集群之间用加密文件进行通讯 +2.外部进入数据库,通过帐号密码进行安全保证 + + + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +创建副本集步骤: +1.在yml文件所在目录的dbconfig文件夹下,执行openssl rand -base64 1024 > mongodb.key 创建加密文件:如果没安装openssl,执行sudo apt-get install openssl和sudo apt-get install libssl-dev【libssl-dev是openssl的常用库】 +2.chmod 600 mongodb.key修改文件为所拥有的用户才有读写权限 +3.docker-compose -f docker-compose.rel.yaml up -d : 执行docker-compose up -d 来执行那个yml文件,里面已经配置好了数据库副本集的其他配置【执行自定义文件用 docker-compose -f docker-compose.rel.yaml up -d 】 + 注意,这里的dbconfig是自己在提前创建好的,里面有各个集群的conf配置文件,配置文件里面已经把各个集群的密码认证文件mongodb.key的路径配置好了,但配置文件的设置,需要在docker容器启动后,去容器里面设置 + 如果出错了一直restart,可以执行: docker logs -f 容器名称 来查看错误原因 +4.把集群密码认证文件mongodb.key和各个数据库集群的.conf文件拷贝进入各个副本集【每个副本都要拷贝】,它们都在dbconfig文件夹下,所以只要拷贝整个文件夹即可: + //拷贝key到数据库的容器内:可以先docker exec -it db-master ls查看下到底里面有没有 dbconfig文件 + docker cp dbconfig db-master:/ 【最后的:/表示把文件放到根目录】 + docker cp dbconfig db-slave:/ + docker cp dbconfig db-arbiter:/ + +5.进入每一个db容器,设置它们的conf文件 + docker exec -it db-master mongod --config ./dbconfig/master.conf + docker exec -it db-slave mongod --config ./dbconfig/slave.conf + docker exec -it db-arbiter mongod --config ./dbconfig/arbiter.conf + +4.执行docker exec -it db-master mongo admin :进入mongo主数据库 +5.初始化集群:rs.initiate({_id:"mongoset",members:[{_id:0,host:"43.143.25.248:27017"},{_id:1,host:"43.143.25.248:27018"},{_id:2,host:"43.143.25.248:27019",arbiterOnly:true}]}) + 这里要特别注意,host的ip一定要添加在.conf文件里面的bindIp属性里面,否则数据库是不会陌生的ip允许访问的, + 还有最重要的一点就是,虽然各个mongo的docker容器的27017默认端口被映射到了服务器的27017,27018,27019等端口,但是这个只是服务器内部的端口访问,这些端口对外网还是不开启的,这就造成了很严重的一点 + 就是如果服务器不开启27017,27018,27019等端口,那么rs.initiate()执行的时候,访问这些端口会被拒绝,集群初始化就会失败 + 最最关键的一点,在web程序中设置数据库集群的访问连接的时候【在config.js文件中的db字段中设置,线上环境是db.prod】,要用把三个数据库程序的服务名称来代替服务器的url, + 这样web程序【node后台】在接受用户操作的时候,会通过config.js中对应的集群url来执行数据库操作,这个时候只要任意一个数据库程序服务【database,arbiter,slave】中数据变化,都会同步到其他数据库服务程序 + database,arbiter,slave作为集群中的三个数据库服务,里面各自设置了对应的volume数据卷绑定,分别对应master-data,arbiter-data,slave-data这三个volume数据卷 + + +6.开启备机可读:rs.secondaryOk();然后查看集群状态:rs.status(),数据库集群到这里基本就配置好了,接下来就是给数据库创建管理员 +//7.增加database这个服务,也就是db-master这个容器的数据库的优先级: + //config = rs.conf() + //config.members[0].priority=2 + //rs.reconfig(config) + //rs.conf() //这个表示查看新配置 + +8.继续设置密码不需要这个auth验证;//执行db.auth("jeffreychen","out103496"),来鉴权,否则无法创建管理员,对应的帐号密码在yml文件中,进入那个数据库的容器,就用对应的那个数据库容器的帐号密码 +9.创建数据库管理员账号,主节点创建管理员,其他副本集数据库会自动同步: + db.createUser({ + user: 'adsf', + pwd: 'fdsf', + roles: [{ + role: 'clusterAdmin',//超级管理员权限,除了local和config仓库,对其他任何仓库都有查看的权限【没有修改其他仓库的权限】,当前的admin数据库有admin权限 + db: 'admin' + },{ + role: 'readAnyDatabase', + db: 'admin' + },{ + role : 'readWrite', + db : 'config' + },{ + role : 'readWrite', + db : 'local' + }] + }) +10.执行use gpclubs 切换到gpclubs仓库,,因为每个仓库的管理员,都需要先切换到该仓库,然后才能创建,在其他仓库设置另外一个数据库的管理员是无效的 +11.添加gpclubs数据库的管理员 + db.createUser({ + user: 'dddd', + pwd: 'dddd', + roles: [{ + role: 'readWrite', + db: 'gpclubs' + }] + }) + +9.全部完成以后退出,到了这里,集群和node都已经开启了,查看线上站点是否正常;然后关闭其中的某个数据库容器,比如关闭db-master容器,执行docker exec -it “容器名称” , + 并用rs.status()查看“从数据库:”是否变成“主数据库”【一个primary类型的数据库被关闭,另一个secondary类型的数据库变成primary类型】,同时再看线上是否因为关闭了一个数据库而导致数据库访问出问题 + 自测证明:只要存在任意2个数据库正常,数据库操作就能正常运行;少于2个就不能正常运行;三个数据库关闭任意一个都不影响运行,如果是primary类型被关闭,自动给会有其他的顶替它成为primary + + + //如果副本创建失败,如何清空重新来 + 1.docker-compose down先关闭容器 + 2.docker ps -a查看所有容器 + 3.docker stop 容器名称 ,停止那些以为在运行而删除失败的容器 + 4.docker rm 容器名称,以为之前一步已经停止了容器,这里就可以直接删除了 + 5.docker volume rm 数据卷,删除没有必要的数据卷,如果都不需要,可以直接执行docker volume prune来全部删除没有挂载容器的数据卷 + + //一般数据迭代,只需要发布前后端代码,不需要动数据库,所以只需要关闭和删除web容器,然后再重新启动web容器即可,如果删除了其他容器,那么容器里面的数据库设置都会被删除,包括集群设置也会没有,又得重新设置集群,创建管理员 + 所以版本迭代,只需要 + 1.docker stop web + 2.docker rm web + 3.docker-compose up -d + + + + +!!!!!!!!!!!!!!! +详细交互流程如下: + 1.用户发起操作,浏览器发送请求数据 + 2.用户浏览器向对应的服务器发起请求 + 3.linux服务器开启的端口是80端口,接收到了用户浏览器发起的请求 + 4.linux服务器已经启动了gp-web这个容器【注意gp-web是容器名称,而web是服务名称,docker内的容器之间,通过服务名称来相互通信,但是服务名称和容器名称是不同的】,gp-web这个容器就是一个node程序,也就是网站的node服务器 + 5.gp-web这个容器就是node服务器,node服务器接收到浏览器请求的数据,通过里面的路由等一系列处理,最终到了node程序和数据库服务交互的节点 + 6.node程序里面根据config.js里面的数据库请求的url,向数据库【集群】发送请求, + 一般是“数据库集群”,所以url需要是一个数据库集群的url,例如 mongodb://gp:Z103496out@database:27017,database:27018,database:27019/gpclubs?retryWrites=false&replicaSet=mongoset + 注意这里不能把第二个database改成slave,把第三个database改成arbiter,这样会造成集群url失效,最终导致添加评论的时候失效【因为评论要用到事务,而mongo的事务依赖于集群,一旦集群的url错了,就全错了】 + 这里特别要注意的是,url里面的前缀不是数据库的ip地址,而是docker程序里面的服务名称【不是容器名称,千万别搞错,不是db-slave,而是slave】 + + 7.每个数据库服务【例如db-slave】都已在之前通过docker exec -it db-slave mongod --config ./dbconfig/slave.conf这种配置文件绑定命令,设置好了数据库服务的各种配置【数据放哪里,log放哪里,安全性配置等】 + 而且多个数据库服务之前已经通过rs.initiate({_id:"mongoset",members:[{_id:0,host:"43.143.25.248:27017"},{_id:1,host:"43.143.25.248:27018"},{_id:2,host:"43.143.25.248:27019",arbiterOnly:true}]})设置好了集群, + 之前也已经用db.createUser创建好了数据库管理员帐号,所以node程序的数据请求一过来,结果上面第6步的url连接到副本集,会自动通过副本集内部一些列的操作,把数据同步到三个“数据库服务器”程序,也就是三个容器,分别是db-master-slave,db-arbiter + 8.数据库内容同步到三个容器以后,接下来就是容器内部各自的事情了,因为每个容器都设置了对应的volume, + 例如容器设置了target: /data/db ,数据在容器里面的保存位置,以容器的根目录为根目录,所以首先数据是放到容器下的/data/db文件夹里面, + 而容器设置了source: slave-data ,所以容器还会把/data/db下的数据同步到slave-data这个数据卷,slave-data这个数据卷是由docker统一自己管理的,只需要知道它放在本地的/var/snap/docker/common/var-lib-docker/volumes/下面即可, + 里面的文件夹名称是按照slave-data以及其他参数来自动设定文件夹名称的,最终的路径是/var/snap/docker/common/var-lib-docker/volumes/koa-node_slave-data/_data, + 其中koa-node_slave-data/_data:koa-node是文件夹根目录,slave-data是数据卷名称,按照“根目录文件夹名称_数据卷名称/_data”来产生本地数据保存路径 +!!!!!!!!!!!!!!! + + + +window下远程连接数据库: + 打开window下的mongodb compass软件,输入config.js文件里面的线上数据库url即可,例如mongodb://账号:密码@43.143.25.248:27017,43.143.25.248:27018,43.143.25.248:27019/gpclubs?retryWrites=false&replicaSet=mongoset + 特别注意,我的mongo集群的bindip设置设置了所有ip都可以访问,所以只要知道数据库的帐号密码,就可以直接在任何机子上访问数据库,这个是不安全了,因为我自己住的地方的ip是动态的,所以不能限制访问数据库的ip,不然自己也没法访问 + 但是如果真的是线上站点,那么必须给数据库的访问地址绑定ip,只能特定的ip才能访问 + + +mongo数据库命令: + +3、查询数据库 + + show dbs + + 或 + + show databases + +4、创建数据库 + + use dbName + + 查看表 + + show tables; + +5、插入数据 + + db..insert(); + + 如:db.members.insert({name:"Michael",age:18,...}); + +6、查询 + + db..find(); + +7、修改 + + 如:db.members.update({name:"Michael"},{$set:{age:20}}); + +8、删除表中的数据 + + 如:db.members.remove({name:"Michael"}); + + 删除全部:db.members.remove({}); + +9、删除表 + + db.members.drop(); + +10、删除数据库 + + db.dropDatabase(); \ No newline at end of file diff --git a/nginx.readme b/nginx.readme new file mode 100644 index 0000000..9376230 --- /dev/null +++ b/nginx.readme @@ -0,0 +1,57 @@ +菜鸟教程:https://www.runoob.com/linux/nginx-install-setup.html +nginx使用场景和配置项:https://blog.csdn.net/zhanglongfei_test/article/details/119904075 +nginx功能:反向代理|正向代理 负载均衡 http服务器【静态页面】 +说明:普通的java项目,没有高并发的情况下,nginx配置比较简单,或者直接不用nginx做反向代理,直接用tomcat+jsp(安装jdk,这个直接就可以编译和执行java代码) + +关于nginx,apache,tomcat以及动态页面和静态页面:https://www.runoob.com/linux/nginx-install-setup.html + apache:本身只支持静态解析,但可以通过扩展脚本、模块等支持动态页面;常见的网站架构有:apache+php、apache+tomcat等。 + nginx:占用内存少,并发能力强;静态页面处理能力较强,尤其是反向代理服务表现突出,常被用作负载均衡和代理服务器使用;常见的网站架构有:nginx+php、nginx+tomcat、nginx+apache+php等 + nginx的epoll主要是对网络io进行操作,所以nginx适合高并发,静态资源 + tomcat:开源的Java web应用服务器软件,常被称之为servlet容器;tomcat技术先进、性能稳定、而且免费,因而深受Java爱好者的喜爱并得到了广泛使用。tomcat静态页面处理能力较弱 + Web 应用服务器。实际上Tomcat是Apache 服务器的扩展 + +所以,一般java如果开发一个站点,方案是:【一般都做前后端分离,前端开发完以后,把静态资源和mapping.json传给服务端后台(不管是node,php,jsp,asp还是其他)】 + 1.后端用nginx+tomcat:nginx做反向代理和静态资源服务器,tomcat做动态资源服务器【jsp】 + + +关于缓存: + 1.静态资源一直用缓存【缓存cache-cotrol为public】,通过文件名称的hash来区分版本 + 2.动态资源通过cache-control的private,public,no-store un-cache max-age来设置缓存 + + +正向代理:是客户端代理人,代表客户端和服务器去沟通,然后把结果返回给客户端,正向代理就是常用的ip代理,可以隐藏客户端学习,服务器只知道是哪个代理服务器访问在访问它; +反向代理:是服务器代理人,代表服务器和客户端沟通,接受客户端请求后转发给服务器,服务器返回结果后给反向代理服务器,反向代理服务器再把结果返回给客户端;主要是用于服务器的安全隔离,内部环境不能让外部访问,用反向代理服务器可以解决这个问题。 + +Servlet容器(Web容器):独立的Servlet容器是Tomcat的默认模式 + 1.实现 Servlet 规范定义的各种接口和类,为 Servlet 的运行提供底层支持; + 2.管理用户编写的 Servlet 类,以及实例化以后的对象; + 3.提供 HTTP 服务,相当于一个简化的服务器。【也可以自己用nginx作为http服务器,大多用nginx作为http静态资源服务器和反向代理以及负载均衡】 + +我们通常所说的 Web 服务器,比如 Apache、Nginx、IIS 等,它们的功能往往都比较单一,只能提供 http(s) 服务,让用户访问静态资源(HTML 文档、图片、CSS 文件、JavaScript 文件等),它们不能执行任何编程语言,也不能访问数据库,更不能让用户注册和登录。 + +部署网站时都是将源代码直接扔到服务器上,然而源代码自己并不能运行,必须要有解释器的支持;当用户访问动态页面时,解释器负责分析、编译和执行源代码,然后得到处理结果 +解释器是执行脚本语言的核心部件,除此以外还有一些辅助性的部件,例如: +垃圾回收器:负责及时释放不需要的内存,腾出资源供其它页面使用; +标准库:任何编程语言都会附带标准库,它们提供了很多通用性的功能,极大地提高了开发效率,避免重复造轮子。 +我们习惯将以上各种支持脚本语言运行的部件统称为运行环境,或者运行时(Runtime)!!!!!!!! + +!!!!!!!!!!!!!!http://c.biancheng.net/servlet2/container.html这个写得非常好 +部署动态网站一般至少需要三个组件: Web 服务器【Apache、Nginx、IIS】、脚本语言运行时、数据库【 SQL Server,mySQL,mongodb,oracle 】 +脚本语言运行时:包含解释器,垃圾回收器,标准库(通用函数库); + 在java中,对应的是JRE(包含了java虚拟机,java基础类库)+Servlet 容器;JRE只是运行环境和基础莱库,但是不符合Servlet标准,所以得通过Servlet容器来实现Servlet的接口,和JRE做对接 + 一个动态页面对应一个 Servlet 类,开发一个动态页面就是编写一个 Servlet 类,当用户请求到达时,Servlet 容器会根据配置文件(web.xml)来决定调用哪个类 + Servlet 容器接收到请求以后,会根据配置文件(web.xml)找到对应的 Servlet 类,将它加载并实例化,然后调用其中的方法来处理用户请求; + 处理结束后,Servlet 容器将处理结果【静态资源】再转交给 Web 服务器, Web 服务器将处理结果【静态资源】进行封装,以 HTTP 响应的形式发送给最终的用户。 + +常用的 Web 容器有 Tomcat、Jboss、Jetty、WebLogic 等,其中 Tomcat 由 Java 官方提供,是初学者最常使用的。 + + + +nginx命令: + nginx:启动 + nginx -s reload:重新载入配置文件 + nginx -s reopen:重启 + nginx -s stop:关闭 + + +nginx安装,window详见:https://www.jianshu.com/p/f9b41e785a36 \ No newline at end of file diff --git a/nodemon.json b/nodemon.json new file mode 100644 index 0000000..f7b4560 --- /dev/null +++ b/nodemon.json @@ -0,0 +1,6 @@ +{ + "restartable": "rs", + "verbose": true, + "ignore": ["assets/*", "build/*", "node_modules/", ".git/", ".vscode/", "cache/", "log/"], + "ext": "js html" +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..1a9983e --- /dev/null +++ b/package.json @@ -0,0 +1,58 @@ +{ + "name": "demo", + "version": "1.0.0", + "description": "", + "main": "app.js", + "scripts": { + "start": "set NODE_ENV=dev&&nodemon app.js", + "start-prod": "nodemon app.js", + "stops": "taskkill /f /im node.exe", + "dev": "NODE_ENV='dev' nodemon app.js", + "qa-win": "set NODE_ENV=qa&&nodemon app.js", + "qa": "NODE_ENV='qa' node app.js", + "yz": "NODE_ENV='yz' node app.js", + "fe": "node assets/build/index.js", + "prod": "node app.js", + "test": "set NODE_ENV=dev&&node-debug app.js", + "debug-node": "set NODE_ENV=dev&&node --inspect-brk app.js", + "debugs": "set NODE_ENV=dev&&nodemon --inspect-brk app.js", + "debugyz-win": "set NODE_ENV=yz&&nodemon --inspect-brk app.js", + "debugyz": "NODE_ENV='yz' nodemon --inspect-brk=0.0.0.0 app.js", + "dg": "set NODE_ENV=dev&&nodemon --inspect-brk --preload app.js", + "debug-webpack": "set NODE_ENV=prod&&node --inspect-brk ./assets/build/webpack.config.product.js" + }, + "license": "MIT", + "dependencies": { + "base64url": "^3.0.1", + "co-views": "^2.1.0", + "html-minifier": "^4.0.0", + "ip": "^1.1.5", + "jsonwebtoken": "^8.5.1", + "koa": "^2.0.0", + "koa-bodyparser": "^2.2.0", + "koa-compress": "^5.1.0", + "koa-conditional-get": "^1.0.3", + "koa-convert": "^1.2.0", + "koa-etag": "^2.1.1", + "koa-helmet": "^2.0.0", + "koa-jwt": "^4.0.3", + "koa-router": "^5.4.0", + "koa-session": "^6.2.0", + "mongodb": "^4.5.0", + "mongoose": "^6.4.0", + "mongoose-transactions": "^1.1.4", + "node-rsa": "^1.1.1", + "nunjucks": "^3.2.3", + "request-ip": "^2.2.0", + "svg-captcha": "^1.4.0", + "uuid": "^3.1.0", + "xss": "^1.0.13" + }, + "devDependencies": { + "formidable": "^2.0.1", + "koa-static": "^5.0.0", + "nodemon": "^1.9.2", + "should": "^10.0.0", + "supertest": "^2.0.0" + } +} diff --git a/prod.json b/prod.json new file mode 100644 index 0000000..84d1b5a --- /dev/null +++ b/prod.json @@ -0,0 +1,15 @@ +{ + "apps" : [{ + "name" : "demo_prod", + "script" : "./app.js", + "env": { + "NODE_ENV": "prod", + "PORT": "10000" + }, + "instances" : 1, + "watch":true, + }] +} + + + diff --git a/qa.json b/qa.json new file mode 100644 index 0000000..8d760ea --- /dev/null +++ b/qa.json @@ -0,0 +1,11 @@ +{ + "apps" : [{ + "name" : "demo_qa", + "script" : "./app.js", + "env": { + "NODE_ENV": "qa", + "PORT": "10000" + }, + "watch": true + }] +} diff --git a/routes/index.js b/routes/index.js new file mode 100644 index 0000000..d535d91 --- /dev/null +++ b/routes/index.js @@ -0,0 +1,154 @@ +// desc:这个文件,通过路由实现了后端的mvc架构,执行路由的中间通过render和getController来连接各自的view和controller + +const koaRouter=require("koa-router"); +const path = require("path"); +const views = require("co-views");//用于渲染tamplate +const minifier = require('html-minifier').minify; +const router=koaRouter(); +var config = require("../config"); +var reg1 = /\./; +var cacheController = {}; + + + +function* render(viewPath,opts) { + var viewPath=path.join(this.state.controller, viewPath); + this.state.scope.__renderTime = new Date(); + var body = yield views(path.resolve(__dirname + "/../views"), { map: { html: "nunjucks" } })(viewPath, this.state.scope); + if(config.enableHTMLCompress){ + body = minifier(body,{ + removeComments:true, + removeEmptyAttributes: false, + removeEmptyElements:false, + removeTagWhitespace:false, + removeAttributeQuotes:false, + collapseWhitespace:true + }); + } + + this.body = body;//body是一个字符串,返回的都是字符串,告诉浏览器数据用什么格式解析也用字符串传递 + this.state.scope = null; + this.set("Cache-Control", opts.cache||"public"); +} + +//ajax请求和html页面请求一毛一样,yield后面“不能是字符串”否则会出现500 可以是表达式,对象,数组等 +function* renderJSON(JSONData) { + var body = yield JSONData; + this.body = body;//body是一个字符串,返回的都是字符串,告诉浏览器数据用什么格式解析也用字符串传递 + this.state.scope = null; + this.set("Cache-Control", "private"); + this.set("Content-Type", "application/json"); + + //默认是keep-alive,服务器超过一定时间才会关闭Connection,好处是再次请求不需要重新建立连接,坏处是占资源 + //所以只用一次的ajax请求,直接就关,后续还可能多次请求的ajax,就开着 + this.set("Connection", "close"); +} + +//因为调用的时候没有用xhr,是直接get请求图片的url,所以返回的时候,body的数据直接返回给图片的url +function* renderPicture(Data){ + this.body=Data; + this.state.scope = null; + this.set('Content-Type', 'image/svg+xml'); + this.set("Connection", "close"); +} + +//node端的JSONP设置 +function* renderJSONP(JSONPData,callback) { + var body = yield {}; + // this.body = JSONPData; + var str=""; + if(callback){ + str=`${callback}(${JSON.stringify(JSONPData)})`; + } + this.body = str; //返回的数据内容是str,这样前端接收到的script或者其他跨域标签的内容就是str,因为script标签加载后会自动执行,就会执行str这个跳语句 + this.state.scope = null; + + + this.set("Content-Type", "text/javascript");//jsonp这个必须设置,不然chrome报mime错误 + this.set("Cache-Control", "private"); + this.set("Access-Control-Allow-Origin", "http:localhost:8080/");//跨域就需要设置这个,不然没法传 + // this.set("Access-Control-Allow-Origin", "*");//允许所有的跨域请求,这个明显不合适 + this.set("Connection", "close"); +} + + + +function getControllerInstance(controllerName) { + if (!cacheController[controllerName]) { + var controllerPath = path.join(path.resolve(__dirname, "../controllers"), controllerName); + cacheController[controllerName] = require(controllerPath+".js"); + } + return cacheController[controllerName]; +} + +//跳转到对应页面controller之前的公共执行函数,可以添加所有页面公共的数据,包括逻辑判断 +function* getController(controller, context) { + + var arr = controller.split(reg1), + len = arr.length; + if (len < 2) { + context.throw(500, "the controller can't found"); + } + var actionName = arr[len - 1], + mActionName = 'm_'+actionName; + var controllerName = arr.slice(0, len - 1).join("/"); + var ctr = getControllerInstance(controllerName); + if (!ctr) { + context.throw(500, "the controller can't found"); + } + if (!ctr[actionName] && !ctr[mActionName]) { + context.throw(404, "the action can't found"); + } + + + context.state.controller = controllerName; + context.render = render; + context.renderJSON = renderJSON; + context.renderJSONP= renderJSONP; + context.renderPicture=renderPicture; + var ua=context.request.accept.headers['user-agent']; + var isMobile = /mobile/i.test(ua) && !/iPad/i.test(ua); + + var action; + if (ctr[mActionName] && isMobile){ + action = ctr[mActionName].bind(context); + } else if(ctr[actionName]){ + action = ctr[actionName].bind(context); + } else{ + action = ctr[mActionName].bind(context); + } + + + if (!(context.state.cache && context.state.cache.enabled)) { + yield action(context.state.scope); + } +} + + +module.exports = { + router: router, + get(route, controller) { + router.get(route, function* (next) { + yield getController(controller, this); + yield next; + }); + }, + post(route, controller) { + router.post(route, function* (next) { + yield getController(controller, this); + yield next; + }); + }, + del(route, controller) { + router.delete(route, function* (next) { + yield getController(controller, this); + yield next; + }); + }, + put(route, controller) { + router.put(route, function* (next) { + yield getController(controller, this); + yield next; + }); + } +}; diff --git a/routes/mapping.js b/routes/mapping.js new file mode 100644 index 0000000..940022f --- /dev/null +++ b/routes/mapping.js @@ -0,0 +1,66 @@ +// module.exports = [ + +// //demo +// { +// match: "/recommend/list", +// controller: "recommend.list" +// },{ +// match: "/recommend/index", +// controller: "recommend.index" +// } + +// ] + +var router = require("./index"), + get = router.get, + post = router.post, + put = router.put; + + + +get("/recommend/error_page", "recommend.error_page"); +get("/recommend/react_demo", "recommend.react_demo"); +get("/recommend/redux_demo", "recommend.redux_demo"); +get("/recommend/home", "recommend.home"); +get("/index", "recommend.home"); +get("/", "recommend.home"); +get("/recommend/personal", "recommend.personal"); + +get("/ajax/logout", "ajax.logout"); +get("/ajax/search", "ajax.search"); +get("/ajax/user_info", "ajax.user_info"); +get("/ajax/person_collection_list", "ajax.person_collection_list"); +get("/ajax/person_attention_list", "ajax.person_attention_list"); +get("/ajax/person_fans_list", "ajax.person_fans_list"); +get("/ajax/person_article_list", "ajax.person_article_list"); +get("/ajax/article_info", "ajax.article_info"); +get("/ajax/article_tag_info", "ajax.article_tag_info"); +get("/ajax/jsonp", "ajax.jsonp");//没用到,可以关闭 + + + + + +// post("/ajax/add_article_tag", "ajax.add_article_tag");//添加或删除文章的标签 +post("/ajax/modify_pwd", "ajax.modify_pwd");//修改密码 +post("/ajax/update_user_info", "ajax.update_user_info"); +post("/ajax/add_article_collect", "ajax.add_article_collect");//文章收藏或取消 +post("/ajax/add_article_fav", "ajax.add_article_fav");//文章点赞或取消 +post("/ajax/add_user_attention", "ajax.add_user_attention");//关注用户或取消 +post("/ajax/add_comment_fav", "ajax.add_comment_fav");//给评论点赞或取消 +post("/ajax/add_article_comment", "ajax.add_article_comment");//添加评论 +post("/ajax/login", "ajax.login");//登录数据是非对称加密的 +post("/ajax/reigst_user", "ajax.reigst_user");//注册数据是非对称加密的 +get("/ajax/captcha", "ajax.captcha");//动态图片验证码,注册登录要用 +post("/ajax/dynomic_code", "ajax.dynomic_code");//登陆时候的动态码,登录保密的关键 +post("/ajax/create_article", "ajax.create_article");//创建文章 +post("/ajax/upload", "ajax.upload");//上传图片 + + + + +// router.get('/api/getCaptcha', function(req, res, next) { + +// return api.getCaptcha(req, res, next); + +// }) \ No newline at end of file diff --git a/static/2022-09-01-tag1/assets-mapping.json b/static/2022-09-01-tag1/assets-mapping.json new file mode 100644 index 0000000..19ac344 --- /dev/null +++ b/static/2022-09-01-tag1/assets-mapping.json @@ -0,0 +1 @@ +{"/recommend/app/css_example/bundle.css":"/recommend/app/css_example/bundle-2022_9_2_1662085369265.css","/recommend/app/css_example/bundle.js":"/recommend/app/css_example/bundle-2022_9_2_1662085369265.js","/recommend/app/error_page/bundle.css":"/recommend/app/error_page/bundle-2022_9_2_1662085369265.css","/recommend/app/error_page/bundle.js":"/recommend/app/error_page/bundle-2022_9_2_1662085369265.js","/recommend/app/home/bundle.css":"/recommend/app/home/bundle-2022_9_2_1662085369265.css","/recommend/app/home/bundle.js":"/recommend/app/home/bundle-2022_9_2_1662085369265.js","/recommend/app/personal/bundle.css":"/recommend/app/personal/bundle-2022_9_2_1662085369265.css","/recommend/app/personal/bundle.js":"/recommend/app/personal/bundle-2022_9_2_1662085369265.js","/recommend/app/react_demo/bundle.js":"/recommend/app/react_demo/bundle-2022_9_2_1662085369265.js","/recommend/app/redux_demo/bundle.js":"/recommend/app/redux_demo/bundle-2022_9_2_1662085369265.js","/recommend/app/vue_demo/bundle.js":"/recommend/app/vue_demo/bundle-2022_9_2_1662085369265.js","/recommend/common/assets/bundle.js":"/recommend/common/assets/bundle-2022_9_2_1662085369265.js","/recommend/common/mc/bundle.css":"/recommend/common/mc/bundle-2022_9_2_1662085369265.css","/recommend/common/mc/bundle.js":"/recommend/common/mc/bundle-2022_9_2_1662085369265.js","/recommend/common/pc/bundle.css":"/recommend/common/pc/bundle-2022_9_2_1662085369265.css","/recommend/common/pc/bundle.js":"/recommend/common/pc/bundle-2022_9_2_1662085369265.js","/recommend/dll/prod/dll.js":"/recommend/dll/prod/dll_2022_8_21_1661074952873.js"} \ No newline at end of file diff --git a/static/2022-09-01-tag1/recommend/app/css_example/bundle-2022_9_2_1662085369265.css b/static/2022-09-01-tag1/recommend/app/css_example/bundle-2022_9_2_1662085369265.css new file mode 100644 index 0000000..5598c79 --- /dev/null +++ b/static/2022-09-01-tag1/recommend/app/css_example/bundle-2022_9_2_1662085369265.css @@ -0,0 +1 @@ +.container{background:#e3e3e3;height:200px;margin:0 50px}.center{background:#a0a0a0;height:200px;margin:0 auto;width:100px}.wrapper1{background:red;float:left;height:400px;margin:10px;overflow:hidden;position:relative;width:400px}.wrapper1 .inner1{background-color:#fff;height:200px;left:50%;margin-left:-100px;margin-top:-100px;position:absolute;top:50%;width:200px}.wrapper2{-moz-box-align:center;-ms-flex-align:center;-moz-box-pack:center;-ms-flex-pack:center;-webkit-align-items:center;align-items:center;background:red;display:-webkit-flex;display:-moz-box;display:-ms-flexbox;display:flex;height:400px;-webkit-justify-content:center;justify-content:center;margin:10px;width:400px}.wrapper2 .inner2{background-color:#fff;height:200px;width:200px}.wrapper3{background:#456321;float:left;height:400px;margin:10px;text-align:center;width:400px}.wrapper3 span{content:"";height:100%}.wrapper3 .inner3,.wrapper3 span{display:inline-block;vertical-align:middle}.wrapper3 .inner3{background-color:#fff;max-width:100%;width:200px}.box .bl0{background-color:#e3e3e3;float:left;width:200px}.box .br0{background-color:#a0a0a0;overflow:hidden}.box .br0:after{clear:both;content:""}.box{overflow:hidden}.box .bl{background-color:#e3e3e3;float:left;width:200px}.box .br{background-color:#a0a0a0;margin-left:200px}.box{position:relative}.box .bl1{background-color:#e3e3e3;position:absolute;width:200px}.box .br1{background-color:#a0a0a0;clear:both;height:200px;margin-left:200px}.box2{display:-webkit-flex;display:-moz-box;display:-ms-flexbox;display:flex}.box2 .bl2{background-color:#e3e3e3;width:200px}.box2 .br2{-moz-box-flex:1;-ms-flex-positive:1;background-color:#a0a0a0;-webkit-flex-grow:1;flex-grow:1}.content{position:relative}.content .left-content{left:0}.content .left-content,.content .right-content{background-color:#a0a0a0;position:absolute;top:0;width:100px}.content .right-content{right:0}.content .center-content{background-color:#e3e3e3;margin:0 100px}.content1 .left-content1{background-color:#a0a0a0;float:left;width:100px}.content1 .right-content1{background-color:#a0a0a0;float:right;width:100px}.content1 .center-content1{background-color:#e3e3e3;margin:0 200px} \ No newline at end of file diff --git a/static/2022-09-01-tag1/recommend/app/css_example/bundle-2022_9_2_1662085369265.js b/static/2022-09-01-tag1/recommend/app/css_example/bundle-2022_9_2_1662085369265.js new file mode 100644 index 0000000..cd434e3 --- /dev/null +++ b/static/2022-09-01-tag1/recommend/app/css_example/bundle-2022_9_2_1662085369265.js @@ -0,0 +1 @@ +(()=>{var e={63995:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>r});const r={container:"container",center:"center",wrapper1:"wrapper1",inner1:"inner1",wrapper2:"wrapper2",inner2:"inner2",wrapper3:"wrapper3",inner3:"inner3",box:"box",bl0:"bl0",br0:"br0",bl:"bl",br:"br",bl1:"bl1",br1:"br1",box2:"box2",bl2:"bl2",br2:"br2",content:"content","left-content":"left-content","right-content":"right-content","center-content":"center-content",content1:"content1","left-content1":"left-content1","right-content1":"right-content1","center-content1":"center-content1"}}},t={};function n(r){var o=t[r];if(void 0!==o)return o.exports;var c=t[r]={exports:{}};return e[r](c,c.exports,n),c.exports}n.d=(e,t)=>{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n(63995)})(); \ No newline at end of file diff --git a/static/2022-09-01-tag1/recommend/app/error_page/bundle-2022_9_2_1662085369265.css b/static/2022-09-01-tag1/recommend/app/error_page/bundle-2022_9_2_1662085369265.css new file mode 100644 index 0000000..86921c5 --- /dev/null +++ b/static/2022-09-01-tag1/recommend/app/error_page/bundle-2022_9_2_1662085369265.css @@ -0,0 +1 @@ +.error_wrapper{height:100%;text-align:center;width:100%}.error_wrapper .error_inner{margin:100px auto}.error_wrapper .back_home{font-size:16px;margin-left:100px}.error_wrapper a.back_home:hover{color:red} \ No newline at end of file diff --git a/static/2022-09-01-tag1/recommend/app/error_page/bundle-2022_9_2_1662085369265.js b/static/2022-09-01-tag1/recommend/app/error_page/bundle-2022_9_2_1662085369265.js new file mode 100644 index 0000000..7fd1542 --- /dev/null +++ b/static/2022-09-01-tag1/recommend/app/error_page/bundle-2022_9_2_1662085369265.js @@ -0,0 +1,2 @@ +/*! For license information please see bundle-2022_9_2_1662085369265.js.LICENSE.txt */ +(()=>{"use strict";var e={97898:(e,t,n)=>{n.r(t),n.d(t,{default:()=>a});var r=n(61370),i=n.n(r),o=new URL(n(62911),n.b);const a=' 返回首页 '},61370:e=>{e.exports=function(e,t){return t||(t={}),e?(e=String(e.__esModule?e.default:e),t.hash&&(e+=t.hash),t.maybeNeedQuotes&&/[\t\n\f\r "'=<>`]/.test(e)?'"'.concat(e,'"'):e):e}},65546:(e,t,n)=>{n.r(t),n.d(t,{default:()=>r});const r={error_wrapper:"error_wrapper",error_inner:"error_inner",back_home:"back_home"}},62911:(e,t,n)=>{e.exports=n.p+"app/error_page/error_404-50a1d.png"}},t={};function n(r){var i=t[r];if(void 0!==i)return i.exports;var o=t[r]={exports:{}};return e[r](o,o.exports,n),o.exports}n.m=e,n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.p="/recommend/",n.b=document.baseURI||self.location.href,(()=>{var e=Object.freeze({});function t(e){return null==e}function r(e){return null!=e}function i(e){return!0===e}function o(e){return"string"==typeof e||"number"==typeof e||"symbol"==typeof e||"boolean"==typeof e}function a(e){return null!==e&&"object"==typeof e}var s=Object.prototype.toString;function c(e){return"[object Object]"===s.call(e)}function u(e){return"[object RegExp]"===s.call(e)}function l(e){var t=parseFloat(String(e));return t>=0&&Math.floor(t)===t&&isFinite(e)}function f(e){return r(e)&&"function"==typeof e.then&&"function"==typeof e.catch}function p(e){return null==e?"":Array.isArray(e)||c(e)&&e.toString===s?JSON.stringify(e,null,2):String(e)}function d(e){var t=parseFloat(e);return isNaN(t)?e:t}function v(e,t){for(var n=Object.create(null),r=e.split(","),i=0;i-1)return e.splice(n,1)}}var g=Object.prototype.hasOwnProperty;function _(e,t){return g.call(e,t)}function b(e){var t=Object.create(null);return function(n){return t[n]||(t[n]=e(n))}}var $=/-(\w)/g,w=b((function(e){return e.replace($,(function(e,t){return t?t.toUpperCase():""}))})),C=b((function(e){return e.charAt(0).toUpperCase()+e.slice(1)})),x=/\B([A-Z])/g,k=b((function(e){return e.replace(x,"-$1").toLowerCase()}));var A=Function.prototype.bind?function(e,t){return e.bind(t)}:function(e,t){function n(n){var r=arguments.length;return r?r>1?e.apply(t,arguments):e.call(t,n):e.call(t)}return n._length=e.length,n};function O(e,t){t=t||0;for(var n=e.length-t,r=new Array(n);n--;)r[n]=e[n+t];return r}function S(e,t){for(var n in t)e[n]=t[n];return e}function T(e){for(var t={},n=0;n0,Q=Z&&Z.indexOf("edge/")>0,Y=(Z&&Z.indexOf("android"),Z&&/iphone|ipad|ipod|ios/.test(Z)||"ios"===W),ee=(Z&&/chrome\/\d+/.test(Z),Z&&/phantomjs/.test(Z),Z&&Z.match(/firefox\/(\d+)/)),te={}.watch,ne=!1;if(J)try{var re={};Object.defineProperty(re,"passive",{get:function(){ne=!0}}),window.addEventListener("test-passive",null,re)}catch(e){}var ie=function(){return void 0===z&&(z=!J&&!q&&void 0!==n.g&&(n.g.process&&"server"===n.g.process.env.VUE_ENV)),z},oe=J&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__;function ae(e){return"function"==typeof e&&/native code/.test(e.toString())}var se,ce="undefined"!=typeof Symbol&&ae(Symbol)&&"undefined"!=typeof Reflect&&ae(Reflect.ownKeys);se="undefined"!=typeof Set&&ae(Set)?Set:function(){function e(){this.set=Object.create(null)}return e.prototype.has=function(e){return!0===this.set[e]},e.prototype.add=function(e){this.set[e]=!0},e.prototype.clear=function(){this.set=Object.create(null)},e}();var ue=N,le=0,fe=function(){this.id=le++,this.subs=[]};fe.prototype.addSub=function(e){this.subs.push(e)},fe.prototype.removeSub=function(e){y(this.subs,e)},fe.prototype.depend=function(){fe.target&&fe.target.addDep(this)},fe.prototype.notify=function(){var e=this.subs.slice();for(var t=0,n=e.length;t-1)if(o&&!_(i,"default"))a=!1;else if(""===a||a===k(e)){var c=Ve(String,i.type);(c<0||s0&&(dt((s=vt(s,(n||"")+"_"+a))[0])&&dt(u)&&(l[c]=ge(u.text+s[0].text),s.shift()),l.push.apply(l,s)):o(s)?dt(u)?l[c]=ge(u.text+s):""!==s&&l.push(ge(s)):dt(s)&&dt(u)?l[c]=ge(u.text+s.text):(i(e._isVList)&&r(s.tag)&&t(s.key)&&r(n)&&(s.key="__vlist"+n+"_"+a+"__"),l.push(s)));return l}function ht(e,t){if(e){for(var n=Object.create(null),r=ce?Reflect.ownKeys(e):Object.keys(e),i=0;i0,a=t?!!t.$stable:!o,s=t&&t.$key;if(t){if(t._normalized)return t._normalized;if(a&&r&&r!==e&&s===r.$key&&!o&&!r.$hasNormal)return r;for(var c in i={},t)t[c]&&"$"!==c[0]&&(i[c]=bt(n,c,t[c]))}else i={};for(var u in n)u in i||(i[u]=$t(n,u));return t&&Object.isExtensible(t)&&(t._normalized=i),B(i,"$stable",a),B(i,"$key",s),B(i,"$hasNormal",o),i}function bt(e,t,n){var r=function(){var e=arguments.length?n.apply(null,arguments):n({}),t=(e=e&&"object"==typeof e&&!Array.isArray(e)?[e]:pt(e))&&e[0];return e&&(!t||1===e.length&&t.isComment&&!gt(t))?void 0:e};return n.proxy&&Object.defineProperty(e,t,{get:r,enumerable:!0,configurable:!0}),r}function $t(e,t){return function(){return e[t]}}function wt(e,t){var n,i,o,s,c;if(Array.isArray(e)||"string"==typeof e)for(n=new Array(e.length),i=0,o=e.length;idocument.createEvent("Event").timeStamp&&(vn=function(){return hn.now()})}function mn(){var e,t;for(dn=vn(),fn=!0,sn.sort((function(e,t){return e.id-t.id})),pn=0;pnpn&&sn[n].id>e.id;)n--;sn.splice(n+1,0,e)}else sn.push(e);ln||(ln=!0,rt(mn))}}(this)},gn.prototype.run=function(){if(this.active){var e=this.get();if(e!==this.value||a(e)||this.deep){var t=this.value;if(this.value=e,this.user){var n='callback for watcher "'+this.expression+'"';Ke(this.cb,this.vm,[e,t],this.vm,n)}else this.cb.call(this.vm,e,t)}}},gn.prototype.evaluate=function(){this.value=this.get(),this.dirty=!1},gn.prototype.depend=function(){for(var e=this.deps.length;e--;)this.deps[e].depend()},gn.prototype.teardown=function(){if(this.active){this.vm._isBeingDestroyed||y(this.vm._watchers,this);for(var e=this.deps.length;e--;)this.deps[e].removeSub(this);this.active=!1}};var _n={enumerable:!0,configurable:!0,get:N,set:N};function bn(e,t,n){_n.get=function(){return this[t][n]},_n.set=function(e){this[t][n]=e},Object.defineProperty(e,n,_n)}function $n(e){e._watchers=[];var t=e.$options;t.props&&function(e,t){var n=e.$options.propsData||{},r=e._props={},i=e.$options._propKeys=[];e.$parent&&xe(!1);var o=function(o){i.push(o);var a=Re(o,t,n,e);Oe(r,o,a),o in e||bn(e,"_props",o)};for(var a in t)o(a);xe(!0)}(e,t.props),t.methods&&function(e,t){e.$options.props;for(var n in t)e[n]="function"!=typeof t[n]?N:A(t[n],e)}(e,t.methods),t.data?function(e){var t=e.$options.data;c(t=e._data="function"==typeof t?function(e,t){de();try{return e.call(t,t)}catch(e){return ze(e,t,"data()"),{}}finally{ve()}}(t,e):t||{})||(t={});var n=Object.keys(t),r=e.$options.props,i=(e.$options.methods,n.length);for(;i--;){var o=n[i];0,r&&_(r,o)||U(o)||bn(e,"_data",o)}Ae(t,!0)}(e):Ae(e._data={},!0),t.computed&&function(e,t){var n=e._computedWatchers=Object.create(null),r=ie();for(var i in t){var o=t[i],a="function"==typeof o?o:o.get;0,r||(n[i]=new gn(e,a||N,N,wn)),i in e||Cn(e,i,o)}}(e,t.computed),t.watch&&t.watch!==te&&function(e,t){for(var n in t){var r=t[n];if(Array.isArray(r))for(var i=0;i-1:"string"==typeof e?e.split(",").indexOf(t)>-1:!!u(e)&&e.test(t)}function Mn(e,t){var n=e.cache,r=e.keys,i=e._vnode;for(var o in n){var a=n[o];if(a){var s=a.name;s&&!t(s)&&Dn(n,o,r,i)}}}function Dn(e,t,n,r){var i=e[t];!i||r&&i.tag===r.tag||i.componentInstance.$destroy(),e[t]=null,y(n,t)}!function(t){t.prototype._init=function(t){var n=this;n._uid=On++,n._isVue=!0,t&&t._isComponent?function(e,t){var n=e.$options=Object.create(e.constructor.options),r=t._parentVnode;n.parent=t.parent,n._parentVnode=r;var i=r.componentOptions;n.propsData=i.propsData,n._parentListeners=i.listeners,n._renderChildren=i.children,n._componentTag=i.tag,t.render&&(n.render=t.render,n.staticRenderFns=t.staticRenderFns)}(n,t):n.$options=Pe(Sn(n.constructor),t||{},n),n._renderProxy=n,n._self=n,function(e){var t=e.$options,n=t.parent;if(n&&!t.abstract){for(;n.$options.abstract&&n.$parent;)n=n.$parent;n.$children.push(e)}e.$parent=n,e.$root=n?n.$root:e,e.$children=[],e.$refs={},e._watcher=null,e._inactive=null,e._directInactive=!1,e._isMounted=!1,e._isDestroyed=!1,e._isBeingDestroyed=!1}(n),function(e){e._events=Object.create(null),e._hasHookEvent=!1;var t=e.$options._parentListeners;t&&Yt(e,t)}(n),function(t){t._vnode=null,t._staticTrees=null;var n=t.$options,r=t.$vnode=n._parentVnode,i=r&&r.context;t.$slots=mt(n._renderChildren,i),t.$scopedSlots=e,t._c=function(e,n,r,i){return zt(t,e,n,r,i,!1)},t.$createElement=function(e,n,r,i){return zt(t,e,n,r,i,!0)};var o=r&&r.data;Oe(t,"$attrs",o&&o.attrs||e,null,!0),Oe(t,"$listeners",n._parentListeners||e,null,!0)}(n),an(n,"beforeCreate"),function(e){var t=ht(e.$options.inject,e);t&&(xe(!1),Object.keys(t).forEach((function(n){Oe(e,n,t[n])})),xe(!0))}(n),$n(n),function(e){var t=e.$options.provide;t&&(e._provided="function"==typeof t?t.call(e):t)}(n),an(n,"created"),n.$options.el&&n.$mount(n.$options.el)}}(Tn),function(e){var t={get:function(){return this._data}},n={get:function(){return this._props}};Object.defineProperty(e.prototype,"$data",t),Object.defineProperty(e.prototype,"$props",n),e.prototype.$set=Se,e.prototype.$delete=Te,e.prototype.$watch=function(e,t,n){var r=this;if(c(t))return An(r,e,t,n);(n=n||{}).user=!0;var i=new gn(r,e,t,n);if(n.immediate){var o='callback for immediate watcher "'+i.expression+'"';de(),Ke(t,r,[i.value],r,o),ve()}return function(){i.teardown()}}}(Tn),function(e){var t=/^hook:/;e.prototype.$on=function(e,n){var r=this;if(Array.isArray(e))for(var i=0,o=e.length;i1?O(n):n;for(var r=O(arguments,1),i='event handler for "'+e+'"',o=0,a=n.length;oparseInt(this.max)&&Dn(t,n[0],n,this._vnode),this.vnodeToCache=null}}},created:function(){this.cache=Object.create(null),this.keys=[]},destroyed:function(){for(var e in this.cache)Dn(this.cache,e,this.keys)},mounted:function(){var e=this;this.cacheVNode(),this.$watch("include",(function(t){Mn(e,(function(e){return En(t,e)}))})),this.$watch("exclude",(function(t){Mn(e,(function(e){return!En(t,e)}))}))},updated:function(){this.cacheVNode()},render:function(){var e=this.$slots.default,t=Zt(e),n=t&&t.componentOptions;if(n){var r=jn(n),i=this.include,o=this.exclude;if(i&&(!r||!En(i,r))||o&&r&&En(o,r))return t;var a=this.cache,s=this.keys,c=null==t.key?n.Ctor.cid+(n.tag?"::"+n.tag:""):t.key;a[c]?(t.componentInstance=a[c].componentInstance,y(s,c),s.push(c)):(this.vnodeToCache=t,this.keyToCache=c),t.data.keepAlive=!0}return t||e&&e[0]}},Pn={KeepAlive:Ln};!function(e){var t={get:function(){return R}};Object.defineProperty(e,"config",t),e.util={warn:ue,extend:S,mergeOptions:Pe,defineReactive:Oe},e.set=Se,e.delete=Te,e.nextTick=rt,e.observable=function(e){return Ae(e),e},e.options=Object.create(null),P.forEach((function(t){e.options[t+"s"]=Object.create(null)})),e.options._base=e,S(e.options.components,Pn),function(e){e.use=function(e){var t=this._installedPlugins||(this._installedPlugins=[]);if(t.indexOf(e)>-1)return this;var n=O(arguments,1);return n.unshift(this),"function"==typeof e.install?e.install.apply(e,n):"function"==typeof e&&e.apply(null,n),t.push(e),this}}(e),function(e){e.mixin=function(e){return this.options=Pe(this.options,e),this}}(e),Nn(e),function(e){P.forEach((function(t){e[t]=function(e,n){return n?("component"===t&&c(n)&&(n.name=n.name||e,n=this.options._base.extend(n)),"directive"===t&&"function"==typeof n&&(n={bind:n,update:n}),this.options[t+"s"][e]=n,n):this.options[t+"s"][e]}}))}(e)}(Tn),Object.defineProperty(Tn.prototype,"$isServer",{get:ie}),Object.defineProperty(Tn.prototype,"$ssrContext",{get:function(){return this.$vnode&&this.$vnode.ssrContext}}),Object.defineProperty(Tn,"FunctionalRenderContext",{value:Pt}),Tn.version="2.6.14";var Fn=v("style,class"),Rn=v("input,textarea,option,select,progress"),Hn=function(e,t,n){return"value"===n&&Rn(e)&&"button"!==t||"selected"===n&&"option"===e||"checked"===n&&"input"===e||"muted"===n&&"video"===e},Un=v("contenteditable,draggable,spellcheck"),Bn=v("events,caret,typing,plaintext-only"),Vn=v("allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,default,defaultchecked,defaultmuted,defaultselected,defer,disabled,enabled,formnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,muted,nohref,noresize,noshade,novalidate,nowrap,open,pauseonexit,readonly,required,reversed,scoped,seamless,selected,sortable,truespeed,typemustmatch,visible"),zn="http://www.w3.org/1999/xlink",Kn=function(e){return":"===e.charAt(5)&&"xlink"===e.slice(0,5)},Jn=function(e){return Kn(e)?e.slice(6,e.length):""},qn=function(e){return null==e||!1===e};function Wn(e){for(var t=e.data,n=e,i=e;r(i.componentInstance);)(i=i.componentInstance._vnode)&&i.data&&(t=Zn(i.data,t));for(;r(n=n.parent);)n&&n.data&&(t=Zn(t,n.data));return function(e,t){if(r(e)||r(t))return Gn(e,Xn(t));return""}(t.staticClass,t.class)}function Zn(e,t){return{staticClass:Gn(e.staticClass,t.staticClass),class:r(e.class)?[e.class,t.class]:t.class}}function Gn(e,t){return e?t?e+" "+t:e:t||""}function Xn(e){return Array.isArray(e)?function(e){for(var t,n="",i=0,o=e.length;i-1?wr(e,t,n):Vn(t)?qn(n)?e.removeAttribute(t):(n="allowfullscreen"===t&&"EMBED"===e.tagName?"true":t,e.setAttribute(t,n)):Un(t)?e.setAttribute(t,function(e,t){return qn(t)||"false"===t?"false":"contenteditable"===e&&Bn(t)?t:"true"}(t,n)):Kn(t)?qn(n)?e.removeAttributeNS(zn,Jn(t)):e.setAttributeNS(zn,t,n):wr(e,t,n)}function wr(e,t,n){if(qn(n))e.removeAttribute(t);else{if(G&&!X&&"TEXTAREA"===e.tagName&&"placeholder"===t&&""!==n&&!e.__ieph){var r=function(t){t.stopImmediatePropagation(),e.removeEventListener("input",r)};e.addEventListener("input",r),e.__ieph=!0}e.setAttribute(t,n)}}var Cr={create:br,update:br};function xr(e,n){var i=n.elm,o=n.data,a=e.data;if(!(t(o.staticClass)&&t(o.class)&&(t(a)||t(a.staticClass)&&t(a.class)))){var s=Wn(n),c=i._transitionClasses;r(c)&&(s=Gn(s,Xn(c))),s!==i._prevClass&&(i.setAttribute("class",s),i._prevClass=s)}}var kr,Ar,Or,Sr,Tr,Nr,jr={create:xr,update:xr},Er=/[\w).+\-_$\]]/;function Mr(e){var t,n,r,i,o,a=!1,s=!1,c=!1,u=!1,l=0,f=0,p=0,d=0;for(r=0;r=0&&" "===(h=e.charAt(v));v--);h&&Er.test(h)||(u=!0)}}else void 0===i?(d=r+1,i=e.slice(0,r).trim()):m();function m(){(o||(o=[])).push(e.slice(d,r).trim()),d=r+1}if(void 0===i?i=e.slice(0,r).trim():0!==d&&m(),o)for(r=0;r-1?{exp:e.slice(0,Sr),key:'"'+e.slice(Sr+1)+'"'}:{exp:e,key:null};Ar=e,Sr=Tr=Nr=0;for(;!Gr();)Xr(Or=Zr())?Yr(Or):91===Or&&Qr(Or);return{exp:e.slice(0,Tr),key:e.slice(Tr+1,Nr)}}(e);return null===n.key?e+"="+t:"$set("+n.exp+", "+n.key+", "+t+")"}function Zr(){return Ar.charCodeAt(++Sr)}function Gr(){return Sr>=kr}function Xr(e){return 34===e||39===e}function Qr(e){var t=1;for(Tr=Sr;!Gr();)if(Xr(e=Zr()))Yr(e);else if(91===e&&t++,93===e&&t--,0===t){Nr=Sr;break}}function Yr(e){for(var t=e;!Gr()&&(e=Zr())!==t;);}var ei,ti="__r";function ni(e,t,n){var r=ei;return function i(){var o=t.apply(null,arguments);null!==o&&oi(e,i,n,r)}}var ri=Ze&&!(ee&&Number(ee[1])<=53);function ii(e,t,n,r){if(ri){var i=dn,o=t;t=o._wrapper=function(e){if(e.target===e.currentTarget||e.timeStamp>=i||e.timeStamp<=0||e.target.ownerDocument!==document)return o.apply(this,arguments)}}ei.addEventListener(e,t,ne?{capture:n,passive:r}:n)}function oi(e,t,n,r){(r||ei).removeEventListener(e,t._wrapper||t,n)}function ai(e,n){if(!t(e.data.on)||!t(n.data.on)){var i=n.data.on||{},o=e.data.on||{};ei=n.elm,function(e){if(r(e.__r)){var t=G?"change":"input";e[t]=[].concat(e.__r,e[t]||[]),delete e.__r}r(e.__c)&&(e.change=[].concat(e.__c,e.change||[]),delete e.__c)}(i),ut(i,o,ii,oi,ni,n.context),ei=void 0}}var si,ci={create:ai,update:ai};function ui(e,n){if(!t(e.data.domProps)||!t(n.data.domProps)){var i,o,a=n.elm,s=e.data.domProps||{},c=n.data.domProps||{};for(i in r(c.__ob__)&&(c=n.data.domProps=S({},c)),s)i in c||(a[i]="");for(i in c){if(o=c[i],"textContent"===i||"innerHTML"===i){if(n.children&&(n.children.length=0),o===s[i])continue;1===a.childNodes.length&&a.removeChild(a.childNodes[0])}if("value"===i&&"PROGRESS"!==a.tagName){a._value=o;var u=t(o)?"":String(o);li(a,u)&&(a.value=u)}else if("innerHTML"===i&&er(a.tagName)&&t(a.innerHTML)){(si=si||document.createElement("div")).innerHTML=""+o+"";for(var l=si.firstChild;a.firstChild;)a.removeChild(a.firstChild);for(;l.firstChild;)a.appendChild(l.firstChild)}else if(o!==s[i])try{a[i]=o}catch(e){}}}}function li(e,t){return!e.composing&&("OPTION"===e.tagName||function(e,t){var n=!0;try{n=document.activeElement!==e}catch(e){}return n&&e.value!==t}(e,t)||function(e,t){var n=e.value,i=e._vModifiers;if(r(i)){if(i.number)return d(n)!==d(t);if(i.trim)return n.trim()!==t.trim()}return n!==t}(e,t))}var fi={create:ui,update:ui},pi=b((function(e){var t={},n=/:(.+)/;return e.split(/;(?![^(]*\))/g).forEach((function(e){if(e){var r=e.split(n);r.length>1&&(t[r[0].trim()]=r[1].trim())}})),t}));function di(e){var t=vi(e.style);return e.staticStyle?S(e.staticStyle,t):t}function vi(e){return Array.isArray(e)?T(e):"string"==typeof e?pi(e):e}var hi,mi=/^--/,yi=/\s*!important$/,gi=function(e,t,n){if(mi.test(t))e.style.setProperty(t,n);else if(yi.test(n))e.style.setProperty(k(t),n.replace(yi,""),"important");else{var r=bi(t);if(Array.isArray(n))for(var i=0,o=n.length;i-1?t.split(Ci).forEach((function(t){return e.classList.add(t)})):e.classList.add(t);else{var n=" "+(e.getAttribute("class")||"")+" ";n.indexOf(" "+t+" ")<0&&e.setAttribute("class",(n+t).trim())}}function ki(e,t){if(t&&(t=t.trim()))if(e.classList)t.indexOf(" ")>-1?t.split(Ci).forEach((function(t){return e.classList.remove(t)})):e.classList.remove(t),e.classList.length||e.removeAttribute("class");else{for(var n=" "+(e.getAttribute("class")||"")+" ",r=" "+t+" ";n.indexOf(r)>=0;)n=n.replace(r," ");(n=n.trim())?e.setAttribute("class",n):e.removeAttribute("class")}}function Ai(e){if(e){if("object"==typeof e){var t={};return!1!==e.css&&S(t,Oi(e.name||"v")),S(t,e),t}return"string"==typeof e?Oi(e):void 0}}var Oi=b((function(e){return{enterClass:e+"-enter",enterToClass:e+"-enter-to",enterActiveClass:e+"-enter-active",leaveClass:e+"-leave",leaveToClass:e+"-leave-to",leaveActiveClass:e+"-leave-active"}})),Si=J&&!X,Ti="transition",Ni="animation",ji="transition",Ei="transitionend",Mi="animation",Di="animationend";Si&&(void 0===window.ontransitionend&&void 0!==window.onwebkittransitionend&&(ji="WebkitTransition",Ei="webkitTransitionEnd"),void 0===window.onanimationend&&void 0!==window.onwebkitanimationend&&(Mi="WebkitAnimation",Di="webkitAnimationEnd"));var Ii=J?window.requestAnimationFrame?window.requestAnimationFrame.bind(window):setTimeout:function(e){return e()};function Li(e){Ii((function(){Ii(e)}))}function Pi(e,t){var n=e._transitionClasses||(e._transitionClasses=[]);n.indexOf(t)<0&&(n.push(t),xi(e,t))}function Fi(e,t){e._transitionClasses&&y(e._transitionClasses,t),ki(e,t)}function Ri(e,t,n){var r=Ui(e,t),i=r.type,o=r.timeout,a=r.propCount;if(!i)return n();var s=i===Ti?Ei:Di,c=0,u=function(){e.removeEventListener(s,l),n()},l=function(t){t.target===e&&++c>=a&&u()};setTimeout((function(){c0&&(n=Ti,l=a,f=o.length):t===Ni?u>0&&(n=Ni,l=u,f=c.length):f=(n=(l=Math.max(a,u))>0?a>u?Ti:Ni:null)?n===Ti?o.length:c.length:0,{type:n,timeout:l,propCount:f,hasTransform:n===Ti&&Hi.test(r[ji+"Property"])}}function Bi(e,t){for(;e.length1}function Wi(e,t){!0!==t.data.show&&zi(t)}var Zi=function(e){var n,a,s={},c=e.modules,u=e.nodeOps;for(n=0;nv?_(e,t(i[y+1])?null:i[y+1].elm,i,d,y,o):d>y&&$(n,p,v)}(p,h,y,o,l):r(y)?(r(e.text)&&u.setTextContent(p,""),_(p,null,y,0,y.length-1,o)):r(h)?$(h,0,h.length-1):r(e.text)&&u.setTextContent(p,""):e.text!==n.text&&u.setTextContent(p,n.text),r(v)&&r(d=v.hook)&&r(d=d.postpatch)&&d(e,n)}}}function k(e,t,n){if(i(n)&&r(e.parent))e.parent.data.pendingInsert=t;else for(var o=0;o-1,a.selected!==o&&(a.selected=o);else if(M(eo(a),r))return void(e.selectedIndex!==s&&(e.selectedIndex=s));i||(e.selectedIndex=-1)}}function Yi(e,t){return t.every((function(t){return!M(t,e)}))}function eo(e){return"_value"in e?e._value:e.value}function to(e){e.target.composing=!0}function no(e){e.target.composing&&(e.target.composing=!1,ro(e.target,"input"))}function ro(e,t){var n=document.createEvent("HTMLEvents");n.initEvent(t,!0,!0),e.dispatchEvent(n)}function io(e){return!e.componentInstance||e.data&&e.data.transition?e:io(e.componentInstance._vnode)}var oo={bind:function(e,t,n){var r=t.value,i=(n=io(n)).data&&n.data.transition,o=e.__vOriginalDisplay="none"===e.style.display?"":e.style.display;r&&i?(n.data.show=!0,zi(n,(function(){e.style.display=o}))):e.style.display=r?o:"none"},update:function(e,t,n){var r=t.value;!r!=!t.oldValue&&((n=io(n)).data&&n.data.transition?(n.data.show=!0,r?zi(n,(function(){e.style.display=e.__vOriginalDisplay})):Ki(n,(function(){e.style.display="none"}))):e.style.display=r?e.__vOriginalDisplay:"none")},unbind:function(e,t,n,r,i){i||(e.style.display=e.__vOriginalDisplay)}},ao={model:Gi,show:oo},so={name:String,appear:Boolean,css:Boolean,mode:String,type:String,enterClass:String,leaveClass:String,enterToClass:String,leaveToClass:String,enterActiveClass:String,leaveActiveClass:String,appearClass:String,appearActiveClass:String,appearToClass:String,duration:[Number,String,Object]};function co(e){var t=e&&e.componentOptions;return t&&t.Ctor.options.abstract?co(Zt(t.children)):e}function uo(e){var t={},n=e.$options;for(var r in n.propsData)t[r]=e[r];var i=n._parentListeners;for(var o in i)t[w(o)]=i[o];return t}function lo(e,t){if(/\d-keep-alive$/.test(t.tag))return e("keep-alive",{props:t.componentOptions.propsData})}var fo=function(e){return e.tag||gt(e)},po=function(e){return"show"===e.name},vo={name:"transition",props:so,abstract:!0,render:function(e){var t=this,n=this.$slots.default;if(n&&(n=n.filter(fo)).length){0;var r=this.mode;0;var i=n[0];if(function(e){for(;e=e.parent;)if(e.data.transition)return!0}(this.$vnode))return i;var a=co(i);if(!a)return i;if(this._leaving)return lo(e,i);var s="__transition-"+this._uid+"-";a.key=null==a.key?a.isComment?s+"comment":s+a.tag:o(a.key)?0===String(a.key).indexOf(s)?a.key:s+a.key:a.key;var c=(a.data||(a.data={})).transition=uo(this),u=this._vnode,l=co(u);if(a.data.directives&&a.data.directives.some(po)&&(a.data.show=!0),l&&l.data&&!function(e,t){return t.key===e.key&&t.tag===e.tag}(a,l)&&!gt(l)&&(!l.componentInstance||!l.componentInstance._vnode.isComment)){var f=l.data.transition=S({},c);if("out-in"===r)return this._leaving=!0,lt(f,"afterLeave",(function(){t._leaving=!1,t.$forceUpdate()})),lo(e,i);if("in-out"===r){if(gt(a))return u;var p,d=function(){p()};lt(c,"afterEnter",d),lt(c,"enterCancelled",d),lt(f,"delayLeave",(function(e){p=e}))}}return i}}},ho=S({tag:String,moveClass:String},so);function mo(e){e.elm._moveCb&&e.elm._moveCb(),e.elm._enterCb&&e.elm._enterCb()}function yo(e){e.data.newPos=e.elm.getBoundingClientRect()}function go(e){var t=e.data.pos,n=e.data.newPos,r=t.left-n.left,i=t.top-n.top;if(r||i){e.data.moved=!0;var o=e.elm.style;o.transform=o.WebkitTransform="translate("+r+"px,"+i+"px)",o.transitionDuration="0s"}}delete ho.mode;var _o={Transition:vo,TransitionGroup:{props:ho,beforeMount:function(){var e=this,t=this._update;this._update=function(n,r){var i=tn(e);e.__patch__(e._vnode,e.kept,!1,!0),e._vnode=e.kept,i(),t.call(e,n,r)}},render:function(e){for(var t=this.tag||this.$vnode.data.tag||"span",n=Object.create(null),r=this.prevChildren=this.children,i=this.$slots.default||[],o=this.children=[],a=uo(this),s=0;s-1?rr[e]=t.constructor===window.HTMLUnknownElement||t.constructor===window.HTMLElement:rr[e]=/HTMLUnknownElement/.test(t.toString())},S(Tn.options.directives,ao),S(Tn.options.components,_o),Tn.prototype.__patch__=J?Zi:N,Tn.prototype.$mount=function(e,t){return function(e,t,n){var r;return e.$el=t,e.$options.render||(e.$options.render=ye),an(e,"beforeMount"),r=function(){e._update(e._render(),n)},new gn(e,r,N,{before:function(){e._isMounted&&!e._isDestroyed&&an(e,"beforeUpdate")}},!0),n=!1,null==e.$vnode&&(e._isMounted=!0,an(e,"mounted")),e}(this,e=e&&J?or(e):void 0,t)},J&&setTimeout((function(){R.devtools&&oe&&oe.emit("init",Tn)}),0);var bo=/\{\{((?:.|\r?\n)+?)\}\}/g,$o=/[-.*+?^${}()|[\]\/\\]/g,wo=b((function(e){var t=e[0].replace($o,"\\$&"),n=e[1].replace($o,"\\$&");return new RegExp(t+"((?:.|\\n)+?)"+n,"g")}));var Co={staticKeys:["staticClass"],transformNode:function(e,t){t.warn;var n=zr(e,"class");n&&(e.staticClass=JSON.stringify(n));var r=Vr(e,"class",!1);r&&(e.classBinding=r)},genData:function(e){var t="";return e.staticClass&&(t+="staticClass:"+e.staticClass+","),e.classBinding&&(t+="class:"+e.classBinding+","),t}};var xo,ko={staticKeys:["staticStyle"],transformNode:function(e,t){t.warn;var n=zr(e,"style");n&&(e.staticStyle=JSON.stringify(pi(n)));var r=Vr(e,"style",!1);r&&(e.styleBinding=r)},genData:function(e){var t="";return e.staticStyle&&(t+="staticStyle:"+e.staticStyle+","),e.styleBinding&&(t+="style:("+e.styleBinding+"),"),t}},Ao=function(e){return(xo=xo||document.createElement("div")).innerHTML=e,xo.textContent},Oo=v("area,base,br,col,embed,frame,hr,img,input,isindex,keygen,link,meta,param,source,track,wbr"),So=v("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source"),To=v("address,article,aside,base,blockquote,body,caption,col,colgroup,dd,details,dialog,div,dl,dt,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,head,header,hgroup,hr,html,legend,li,menuitem,meta,optgroup,option,param,rp,rt,source,style,summary,tbody,td,tfoot,th,thead,title,tr,track"),No=/^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/,jo=/^\s*((?:v-[\w-]+:|@|:|#)\[[^=]+?\][^\s"'<>\/=]*)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/,Eo="[a-zA-Z_][\\-\\.0-9_a-zA-Z"+H.source+"]*",Mo="((?:"+Eo+"\\:)?"+Eo+")",Do=new RegExp("^<"+Mo),Io=/^\s*(\/?)>/,Lo=new RegExp("^<\\/"+Mo+"[^>]*>"),Po=/^]+>/i,Fo=/^",""":'"',"&":"&"," ":"\n"," ":"\t","'":"'"},Vo=/&(?:lt|gt|quot|amp|#39);/g,zo=/&(?:lt|gt|quot|amp|#39|#10|#9);/g,Ko=v("pre,textarea",!0),Jo=function(e,t){return e&&Ko(e)&&"\n"===t[0]};function qo(e,t){var n=t?zo:Vo;return e.replace(n,(function(e){return Bo[e]}))}var Wo,Zo,Go,Xo,Qo,Yo,ea,ta,na=/^@|^v-on:/,ra=/^v-|^@|^:|^#/,ia=/([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/,oa=/,([^,\}\]]*)(?:,([^,\}\]]*))?$/,aa=/^\(|\)$/g,sa=/^\[.*\]$/,ca=/:(.*)$/,ua=/^:|^\.|^v-bind:/,la=/\.[^.\]]+(?=[^\]]*$)/g,fa=/^v-slot(:|$)|^#/,pa=/[\r\n]/,da=/[ \f\t\r\n]+/g,va=b(Ao),ha="_empty_";function ma(e,t,n){return{type:1,tag:e,attrsList:t,attrsMap:Ca(t),rawAttrsMap:{},parent:n,children:[]}}function ya(e,t){Wo=t.warn||Ir,Yo=t.isPreTag||j,ea=t.mustUseProp||j,ta=t.getTagNamespace||j;var n=t.isReservedTag||j;(function(e){return!(!(e.component||e.attrsMap[":is"]||e.attrsMap["v-bind:is"])&&(e.attrsMap.is?n(e.attrsMap.is):n(e.tag)))}),Go=Lr(t.modules,"transformNode"),Xo=Lr(t.modules,"preTransformNode"),Qo=Lr(t.modules,"postTransformNode"),Zo=t.delimiters;var r,i,o=[],a=!1!==t.preserveWhitespace,s=t.whitespace,c=!1,u=!1;function l(e){if(f(e),c||e.processed||(e=ga(e,t)),o.length||e===r||r.if&&(e.elseif||e.else)&&ba(r,{exp:e.elseif,block:e}),i&&!e.forbidden)if(e.elseif||e.else)a=e,s=function(e){for(var t=e.length;t--;){if(1===e[t].type)return e[t];e.pop()}}(i.children),s&&s.if&&ba(s,{exp:a.elseif,block:a});else{if(e.slotScope){var n=e.slotTarget||'"default"';(i.scopedSlots||(i.scopedSlots={}))[n]=e}i.children.push(e),e.parent=i}var a,s;e.children=e.children.filter((function(e){return!e.slotScope})),f(e),e.pre&&(c=!1),Yo(e.tag)&&(u=!1);for(var l=0;l]*>)","i")),p=e.replace(f,(function(e,n,r){return u=r.length,Ho(l)||"noscript"===l||(n=n.replace(//g,"$1").replace(//g,"$1")),Jo(l,n)&&(n=n.slice(1)),t.chars&&t.chars(n),""}));c+=e.length-p.length,e=p,A(l,c-u,c)}else{var d=e.indexOf("<");if(0===d){if(Fo.test(e)){var v=e.indexOf("--\x3e");if(v>=0){t.shouldKeepComment&&t.comment(e.substring(4,v),c,c+v+3),C(v+3);continue}}if(Ro.test(e)){var h=e.indexOf("]>");if(h>=0){C(h+2);continue}}var m=e.match(Po);if(m){C(m[0].length);continue}var y=e.match(Lo);if(y){var g=c;C(y[0].length),A(y[1],g,c);continue}var _=x();if(_){k(_),Jo(_.tagName,e)&&C(1);continue}}var b=void 0,$=void 0,w=void 0;if(d>=0){for($=e.slice(d);!(Lo.test($)||Do.test($)||Fo.test($)||Ro.test($)||(w=$.indexOf("<",1))<0);)d+=w,$=e.slice(d);b=e.substring(0,d)}d<0&&(b=e),b&&C(b.length),t.chars&&b&&t.chars(b,c-b.length,c)}if(e===n){t.chars&&t.chars(e);break}}function C(t){c+=t,e=e.substring(t)}function x(){var t=e.match(Do);if(t){var n,r,i={tagName:t[1],attrs:[],start:c};for(C(t[0].length);!(n=e.match(Io))&&(r=e.match(jo)||e.match(No));)r.start=c,C(r[0].length),r.end=c,i.attrs.push(r);if(n)return i.unarySlash=n[1],C(n[0].length),i.end=c,i}}function k(e){var n=e.tagName,c=e.unarySlash;o&&("p"===r&&To(n)&&A(r),s(n)&&r===n&&A(n));for(var u=a(n)||!!c,l=e.attrs.length,f=new Array(l),p=0;p=0&&i[a].lowerCasedTag!==s;a--);else a=0;if(a>=0){for(var u=i.length-1;u>=a;u--)t.end&&t.end(i[u].tag,n,o);i.length=a,r=a&&i[a-1].tag}else"br"===s?t.start&&t.start(e,[],!0,n,o):"p"===s&&(t.start&&t.start(e,[],!1,n,o),t.end&&t.end(e,n,o))}A()}(e,{warn:Wo,expectHTML:t.expectHTML,isUnaryTag:t.isUnaryTag,canBeLeftOpenTag:t.canBeLeftOpenTag,shouldDecodeNewlines:t.shouldDecodeNewlines,shouldDecodeNewlinesForHref:t.shouldDecodeNewlinesForHref,shouldKeepComment:t.comments,outputSourceRange:t.outputSourceRange,start:function(e,n,a,s,f){var p=i&&i.ns||ta(e);G&&"svg"===p&&(n=function(e){for(var t=[],n=0;nc&&(s.push(o=e.slice(c,i)),a.push(JSON.stringify(o)));var u=Mr(r[1].trim());a.push("_s("+u+")"),s.push({"@binding":u}),c=i+r[0].length}return c-1"+("true"===o?":("+t+")":":_q("+t+","+o+")")),Br(e,"change","var $$a="+t+",$$el=$event.target,$$c=$$el.checked?("+o+"):("+a+");if(Array.isArray($$a)){var $$v="+(r?"_n("+i+")":i)+",$$i=_i($$a,$$v);if($$el.checked){$$i<0&&("+Wr(t,"$$a.concat([$$v])")+")}else{$$i>-1&&("+Wr(t,"$$a.slice(0,$$i).concat($$a.slice($$i+1))")+")}}else{"+Wr(t,"$$c")+"}",null,!0)}(e,r,i);else if("input"===o&&"radio"===a)!function(e,t,n){var r=n&&n.number,i=Vr(e,"value")||"null";Pr(e,"checked","_q("+t+","+(i=r?"_n("+i+")":i)+")"),Br(e,"change",Wr(t,i),null,!0)}(e,r,i);else if("input"===o||"textarea"===o)!function(e,t,n){var r=e.attrsMap.type;0;var i=n||{},o=i.lazy,a=i.number,s=i.trim,c=!o&&"range"!==r,u=o?"change":"range"===r?ti:"input",l="$event.target.value";s&&(l="$event.target.value.trim()");a&&(l="_n("+l+")");var f=Wr(t,l);c&&(f="if($event.target.composing)return;"+f);Pr(e,"value","("+t+")"),Br(e,u,f,null,!0),(s||a)&&Br(e,"blur","$forceUpdate()")}(e,r,i);else{if(!R.isReservedTag(o))return qr(e,r,i),!1}return!0},text:function(e,t){t.value&&Pr(e,"textContent","_s("+t.value+")",t)},html:function(e,t){t.value&&Pr(e,"innerHTML","_s("+t.value+")",t)}},ja={expectHTML:!0,modules:Oa,directives:Na,isPreTag:function(e){return"pre"===e},isUnaryTag:Oo,mustUseProp:Hn,canBeLeftOpenTag:So,isReservedTag:tr,getTagNamespace:nr,staticKeys:function(e){return e.reduce((function(e,t){return e.concat(t.staticKeys||[])}),[]).join(",")}(Oa)},Ea=b((function(e){return v("type,tag,attrsList,attrsMap,plain,parent,children,attrs,start,end,rawAttrsMap"+(e?","+e:""))}));function Ma(e,t){e&&(Sa=Ea(t.staticKeys||""),Ta=t.isReservedTag||j,Da(e),Ia(e,!1))}function Da(e){if(e.static=function(e){if(2===e.type)return!1;if(3===e.type)return!0;return!(!e.pre&&(e.hasBindings||e.if||e.for||h(e.tag)||!Ta(e.tag)||function(e){for(;e.parent;){if("template"!==(e=e.parent).tag)return!1;if(e.for)return!0}return!1}(e)||!Object.keys(e).every(Sa)))}(e),1===e.type){if(!Ta(e.tag)&&"slot"!==e.tag&&null==e.attrsMap["inline-template"])return;for(var t=0,n=e.children.length;t|^function(?:\s+[\w$]+)?\s*\(/,Pa=/\([^)]*?\);*$/,Fa=/^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['[^']*?']|\["[^"]*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*$/,Ra={esc:27,tab:9,enter:13,space:32,up:38,left:37,right:39,down:40,delete:[8,46]},Ha={esc:["Esc","Escape"],tab:"Tab",enter:"Enter",space:[" ","Spacebar"],up:["Up","ArrowUp"],left:["Left","ArrowLeft"],right:["Right","ArrowRight"],down:["Down","ArrowDown"],delete:["Backspace","Delete","Del"]},Ua=function(e){return"if("+e+")return null;"},Ba={stop:"$event.stopPropagation();",prevent:"$event.preventDefault();",self:Ua("$event.target !== $event.currentTarget"),ctrl:Ua("!$event.ctrlKey"),shift:Ua("!$event.shiftKey"),alt:Ua("!$event.altKey"),meta:Ua("!$event.metaKey"),left:Ua("'button' in $event && $event.button !== 0"),middle:Ua("'button' in $event && $event.button !== 1"),right:Ua("'button' in $event && $event.button !== 2")};function Va(e,t){var n=t?"nativeOn:":"on:",r="",i="";for(var o in e){var a=za(e[o]);e[o]&&e[o].dynamic?i+=o+","+a+",":r+='"'+o+'":'+a+","}return r="{"+r.slice(0,-1)+"}",i?n+"_d("+r+",["+i.slice(0,-1)+"])":n+r}function za(e){if(!e)return"function(){}";if(Array.isArray(e))return"["+e.map((function(e){return za(e)})).join(",")+"]";var t=Fa.test(e.value),n=La.test(e.value),r=Fa.test(e.value.replace(Pa,""));if(e.modifiers){var i="",o="",a=[];for(var s in e.modifiers)if(Ba[s])o+=Ba[s],Ra[s]&&a.push(s);else if("exact"===s){var c=e.modifiers;o+=Ua(["ctrl","shift","alt","meta"].filter((function(e){return!c[e]})).map((function(e){return"$event."+e+"Key"})).join("||"))}else a.push(s);return a.length&&(i+=function(e){return"if(!$event.type.indexOf('key')&&"+e.map(Ka).join("&&")+")return null;"}(a)),o&&(i+=o),"function($event){"+i+(t?"return "+e.value+".apply(null, arguments)":n?"return ("+e.value+").apply(null, arguments)":r?"return "+e.value:e.value)+"}"}return t||n?e.value:"function($event){"+(r?"return "+e.value:e.value)+"}"}function Ka(e){var t=parseInt(e,10);if(t)return"$event.keyCode!=="+t;var n=Ra[e],r=Ha[e];return"_k($event.keyCode,"+JSON.stringify(e)+","+JSON.stringify(n)+",$event.key,"+JSON.stringify(r)+")"}var Ja={on:function(e,t){e.wrapListeners=function(e){return"_g("+e+","+t.value+")"}},bind:function(e,t){e.wrapData=function(n){return"_b("+n+",'"+e.tag+"',"+t.value+","+(t.modifiers&&t.modifiers.prop?"true":"false")+(t.modifiers&&t.modifiers.sync?",true":"")+")"}},cloak:N},qa=function(e){this.options=e,this.warn=e.warn||Ir,this.transforms=Lr(e.modules,"transformCode"),this.dataGenFns=Lr(e.modules,"genData"),this.directives=S(S({},Ja),e.directives);var t=e.isReservedTag||j;this.maybeComponent=function(e){return!!e.component||!t(e.tag)},this.onceId=0,this.staticRenderFns=[],this.pre=!1};function Wa(e,t){var n=new qa(t);return{render:"with(this){return "+(e?"script"===e.tag?"null":Za(e,n):'_c("div")')+"}",staticRenderFns:n.staticRenderFns}}function Za(e,t){if(e.parent&&(e.pre=e.pre||e.parent.pre),e.staticRoot&&!e.staticProcessed)return Ga(e,t);if(e.once&&!e.onceProcessed)return Xa(e,t);if(e.for&&!e.forProcessed)return es(e,t);if(e.if&&!e.ifProcessed)return Qa(e,t);if("template"!==e.tag||e.slotTarget||t.pre){if("slot"===e.tag)return function(e,t){var n=e.slotName||'"default"',r=is(e,t),i="_t("+n+(r?",function(){return "+r+"}":""),o=e.attrs||e.dynamicAttrs?ss((e.attrs||[]).concat(e.dynamicAttrs||[]).map((function(e){return{name:w(e.name),value:e.value,dynamic:e.dynamic}}))):null,a=e.attrsMap["v-bind"];!o&&!a||r||(i+=",null");o&&(i+=","+o);a&&(i+=(o?"":",null")+","+a);return i+")"}(e,t);var n;if(e.component)n=function(e,t,n){var r=t.inlineTemplate?null:is(t,n,!0);return"_c("+e+","+ts(t,n)+(r?","+r:"")+")"}(e.component,e,t);else{var r;(!e.plain||e.pre&&t.maybeComponent(e))&&(r=ts(e,t));var i=e.inlineTemplate?null:is(e,t,!0);n="_c('"+e.tag+"'"+(r?","+r:"")+(i?","+i:"")+")"}for(var o=0;o>>0}(a):"")+")"}(e,e.scopedSlots,t)+","),e.model&&(n+="model:{value:"+e.model.value+",callback:"+e.model.callback+",expression:"+e.model.expression+"},"),e.inlineTemplate){var o=function(e,t){var n=e.children[0];0;if(n&&1===n.type){var r=Wa(n,t.options);return"inlineTemplate:{render:function(){"+r.render+"},staticRenderFns:["+r.staticRenderFns.map((function(e){return"function(){"+e+"}"})).join(",")+"]}"}}(e,t);o&&(n+=o+",")}return n=n.replace(/,$/,"")+"}",e.dynamicAttrs&&(n="_b("+n+',"'+e.tag+'",'+ss(e.dynamicAttrs)+")"),e.wrapData&&(n=e.wrapData(n)),e.wrapListeners&&(n=e.wrapListeners(n)),n}function ns(e){return 1===e.type&&("slot"===e.tag||e.children.some(ns))}function rs(e,t){var n=e.attrsMap["slot-scope"];if(e.if&&!e.ifProcessed&&!n)return Qa(e,t,rs,"null");if(e.for&&!e.forProcessed)return es(e,t,rs);var r=e.slotScope===ha?"":String(e.slotScope),i="function("+r+"){return "+("template"===e.tag?e.if&&n?"("+e.if+")?"+(is(e,t)||"undefined")+":undefined":is(e,t)||"undefined":Za(e,t))+"}",o=r?"":",proxy:true";return"{key:"+(e.slotTarget||'"default"')+",fn:"+i+o+"}"}function is(e,t,n,r,i){var o=e.children;if(o.length){var a=o[0];if(1===o.length&&a.for&&"template"!==a.tag&&"slot"!==a.tag){var s=n?t.maybeComponent(a)?",1":",0":"";return""+(r||Za)(a,t)+s}var c=n?function(e,t){for(var n=0,r=0;r':'',ps.innerHTML.indexOf(" ")>0}var ys=!!J&&ms(!1),gs=!!J&&ms(!0),_s=b((function(e){var t=or(e);return t&&t.innerHTML})),bs=Tn.prototype.$mount;Tn.prototype.$mount=function(e,t){if((e=e&&or(e))===document.body||e===document.documentElement)return this;var n=this.$options;if(!n.render){var r=n.template;if(r)if("string"==typeof r)"#"===r.charAt(0)&&(r=_s(r));else{if(!r.nodeType)return this;r=r.innerHTML}else e&&(r=function(e){if(e.outerHTML)return e.outerHTML;var t=document.createElement("div");return t.appendChild(e.cloneNode(!0)),t.innerHTML}(e));if(r){0;var i=hs(r,{outputSourceRange:!1,shouldDecodeNewlines:ys,shouldDecodeNewlinesForHref:gs,delimiters:n.delimiters,comments:n.comments},this),o=i.render,a=i.staticRenderFns;n.render=o,n.staticRenderFns=a}}return bs.call(this,e,t)},Tn.compile=hs;const $s=Tn;n(65546);new $s({el:"#container",data:function(){return JSON.parse(decodeURIComponent(window.INIT_DATA))},created:function(){console.log("调用了created钩子函数")},beforeCreate:function(){console.log("调用了beforeCreat钩子函数")},beforeMount:function(){console.log("调用了beforeMount钩子函数")},mounted:function(){console.log("调用了mounted钩子函数")},computed:{},methods:{},components:{},template:n(97898).default})})()})(); \ No newline at end of file diff --git a/static/2022-09-01-tag1/recommend/app/error_page/bundle-2022_9_2_1662085369265.js.LICENSE.txt b/static/2022-09-01-tag1/recommend/app/error_page/bundle-2022_9_2_1662085369265.js.LICENSE.txt new file mode 100644 index 0000000..39b67f3 --- /dev/null +++ b/static/2022-09-01-tag1/recommend/app/error_page/bundle-2022_9_2_1662085369265.js.LICENSE.txt @@ -0,0 +1,5 @@ +/*! + * Vue.js v2.6.14 + * (c) 2014-2021 Evan You + * Released under the MIT License. + */ diff --git a/static/2022-09-01-tag1/recommend/app/error_page/error_404-50a1d.png b/static/2022-09-01-tag1/recommend/app/error_page/error_404-50a1d.png new file mode 100644 index 0000000..b0f1bd0 Binary files /dev/null and b/static/2022-09-01-tag1/recommend/app/error_page/error_404-50a1d.png differ diff --git a/static/2022-09-01-tag1/recommend/app/home/bundle-2022_9_2_1662085369265.css b/static/2022-09-01-tag1/recommend/app/home/bundle-2022_9_2_1662085369265.css new file mode 100644 index 0000000..a155c7f --- /dev/null +++ b/static/2022-09-01-tag1/recommend/app/home/bundle-2022_9_2_1662085369265.css @@ -0,0 +1 @@ +.ant-input{-moz-font-feature-settings:"tnum";font-feature-settings:"tnum";background-color:#fff;background-image:none;border:1px solid #d9d9d9;border-radius:4px;-moz-box-sizing:border-box;box-sizing:border-box;color:rgba(0,0,0,.65);display:inline-block;font-size:14px;font-variant:tabular-nums;height:32px;line-height:1.5;list-style:none;margin:0;padding:4px 11px;position:relative;transition:all .3s;width:100%}.ant-input::-moz-placeholder{color:#bfbfbf;opacity:1}.ant-input:-ms-input-placeholder{color:#bfbfbf}.ant-input::-webkit-input-placeholder{color:#bfbfbf}.ant-input:-moz-placeholder-shown{text-overflow:ellipsis}.ant-input:-ms-input-placeholder{text-overflow:ellipsis}.ant-input:placeholder-shown{text-overflow:ellipsis}.ant-input:focus,.ant-input:hover{border-color:#40a9ff;border-right-width:1px!important}.ant-input:focus{box-shadow:0 0 0 2px rgba(24,144,255,.2);outline:0}.ant-input-disabled{background-color:#f5f5f5;color:rgba(0,0,0,.25);cursor:not-allowed;opacity:1}.ant-input-disabled:hover{border-color:#d9d9d9;border-right-width:1px!important}.ant-input[disabled]{background-color:#f5f5f5;color:rgba(0,0,0,.25);cursor:not-allowed;opacity:1}.ant-input[disabled]:hover{border-color:#d9d9d9;border-right-width:1px!important}textarea.ant-input{height:auto;line-height:1.5;max-width:100%;min-height:32px;transition:all .3s,height 0s;vertical-align:bottom}.ant-input-lg{font-size:16px;height:40px;padding:6px 11px}.ant-input-sm{height:24px;padding:1px 7px}.ant-input-group{-moz-font-feature-settings:"tnum";font-feature-settings:"tnum";border-collapse:separate;border-spacing:0;-moz-box-sizing:border-box;box-sizing:border-box;color:rgba(0,0,0,.65);display:table;font-size:14px;font-variant:tabular-nums;line-height:1.5;list-style:none;margin:0;padding:0;position:relative;width:100%}.ant-input-group[class*=col-]{float:none;padding-left:0;padding-right:0}.ant-input-group>[class*=col-]{padding-right:8px}.ant-input-group>[class*=col-]:last-child{padding-right:0}.ant-input-group-addon,.ant-input-group-wrap,.ant-input-group>.ant-input{display:table-cell}.ant-input-group-addon:not(:first-child):not(:last-child),.ant-input-group-wrap:not(:first-child):not(:last-child),.ant-input-group>.ant-input:not(:first-child):not(:last-child){border-radius:0}.ant-input-group-addon,.ant-input-group-wrap{vertical-align:middle;white-space:nowrap;width:1px}.ant-input-group-wrap>*{display:block!important}.ant-input-group .ant-input{float:left;margin-bottom:0;text-align:inherit;width:100%}.ant-input-group .ant-input:focus,.ant-input-group .ant-input:hover{border-right-width:1px;z-index:1}.ant-input-group-addon{background-color:#fafafa;border:1px solid #d9d9d9;border-radius:4px;color:rgba(0,0,0,.65);font-size:14px;font-weight:400;padding:0 11px;position:relative;text-align:center;transition:all .3s}.ant-input-group-addon .ant-select{margin:-5px -11px}.ant-input-group-addon .ant-select .ant-select-selection{background-color:inherit;border:1px solid transparent;box-shadow:none;margin:-1px}.ant-input-group-addon .ant-select-focused .ant-select-selection,.ant-input-group-addon .ant-select-open .ant-select-selection{color:#1890ff}.ant-input-group-addon>i:only-child:after{bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-input-group-addon:first-child,.ant-input-group-addon:first-child .ant-select .ant-select-selection,.ant-input-group>.ant-input:first-child,.ant-input-group>.ant-input:first-child .ant-select .ant-select-selection{border-bottom-right-radius:0;border-top-right-radius:0}.ant-input-group>.ant-input-affix-wrapper:not(:first-child) .ant-input{border-bottom-left-radius:0;border-top-left-radius:0}.ant-input-group>.ant-input-affix-wrapper:not(:last-child) .ant-input{border-bottom-right-radius:0;border-top-right-radius:0}.ant-input-group-addon:first-child{border-right:0}.ant-input-group-addon:last-child{border-left:0}.ant-input-group-addon:last-child,.ant-input-group-addon:last-child .ant-select .ant-select-selection,.ant-input-group>.ant-input:last-child,.ant-input-group>.ant-input:last-child .ant-select .ant-select-selection{border-bottom-left-radius:0;border-top-left-radius:0}.ant-input-group-lg .ant-input,.ant-input-group-lg>.ant-input-group-addon{font-size:16px;height:40px;padding:6px 11px}.ant-input-group-sm .ant-input,.ant-input-group-sm>.ant-input-group-addon{height:24px;padding:1px 7px}.ant-input-group-lg .ant-select-selection--single{height:40px}.ant-input-group-sm .ant-select-selection--single{height:24px}.ant-input-group .ant-input-affix-wrapper{display:table-cell;float:left;width:100%}.ant-input-group.ant-input-group-compact{zoom:1;display:block}.ant-input-group.ant-input-group-compact:after,.ant-input-group.ant-input-group-compact:before{content:"";display:table}.ant-input-group.ant-input-group-compact:after{clear:both}.ant-input-group.ant-input-group-compact-addon:not(:first-child):not(:last-child),.ant-input-group.ant-input-group-compact-wrap:not(:first-child):not(:last-child),.ant-input-group.ant-input-group-compact>.ant-input:not(:first-child):not(:last-child){border-right-width:1px}.ant-input-group.ant-input-group-compact-addon:not(:first-child):not(:last-child):focus,.ant-input-group.ant-input-group-compact-addon:not(:first-child):not(:last-child):hover,.ant-input-group.ant-input-group-compact-wrap:not(:first-child):not(:last-child):focus,.ant-input-group.ant-input-group-compact-wrap:not(:first-child):not(:last-child):hover,.ant-input-group.ant-input-group-compact>.ant-input:not(:first-child):not(:last-child):focus,.ant-input-group.ant-input-group-compact>.ant-input:not(:first-child):not(:last-child):hover{z-index:1}.ant-input-group.ant-input-group-compact>*{border-radius:0;display:inline-block;float:none;vertical-align:top}.ant-input-group.ant-input-group-compact>:not(:last-child){border-right-width:1px;margin-right:-1px}.ant-input-group.ant-input-group-compact .ant-input{float:none}.ant-input-group.ant-input-group-compact>.ant-calendar-picker .ant-input,.ant-input-group.ant-input-group-compact>.ant-cascader-picker .ant-input,.ant-input-group.ant-input-group-compact>.ant-input-group-wrapper .ant-input,.ant-input-group.ant-input-group-compact>.ant-mention-wrapper .ant-mention-editor,.ant-input-group.ant-input-group-compact>.ant-select-auto-complete .ant-input,.ant-input-group.ant-input-group-compact>.ant-select>.ant-select-selection,.ant-input-group.ant-input-group-compact>.ant-time-picker .ant-time-picker-input{border-radius:0;border-right-width:1px}.ant-input-group.ant-input-group-compact>.ant-calendar-picker .ant-input:focus,.ant-input-group.ant-input-group-compact>.ant-calendar-picker .ant-input:hover,.ant-input-group.ant-input-group-compact>.ant-cascader-picker .ant-input:focus,.ant-input-group.ant-input-group-compact>.ant-cascader-picker .ant-input:hover,.ant-input-group.ant-input-group-compact>.ant-input-group-wrapper .ant-input:focus,.ant-input-group.ant-input-group-compact>.ant-input-group-wrapper .ant-input:hover,.ant-input-group.ant-input-group-compact>.ant-mention-wrapper .ant-mention-editor:focus,.ant-input-group.ant-input-group-compact>.ant-mention-wrapper .ant-mention-editor:hover,.ant-input-group.ant-input-group-compact>.ant-select-auto-complete .ant-input:focus,.ant-input-group.ant-input-group-compact>.ant-select-auto-complete .ant-input:hover,.ant-input-group.ant-input-group-compact>.ant-select-focused,.ant-input-group.ant-input-group-compact>.ant-select>.ant-select-selection:focus,.ant-input-group.ant-input-group-compact>.ant-select>.ant-select-selection:hover,.ant-input-group.ant-input-group-compact>.ant-time-picker .ant-time-picker-input:focus,.ant-input-group.ant-input-group-compact>.ant-time-picker .ant-time-picker-input:hover{z-index:1}.ant-input-group.ant-input-group-compact>.ant-calendar-picker:first-child .ant-input,.ant-input-group.ant-input-group-compact>.ant-cascader-picker:first-child .ant-input,.ant-input-group.ant-input-group-compact>.ant-mention-wrapper:first-child .ant-mention-editor,.ant-input-group.ant-input-group-compact>.ant-select-auto-complete:first-child .ant-input,.ant-input-group.ant-input-group-compact>.ant-select:first-child>.ant-select-selection,.ant-input-group.ant-input-group-compact>.ant-time-picker:first-child .ant-time-picker-input,.ant-input-group.ant-input-group-compact>:first-child{border-bottom-left-radius:4px;border-top-left-radius:4px}.ant-input-group.ant-input-group-compact>.ant-calendar-picker:last-child .ant-input,.ant-input-group.ant-input-group-compact>.ant-cascader-picker-focused:last-child .ant-input,.ant-input-group.ant-input-group-compact>.ant-cascader-picker:last-child .ant-input,.ant-input-group.ant-input-group-compact>.ant-mention-wrapper:last-child .ant-mention-editor,.ant-input-group.ant-input-group-compact>.ant-select-auto-complete:last-child .ant-input,.ant-input-group.ant-input-group-compact>.ant-select:last-child>.ant-select-selection,.ant-input-group.ant-input-group-compact>.ant-time-picker:last-child .ant-time-picker-input,.ant-input-group.ant-input-group-compact>:last-child{border-bottom-right-radius:4px;border-right-width:1px;border-top-right-radius:4px}.ant-input-group.ant-input-group-compact>.ant-select-auto-complete .ant-input{vertical-align:top}.ant-input-group-wrapper{display:inline-block;text-align:start;vertical-align:top;width:100%}.ant-input-affix-wrapper{-moz-font-feature-settings:"tnum";font-feature-settings:"tnum";-moz-box-sizing:border-box;box-sizing:border-box;color:rgba(0,0,0,.65);display:inline-block;font-size:14px;font-variant:tabular-nums;line-height:1.5;list-style:none;margin:0;padding:0;position:relative;text-align:start;width:100%}.ant-input-affix-wrapper:hover .ant-input:not(.ant-input-disabled){border-color:#40a9ff;border-right-width:1px!important}.ant-input-affix-wrapper .ant-input{position:relative;text-align:inherit}.ant-input-affix-wrapper .ant-input-prefix,.ant-input-affix-wrapper .ant-input-suffix{-moz-box-align:center;-ms-flex-align:center;-webkit-align-items:center;align-items:center;color:rgba(0,0,0,.65);display:-webkit-flex;display:-moz-box;display:-ms-flexbox;display:flex;line-height:0;position:absolute;top:50%;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);transform:translateY(-50%);z-index:2}.ant-input-affix-wrapper .ant-input-prefix :not(.anticon),.ant-input-affix-wrapper .ant-input-suffix :not(.anticon){line-height:1.5}.ant-input-affix-wrapper .ant-input-disabled~.ant-input-suffix .anticon{color:rgba(0,0,0,.25);cursor:not-allowed}.ant-input-affix-wrapper .ant-input-prefix{left:12px}.ant-input-affix-wrapper .ant-input-suffix{right:12px}.ant-input-affix-wrapper .ant-input:not(:first-child){padding-left:30px}.ant-input-affix-wrapper .ant-input:not(:last-child){padding-right:30px}.ant-input-affix-wrapper.ant-input-affix-wrapper-input-with-clear-btn .ant-input:not(:last-child){padding-right:49px}.ant-input-affix-wrapper.ant-input-affix-wrapper-textarea-with-clear-btn .ant-input{padding-right:22px}.ant-input-password-icon{color:rgba(0,0,0,.45);cursor:pointer;transition:all .3s}.ant-input-password-icon:hover{color:#333}.ant-input-clear-icon{color:rgba(0,0,0,.25);cursor:pointer;font-size:12px;transition:color .3s;vertical-align:0}.ant-input-clear-icon:hover{color:rgba(0,0,0,.45)}.ant-input-clear-icon:active{color:rgba(0,0,0,.65)}.ant-input-clear-icon+i{margin-left:6px}.ant-input-textarea-clear-icon{color:rgba(0,0,0,.25);cursor:pointer;font-size:12px;margin:8px 8px 0 0;position:absolute;right:0;top:0;transition:color .3s}.ant-input-textarea-clear-icon:hover{color:rgba(0,0,0,.45)}.ant-input-textarea-clear-icon:active{color:rgba(0,0,0,.65)}.ant-input-textarea-clear-icon+i{margin-left:6px}.ant-input-search-icon{color:rgba(0,0,0,.45);cursor:pointer;transition:all .3s}.ant-input-search-icon:hover{color:rgba(0,0,0,.8)}.ant-input-search-enter-button input{border-right:0}.ant-input-search-enter-button input+.ant-input-group-addon,.ant-input-search-enter-button+.ant-input-group-addon{border:0;padding:0}.ant-input-search-enter-button input+.ant-input-group-addon .ant-input-search-button,.ant-input-search-enter-button+.ant-input-group-addon .ant-input-search-button{border-bottom-left-radius:0;border-top-left-radius:0}.ant-btn{background-color:#fff;background-image:none;border:1px solid #d9d9d9;border-radius:4px;box-shadow:0 2px 0 rgba(0,0,0,.015);color:rgba(0,0,0,.65);cursor:pointer;display:inline-block;font-size:14px;font-weight:400;height:32px;line-height:1.499;padding:0 15px;position:relative;text-align:center;-ms-touch-action:manipulation;touch-action:manipulation;transition:all .3s cubic-bezier(.645,.045,.355,1);-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;white-space:nowrap}.ant-btn>.anticon{line-height:1}.ant-btn,.ant-btn:active,.ant-btn:focus{outline:0}.ant-btn:not([disabled]):hover{text-decoration:none}.ant-btn:not([disabled]):active{box-shadow:none;outline:0}.ant-btn.disabled,.ant-btn[disabled]{cursor:not-allowed}.ant-btn.disabled>*,.ant-btn[disabled]>*{pointer-events:none}.ant-btn-lg{border-radius:4px;font-size:16px;height:40px;padding:0 15px}.ant-btn-sm{border-radius:4px;font-size:14px;height:24px;padding:0 7px}.ant-btn>a:only-child{color:currentColor}.ant-btn>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn:focus,.ant-btn:hover{background-color:#fff;border-color:#40a9ff;color:#40a9ff}.ant-btn:focus>a:only-child,.ant-btn:hover>a:only-child{color:currentColor}.ant-btn:focus>a:only-child:after,.ant-btn:hover>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn.active,.ant-btn:active{background-color:#fff;border-color:#096dd9;color:#096dd9}.ant-btn.active>a:only-child,.ant-btn:active>a:only-child{color:currentColor}.ant-btn.active>a:only-child:after,.ant-btn:active>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-disabled,.ant-btn-disabled.active,.ant-btn-disabled:active,.ant-btn-disabled:focus,.ant-btn-disabled:hover,.ant-btn.disabled,.ant-btn.disabled.active,.ant-btn.disabled:active,.ant-btn.disabled:focus,.ant-btn.disabled:hover,.ant-btn[disabled],.ant-btn[disabled].active,.ant-btn[disabled]:active,.ant-btn[disabled]:focus,.ant-btn[disabled]:hover{background-color:#f5f5f5;border-color:#d9d9d9;box-shadow:none;color:rgba(0,0,0,.25);text-shadow:none}.ant-btn-disabled.active>a:only-child,.ant-btn-disabled:active>a:only-child,.ant-btn-disabled:focus>a:only-child,.ant-btn-disabled:hover>a:only-child,.ant-btn-disabled>a:only-child,.ant-btn.disabled.active>a:only-child,.ant-btn.disabled:active>a:only-child,.ant-btn.disabled:focus>a:only-child,.ant-btn.disabled:hover>a:only-child,.ant-btn.disabled>a:only-child,.ant-btn[disabled].active>a:only-child,.ant-btn[disabled]:active>a:only-child,.ant-btn[disabled]:focus>a:only-child,.ant-btn[disabled]:hover>a:only-child,.ant-btn[disabled]>a:only-child{color:currentColor}.ant-btn-disabled.active>a:only-child:after,.ant-btn-disabled:active>a:only-child:after,.ant-btn-disabled:focus>a:only-child:after,.ant-btn-disabled:hover>a:only-child:after,.ant-btn-disabled>a:only-child:after,.ant-btn.disabled.active>a:only-child:after,.ant-btn.disabled:active>a:only-child:after,.ant-btn.disabled:focus>a:only-child:after,.ant-btn.disabled:hover>a:only-child:after,.ant-btn.disabled>a:only-child:after,.ant-btn[disabled].active>a:only-child:after,.ant-btn[disabled]:active>a:only-child:after,.ant-btn[disabled]:focus>a:only-child:after,.ant-btn[disabled]:hover>a:only-child:after,.ant-btn[disabled]>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn.active,.ant-btn:active,.ant-btn:focus,.ant-btn:hover{background:#fff;text-decoration:none}.ant-btn>i,.ant-btn>span{display:inline-block;pointer-events:none;transition:margin-left .3s cubic-bezier(.645,.045,.355,1)}.ant-btn-primary{background-color:#1890ff;border-color:#1890ff;box-shadow:0 2px 0 rgba(0,0,0,.045);color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.12)}.ant-btn-primary>a:only-child{color:currentColor}.ant-btn-primary>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-primary:focus,.ant-btn-primary:hover{background-color:#40a9ff;border-color:#40a9ff;color:#fff}.ant-btn-primary:focus>a:only-child,.ant-btn-primary:hover>a:only-child{color:currentColor}.ant-btn-primary:focus>a:only-child:after,.ant-btn-primary:hover>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-primary.active,.ant-btn-primary:active{background-color:#096dd9;border-color:#096dd9;color:#fff}.ant-btn-primary.active>a:only-child,.ant-btn-primary:active>a:only-child{color:currentColor}.ant-btn-primary.active>a:only-child:after,.ant-btn-primary:active>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-primary-disabled,.ant-btn-primary-disabled.active,.ant-btn-primary-disabled:active,.ant-btn-primary-disabled:focus,.ant-btn-primary-disabled:hover,.ant-btn-primary.disabled,.ant-btn-primary.disabled.active,.ant-btn-primary.disabled:active,.ant-btn-primary.disabled:focus,.ant-btn-primary.disabled:hover,.ant-btn-primary[disabled],.ant-btn-primary[disabled].active,.ant-btn-primary[disabled]:active,.ant-btn-primary[disabled]:focus,.ant-btn-primary[disabled]:hover{background-color:#f5f5f5;border-color:#d9d9d9;box-shadow:none;color:rgba(0,0,0,.25);text-shadow:none}.ant-btn-primary-disabled.active>a:only-child,.ant-btn-primary-disabled:active>a:only-child,.ant-btn-primary-disabled:focus>a:only-child,.ant-btn-primary-disabled:hover>a:only-child,.ant-btn-primary-disabled>a:only-child,.ant-btn-primary.disabled.active>a:only-child,.ant-btn-primary.disabled:active>a:only-child,.ant-btn-primary.disabled:focus>a:only-child,.ant-btn-primary.disabled:hover>a:only-child,.ant-btn-primary.disabled>a:only-child,.ant-btn-primary[disabled].active>a:only-child,.ant-btn-primary[disabled]:active>a:only-child,.ant-btn-primary[disabled]:focus>a:only-child,.ant-btn-primary[disabled]:hover>a:only-child,.ant-btn-primary[disabled]>a:only-child{color:currentColor}.ant-btn-primary-disabled.active>a:only-child:after,.ant-btn-primary-disabled:active>a:only-child:after,.ant-btn-primary-disabled:focus>a:only-child:after,.ant-btn-primary-disabled:hover>a:only-child:after,.ant-btn-primary-disabled>a:only-child:after,.ant-btn-primary.disabled.active>a:only-child:after,.ant-btn-primary.disabled:active>a:only-child:after,.ant-btn-primary.disabled:focus>a:only-child:after,.ant-btn-primary.disabled:hover>a:only-child:after,.ant-btn-primary.disabled>a:only-child:after,.ant-btn-primary[disabled].active>a:only-child:after,.ant-btn-primary[disabled]:active>a:only-child:after,.ant-btn-primary[disabled]:focus>a:only-child:after,.ant-btn-primary[disabled]:hover>a:only-child:after,.ant-btn-primary[disabled]>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-group .ant-btn-primary:not(:first-child):not(:last-child){border-left-color:#40a9ff;border-right-color:#40a9ff}.ant-btn-group .ant-btn-primary:not(:first-child):not(:last-child):disabled{border-color:#d9d9d9}.ant-btn-group .ant-btn-primary:first-child:not(:last-child){border-right-color:#40a9ff}.ant-btn-group .ant-btn-primary:first-child:not(:last-child)[disabled]{border-right-color:#d9d9d9}.ant-btn-group .ant-btn-primary+.ant-btn-primary,.ant-btn-group .ant-btn-primary:last-child:not(:first-child){border-left-color:#40a9ff}.ant-btn-group .ant-btn-primary+.ant-btn-primary[disabled],.ant-btn-group .ant-btn-primary:last-child:not(:first-child)[disabled]{border-left-color:#d9d9d9}.ant-btn-ghost{background-color:transparent;border-color:#d9d9d9;color:rgba(0,0,0,.65)}.ant-btn-ghost>a:only-child{color:currentColor}.ant-btn-ghost>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-ghost:focus,.ant-btn-ghost:hover{background-color:transparent;border-color:#40a9ff;color:#40a9ff}.ant-btn-ghost:focus>a:only-child,.ant-btn-ghost:hover>a:only-child{color:currentColor}.ant-btn-ghost:focus>a:only-child:after,.ant-btn-ghost:hover>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-ghost.active,.ant-btn-ghost:active{background-color:transparent;border-color:#096dd9;color:#096dd9}.ant-btn-ghost.active>a:only-child,.ant-btn-ghost:active>a:only-child{color:currentColor}.ant-btn-ghost.active>a:only-child:after,.ant-btn-ghost:active>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-ghost-disabled,.ant-btn-ghost-disabled.active,.ant-btn-ghost-disabled:active,.ant-btn-ghost-disabled:focus,.ant-btn-ghost-disabled:hover,.ant-btn-ghost.disabled,.ant-btn-ghost.disabled.active,.ant-btn-ghost.disabled:active,.ant-btn-ghost.disabled:focus,.ant-btn-ghost.disabled:hover,.ant-btn-ghost[disabled],.ant-btn-ghost[disabled].active,.ant-btn-ghost[disabled]:active,.ant-btn-ghost[disabled]:focus,.ant-btn-ghost[disabled]:hover{background-color:#f5f5f5;border-color:#d9d9d9;box-shadow:none;color:rgba(0,0,0,.25);text-shadow:none}.ant-btn-ghost-disabled.active>a:only-child,.ant-btn-ghost-disabled:active>a:only-child,.ant-btn-ghost-disabled:focus>a:only-child,.ant-btn-ghost-disabled:hover>a:only-child,.ant-btn-ghost-disabled>a:only-child,.ant-btn-ghost.disabled.active>a:only-child,.ant-btn-ghost.disabled:active>a:only-child,.ant-btn-ghost.disabled:focus>a:only-child,.ant-btn-ghost.disabled:hover>a:only-child,.ant-btn-ghost.disabled>a:only-child,.ant-btn-ghost[disabled].active>a:only-child,.ant-btn-ghost[disabled]:active>a:only-child,.ant-btn-ghost[disabled]:focus>a:only-child,.ant-btn-ghost[disabled]:hover>a:only-child,.ant-btn-ghost[disabled]>a:only-child{color:currentColor}.ant-btn-ghost-disabled.active>a:only-child:after,.ant-btn-ghost-disabled:active>a:only-child:after,.ant-btn-ghost-disabled:focus>a:only-child:after,.ant-btn-ghost-disabled:hover>a:only-child:after,.ant-btn-ghost-disabled>a:only-child:after,.ant-btn-ghost.disabled.active>a:only-child:after,.ant-btn-ghost.disabled:active>a:only-child:after,.ant-btn-ghost.disabled:focus>a:only-child:after,.ant-btn-ghost.disabled:hover>a:only-child:after,.ant-btn-ghost.disabled>a:only-child:after,.ant-btn-ghost[disabled].active>a:only-child:after,.ant-btn-ghost[disabled]:active>a:only-child:after,.ant-btn-ghost[disabled]:focus>a:only-child:after,.ant-btn-ghost[disabled]:hover>a:only-child:after,.ant-btn-ghost[disabled]>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-dashed{background-color:#fff;border-color:#d9d9d9;border-style:dashed;color:rgba(0,0,0,.65)}.ant-btn-dashed>a:only-child{color:currentColor}.ant-btn-dashed>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-dashed:focus,.ant-btn-dashed:hover{background-color:#fff;border-color:#40a9ff;color:#40a9ff}.ant-btn-dashed:focus>a:only-child,.ant-btn-dashed:hover>a:only-child{color:currentColor}.ant-btn-dashed:focus>a:only-child:after,.ant-btn-dashed:hover>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-dashed.active,.ant-btn-dashed:active{background-color:#fff;border-color:#096dd9;color:#096dd9}.ant-btn-dashed.active>a:only-child,.ant-btn-dashed:active>a:only-child{color:currentColor}.ant-btn-dashed.active>a:only-child:after,.ant-btn-dashed:active>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-dashed-disabled,.ant-btn-dashed-disabled.active,.ant-btn-dashed-disabled:active,.ant-btn-dashed-disabled:focus,.ant-btn-dashed-disabled:hover,.ant-btn-dashed.disabled,.ant-btn-dashed.disabled.active,.ant-btn-dashed.disabled:active,.ant-btn-dashed.disabled:focus,.ant-btn-dashed.disabled:hover,.ant-btn-dashed[disabled],.ant-btn-dashed[disabled].active,.ant-btn-dashed[disabled]:active,.ant-btn-dashed[disabled]:focus,.ant-btn-dashed[disabled]:hover{background-color:#f5f5f5;border-color:#d9d9d9;box-shadow:none;color:rgba(0,0,0,.25);text-shadow:none}.ant-btn-dashed-disabled.active>a:only-child,.ant-btn-dashed-disabled:active>a:only-child,.ant-btn-dashed-disabled:focus>a:only-child,.ant-btn-dashed-disabled:hover>a:only-child,.ant-btn-dashed-disabled>a:only-child,.ant-btn-dashed.disabled.active>a:only-child,.ant-btn-dashed.disabled:active>a:only-child,.ant-btn-dashed.disabled:focus>a:only-child,.ant-btn-dashed.disabled:hover>a:only-child,.ant-btn-dashed.disabled>a:only-child,.ant-btn-dashed[disabled].active>a:only-child,.ant-btn-dashed[disabled]:active>a:only-child,.ant-btn-dashed[disabled]:focus>a:only-child,.ant-btn-dashed[disabled]:hover>a:only-child,.ant-btn-dashed[disabled]>a:only-child{color:currentColor}.ant-btn-dashed-disabled.active>a:only-child:after,.ant-btn-dashed-disabled:active>a:only-child:after,.ant-btn-dashed-disabled:focus>a:only-child:after,.ant-btn-dashed-disabled:hover>a:only-child:after,.ant-btn-dashed-disabled>a:only-child:after,.ant-btn-dashed.disabled.active>a:only-child:after,.ant-btn-dashed.disabled:active>a:only-child:after,.ant-btn-dashed.disabled:focus>a:only-child:after,.ant-btn-dashed.disabled:hover>a:only-child:after,.ant-btn-dashed.disabled>a:only-child:after,.ant-btn-dashed[disabled].active>a:only-child:after,.ant-btn-dashed[disabled]:active>a:only-child:after,.ant-btn-dashed[disabled]:focus>a:only-child:after,.ant-btn-dashed[disabled]:hover>a:only-child:after,.ant-btn-dashed[disabled]>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-danger{background-color:#ff4d4f;border-color:#ff4d4f;box-shadow:0 2px 0 rgba(0,0,0,.045);color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.12)}.ant-btn-danger>a:only-child{color:currentColor}.ant-btn-danger>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-danger:focus,.ant-btn-danger:hover{background-color:#ff7875;border-color:#ff7875;color:#fff}.ant-btn-danger:focus>a:only-child,.ant-btn-danger:hover>a:only-child{color:currentColor}.ant-btn-danger:focus>a:only-child:after,.ant-btn-danger:hover>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-danger.active,.ant-btn-danger:active{background-color:#d9363e;border-color:#d9363e;color:#fff}.ant-btn-danger.active>a:only-child,.ant-btn-danger:active>a:only-child{color:currentColor}.ant-btn-danger.active>a:only-child:after,.ant-btn-danger:active>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-danger-disabled,.ant-btn-danger-disabled.active,.ant-btn-danger-disabled:active,.ant-btn-danger-disabled:focus,.ant-btn-danger-disabled:hover,.ant-btn-danger.disabled,.ant-btn-danger.disabled.active,.ant-btn-danger.disabled:active,.ant-btn-danger.disabled:focus,.ant-btn-danger.disabled:hover,.ant-btn-danger[disabled],.ant-btn-danger[disabled].active,.ant-btn-danger[disabled]:active,.ant-btn-danger[disabled]:focus,.ant-btn-danger[disabled]:hover{background-color:#f5f5f5;border-color:#d9d9d9;box-shadow:none;color:rgba(0,0,0,.25);text-shadow:none}.ant-btn-danger-disabled.active>a:only-child,.ant-btn-danger-disabled:active>a:only-child,.ant-btn-danger-disabled:focus>a:only-child,.ant-btn-danger-disabled:hover>a:only-child,.ant-btn-danger-disabled>a:only-child,.ant-btn-danger.disabled.active>a:only-child,.ant-btn-danger.disabled:active>a:only-child,.ant-btn-danger.disabled:focus>a:only-child,.ant-btn-danger.disabled:hover>a:only-child,.ant-btn-danger.disabled>a:only-child,.ant-btn-danger[disabled].active>a:only-child,.ant-btn-danger[disabled]:active>a:only-child,.ant-btn-danger[disabled]:focus>a:only-child,.ant-btn-danger[disabled]:hover>a:only-child,.ant-btn-danger[disabled]>a:only-child{color:currentColor}.ant-btn-danger-disabled.active>a:only-child:after,.ant-btn-danger-disabled:active>a:only-child:after,.ant-btn-danger-disabled:focus>a:only-child:after,.ant-btn-danger-disabled:hover>a:only-child:after,.ant-btn-danger-disabled>a:only-child:after,.ant-btn-danger.disabled.active>a:only-child:after,.ant-btn-danger.disabled:active>a:only-child:after,.ant-btn-danger.disabled:focus>a:only-child:after,.ant-btn-danger.disabled:hover>a:only-child:after,.ant-btn-danger.disabled>a:only-child:after,.ant-btn-danger[disabled].active>a:only-child:after,.ant-btn-danger[disabled]:active>a:only-child:after,.ant-btn-danger[disabled]:focus>a:only-child:after,.ant-btn-danger[disabled]:hover>a:only-child:after,.ant-btn-danger[disabled]>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-link{background-color:transparent;border-color:transparent;box-shadow:none;color:#1890ff}.ant-btn-link>a:only-child{color:currentColor}.ant-btn-link>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-link:focus,.ant-btn-link:hover{background-color:transparent;border-color:#40a9ff;color:#40a9ff}.ant-btn-link:focus>a:only-child,.ant-btn-link:hover>a:only-child{color:currentColor}.ant-btn-link:focus>a:only-child:after,.ant-btn-link:hover>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-link.active,.ant-btn-link:active{background-color:transparent;border-color:#096dd9;color:#096dd9}.ant-btn-link.active>a:only-child,.ant-btn-link:active>a:only-child{color:currentColor}.ant-btn-link.active>a:only-child:after,.ant-btn-link:active>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-link-disabled,.ant-btn-link-disabled.active,.ant-btn-link-disabled:active,.ant-btn-link-disabled:focus,.ant-btn-link-disabled:hover,.ant-btn-link.disabled,.ant-btn-link.disabled.active,.ant-btn-link.disabled:active,.ant-btn-link.disabled:focus,.ant-btn-link.disabled:hover,.ant-btn-link[disabled],.ant-btn-link[disabled].active,.ant-btn-link[disabled]:active,.ant-btn-link[disabled]:focus,.ant-btn-link[disabled]:hover{background-color:#f5f5f5;border-color:#d9d9d9}.ant-btn-link:active,.ant-btn-link:focus,.ant-btn-link:hover{border-color:transparent}.ant-btn-link-disabled,.ant-btn-link-disabled.active,.ant-btn-link-disabled:active,.ant-btn-link-disabled:focus,.ant-btn-link-disabled:hover,.ant-btn-link.disabled,.ant-btn-link.disabled.active,.ant-btn-link.disabled:active,.ant-btn-link.disabled:focus,.ant-btn-link.disabled:hover,.ant-btn-link[disabled],.ant-btn-link[disabled].active,.ant-btn-link[disabled]:active,.ant-btn-link[disabled]:focus,.ant-btn-link[disabled]:hover{background-color:transparent;border-color:transparent;box-shadow:none;color:rgba(0,0,0,.25);text-shadow:none}.ant-btn-link-disabled.active>a:only-child,.ant-btn-link-disabled:active>a:only-child,.ant-btn-link-disabled:focus>a:only-child,.ant-btn-link-disabled:hover>a:only-child,.ant-btn-link-disabled>a:only-child,.ant-btn-link.disabled.active>a:only-child,.ant-btn-link.disabled:active>a:only-child,.ant-btn-link.disabled:focus>a:only-child,.ant-btn-link.disabled:hover>a:only-child,.ant-btn-link.disabled>a:only-child,.ant-btn-link[disabled].active>a:only-child,.ant-btn-link[disabled]:active>a:only-child,.ant-btn-link[disabled]:focus>a:only-child,.ant-btn-link[disabled]:hover>a:only-child,.ant-btn-link[disabled]>a:only-child{color:currentColor}.ant-btn-link-disabled.active>a:only-child:after,.ant-btn-link-disabled:active>a:only-child:after,.ant-btn-link-disabled:focus>a:only-child:after,.ant-btn-link-disabled:hover>a:only-child:after,.ant-btn-link-disabled>a:only-child:after,.ant-btn-link.disabled.active>a:only-child:after,.ant-btn-link.disabled:active>a:only-child:after,.ant-btn-link.disabled:focus>a:only-child:after,.ant-btn-link.disabled:hover>a:only-child:after,.ant-btn-link.disabled>a:only-child:after,.ant-btn-link[disabled].active>a:only-child:after,.ant-btn-link[disabled]:active>a:only-child:after,.ant-btn-link[disabled]:focus>a:only-child:after,.ant-btn-link[disabled]:hover>a:only-child:after,.ant-btn-link[disabled]>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-icon-only{border-radius:4px;font-size:16px;height:32px;padding:0;width:32px}.ant-btn-icon-only.ant-btn-lg{border-radius:4px;font-size:18px;height:40px;padding:0;width:40px}.ant-btn-icon-only.ant-btn-sm{border-radius:4px;font-size:14px;height:24px;padding:0;width:24px}.ant-btn-icon-only>i{vertical-align:middle}.ant-btn-round{border-radius:32px;font-size:14px;height:32px;padding:0 16px}.ant-btn-round.ant-btn-lg{border-radius:40px;font-size:16px;height:40px;padding:0 20px}.ant-btn-round.ant-btn-sm{border-radius:24px;font-size:14px;height:24px;padding:0 12px}.ant-btn-round.ant-btn-icon-only{width:auto}.ant-btn-circle,.ant-btn-circle-outline{border-radius:50%;min-width:32px;padding-left:0;padding-right:0;text-align:center}.ant-btn-circle-outline.ant-btn-lg,.ant-btn-circle.ant-btn-lg{border-radius:50%;min-width:40px}.ant-btn-circle-outline.ant-btn-sm,.ant-btn-circle.ant-btn-sm{border-radius:50%;min-width:24px}.ant-btn:before{background:#fff;border-radius:inherit;bottom:-1px;content:"";display:none;left:-1px;opacity:.35;pointer-events:none;position:absolute;right:-1px;top:-1px;transition:opacity .2s;z-index:1}.ant-btn .anticon{transition:margin-left .3s cubic-bezier(.645,.045,.355,1)}.ant-btn .anticon.anticon-minus>svg,.ant-btn .anticon.anticon-plus>svg{shape-rendering:optimizeSpeed}.ant-btn.ant-btn-loading{position:relative}.ant-btn.ant-btn-loading:not([disabled]){pointer-events:none}.ant-btn.ant-btn-loading:before{display:block}.ant-btn.ant-btn-loading:not(.ant-btn-circle):not(.ant-btn-circle-outline):not(.ant-btn-icon-only){padding-left:29px}.ant-btn.ant-btn-loading:not(.ant-btn-circle):not(.ant-btn-circle-outline):not(.ant-btn-icon-only) .anticon:not(:last-child){margin-left:-14px}.ant-btn-sm.ant-btn-loading:not(.ant-btn-circle):not(.ant-btn-circle-outline):not(.ant-btn-icon-only){padding-left:24px}.ant-btn-sm.ant-btn-loading:not(.ant-btn-circle):not(.ant-btn-circle-outline):not(.ant-btn-icon-only) .anticon{margin-left:-17px}.ant-btn-group{display:-webkit-inline-flex;display:-moz-inline-box;display:-ms-inline-flexbox;display:inline-flex}.ant-btn-group,.ant-btn-group>.ant-btn,.ant-btn-group>span>.ant-btn{position:relative}.ant-btn-group>.ant-btn.active,.ant-btn-group>.ant-btn:active,.ant-btn-group>.ant-btn:focus,.ant-btn-group>.ant-btn:hover,.ant-btn-group>span>.ant-btn.active,.ant-btn-group>span>.ant-btn:active,.ant-btn-group>span>.ant-btn:focus,.ant-btn-group>span>.ant-btn:hover{z-index:2}.ant-btn-group>.ant-btn:disabled,.ant-btn-group>span>.ant-btn:disabled{z-index:0}.ant-btn-group>.ant-btn-icon-only{font-size:14px}.ant-btn-group-lg>.ant-btn,.ant-btn-group-lg>span>.ant-btn{border-radius:0;font-size:16px;height:40px;line-height:38px;padding:0 15px}.ant-btn-group-lg>.ant-btn.ant-btn-icon-only{height:40px;padding-left:0;padding-right:0;width:40px}.ant-btn-group-sm>.ant-btn,.ant-btn-group-sm>span>.ant-btn{border-radius:0;font-size:14px;height:24px;line-height:22px;padding:0 7px}.ant-btn-group-sm>.ant-btn>.anticon,.ant-btn-group-sm>span>.ant-btn>.anticon{font-size:14px}.ant-btn-group-sm>.ant-btn.ant-btn-icon-only{height:24px;padding-left:0;padding-right:0;width:24px}.ant-btn+.ant-btn-group,.ant-btn-group .ant-btn+.ant-btn,.ant-btn-group .ant-btn+span,.ant-btn-group span+.ant-btn,.ant-btn-group+.ant-btn,.ant-btn-group+.ant-btn-group,.ant-btn-group>span+span{margin-left:-1px}.ant-btn-group .ant-btn-primary+.ant-btn:not(.ant-btn-primary):not([disabled]){border-left-color:transparent}.ant-btn-group .ant-btn{border-radius:0}.ant-btn-group>.ant-btn:first-child,.ant-btn-group>span:first-child>.ant-btn{margin-left:0}.ant-btn-group>.ant-btn:only-child,.ant-btn-group>span:only-child>.ant-btn{border-radius:4px}.ant-btn-group>.ant-btn:first-child:not(:last-child),.ant-btn-group>span:first-child:not(:last-child)>.ant-btn{border-bottom-left-radius:4px;border-top-left-radius:4px}.ant-btn-group>.ant-btn:last-child:not(:first-child),.ant-btn-group>span:last-child:not(:first-child)>.ant-btn{border-bottom-right-radius:4px;border-top-right-radius:4px}.ant-btn-group-sm>.ant-btn:only-child,.ant-btn-group-sm>span:only-child>.ant-btn{border-radius:4px}.ant-btn-group-sm>.ant-btn:first-child:not(:last-child),.ant-btn-group-sm>span:first-child:not(:last-child)>.ant-btn{border-bottom-left-radius:4px;border-top-left-radius:4px}.ant-btn-group-sm>.ant-btn:last-child:not(:first-child),.ant-btn-group-sm>span:last-child:not(:first-child)>.ant-btn{border-bottom-right-radius:4px;border-top-right-radius:4px}.ant-btn-group>.ant-btn-group{float:left}.ant-btn-group>.ant-btn-group:not(:first-child):not(:last-child)>.ant-btn{border-radius:0}.ant-btn-group>.ant-btn-group:first-child:not(:last-child)>.ant-btn:last-child{border-bottom-right-radius:0;border-top-right-radius:0;padding-right:8px}.ant-btn-group>.ant-btn-group:last-child:not(:first-child)>.ant-btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0;padding-left:8px}.ant-btn:active>span,.ant-btn:focus>span{position:relative}.ant-btn>.anticon+span,.ant-btn>span+.anticon{margin-left:8px}.ant-btn-background-ghost{background:transparent!important;border-color:#fff;color:#fff}.ant-btn-background-ghost.ant-btn-primary{background-color:transparent;border-color:#1890ff;color:#1890ff;text-shadow:none}.ant-btn-background-ghost.ant-btn-primary>a:only-child{color:currentColor}.ant-btn-background-ghost.ant-btn-primary>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-background-ghost.ant-btn-primary:focus,.ant-btn-background-ghost.ant-btn-primary:hover{background-color:transparent;border-color:#40a9ff;color:#40a9ff}.ant-btn-background-ghost.ant-btn-primary:focus>a:only-child,.ant-btn-background-ghost.ant-btn-primary:hover>a:only-child{color:currentColor}.ant-btn-background-ghost.ant-btn-primary:focus>a:only-child:after,.ant-btn-background-ghost.ant-btn-primary:hover>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-background-ghost.ant-btn-primary.active,.ant-btn-background-ghost.ant-btn-primary:active{background-color:transparent;border-color:#096dd9;color:#096dd9}.ant-btn-background-ghost.ant-btn-primary.active>a:only-child,.ant-btn-background-ghost.ant-btn-primary:active>a:only-child{color:currentColor}.ant-btn-background-ghost.ant-btn-primary.active>a:only-child:after,.ant-btn-background-ghost.ant-btn-primary:active>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-background-ghost.ant-btn-primary-disabled,.ant-btn-background-ghost.ant-btn-primary-disabled.active,.ant-btn-background-ghost.ant-btn-primary-disabled:active,.ant-btn-background-ghost.ant-btn-primary-disabled:focus,.ant-btn-background-ghost.ant-btn-primary-disabled:hover,.ant-btn-background-ghost.ant-btn-primary.disabled,.ant-btn-background-ghost.ant-btn-primary.disabled.active,.ant-btn-background-ghost.ant-btn-primary.disabled:active,.ant-btn-background-ghost.ant-btn-primary.disabled:focus,.ant-btn-background-ghost.ant-btn-primary.disabled:hover,.ant-btn-background-ghost.ant-btn-primary[disabled],.ant-btn-background-ghost.ant-btn-primary[disabled].active,.ant-btn-background-ghost.ant-btn-primary[disabled]:active,.ant-btn-background-ghost.ant-btn-primary[disabled]:focus,.ant-btn-background-ghost.ant-btn-primary[disabled]:hover{background-color:#f5f5f5;border-color:#d9d9d9;box-shadow:none;color:rgba(0,0,0,.25);text-shadow:none}.ant-btn-background-ghost.ant-btn-primary-disabled.active>a:only-child,.ant-btn-background-ghost.ant-btn-primary-disabled:active>a:only-child,.ant-btn-background-ghost.ant-btn-primary-disabled:focus>a:only-child,.ant-btn-background-ghost.ant-btn-primary-disabled:hover>a:only-child,.ant-btn-background-ghost.ant-btn-primary-disabled>a:only-child,.ant-btn-background-ghost.ant-btn-primary.disabled.active>a:only-child,.ant-btn-background-ghost.ant-btn-primary.disabled:active>a:only-child,.ant-btn-background-ghost.ant-btn-primary.disabled:focus>a:only-child,.ant-btn-background-ghost.ant-btn-primary.disabled:hover>a:only-child,.ant-btn-background-ghost.ant-btn-primary.disabled>a:only-child,.ant-btn-background-ghost.ant-btn-primary[disabled].active>a:only-child,.ant-btn-background-ghost.ant-btn-primary[disabled]:active>a:only-child,.ant-btn-background-ghost.ant-btn-primary[disabled]:focus>a:only-child,.ant-btn-background-ghost.ant-btn-primary[disabled]:hover>a:only-child,.ant-btn-background-ghost.ant-btn-primary[disabled]>a:only-child{color:currentColor}.ant-btn-background-ghost.ant-btn-primary-disabled.active>a:only-child:after,.ant-btn-background-ghost.ant-btn-primary-disabled:active>a:only-child:after,.ant-btn-background-ghost.ant-btn-primary-disabled:focus>a:only-child:after,.ant-btn-background-ghost.ant-btn-primary-disabled:hover>a:only-child:after,.ant-btn-background-ghost.ant-btn-primary-disabled>a:only-child:after,.ant-btn-background-ghost.ant-btn-primary.disabled.active>a:only-child:after,.ant-btn-background-ghost.ant-btn-primary.disabled:active>a:only-child:after,.ant-btn-background-ghost.ant-btn-primary.disabled:focus>a:only-child:after,.ant-btn-background-ghost.ant-btn-primary.disabled:hover>a:only-child:after,.ant-btn-background-ghost.ant-btn-primary.disabled>a:only-child:after,.ant-btn-background-ghost.ant-btn-primary[disabled].active>a:only-child:after,.ant-btn-background-ghost.ant-btn-primary[disabled]:active>a:only-child:after,.ant-btn-background-ghost.ant-btn-primary[disabled]:focus>a:only-child:after,.ant-btn-background-ghost.ant-btn-primary[disabled]:hover>a:only-child:after,.ant-btn-background-ghost.ant-btn-primary[disabled]>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-background-ghost.ant-btn-danger{background-color:transparent;border-color:#ff4d4f;color:#ff4d4f;text-shadow:none}.ant-btn-background-ghost.ant-btn-danger>a:only-child{color:currentColor}.ant-btn-background-ghost.ant-btn-danger>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-background-ghost.ant-btn-danger:focus,.ant-btn-background-ghost.ant-btn-danger:hover{background-color:transparent;border-color:#ff7875;color:#ff7875}.ant-btn-background-ghost.ant-btn-danger:focus>a:only-child,.ant-btn-background-ghost.ant-btn-danger:hover>a:only-child{color:currentColor}.ant-btn-background-ghost.ant-btn-danger:focus>a:only-child:after,.ant-btn-background-ghost.ant-btn-danger:hover>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-background-ghost.ant-btn-danger.active,.ant-btn-background-ghost.ant-btn-danger:active{background-color:transparent;border-color:#d9363e;color:#d9363e}.ant-btn-background-ghost.ant-btn-danger.active>a:only-child,.ant-btn-background-ghost.ant-btn-danger:active>a:only-child{color:currentColor}.ant-btn-background-ghost.ant-btn-danger.active>a:only-child:after,.ant-btn-background-ghost.ant-btn-danger:active>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-background-ghost.ant-btn-danger-disabled,.ant-btn-background-ghost.ant-btn-danger-disabled.active,.ant-btn-background-ghost.ant-btn-danger-disabled:active,.ant-btn-background-ghost.ant-btn-danger-disabled:focus,.ant-btn-background-ghost.ant-btn-danger-disabled:hover,.ant-btn-background-ghost.ant-btn-danger.disabled,.ant-btn-background-ghost.ant-btn-danger.disabled.active,.ant-btn-background-ghost.ant-btn-danger.disabled:active,.ant-btn-background-ghost.ant-btn-danger.disabled:focus,.ant-btn-background-ghost.ant-btn-danger.disabled:hover,.ant-btn-background-ghost.ant-btn-danger[disabled],.ant-btn-background-ghost.ant-btn-danger[disabled].active,.ant-btn-background-ghost.ant-btn-danger[disabled]:active,.ant-btn-background-ghost.ant-btn-danger[disabled]:focus,.ant-btn-background-ghost.ant-btn-danger[disabled]:hover{background-color:#f5f5f5;border-color:#d9d9d9;box-shadow:none;color:rgba(0,0,0,.25);text-shadow:none}.ant-btn-background-ghost.ant-btn-danger-disabled.active>a:only-child,.ant-btn-background-ghost.ant-btn-danger-disabled:active>a:only-child,.ant-btn-background-ghost.ant-btn-danger-disabled:focus>a:only-child,.ant-btn-background-ghost.ant-btn-danger-disabled:hover>a:only-child,.ant-btn-background-ghost.ant-btn-danger-disabled>a:only-child,.ant-btn-background-ghost.ant-btn-danger.disabled.active>a:only-child,.ant-btn-background-ghost.ant-btn-danger.disabled:active>a:only-child,.ant-btn-background-ghost.ant-btn-danger.disabled:focus>a:only-child,.ant-btn-background-ghost.ant-btn-danger.disabled:hover>a:only-child,.ant-btn-background-ghost.ant-btn-danger.disabled>a:only-child,.ant-btn-background-ghost.ant-btn-danger[disabled].active>a:only-child,.ant-btn-background-ghost.ant-btn-danger[disabled]:active>a:only-child,.ant-btn-background-ghost.ant-btn-danger[disabled]:focus>a:only-child,.ant-btn-background-ghost.ant-btn-danger[disabled]:hover>a:only-child,.ant-btn-background-ghost.ant-btn-danger[disabled]>a:only-child{color:currentColor}.ant-btn-background-ghost.ant-btn-danger-disabled.active>a:only-child:after,.ant-btn-background-ghost.ant-btn-danger-disabled:active>a:only-child:after,.ant-btn-background-ghost.ant-btn-danger-disabled:focus>a:only-child:after,.ant-btn-background-ghost.ant-btn-danger-disabled:hover>a:only-child:after,.ant-btn-background-ghost.ant-btn-danger-disabled>a:only-child:after,.ant-btn-background-ghost.ant-btn-danger.disabled.active>a:only-child:after,.ant-btn-background-ghost.ant-btn-danger.disabled:active>a:only-child:after,.ant-btn-background-ghost.ant-btn-danger.disabled:focus>a:only-child:after,.ant-btn-background-ghost.ant-btn-danger.disabled:hover>a:only-child:after,.ant-btn-background-ghost.ant-btn-danger.disabled>a:only-child:after,.ant-btn-background-ghost.ant-btn-danger[disabled].active>a:only-child:after,.ant-btn-background-ghost.ant-btn-danger[disabled]:active>a:only-child:after,.ant-btn-background-ghost.ant-btn-danger[disabled]:focus>a:only-child:after,.ant-btn-background-ghost.ant-btn-danger[disabled]:hover>a:only-child:after,.ant-btn-background-ghost.ant-btn-danger[disabled]>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-background-ghost.ant-btn-link{background-color:transparent;border-color:transparent;color:#1890ff;color:#fff;text-shadow:none}.ant-btn-background-ghost.ant-btn-link>a:only-child{color:currentColor}.ant-btn-background-ghost.ant-btn-link>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-background-ghost.ant-btn-link:focus,.ant-btn-background-ghost.ant-btn-link:hover{background-color:transparent;border-color:transparent;color:#40a9ff}.ant-btn-background-ghost.ant-btn-link:focus>a:only-child,.ant-btn-background-ghost.ant-btn-link:hover>a:only-child{color:currentColor}.ant-btn-background-ghost.ant-btn-link:focus>a:only-child:after,.ant-btn-background-ghost.ant-btn-link:hover>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-background-ghost.ant-btn-link.active,.ant-btn-background-ghost.ant-btn-link:active{background-color:transparent;border-color:transparent;color:#096dd9}.ant-btn-background-ghost.ant-btn-link.active>a:only-child,.ant-btn-background-ghost.ant-btn-link:active>a:only-child{color:currentColor}.ant-btn-background-ghost.ant-btn-link.active>a:only-child:after,.ant-btn-background-ghost.ant-btn-link:active>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-background-ghost.ant-btn-link-disabled,.ant-btn-background-ghost.ant-btn-link-disabled.active,.ant-btn-background-ghost.ant-btn-link-disabled:active,.ant-btn-background-ghost.ant-btn-link-disabled:focus,.ant-btn-background-ghost.ant-btn-link-disabled:hover,.ant-btn-background-ghost.ant-btn-link.disabled,.ant-btn-background-ghost.ant-btn-link.disabled.active,.ant-btn-background-ghost.ant-btn-link.disabled:active,.ant-btn-background-ghost.ant-btn-link.disabled:focus,.ant-btn-background-ghost.ant-btn-link.disabled:hover,.ant-btn-background-ghost.ant-btn-link[disabled],.ant-btn-background-ghost.ant-btn-link[disabled].active,.ant-btn-background-ghost.ant-btn-link[disabled]:active,.ant-btn-background-ghost.ant-btn-link[disabled]:focus,.ant-btn-background-ghost.ant-btn-link[disabled]:hover{background-color:#f5f5f5;border-color:#d9d9d9;box-shadow:none;color:rgba(0,0,0,.25);text-shadow:none}.ant-btn-background-ghost.ant-btn-link-disabled.active>a:only-child,.ant-btn-background-ghost.ant-btn-link-disabled:active>a:only-child,.ant-btn-background-ghost.ant-btn-link-disabled:focus>a:only-child,.ant-btn-background-ghost.ant-btn-link-disabled:hover>a:only-child,.ant-btn-background-ghost.ant-btn-link-disabled>a:only-child,.ant-btn-background-ghost.ant-btn-link.disabled.active>a:only-child,.ant-btn-background-ghost.ant-btn-link.disabled:active>a:only-child,.ant-btn-background-ghost.ant-btn-link.disabled:focus>a:only-child,.ant-btn-background-ghost.ant-btn-link.disabled:hover>a:only-child,.ant-btn-background-ghost.ant-btn-link.disabled>a:only-child,.ant-btn-background-ghost.ant-btn-link[disabled].active>a:only-child,.ant-btn-background-ghost.ant-btn-link[disabled]:active>a:only-child,.ant-btn-background-ghost.ant-btn-link[disabled]:focus>a:only-child,.ant-btn-background-ghost.ant-btn-link[disabled]:hover>a:only-child,.ant-btn-background-ghost.ant-btn-link[disabled]>a:only-child{color:currentColor}.ant-btn-background-ghost.ant-btn-link-disabled.active>a:only-child:after,.ant-btn-background-ghost.ant-btn-link-disabled:active>a:only-child:after,.ant-btn-background-ghost.ant-btn-link-disabled:focus>a:only-child:after,.ant-btn-background-ghost.ant-btn-link-disabled:hover>a:only-child:after,.ant-btn-background-ghost.ant-btn-link-disabled>a:only-child:after,.ant-btn-background-ghost.ant-btn-link.disabled.active>a:only-child:after,.ant-btn-background-ghost.ant-btn-link.disabled:active>a:only-child:after,.ant-btn-background-ghost.ant-btn-link.disabled:focus>a:only-child:after,.ant-btn-background-ghost.ant-btn-link.disabled:hover>a:only-child:after,.ant-btn-background-ghost.ant-btn-link.disabled>a:only-child:after,.ant-btn-background-ghost.ant-btn-link[disabled].active>a:only-child:after,.ant-btn-background-ghost.ant-btn-link[disabled]:active>a:only-child:after,.ant-btn-background-ghost.ant-btn-link[disabled]:focus>a:only-child:after,.ant-btn-background-ghost.ant-btn-link[disabled]:hover>a:only-child:after,.ant-btn-background-ghost.ant-btn-link[disabled]>a:only-child:after{background:transparent;bottom:0;content:"";left:0;position:absolute;right:0;top:0}.ant-btn-two-chinese-chars:first-letter{letter-spacing:.34em}.ant-btn-two-chinese-chars>:not(.anticon){letter-spacing:.34em;margin-right:-.34em}.ant-btn-block{width:100%}.ant-btn:empty{vertical-align:top}a.ant-btn{line-height:30px;padding-top:.1px}a.ant-btn-lg{line-height:38px}a.ant-btn-sm{line-height:22px}.ant-tabs.ant-tabs-card .ant-tabs-card-bar .ant-tabs-nav-container{height:40px}.ant-tabs.ant-tabs-card .ant-tabs-card-bar .ant-tabs-ink-bar{visibility:hidden}.ant-tabs.ant-tabs-card .ant-tabs-card-bar .ant-tabs-tab{background:#fafafa;border:1px solid #e8e8e8;border-radius:4px 4px 0 0;height:40px;line-height:38px;margin:0 2px 0 0;padding:0 16px;transition:all .3s cubic-bezier(.645,.045,.355,1)}.ant-tabs.ant-tabs-card .ant-tabs-card-bar .ant-tabs-tab-active{background:#fff;border-color:#e8e8e8;border-bottom:1px solid #fff;color:#1890ff;height:40px}.ant-tabs.ant-tabs-card .ant-tabs-card-bar .ant-tabs-tab-active:before{border-top:2px solid transparent}.ant-tabs.ant-tabs-card .ant-tabs-card-bar .ant-tabs-tab-disabled{color:#1890ff;color:rgba(0,0,0,.25)}.ant-tabs.ant-tabs-card .ant-tabs-card-bar .ant-tabs-tab-inactive{padding:0}.ant-tabs.ant-tabs-card .ant-tabs-card-bar .ant-tabs-nav-wrap{margin-bottom:0}.ant-tabs.ant-tabs-card .ant-tabs-card-bar .ant-tabs-tab .ant-tabs-close-x{color:rgba(0,0,0,.45);font-size:12px;height:16px;height:14px;margin-left:3px;margin-right:-5px;overflow:hidden;transition:all .3s;vertical-align:middle;width:16px}.ant-tabs.ant-tabs-card .ant-tabs-card-bar .ant-tabs-tab .ant-tabs-close-x:hover{color:rgba(0,0,0,.85)}.ant-tabs.ant-tabs-card .ant-tabs-card-content>.ant-tabs-tabpane,.ant-tabs.ant-tabs-editable-card .ant-tabs-card-content>.ant-tabs-tabpane{transition:none!important}.ant-tabs.ant-tabs-card .ant-tabs-card-content>.ant-tabs-tabpane-inactive,.ant-tabs.ant-tabs-editable-card .ant-tabs-card-content>.ant-tabs-tabpane-inactive{overflow:hidden}.ant-tabs.ant-tabs-card .ant-tabs-card-bar .ant-tabs-tab:hover .anticon-close{opacity:1}.ant-tabs-extra-content{line-height:45px}.ant-tabs-extra-content .ant-tabs-new-tab{border:1px solid #e8e8e8;border-radius:2px;color:rgba(0,0,0,.65);cursor:pointer;font-size:12px;height:20px;line-height:20px;position:relative;text-align:center;transition:all .3s;width:20px}.ant-tabs-extra-content .ant-tabs-new-tab:hover{border-color:#1890ff;color:#1890ff}.ant-tabs-extra-content .ant-tabs-new-tab svg{bottom:0;left:0;margin:auto;position:absolute;right:0;top:0}.ant-tabs.ant-tabs-large .ant-tabs-extra-content{line-height:56px}.ant-tabs.ant-tabs-small .ant-tabs-extra-content{line-height:37px}.ant-tabs.ant-tabs-card .ant-tabs-extra-content{line-height:40px}.ant-tabs-vertical.ant-tabs-card .ant-tabs-card-bar.ant-tabs-left-bar .ant-tabs-nav-container,.ant-tabs-vertical.ant-tabs-card .ant-tabs-card-bar.ant-tabs-right-bar .ant-tabs-nav-container{height:100%}.ant-tabs-vertical.ant-tabs-card .ant-tabs-card-bar.ant-tabs-left-bar .ant-tabs-tab,.ant-tabs-vertical.ant-tabs-card .ant-tabs-card-bar.ant-tabs-right-bar .ant-tabs-tab{border-bottom:1px solid #e8e8e8;margin-bottom:8px}.ant-tabs-vertical.ant-tabs-card .ant-tabs-card-bar.ant-tabs-left-bar .ant-tabs-tab-active,.ant-tabs-vertical.ant-tabs-card .ant-tabs-card-bar.ant-tabs-right-bar .ant-tabs-tab-active{padding-bottom:4px}.ant-tabs-vertical.ant-tabs-card .ant-tabs-card-bar.ant-tabs-left-bar .ant-tabs-tab:last-child,.ant-tabs-vertical.ant-tabs-card .ant-tabs-card-bar.ant-tabs-right-bar .ant-tabs-tab:last-child{margin-bottom:8px}.ant-tabs-vertical.ant-tabs-card .ant-tabs-card-bar.ant-tabs-left-bar .ant-tabs-new-tab,.ant-tabs-vertical.ant-tabs-card .ant-tabs-card-bar.ant-tabs-right-bar .ant-tabs-new-tab{width:90%}.ant-tabs-vertical.ant-tabs-card.ant-tabs-left .ant-tabs-card-bar.ant-tabs-left-bar .ant-tabs-nav-wrap{margin-right:0}.ant-tabs-vertical.ant-tabs-card.ant-tabs-left .ant-tabs-card-bar.ant-tabs-left-bar .ant-tabs-tab{border-radius:4px 0 0 4px;border-right:0;margin-right:1px}.ant-tabs-vertical.ant-tabs-card.ant-tabs-left .ant-tabs-card-bar.ant-tabs-left-bar .ant-tabs-tab-active{margin-right:-1px;padding-right:18px}.ant-tabs-vertical.ant-tabs-card.ant-tabs-right .ant-tabs-card-bar.ant-tabs-right-bar .ant-tabs-nav-wrap{margin-left:0}.ant-tabs-vertical.ant-tabs-card.ant-tabs-right .ant-tabs-card-bar.ant-tabs-right-bar .ant-tabs-tab{border-left:0;border-radius:0 4px 4px 0;margin-left:1px}.ant-tabs-vertical.ant-tabs-card.ant-tabs-right .ant-tabs-card-bar.ant-tabs-right-bar .ant-tabs-tab-active{margin-left:-1px;padding-left:18px}.ant-tabs .ant-tabs-card-bar.ant-tabs-bottom-bar .ant-tabs-tab{border-bottom:1px solid #e8e8e8;border-radius:0 0 4px 4px;border-top:0;height:auto}.ant-tabs .ant-tabs-card-bar.ant-tabs-bottom-bar .ant-tabs-tab-active{color:#1890ff;padding-bottom:0;padding-top:1px}.ant-tabs{-moz-font-feature-settings:"tnum";font-feature-settings:"tnum";zoom:1;-moz-box-sizing:border-box;box-sizing:border-box;color:rgba(0,0,0,.65);font-size:14px;font-variant:tabular-nums;line-height:1.5;list-style:none;margin:0;overflow:hidden;padding:0;position:relative}.ant-tabs:after,.ant-tabs:before{content:"";display:table}.ant-tabs:after{clear:both}.ant-tabs-ink-bar{background-color:#1890ff;bottom:1px;-moz-box-sizing:border-box;box-sizing:border-box;height:2px;left:0;position:absolute;-webkit-transform-origin:0 0;-ms-transform-origin:0 0;transform-origin:0 0;width:0;z-index:1}.ant-tabs-bar{border-bottom:1px solid #e8e8e8;margin:0 0 16px;outline:none}.ant-tabs-bar,.ant-tabs-nav-container{transition:padding .3s cubic-bezier(.645,.045,.355,1)}.ant-tabs-nav-container{zoom:1;-moz-box-sizing:border-box;box-sizing:border-box;font-size:14px;line-height:1.5;margin-bottom:-1px;overflow:hidden;position:relative;white-space:nowrap}.ant-tabs-nav-container:after,.ant-tabs-nav-container:before{content:"";display:table}.ant-tabs-nav-container:after{clear:both}.ant-tabs-nav-container-scrolling{padding-left:32px;padding-right:32px}.ant-tabs-bottom .ant-tabs-bottom-bar{border-bottom:none;border-top:1px solid #e8e8e8;margin-bottom:0;margin-top:16px}.ant-tabs-bottom .ant-tabs-bottom-bar .ant-tabs-ink-bar{bottom:auto;top:1px}.ant-tabs-bottom .ant-tabs-bottom-bar .ant-tabs-nav-container{margin-bottom:0;margin-top:-1px}.ant-tabs-tab-next,.ant-tabs-tab-prev{background-color:transparent;border:0;color:rgba(0,0,0,.45);cursor:pointer;height:100%;opacity:0;pointer-events:none;position:absolute;text-align:center;transition:width .3s cubic-bezier(.645,.045,.355,1),opacity .3s cubic-bezier(.645,.045,.355,1),color .3s cubic-bezier(.645,.045,.355,1);-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:0;z-index:2}.ant-tabs-tab-next.ant-tabs-tab-arrow-show,.ant-tabs-tab-prev.ant-tabs-tab-arrow-show{height:100%;opacity:1;pointer-events:auto;width:32px}.ant-tabs-tab-next:hover,.ant-tabs-tab-prev:hover{color:rgba(0,0,0,.65)}.ant-tabs-tab-next-icon,.ant-tabs-tab-prev-icon{font-style:normal;font-variant:normal;font-weight:700;left:50%;line-height:inherit;position:absolute;text-align:center;text-transform:none;top:50%;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.ant-tabs-tab-next-icon-target,.ant-tabs-tab-prev-icon-target{display:block;display:inline-block;font-size:12px;font-size:10px\9;-webkit-transform:scale(.83333) rotate(0deg);-ms-transform:scale(.83333) rotate(0deg);transform:scale(.83333) rotate(0deg)}:root .ant-tabs-tab-next-icon-target,:root .ant-tabs-tab-prev-icon-target{font-size:12px}.ant-tabs-tab-btn-disabled{cursor:not-allowed}.ant-tabs-tab-btn-disabled,.ant-tabs-tab-btn-disabled:hover{color:rgba(0,0,0,.25)}.ant-tabs-tab-next{right:2px}.ant-tabs-tab-prev{left:0}:root .ant-tabs-tab-prev{-webkit-filter:none;filter:none}.ant-tabs-nav-wrap{margin-bottom:-1px;overflow:hidden}.ant-tabs-nav-scroll{overflow:hidden;white-space:nowrap}.ant-tabs-nav{-moz-box-sizing:border-box;box-sizing:border-box;display:inline-block;list-style:none;margin:0;padding-left:0;position:relative;transition:-webkit-transform .3s cubic-bezier(.645,.045,.355,1);transition:transform .3s cubic-bezier(.645,.045,.355,1);transition:transform .3s cubic-bezier(.645,.045,.355,1),-webkit-transform .3s cubic-bezier(.645,.045,.355,1)}.ant-tabs-nav:after,.ant-tabs-nav:before{content:" ";display:table}.ant-tabs-nav:after{clear:both}.ant-tabs-nav .ant-tabs-tab{-moz-box-sizing:border-box;box-sizing:border-box;cursor:pointer;display:inline-block;height:100%;margin:0 32px 0 0;padding:12px 16px;position:relative;text-decoration:none;transition:color .3s cubic-bezier(.645,.045,.355,1)}.ant-tabs-nav .ant-tabs-tab:before{border-radius:4px 4px 0 0;border-top:2px solid transparent;content:"";left:0;pointer-events:none;position:absolute;top:-1px;transition:all .3s;width:100%}.ant-tabs-nav .ant-tabs-tab:last-child{margin-right:0}.ant-tabs-nav .ant-tabs-tab:hover{color:#40a9ff}.ant-tabs-nav .ant-tabs-tab:active{color:#096dd9}.ant-tabs-nav .ant-tabs-tab .anticon{margin-right:8px}.ant-tabs-nav .ant-tabs-tab-active{color:#1890ff;text-shadow:0 0 .25px currentColor}.ant-tabs-nav .ant-tabs-tab-disabled,.ant-tabs-nav .ant-tabs-tab-disabled:hover{color:rgba(0,0,0,.25);cursor:not-allowed}.ant-tabs .ant-tabs-large-bar .ant-tabs-nav-container{font-size:16px}.ant-tabs .ant-tabs-large-bar .ant-tabs-tab{padding:16px}.ant-tabs .ant-tabs-small-bar .ant-tabs-nav-container{font-size:14px}.ant-tabs .ant-tabs-small-bar .ant-tabs-tab{padding:8px 16px}.ant-tabs-content:before{content:"";display:block;overflow:hidden}.ant-tabs .ant-tabs-bottom-content,.ant-tabs .ant-tabs-top-content{width:100%}.ant-tabs .ant-tabs-bottom-content>.ant-tabs-tabpane,.ant-tabs .ant-tabs-top-content>.ant-tabs-tabpane{-ms-flex-negative:0;-webkit-backface-visibility:hidden;-webkit-flex-shrink:0;flex-shrink:0;opacity:1;transition:opacity .45s;width:100%}.ant-tabs .ant-tabs-bottom-content>.ant-tabs-tabpane-inactive,.ant-tabs .ant-tabs-top-content>.ant-tabs-tabpane-inactive{height:0;opacity:0;overflow:hidden;padding:0!important;pointer-events:none}.ant-tabs .ant-tabs-bottom-content>.ant-tabs-tabpane-inactive input,.ant-tabs .ant-tabs-top-content>.ant-tabs-tabpane-inactive input{visibility:hidden}.ant-tabs .ant-tabs-bottom-content.ant-tabs-content-animated,.ant-tabs .ant-tabs-top-content.ant-tabs-content-animated{-moz-box-orient:horizontal;-moz-box-direction:normal;display:-webkit-flex;display:-moz-box;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;transition:margin-left .3s cubic-bezier(.645,.045,.355,1);will-change:margin-left}.ant-tabs .ant-tabs-left-bar,.ant-tabs .ant-tabs-right-bar{border-bottom:0;height:100%}.ant-tabs .ant-tabs-left-bar .ant-tabs-tab-arrow-show,.ant-tabs .ant-tabs-right-bar .ant-tabs-tab-arrow-show{height:32px;width:100%}.ant-tabs .ant-tabs-left-bar .ant-tabs-tab,.ant-tabs .ant-tabs-right-bar .ant-tabs-tab{display:block;float:none;margin:0 0 16px;padding:8px 24px}.ant-tabs .ant-tabs-left-bar .ant-tabs-tab:last-child,.ant-tabs .ant-tabs-right-bar .ant-tabs-tab:last-child{margin-bottom:0}.ant-tabs .ant-tabs-left-bar .ant-tabs-extra-content,.ant-tabs .ant-tabs-right-bar .ant-tabs-extra-content{text-align:center}.ant-tabs .ant-tabs-left-bar .ant-tabs-nav-scroll,.ant-tabs .ant-tabs-right-bar .ant-tabs-nav-scroll{width:auto}.ant-tabs .ant-tabs-left-bar .ant-tabs-nav-container,.ant-tabs .ant-tabs-left-bar .ant-tabs-nav-wrap,.ant-tabs .ant-tabs-right-bar .ant-tabs-nav-container,.ant-tabs .ant-tabs-right-bar .ant-tabs-nav-wrap{height:100%}.ant-tabs .ant-tabs-left-bar .ant-tabs-nav-container,.ant-tabs .ant-tabs-right-bar .ant-tabs-nav-container{margin-bottom:0}.ant-tabs .ant-tabs-left-bar .ant-tabs-nav-container.ant-tabs-nav-container-scrolling,.ant-tabs .ant-tabs-right-bar .ant-tabs-nav-container.ant-tabs-nav-container-scrolling{padding:32px 0}.ant-tabs .ant-tabs-left-bar .ant-tabs-nav-wrap,.ant-tabs .ant-tabs-right-bar .ant-tabs-nav-wrap{margin-bottom:0}.ant-tabs .ant-tabs-left-bar .ant-tabs-nav,.ant-tabs .ant-tabs-right-bar .ant-tabs-nav{width:100%}.ant-tabs .ant-tabs-left-bar .ant-tabs-ink-bar,.ant-tabs .ant-tabs-right-bar .ant-tabs-ink-bar{bottom:auto;height:0;left:auto;top:0;width:2px}.ant-tabs .ant-tabs-left-bar .ant-tabs-tab-next,.ant-tabs .ant-tabs-right-bar .ant-tabs-tab-next{bottom:0;height:32px;right:0;width:100%}.ant-tabs .ant-tabs-left-bar .ant-tabs-tab-prev,.ant-tabs .ant-tabs-right-bar .ant-tabs-tab-prev{height:32px;top:0;width:100%}.ant-tabs .ant-tabs-left-content,.ant-tabs .ant-tabs-right-content{margin-top:0!important;overflow:hidden;width:auto}.ant-tabs .ant-tabs-left-bar{border-right:1px solid #e8e8e8;float:left;margin-bottom:0;margin-right:-1px}.ant-tabs .ant-tabs-left-bar .ant-tabs-tab{text-align:right}.ant-tabs .ant-tabs-left-bar .ant-tabs-nav-container,.ant-tabs .ant-tabs-left-bar .ant-tabs-nav-wrap{margin-right:-1px}.ant-tabs .ant-tabs-left-bar .ant-tabs-ink-bar{right:1px}.ant-tabs .ant-tabs-left-content{border-left:1px solid #e8e8e8;padding-left:24px}.ant-tabs .ant-tabs-right-bar{border-left:1px solid #e8e8e8;float:right;margin-bottom:0;margin-left:-1px}.ant-tabs .ant-tabs-right-bar .ant-tabs-nav-container,.ant-tabs .ant-tabs-right-bar .ant-tabs-nav-wrap{margin-left:-1px}.ant-tabs .ant-tabs-right-bar .ant-tabs-ink-bar{left:1px}.ant-tabs .ant-tabs-right-content{border-right:1px solid #e8e8e8;padding-right:24px}.ant-tabs-bottom .ant-tabs-ink-bar-animated,.ant-tabs-top .ant-tabs-ink-bar-animated{transition:width .2s cubic-bezier(.645,.045,.355,1),left .3s cubic-bezier(.645,.045,.355,1),-webkit-transform .3s cubic-bezier(.645,.045,.355,1);transition:transform .3s cubic-bezier(.645,.045,.355,1),width .2s cubic-bezier(.645,.045,.355,1),left .3s cubic-bezier(.645,.045,.355,1);transition:transform .3s cubic-bezier(.645,.045,.355,1),width .2s cubic-bezier(.645,.045,.355,1),left .3s cubic-bezier(.645,.045,.355,1),-webkit-transform .3s cubic-bezier(.645,.045,.355,1)}.ant-tabs-left .ant-tabs-ink-bar-animated,.ant-tabs-right .ant-tabs-ink-bar-animated{transition:height .2s cubic-bezier(.645,.045,.355,1),top .3s cubic-bezier(.645,.045,.355,1),-webkit-transform .3s cubic-bezier(.645,.045,.355,1);transition:transform .3s cubic-bezier(.645,.045,.355,1),height .2s cubic-bezier(.645,.045,.355,1),top .3s cubic-bezier(.645,.045,.355,1);transition:transform .3s cubic-bezier(.645,.045,.355,1),height .2s cubic-bezier(.645,.045,.355,1),top .3s cubic-bezier(.645,.045,.355,1),-webkit-transform .3s cubic-bezier(.645,.045,.355,1)}.ant-tabs-no-animation>.ant-tabs-content>.ant-tabs-content-animated,.no-flex>.ant-tabs-content>.ant-tabs-content-animated{margin-left:0!important;-webkit-transform:none!important;-ms-transform:none!important;transform:none!important}.ant-tabs-no-animation>.ant-tabs-content>.ant-tabs-tabpane-inactive,.no-flex>.ant-tabs-content>.ant-tabs-tabpane-inactive{height:0;opacity:0;overflow:hidden;padding:0!important;pointer-events:none}.ant-tabs-no-animation>.ant-tabs-content>.ant-tabs-tabpane-inactive input,.no-flex>.ant-tabs-content>.ant-tabs-tabpane-inactive input{visibility:hidden}.ant-tabs-left-content>.ant-tabs-content-animated,.ant-tabs-right-content>.ant-tabs-content-animated{margin-left:0!important;-webkit-transform:none!important;-ms-transform:none!important;transform:none!important}.ant-tabs-left-content>.ant-tabs-tabpane-inactive,.ant-tabs-right-content>.ant-tabs-tabpane-inactive{height:0;opacity:0;overflow:hidden;padding:0!important;pointer-events:none}.ant-tabs-left-content>.ant-tabs-tabpane-inactive input,.ant-tabs-right-content>.ant-tabs-tabpane-inactive input{visibility:hidden}.wrapper{overflow:hidden;width:100%}.wrapper header{-moz-box-align:center;-ms-flex-align:center;-moz-box-pack:justify;-ms-flex-pack:justify;-webkit-align-items:center;align-items:center;background-color:#1369bf;display:-webkit-flex;display:-moz-box;display:-ms-flexbox;display:flex;height:58px;-webkit-justify-content:space-between;justify-content:space-between;width:100%}.wrapper header h1.header_el{margin-left:9px}.wrapper header .header_el{margin-right:30px;padding:0 20px;width:auto}.wrapper header .user_cneter.header_el{background:url(/recommend/common/assets/img/write-609ef.png) 50% no-repeat;background-size:40px;border:1px solid #e3e3e3;border-radius:10px;cursor:pointer;display:-webkit-flex;display:-moz-box;display:-ms-flexbox;display:flex;font-size:23px;height:40px;margin-top:3px;padding:3px;width:40px}.wrapper header .header_el.global_search{-moz-box-flex:10;-ms-flex-positive:10;-webkit-flex-grow:10;flex-grow:10;padding:0;text-align:center}.wrapper header .global_search input{border-left:0;border-radius:0}.wrapper header .search_select_options{border-bottom-right-radius:0;border-right:1px solid #e3e3e3;border-top-right-radius:0}.wrapper header .search_select_options .ant-select-selection{border-bottom-right-radius:0;border-right:0;border-top-right-radius:0}.wrapper header .search_select_options:after{content:"ˇ";cursor:pointer;font-size:30px;position:absolute;right:5px;top:5px}.wrapper .inner_content{padding:30px}.wrapper .inner_content .tab_content{width:100%}.wrapper .inner_content .detai_content .ant-list-item{-moz-box-flex:1;-ms-flex-positive:1;display:inline-block;-webkit-flex-grow:1;flex-grow:1;padding:0;width:100%}.title_home{cursor:pointer}.ant-tabs .ant-tabs-bottom-content>.ant-tabs-tabpane,.ant-tabs .ant-tabs-top-content>.ant-tabs-tabpane{transition:none}.ant-tabs-tabpane{min-height:100px} \ No newline at end of file diff --git a/static/2022-09-01-tag1/recommend/app/home/bundle-2022_9_2_1662085369265.js b/static/2022-09-01-tag1/recommend/app/home/bundle-2022_9_2_1662085369265.js new file mode 100644 index 0000000..ba6852b --- /dev/null +++ b/static/2022-09-01-tag1/recommend/app/home/bundle-2022_9_2_1662085369265.js @@ -0,0 +1,2 @@ +/*! For license information please see bundle-2022_9_2_1662085369265.js.LICENSE.txt */ +(()=>{var t,e,n,r={70775:function(t,e,n){"use strict";var r=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,"__esModule",{value:!0});var i=r(n(83198));function o(t,e,n){var r;return(r=Math.round(t.h)>=60&&Math.round(t.h)<=240?n?Math.round(t.h)-2*e:Math.round(t.h)+2*e:n?Math.round(t.h)+2*e:Math.round(t.h)-2*e)<0?r+=360:r>=360&&(r-=360),r}function a(t,e,n){return 0===t.h&&0===t.s?t.s:((r=n?Math.round(100*t.s)-16*e:4===e?Math.round(100*t.s)+16:Math.round(100*t.s)+5*e)>100&&(r=100),n&&5===e&&r>10&&(r=10),r<6&&(r=6),r);var r}function s(t,e,n){return n?Math.round(100*t.v)+5*e:Math.round(100*t.v)-15*e}e.default=function(t){for(var e=[],n=i.default(t),r=5;r>0;r-=1){var c=n.toHsv(),u=i.default({h:o(c,r,!0),s:a(c,r,!0),v:s(c,r,!0)}).toHexString();e.push(u)}for(e.push(n.toHexString()),r=1;r<=4;r+=1){c=n.toHsv(),u=i.default({h:o(c,r),s:a(c,r),v:s(c,r)}).toHexString();e.push(u)}return e}},17659:function(t,e,n){"use strict";var r=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,"__esModule",{value:!0});var i=r(n(70775));e.generate=i.default;var o={red:"#F5222D",volcano:"#FA541C",orange:"#FA8C16",gold:"#FAAD14",yellow:"#FADB14",lime:"#A0D911",green:"#52C41A",cyan:"#13C2C2",blue:"#1890FF",geekblue:"#2F54EB",purple:"#722ED1",magenta:"#EB2F96",grey:"#666666"};e.presetPrimaryColors=o;var a={};e.presetPalettes=a,Object.keys(o).forEach((function(t){a[t]=i.default(o[t]),a[t].primary=a[t][5]}));var s=a.red;e.red=s;var c=a.volcano;e.volcano=c;var u=a.gold;e.gold=u;var l=a.orange;e.orange=l;var f=a.yellow;e.yellow=f;var d=a.lime;e.lime=d;var p=a.green;e.green=p;var h=a.cyan;e.cyan=h;var v=a.blue;e.blue=v;var m=a.geekblue;e.geekblue=m;var g=a.purple;e.purple=g;var y=a.magenta;e.magenta=y;var b=a.grey;e.grey=b},96741:(t,e,n)=>{"use strict";n.r(e),n.d(e,{default:()=>h});var r=n(50241),i=n(19343),o=n(94990),a=n(17659);function s(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return Object.keys(t).reduce((function(e,n){var r=t[n];if("class"===n)e.className=r,delete e.class;else e[n]=r;return e}),{})}var c=function(){function t(){(0,i.Z)(this,t),this.collection={}}return(0,o.Z)(t,[{key:"clear",value:function(){this.collection={}}},{key:"delete",value:function(t){return delete this.collection[t]}},{key:"get",value:function(t){return this.collection[t]}},{key:"has",value:function(t){return Boolean(this.collection[t])}},{key:"set",value:function(t,e){return this.collection[t]=e,this}},{key:"size",get:function(){return Object.keys(this.collection).length}}]),t}();function u(t,e,n,i){return t(e.tag,i?(0,r.default)({key:n},i,{attrs:(0,r.default)({},s(e.attrs),i.attrs)}):{key:n,attrs:(0,r.default)({},s(e.attrs))},(e.children||[]).map((function(r,i){return u(t,r,n+"-"+e.tag+"-"+i)})))}function l(t){return(0,a.generate)(t)[0]}function f(t,e){switch(e){case"fill":return t+"-fill";case"outline":return t+"-o";case"twotone":return t+"-twotone";default:throw new TypeError("Unknown theme type: "+e+", name: "+t)}}var d={primaryColor:"#333",secondaryColor:"#E6E6E6"},p={name:"AntdIcon",props:["type","primaryColor","secondaryColor"],displayName:"IconVue",definitions:new c,data:function(){return{twoToneColorPalette:d}},add:function(){for(var t=arguments.length,e=Array(t),n=0;n1&&void 0!==arguments[1]?arguments[1]:d;if(t){var n=p.definitions.get(t);return n&&"function"==typeof n.icon&&(n=(0,r.default)({},n,{icon:n.icon(e.primaryColor,e.secondaryColor)})),n}},setTwoToneColors:function(t){var e=t.primaryColor,n=t.secondaryColor;d.primaryColor=e,d.secondaryColor=n||l(e)},getTwoToneColors:function(){return(0,r.default)({},d)},render:function(t){var e,n=this.$props,i=n.type,o=n.primaryColor,a=n.secondaryColor,s=void 0,c=d;if(o&&(c={primaryColor:o,secondaryColor:a||l(o)}),function(t){return"object"==typeof t&&"string"==typeof t.name&&"string"==typeof t.theme&&("object"==typeof t.icon||"function"==typeof t.icon)}(i))s=i;else if("string"==typeof i&&!(s=p.get(i,c)))return null;return s?(s&&"function"==typeof s.icon&&(s=(0,r.default)({},s,{icon:s.icon(c.primaryColor,c.secondaryColor)})),u(t,s.icon,"svg-"+s.name,{attrs:{"data-icon":s.name,width:"1em",height:"1em",fill:"currentColor","aria-hidden":"true"},on:this.$listeners})):(e="type should be string or icon definiton, but got "+i,process&&process.env||console.error("[@ant-design/icons-vue]: "+e+"."),null)},install:function(t){t.component(p.name,p)}};const h=p},21874:(t,e,n)=>{"use strict";n.d(e,{Z:()=>a});var r=n(94415),i=n(50241),o=n(11981);const a={methods:{setState:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},e=arguments[1],n="function"==typeof t?t(this.$data,this.$props):t;if(this.getDerivedStateFromProps){var r=this.getDerivedStateFromProps((0,o.oZ)(this),(0,i.default)({},this.$data,n));if(null===r)return;n=(0,i.default)({},n,r||{})}(0,i.default)(this.$data,n),this.$forceUpdate(),this.$nextTick((function(){e&&e()}))},__emit:function(){var t=[].slice.call(arguments,0),e=t[0],n=this.$listeners[e];if(t.length&&n)if(Array.isArray(n))for(var i=0,o=n.length;i{"use strict";function r(t){return t.directive("decorator",{})}n.d(e,{Z:()=>i,m:()=>r});const i={install:function(t){r(t)}}},46109:(t,e,n)=>{"use strict";n.d(e,{Z:()=>i});var r={MAC_ENTER:3,BACKSPACE:8,TAB:9,NUM_CENTER:12,ENTER:13,SHIFT:16,CTRL:17,ALT:18,PAUSE:19,CAPS_LOCK:20,ESC:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40,PRINT_SCREEN:44,INSERT:45,DELETE:46,ZERO:48,ONE:49,TWO:50,THREE:51,FOUR:52,FIVE:53,SIX:54,SEVEN:55,EIGHT:56,NINE:57,QUESTION_MARK:63,A:65,B:66,C:67,D:68,E:69,F:70,G:71,H:72,I:73,J:74,K:75,L:76,M:77,N:78,O:79,P:80,Q:81,R:82,S:83,T:84,U:85,V:86,W:87,X:88,Y:89,Z:90,META:91,WIN_KEY_RIGHT:92,CONTEXT_MENU:93,NUM_ZERO:96,NUM_ONE:97,NUM_TWO:98,NUM_THREE:99,NUM_FOUR:100,NUM_FIVE:101,NUM_SIX:102,NUM_SEVEN:103,NUM_EIGHT:104,NUM_NINE:105,NUM_MULTIPLY:106,NUM_PLUS:107,NUM_MINUS:109,NUM_PERIOD:110,NUM_DIVISION:111,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123,NUMLOCK:144,SEMICOLON:186,DASH:189,EQUALS:187,COMMA:188,PERIOD:190,SLASH:191,APOSTROPHE:192,SINGLE_QUOTE:222,OPEN_SQUARE_BRACKET:219,BACKSLASH:220,CLOSE_SQUARE_BRACKET:221,WIN_KEY:224,MAC_FF_META:224,WIN_IME:229,isTextModifyingKeyEvent:function(t){var e=t.keyCode;if(t.altKey&&!t.ctrlKey||t.metaKey||e>=r.F1&&e<=r.F12)return!1;switch(e){case r.ALT:case r.CAPS_LOCK:case r.CONTEXT_MENU:case r.CTRL:case r.DOWN:case r.END:case r.ESC:case r.HOME:case r.INSERT:case r.LEFT:case r.MAC_FF_META:case r.META:case r.NUMLOCK:case r.NUM_CENTER:case r.PAGE_DOWN:case r.PAGE_UP:case r.PAUSE:case r.PRINT_SCREEN:case r.RIGHT:case r.SHIFT:case r.UP:case r.WIN_KEY:case r.WIN_KEY_RIGHT:return!1;default:return!0}},isCharacterKey:function(t){if(t>=r.ZERO&&t<=r.NINE)return!0;if(t>=r.NUM_ZERO&&t<=r.NUM_MULTIPLY)return!0;if(t>=r.A&&t<=r.Z)return!0;if(-1!==window.navigation.userAgent.indexOf("WebKit")&&0===t)return!0;switch(t){case r.SPACE:case r.QUESTION_MARK:case r.NUM_PLUS:case r.NUM_MINUS:case r.NUM_PERIOD:case r.NUM_DIVISION:case r.SEMICOLON:case r.DASH:case r.EQUALS:case r.COMMA:case r.PERIOD:case r.SLASH:case r.APOSTROPHE:case r.SINGLE_QUOTE:case r.OPEN_SQUARE_BRACKET:case r.BACKSLASH:case r.CLOSE_SQUARE_BRACKET:return!0;default:return!1}}};const i=r},98931:(t,e,n)=>{"use strict";n.d(e,{ZP:()=>l,fo:()=>u});var r="undefined"!=typeof window&&window.navigator.userAgent.toLowerCase(),i=r&&r.indexOf("msie 9.0")>0;var o=function(t,e){for(var n=Object.create(null),r=t.split(","),i=0;i{"use strict";n.d(e,{Z:()=>u});var r={transitionstart:{transition:"transitionstart",WebkitTransition:"webkitTransitionStart",MozTransition:"mozTransitionStart",OTransition:"oTransitionStart",msTransition:"MSTransitionStart"},animationstart:{animation:"animationstart",WebkitAnimation:"webkitAnimationStart",MozAnimation:"mozAnimationStart",OAnimation:"oAnimationStart",msAnimation:"MSAnimationStart"}},i={transitionend:{transition:"transitionend",WebkitTransition:"webkitTransitionEnd",MozTransition:"mozTransitionEnd",OTransition:"oTransitionEnd",msTransition:"MSTransitionEnd"},animationend:{animation:"animationend",WebkitAnimation:"webkitAnimationEnd",MozAnimation:"mozAnimationEnd",OAnimation:"oAnimationEnd",msAnimation:"MSAnimationEnd"}},o=[],a=[];function s(t,e,n){t.addEventListener(e,n,!1)}function c(t,e,n){t.removeEventListener(e,n,!1)}"undefined"!=typeof window&&"undefined"!=typeof document&&function(){var t=document.createElement("div").style;function e(e,n){for(var r in e)if(e.hasOwnProperty(r)){var i=e[r];for(var o in i)if(o in t){n.push(i[o]);break}}}"AnimationEvent"in window||(delete r.animationstart.animation,delete i.animationend.animation),"TransitionEvent"in window||(delete r.transitionstart.transition,delete i.transitionend.transition),e(r,o),e(i,a)}();const u={startEvents:o,addStartEventListener:function(t,e){0!==o.length?o.forEach((function(n){s(t,n,e)})):window.setTimeout(e,0)},removeStartEventListener:function(t,e){0!==o.length&&o.forEach((function(n){c(t,n,e)}))},endEvents:a,addEndEventListener:function(t,e){0!==a.length?a.forEach((function(n){s(t,n,e)})):window.setTimeout(e,0)},removeEndEventListener:function(t,e){0!==a.length&&a.forEach((function(n){c(t,n,e)}))}}},11981:(t,e,n)=>{"use strict";n.d(e,{C2:()=>x,CL:()=>_,Ku:()=>l,OU:()=>S,SQ:()=>O,TV:()=>y,ZP:()=>T,cV:()=>h,dG:()=>A,l$:()=>C,m2:()=>f,nI:()=>p,oZ:()=>v,rj:()=>m,vw:()=>b});var r=n(94448),i=n(11190),o=n(50241),a=n(40861),s=n.n(a);n(60042);var c=/-(\w)/g,u=function(t){return t.replace(c,(function(t,e){return e?e.toUpperCase():""}))},l=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",e=arguments[1],n={},r=/;(?![^(]*\))/g,i=/:(.+)/;return t.split(r).forEach((function(t){if(t){var r=t.split(i);if(r.length>1){var o=e?u(r[0].trim()):r[0].trim();n[o]=r[1].trim()}}})),n},f=function(t,e){return e in((t.$options||{}).propsData||{})},d=function(t){return t.data&&t.data.scopedSlots||{}},p=function(t){var e=t.componentOptions||{};return t.$vnode&&(e=t.$vnode.componentOptions||{}),t.children||e.children||[]},h=function(t){if(t.fnOptions)return t.fnOptions;var e=t.componentOptions;return t.$vnode&&(e=t.$vnode.componentOptions),e&&e.Ctor.options||{}},v=function(t){if(t.componentOptions){var e=t.componentOptions,n=e.propsData,r=void 0===n?{}:n,a=e.Ctor,s=((void 0===a?{}:a).options||{}).props||{},c={},u=!0,l=!1,f=void 0;try{for(var d,p=Object.entries(s)[Symbol.iterator]();!(u=(d=p.next()).done);u=!0){var h=d.value,v=(0,i.default)(h,2),m=v[0],g=v[1],y=g.default;void 0!==y&&(c[m]="function"==typeof y&&"Function"!==(b=g.type,_=void 0,(_=b&&b.toString().match(/^\s*function (\w+)/))?_[1]:"")?y.call(t):y)}}catch(t){l=!0,f=t}finally{try{!u&&p.return&&p.return()}finally{if(l)throw f}}return(0,o.default)({},c,r)}var b,_,x=t.$options,w=void 0===x?{}:x,S=t.$props;return function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n={};return Object.keys(t).forEach((function(r){(r in e||void 0!==t[r])&&(n[r]=t[r])})),n}(void 0===S?{}:S,w.propsData)},m=function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:t,r=!(arguments.length>3&&void 0!==arguments[3])||arguments[3];if(t.$createElement){var i=t.$createElement,o=t[e];return void 0!==o?"function"==typeof o&&r?o(i,n):o:t.$scopedSlots[e]&&r&&t.$scopedSlots[e](n)||t.$scopedSlots[e]||t.$slots[e]||void 0}var a=t.context.$createElement,s=g(t)[e];if(void 0!==s)return"function"==typeof s&&r?s(a,n):s;var c=d(t)[e];if(void 0!==c)return"function"==typeof c&&r?c(a,n):c;var u=[],l=t.componentOptions||{};return(l.children||[]).forEach((function(t){t.data&&t.data.slot===e&&(t.data.attrs&&delete t.data.attrs.slot,"template"===t.tag?u.push(t.children):u.push(t))})),u.length?u:void 0},g=function(t){var e=t.componentOptions;return t.$vnode&&(e=t.$vnode.componentOptions),e&&e.propsData||{}},y=function(t,e){return g(t)[e]};function b(t){var e={};return t.componentOptions&&t.componentOptions.listeners?e=t.componentOptions.listeners:t.data&&t.data.on&&(e=t.data.on),(0,o.default)({},e)}function _(t){return(t.$vnode?t.$vnode.componentOptions.listeners:t.$listeners)||{}}function x(t,e){var n={};t.data?n=t.data:t.$vnode&&t.$vnode.data&&(n=t.$vnode.data);var r=n.style||n.staticStyle;if("string"==typeof r)r=l(r,e);else if(e&&r){var i={};return Object.keys(r).forEach((function(t){return i[u(t)]=r[t]})),i}return r}function w(t){return!(t.tag||t.text&&""!==t.text.trim())}function S(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];return t.filter((function(t){return!w(t)}))}var O=function(t,e){return Object.keys(e).forEach((function(n){if(!t[n])throw new Error("not have "+n+" prop");t[n].def&&(t[n]=t[n].def(e[n]))})),t};function A(){var t=[].slice.call(arguments,0),e={};return t.forEach((function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=!0,r=!1,a=void 0;try{for(var c,u=Object.entries(t)[Symbol.iterator]();!(n=(c=u.next()).done);n=!0){var l=c.value,f=(0,i.default)(l,2),d=f[0],p=f[1];e[d]=e[d]||{},s()(p)?(0,o.default)(e[d],p):e[d]=p}}catch(t){r=!0,a=t}finally{try{!n&&u.return&&u.return()}finally{if(r)throw a}}})),e}function C(t){return t&&"object"===(void 0===t?"undefined":(0,r.default)(t))&&"componentOptions"in t&&"context"in t&&void 0!==t.tag}const T=f},55953:(t,e,n)=>{"use strict";n.d(e,{RD:()=>u,Tm:()=>l});var r=n(94415),i=n(50241),o=n(11981),a=n(60042),s=n.n(a);function c(t,e){var n=t.componentOptions,r=t.data,o={};n&&n.listeners&&(o=(0,i.default)({},n.listeners));var a={};r&&r.on&&(a=(0,i.default)({},r.on));var s=new t.constructor(t.tag,r?(0,i.default)({},r,{on:a}):r,t.children,t.text,t.elm,t.context,n?(0,i.default)({},n,{listeners:o}):n,t.asyncFactory);return s.ns=t.ns,s.isStatic=t.isStatic,s.key=t.key,s.isComment=t.isComment,s.fnContext=t.fnContext,s.fnOptions=t.fnOptions,s.fnScopeId=t.fnScopeId,s.isCloned=!0,e&&(t.children&&(s.children=u(t.children,!0)),n&&n.children&&(n.children=u(n.children,!0))),s}function u(t,e){for(var n=t.length,r=new Array(n),i=0;i1&&void 0!==arguments[1]?arguments[1]:{},n=arguments[2],a=t;if(Array.isArray(t)&&(a=(0,o.OU)(t)[0]),!a)return null;var u=c(a,n),l=e.props,f=void 0===l?{}:l,d=e.key,p=e.on,h=void 0===p?{}:p,v=e.nativeOn,m=void 0===v?{}:v,g=e.children,y=e.directives,b=void 0===y?[]:y,_=u.data||{},x={},w={},S=e.attrs,O=void 0===S?{}:S,A=e.ref,C=e.domProps,T=void 0===C?{}:C,k=e.style,E=void 0===k?{}:k,$=e.class,j=void 0===$?{}:$,I=e.scopedSlots,P=void 0===I?{}:I;return w="string"==typeof _.style?(0,o.Ku)(_.style):(0,i.default)({},_.style,w),w="string"==typeof E?(0,i.default)({},w,(0,o.Ku)(w)):(0,i.default)({},w,E),"string"==typeof _.class&&""!==_.class.trim()?_.class.split(" ").forEach((function(t){x[t.trim()]=!0})):Array.isArray(_.class)?s()(_.class).split(" ").forEach((function(t){x[t.trim()]=!0})):x=(0,i.default)({},_.class,x),"string"==typeof j&&""!==j.trim()?j.split(" ").forEach((function(t){x[t.trim()]=!0})):x=(0,i.default)({},x,j),u.data=(0,i.default)({},_,{style:w,attrs:(0,i.default)({},_.attrs,O),class:x,domProps:(0,i.default)({},_.domProps,T),scopedSlots:(0,i.default)({},_.scopedSlots,P),directives:[].concat((0,r.default)(_.directives||[]),(0,r.default)(b))}),u.componentOptions?(u.componentOptions.propsData=u.componentOptions.propsData||{},u.componentOptions.listeners=u.componentOptions.listeners||{},u.componentOptions.propsData=(0,i.default)({},u.componentOptions.propsData,f),u.componentOptions.listeners=(0,i.default)({},u.componentOptions.listeners,h),g&&(u.componentOptions.children=g)):(g&&(u.children=g),u.data.on=(0,i.default)({},u.data.on||{},h)),u.data.on=(0,i.default)({},u.data.on||{},m),void 0!==d&&(u.key=d,u.data.key=d),"string"==typeof A&&(u.data.ref=A),u}},53850:(t,e,n)=>{"use strict";n.d(e,{Z:()=>_});var r=n(94448),i=n(40861),o=n.n(i),a=Object.prototype,s=a.toString,c=a.hasOwnProperty,u=/^\s*function (\w+)/,l=function(t){var e=null!=t?t.type?t.type:t:null,n=e&&e.toString().match(u);return n&&n[1]},f=function(t){if(null==t)return null;var e=t.constructor.toString().match(u);return e&&e[1]},d=Number.isInteger||function(t){return"number"==typeof t&&isFinite(t)&&Math.floor(t)===t},p=Array.isArray||function(t){return"[object Array]"===s.call(t)},h=function(t){return"[object Function]"===s.call(t)},v=function(t,e){var n;return Object.defineProperty(e,"_vueTypes_name",{enumerable:!1,writable:!1,value:t}),n=e,Object.defineProperty(n,"isRequired",{get:function(){return this.required=!0,this},enumerable:!1}),function(t){Object.defineProperty(t,"def",{value:function(t){return void 0===t&&void 0===this.default?(this.default=void 0,this):h(t)||m(this,t)?(this.default=p(t)||o()(t)?function(){return t}:t,this):(g(this._vueTypes_name+' - invalid default value: "'+t+'"',t),this)},enumerable:!1,writable:!1})}(e),h(e.validator)&&(e.validator=e.validator.bind(e)),e},m=function t(e,n){var r=arguments.length>2&&void 0!==arguments[2]&&arguments[2],i=e,a=!0,s=void 0;o()(e)||(i={type:e});var u=i._vueTypes_name?i._vueTypes_name+" - ":"";return c.call(i,"type")&&null!==i.type&&(p(i.type)?(a=i.type.some((function(e){return t(e,n,!0)})),s=i.type.map((function(t){return l(t)})).join(" or ")):a="Array"===(s=l(i))?p(n):"Object"===s?o()(n):"String"===s||"Number"===s||"Boolean"===s||"Function"===s?f(n)===s:n instanceof i.type),a?c.call(i,"validator")&&h(i.validator)?((a=i.validator(n))||!1!==r||g(u+"custom validation failed"),a):a:(!1===r&&g(u+'value "'+n+'" should be of type "'+s+'"'),!1)},g=function(){},y={get any(){return v("any",{type:null})},get func(){return v("function",{type:Function}).def(b.func)},get bool(){return v("boolean",{type:Boolean}).def(b.bool)},get string(){return v("string",{type:String}).def(b.string)},get number(){return v("number",{type:Number}).def(b.number)},get array(){return v("array",{type:Array}).def(b.array)},get object(){return v("object",{type:Object}).def(b.object)},get integer(){return v("integer",{type:Number,validator:function(t){return d(t)}}).def(b.integer)},get symbol(){return v("symbol",{type:null,validator:function(t){return"symbol"===(void 0===t?"undefined":(0,r.default)(t))}})},custom:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"custom validation failed";if("function"!=typeof t)throw new TypeError("[VueTypes error]: You must provide a function as argument");return v(t.name||"<>",{validator:function(){var n=t.apply(void 0,arguments);return n||g(this._vueTypes_name+" - "+e),n}})},oneOf:function(t){if(!p(t))throw new TypeError("[VueTypes error]: You must provide an array as argument");var e='oneOf - value should be one of "'+t.join('", "')+'"',n=t.reduce((function(t,e){return null!=e&&-1===t.indexOf(e.constructor)&&t.push(e.constructor),t}),[]);return v("oneOf",{type:n.length>0?n:null,validator:function(n){var r=-1!==t.indexOf(n);return r||g(e),r}})},instanceOf:function(t){return v("instanceOf",{type:t})},oneOfType:function(t){if(!p(t))throw new TypeError("[VueTypes error]: You must provide an array as argument");var e=!1,n=t.reduce((function(t,n){if(o()(n)){if("oneOf"===n._vueTypes_name)return t.concat(n.type||[]);if(n.type&&!h(n.validator)){if(p(n.type))return t.concat(n.type);t.push(n.type)}else h(n.validator)&&(e=!0);return t}return t.push(n),t}),[]);if(!e)return v("oneOfType",{type:n}).def(void 0);var r=t.map((function(t){return t&&p(t.type)?t.type.map(l):l(t)})).reduce((function(t,e){return t.concat(p(e)?e:[e])}),[]).join('", "');return this.custom((function(e){var n=t.some((function(t){return"oneOf"===t._vueTypes_name?!t.type||m(t.type,e,!0):m(t,e,!0)}));return n||g('oneOfType - value type should be one of "'+r+'"'),n})).def(void 0)},arrayOf:function(t){return v("arrayOf",{type:Array,validator:function(e){var n=e.every((function(e){return m(t,e)}));return n||g('arrayOf - value must be an array of "'+l(t)+'"'),n}})},objectOf:function(t){return v("objectOf",{type:Object,validator:function(e){var n=Object.keys(e).every((function(n){return m(t,e[n])}));return n||g('objectOf - value must be an object of "'+l(t)+'"'),n}})},shape:function(t){var e=Object.keys(t),n=e.filter((function(e){return t[e]&&!0===t[e].required})),r=v("shape",{type:Object,validator:function(r){var i=this;if(!o()(r))return!1;var a=Object.keys(r);return n.length>0&&n.some((function(t){return-1===a.indexOf(t)}))?(g('shape - at least one of required properties "'+n.join('", "')+'" is not present'),!1):a.every((function(n){if(-1===e.indexOf(n))return!0===i._vueTypes_isLoose||(g('shape - object is missing "'+n+'" property'),!1);var o=t[n];return m(o,r[n])}))}});return Object.defineProperty(r,"_vueTypes_isLoose",{enumerable:!1,writable:!0,value:!1}),Object.defineProperty(r,"loose",{get:function(){return this._vueTypes_isLoose=!0,this},enumerable:!1}),r}},b={func:void 0,bool:void 0,string:void 0,number:void 0,array:void 0,object:void 0,integer:void 0};Object.defineProperty(y,"sensibleDefaults",{enumerable:!1,set:function(t){!1===t?b={}:!0===t?b={func:void 0,bool:void 0,string:void 0,number:void 0,array:void 0,object:void 0,integer:void 0}:o()(t)&&(b=t)},get:function(){return b}});const _=y},89554:(t,e,n)=>{"use strict";n.d(e,{Z:()=>s});var r={};function i(t,e){0}function o(t,e,n){e||r[n]||(t(!1,n),r[n]=!0)}const a=function(t,e){o(i,t,e)},s=function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"";a(t,"[antdv: "+e+"] "+n)}},81826:(t,e,n)=>{"use strict";n.d(e,{Z:()=>u});var r=n(67298),i=n(98931),o=n(22120);function a(t){return t.directive("ant-portal",{inserted:function(t,e){var n=e.value,r="function"==typeof n?n(t):n;r!==t.parentNode&&r.appendChild(t)},componentUpdated:function(t,e){var n=e.value,r="function"==typeof n?n(t):n;r!==t.parentNode&&r.appendChild(t)}})}const s={install:function(t){t.use(r.default,{name:"ant-ref"}),(0,i.fo)(t),(0,o.m)(t),a(t)}};var c={};c.install=function(t){c.Vue=t,t.use(s)};const u=c},61553:(t,e,n)=>{"use strict";n.d(e,{W:()=>m});var r=n(53850),i=n(24085),o=n.n(i),a=n(94448),s=n(87609),c=n(50241),u=n(11981),l=n(15417);const f={functional:!0,PRESENTED_IMAGE_DEFAULT:!0,render:function(){var t=arguments[0];return t("svg",{attrs:{width:"184",height:"152",viewBox:"0 0 184 152",xmlns:"http://www.w3.org/2000/svg"}},[t("g",{attrs:{fill:"none",fillRule:"evenodd"}},[t("g",{attrs:{transform:"translate(24 31.67)"}},[t("ellipse",{attrs:{fillOpacity:".8",fill:"#F5F5F7",cx:"67.797",cy:"106.89",rx:"67.797",ry:"12.668"}}),t("path",{attrs:{d:"M122.034 69.674L98.109 40.229c-1.148-1.386-2.826-2.225-4.593-2.225h-51.44c-1.766 0-3.444.839-4.592 2.225L13.56 69.674v15.383h108.475V69.674z",fill:"#AEB8C2"}}),t("path",{attrs:{d:"M101.537 86.214L80.63 61.102c-1.001-1.207-2.507-1.867-4.048-1.867H31.724c-1.54 0-3.047.66-4.048 1.867L6.769 86.214v13.792h94.768V86.214z",fill:"url(#linearGradient-1)",transform:"translate(13.56)"}}),t("path",{attrs:{d:"M33.83 0h67.933a4 4 0 0 1 4 4v93.344a4 4 0 0 1-4 4H33.83a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4z",fill:"#F5F5F7"}}),t("path",{attrs:{d:"M42.678 9.953h50.237a2 2 0 0 1 2 2V36.91a2 2 0 0 1-2 2H42.678a2 2 0 0 1-2-2V11.953a2 2 0 0 1 2-2zM42.94 49.767h49.713a2.262 2.262 0 1 1 0 4.524H42.94a2.262 2.262 0 0 1 0-4.524zM42.94 61.53h49.713a2.262 2.262 0 1 1 0 4.525H42.94a2.262 2.262 0 0 1 0-4.525zM121.813 105.032c-.775 3.071-3.497 5.36-6.735 5.36H20.515c-3.238 0-5.96-2.29-6.734-5.36a7.309 7.309 0 0 1-.222-1.79V69.675h26.318c2.907 0 5.25 2.448 5.25 5.42v.04c0 2.971 2.37 5.37 5.277 5.37h34.785c2.907 0 5.277-2.421 5.277-5.393V75.1c0-2.972 2.343-5.426 5.25-5.426h26.318v33.569c0 .617-.077 1.216-.221 1.789z",fill:"#DCE0E6"}})]),t("path",{attrs:{d:"M149.121 33.292l-6.83 2.65a1 1 0 0 1-1.317-1.23l1.937-6.207c-2.589-2.944-4.109-6.534-4.109-10.408C138.802 8.102 148.92 0 161.402 0 173.881 0 184 8.102 184 18.097c0 9.995-10.118 18.097-22.599 18.097-4.528 0-8.744-1.066-12.28-2.902z",fill:"#DCE0E6"}}),t("g",{attrs:{transform:"translate(149.65 15.383)",fill:"#FFF"}},[t("ellipse",{attrs:{cx:"20.654",cy:"3.167",rx:"2.849",ry:"2.815"}}),t("path",{attrs:{d:"M5.698 5.63H0L2.898.704zM9.259.704h4.985V5.63H9.259z"}})])])])}};var d=n(81826),p={name:"AEmpty",props:(0,c.default)({},{prefixCls:r.Z.string,image:r.Z.any,description:r.Z.any,imageStyle:r.Z.object}),inject:{configProvider:{default:function(){return m}}},methods:{renderEmpty:function(t){var e=this.$createElement,n=this.$props,r=n.prefixCls,i=n.imageStyle,c=(0,this.configProvider.getPrefixCls)("empty",r),l=(0,u.rj)(this,"image")||e(f),d=(0,u.rj)(this,"description"),p=void 0!==d?d:t.description,h="string"==typeof p?p:"empty",v=(0,s.default)({},c,!0),m=null;if("string"==typeof l)m=e("img",{attrs:{alt:h,src:l}});else if("object"===(void 0===l?"undefined":(0,a.default)(l))&&l.PRESENTED_IMAGE_SIMPLE){m=e(l),v[c+"-normal"]=!0}else m=l;return e("div",o()([{class:v},{on:(0,u.CL)(this)}]),[e("div",{class:c+"-image",style:i},[m]),p&&e("p",{class:c+"-description"},[p]),this.$slots.default&&e("div",{class:c+"-footer"},[this.$slots.default])])}},render:function(){var t=arguments[0];return t(l.Z,{attrs:{componentName:"Empty"},scopedSlots:{default:this.renderEmpty}})}};p.PRESENTED_IMAGE_DEFAULT=f,p.PRESENTED_IMAGE_SIMPLE={functional:!0,PRESENTED_IMAGE_SIMPLE:!0,render:function(){var t=arguments[0];return t("svg",{attrs:{width:"64",height:"41",viewBox:"0 0 64 41",xmlns:"http://www.w3.org/2000/svg"}},[t("g",{attrs:{transform:"translate(0 1)",fill:"none",fillRule:"evenodd"}},[t("ellipse",{attrs:{fill:"#F5F5F5",cx:"32",cy:"33",rx:"32",ry:"7"}}),t("g",{attrs:{fillRule:"nonzero",stroke:"#D9D9D9"}},[t("path",{attrs:{d:"M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"}}),t("path",{attrs:{d:"M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z",fill:"#FAFAFA"}})])])])}},p.install=function(t){t.use(d.Z),t.component(p.name,p)};const h=p;var v={functional:!0,inject:{configProvider:{default:function(){return m}}},props:{componentName:r.Z.string},render:function(t,e){var n=arguments[0],r=e.props,i=e.injections;function o(t){var e=(0,i.configProvider.getPrefixCls)("empty");switch(t){case"Table":case"List":return n(h,{attrs:{image:h.PRESENTED_IMAGE_SIMPLE}});case"Select":case"TreeSelect":case"Cascader":case"Transfer":case"Mentions":return n(h,{attrs:{image:h.PRESENTED_IMAGE_SIMPLE},class:e+"-small"});default:return n(h)}}return o(r.componentName)}};var m={getPrefixCls:function(t,e){return e||"ant-"+t},renderEmpty:function(t,e){return t(v,{attrs:{componentName:e}})}}},38540:(t,e,n)=>{"use strict";n.d(e,{Z:()=>C});var r=n(24085),i=n.n(r),o=n(50241),a=n(87609),s=n(94415),c=n(60042),u=n.n(c),l=n(99917),f=n(96741),d=n(53850),p=n(749),h=n(11981),v=new Set;var m=n(89554),g={width:"1em",height:"1em",fill:"currentColor","aria-hidden":"true",focusable:"false"},y=/-fill$/,b=/-o$/,_=/-twotone$/;var x=n(15417);function w(t){return f.default.setTwoToneColors({primaryColor:t})}var S=n(81826);f.default.add.apply(f.default,(0,s.default)(Object.keys(l).filter((function(t){return"default"!==t})).map((function(t){return l[t]})))),w("#1890ff");function O(t,e,n){var r,s=n.$props,c=n.$slots,l=(0,h.CL)(n),d=s.type,p=s.component,v=s.viewBox,x=s.spin,w=s.theme,S=s.twoToneColor,O=s.rotate,A=s.tabIndex,C=(0,h.OU)(c.default);C=0===C.length?void 0:C,(0,m.Z)(Boolean(d||p||C),"Icon","Icon should have `type` prop or `component` prop or `children`.");var T=u()((r={},(0,a.default)(r,"anticon",!0),(0,a.default)(r,"anticon-"+d,!!d),r)),k=u()((0,a.default)({},"anticon-spin",!!x||"loading"===d)),E=O?{msTransform:"rotate("+O+"deg)",transform:"rotate("+O+"deg)"}:void 0,$={attrs:(0,o.default)({},g,{viewBox:v}),class:k,style:E};v||delete $.attrs.viewBox;var j=A;void 0===j&&"click"in l&&(j=-1);var I={attrs:{"aria-label":d&&e.icon+": "+d,tabIndex:j},on:l,class:T,staticClass:""};return t("i",I,[function(){if(p)return t(p,$,[C]);if(C){(0,m.Z)(Boolean(v)||1===C.length&&"use"===C[0].tag,"Icon","Make sure that you provide correct `viewBox` prop (default `0 0 1024 1024`) to the icon.");var e={attrs:(0,o.default)({},g),class:k,style:E};return t("svg",i()([e,{attrs:{viewBox:v}}]),[C])}if("string"==typeof d){var n=d;if(w){var r=function(t){var e=null;return y.test(t)?e="filled":b.test(t)?e="outlined":_.test(t)&&(e="twoTone"),e}(d);(0,m.Z)(!r||w===r,"Icon","The icon name '"+d+"' already specify a theme '"+r+"', the 'theme' prop '"+w+"' will be ignored.")}return n=function(t,e){var n=t;return"filled"===e?n+="-fill":"outlined"===e?n+="-o":"twoTone"===e?n+="-twotone":(0,m.Z)(!1,"Icon","This icon '"+t+"' has unknown theme '"+e+"'"),n}(function(t){return t.replace(y,"").replace(b,"").replace(_,"")}(function(t){var e=t;switch(t){case"cross":e="close";break;case"interation":e="interaction";break;case"canlendar":e="calendar";break;case"colum-height":e="column-height"}return(0,m.Z)(e===t,"Icon","Icon '"+t+"' was a typo and is now deprecated, please use '"+e+"' instead."),e}(n)),w||"outlined"),t(f.default,{attrs:{focusable:"false",type:n,primaryColor:S},class:k,style:E})}}()])}var A={name:"AIcon",props:{tabIndex:d.Z.number,type:d.Z.string,component:d.Z.any,viewBox:d.Z.any,spin:d.Z.bool.def(!1),rotate:d.Z.number,theme:d.Z.oneOf(["filled","outlined","twoTone"]),twoToneColor:d.Z.string,role:d.Z.string},render:function(t){var e=this;return t(x.Z,{attrs:{componentName:"Icon"},scopedSlots:{default:function(n){return O(t,n,e)}}})},createFromIconfontCN:function(t){var e=t.scriptUrl,n=t.extraCommonProps,r=void 0===n?{}:n;if("undefined"!=typeof document&&"undefined"!=typeof window&&"function"==typeof document.createElement&&"string"==typeof e&&e.length&&!v.has(e)){var i=document.createElement("script");i.setAttribute("src",e),i.setAttribute("data-namespace",e),v.add(e),document.body.appendChild(i)}return{functional:!0,name:"AIconfont",props:C.props,render:function(t,e){var n=e.props,i=e.slots,o=e.listeners,a=e.data,s=n.type,c=(0,p.default)(n,["type"]),u=i().default,l=null;s&&(l=t("use",{attrs:{"xlink:href":"#"+s}})),u&&(l=u);var f=(0,h.dG)(r,a,{props:c,on:o});return t(C,f,[l])}}},getTwoToneColor:function(){return f.default.getTwoToneColors().primaryColor}};A.setTwoToneColor=w,A.install=function(t){t.use(S.Z),t.component(A.name,A)};const C=A},15417:(t,e,n)=>{"use strict";n.d(e,{Z:()=>a});var r=n(50241),i=n(53850),o=n(90479);const a={name:"LocaleReceiver",props:{componentName:i.Z.string.def("global"),defaultLocale:i.Z.oneOfType([i.Z.object,i.Z.func]),children:i.Z.func},inject:{localeData:{default:function(){return{}}}},methods:{getLocale:function(){var t=this.componentName,e=this.defaultLocale||o.Z[t||"global"],n=this.localeData.antLocale,i=t&&n?n[t]:{};return(0,r.default)({},"function"==typeof e?e():e,i||{})},getLocaleCode:function(){var t=this.localeData.antLocale,e=t&&t.locale;return t&&t.exist&&!e?o.Z.locale:e}},render:function(){var t=this.$scopedSlots,e=this.children||t.default,n=this.localeData.antLocale;return e(this.getLocale(),this.getLocaleCode(),n)}}},90479:(t,e,n)=>{"use strict";n.d(e,{Z:()=>r});const r=n(53944).Z},53944:(t,e,n)=>{"use strict";n.d(e,{Z:()=>a});var r=n(50241);const i={placeholder:"Select time"};var o={lang:(0,r.default)({placeholder:"Select date",rangePlaceholder:["Start date","End date"]},{today:"Today",now:"Now",backToToday:"Back to today",ok:"Ok",clear:"Clear",month:"Month",year:"Year",timeSelect:"select time",dateSelect:"select date",weekSelect:"Choose a week",monthSelect:"Choose a month",yearSelect:"Choose a year",decadeSelect:"Choose a decade",yearFormat:"YYYY",dateFormat:"M/D/YYYY",dayFormat:"D",dateTimeFormat:"M/D/YYYY HH:mm:ss",monthBeforeYear:!0,previousMonth:"Previous month (PageUp)",nextMonth:"Next month (PageDown)",previousYear:"Last year (Control + left)",nextYear:"Next year (Control + right)",previousDecade:"Last decade",nextDecade:"Next decade",previousCentury:"Last century",nextCentury:"Next century"}),timePickerLocale:(0,r.default)({},i)};const a={locale:"en",Pagination:{items_per_page:"/ page",jump_to:"Go to",jump_to_confirm:"confirm",page:"",prev_page:"Previous Page",next_page:"Next Page",prev_5:"Previous 5 Pages",next_5:"Next 5 Pages",prev_3:"Previous 3 Pages",next_3:"Next 3 Pages"},DatePicker:o,TimePicker:i,Calendar:o,global:{placeholder:"Please select"},Table:{filterTitle:"Filter menu",filterConfirm:"OK",filterReset:"Reset",selectAll:"Select current page",selectInvert:"Invert current page",sortTitle:"Sort",expand:"Expand row",collapse:"Collapse row"},Modal:{okText:"OK",cancelText:"Cancel",justOkText:"OK"},Popconfirm:{okText:"OK",cancelText:"Cancel"},Transfer:{titles:["",""],searchPlaceholder:"Search here",itemUnit:"item",itemsUnit:"items"},Upload:{uploading:"Uploading...",removeFile:"Remove file",uploadError:"Upload error",previewFile:"Preview file",downloadFile:"Download file"},Empty:{description:"No Data"},Icon:{icon:"icon"},Text:{edit:"Edit",copy:"Copy",copied:"Copied",expand:"Expand"},PageHeader:{back:"Back"}}},24085:t=>{var e=/^(attrs|props|on|nativeOn|class|style|hook)$/;function n(t,e){return function(){t&&t.apply(this,arguments),e&&e.apply(this,arguments)}}t.exports=function(t){return t.reduce((function(t,r){var i,o,a,s,c;for(a in r)if(i=t[a],o=r[a],i&&e.test(a))if("class"===a&&("string"==typeof i&&(c=i,t[a]=i={},i[c]=!0),"string"==typeof o&&(c=o,r[a]=o={},o[c]=!0)),"on"===a||"nativeOn"===a||"hook"===a)for(s in o)i[s]=n(i[s],o[s]);else if(Array.isArray(i))t[a]=i.concat(o);else if(Array.isArray(o))t[a]=[i].concat(o);else for(s in o)i[s]=o[s];else t[a]=r[a];return t}),{})}},82691:(t,e,n)=>{"use strict";n.d(e,{Z:()=>o});n(98010),n(63238),n(69217),n(95374),n(55849),n(72264);function r(t,e,n,i){var o=[],a=[],s=null,c=null,u=!1,l=!1,f=t.filter((function(t){var n=t&&t.linkOther&&t.linkOther.targetId==e;return n||o.push(t),n}));return f.sort((function(t,e){return e.time-t.time})),f.forEach((function(t,e){var f=t._id,d=t.id,p=t.time,h=t.content,v=t.level,m=t.linkUser,g=t.linkOther,y=t.linkOrigin,b=t.personInfo,_=t.repliedUserInfo;c=r(o,d=f||d,n,i),b=b&&b.length?b[0]:{},_=_&&_.length?_[0]:{},u=!!(i&&m&&m.uid&&m.uid==n),m&&(m.favNum=m.fav&&m.fav.length||0,m.fav&&m.fav.length&&(l=i&&!!m.fav.some((function(t){return t==n})))),p=new Date(p).format().substr(0,16),s={id:d,time:p,content:h,level:v,linkUser:m,linkOther:g,linkOrigin:y,personInfo:b,repliedUserInfo:_,childArr:c,isAuthor:u,isFavActive:l},a.push(s),s=null,d=null,p=null,h=null,v=null,m=null,g=null,y=null,b=null,c=null,u=!1,l=!1})),a}function i(){var t,e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];window.TempArr||(window.TempArr=[]),e.forEach((function(e){t=e.childArr,e.childArr=null,window.TempArr.push(e),t&&t.length&&i(t)}))}const o={transData:function(t,e,n,o){var a=window.Util,s=(a.Cookies,a.Base64,t=r(t,e,n,o),[]);return t.forEach((function(t){t.childArr&&t.childArr.length&&i(t.childArr);t.childArr=window.TempArr,window.TempArr=null,s.push(t)})),window.TempArr=null,s}}},99917:(t,e,n)=>{"use strict";n.r(e)},27261:(t,e,n)=>{"use strict";n.r(e),n.d(e,{ajax:()=>f});n(52077),n(82759),n(40895),n(63238),n(27471),n(72482),n(26252),n(911),n(83352),n(25613),n(72410),n(95374),n(55849);var r,i,o=window.document,a=/^(?:text|application)\/javascript/i,s=/^(?:text|application)\/xml/i,c="application/json",u="text/html",l=/^\s*$/,f=function t(e){var n=w({},e||{});for(r in t.settings)void 0===n[r]&&(n[r]=t.settings[r]);p(n),n.crossDomain||(n.crossDomain=/^([\w-]+:)?\/\/([^\/]+)/.test(n.url)&&RegExp.$2!=window.location.host);var o=n.dataType,f=/=\?/.test(n.url);if("jsonp"==o||f)return f||(n.url=y(n.url,"callback=?")),t.JSONP(n);n.url||(n.url=window.location.toString()),b(n);var m,_=n.accepts[o],x={},S=/^([\w-]+:)\/\//.test(n.url)?RegExp.$1:window.location.protocol,O=t.settings.xhr();n.crossDomain||(x["X-Requested-With"]="XMLHttpRequest"),_&&(x.Accept=_,_.indexOf(",")>-1&&(_=_.split(",",2)[0]),O.overrideMimeType&&O.overrideMimeType(_)),(n.contentType||n.data&&"GET"!=n.type.toUpperCase())&&"upload"!=n.contentType&&(x["Content-Type"]=n.contentType||"application/x-www-form-urlencoded"),n.headers=w(x,n.headers||{}),O.onreadystatechange=function(){if(4==O.readyState){clearTimeout(m);var t,e=!1;if(O.status>=200&&O.status<300||304==O.status||0==O.status&&"file:"==S){o=o||function(t){return t&&(t==u?"html":t==c?"json":a.test(t)?"script":s.test(t)&&"xml")||"text"}(O.getResponseHeader("content-type")),t=O.responseText;try{"script"==o?(0,eval)(t):"xml"==o?t=O.responseXML:"json"==o&&(t=l.test(t)?null:JSON.parse(t))}catch(t){e=t}e?v(e,"parsererror",O,n):h(t,O,n)}else v(null,"error",O,n)}};var A=!("async"in n)||n.async;for(i in O.open(n.type,n.url,A),n.headers)O.setRequestHeader(i,n.headers[i]);return!1===function(t,e){var n=e.context;if(!1===e.beforeSend.call(n,t,e)||!1===d(e,n,"ajaxBeforeSend",[t,e]))return!1;d(e,n,"ajaxSend",[t,e])}(O,n)?(O.abort(),!1):(n.timeout>0&&(m=setTimeout((function(){O.onreadystatechange=g,O.abort(),v(null,"timeout",O,n)}),n.timeout)),O.send(n.data?n.data:null),O)};function d(t,e,n,r){if(t.global)return!0}function p(t){t.global&&0==f.active++&&d(t)}function h(t,e,n){var r=n.context,i="success";n.success.call(r,t,i,e),d(n),m(i,e,n)}function v(t,e,n,r){var i=r.context;r.error.call(i,n,e,t),d(r),m(e,n,r)}function m(t,e,n){var r=n.context;n.complete&&n.complete.call(r,e,t),d(n),function(t){t.global&&!--f.active&&d(t)}(n)}function g(){}function y(t,e){return(t+"&"+e).replace(/[&?]{1,2}/,"?")}function b(t){var e,n,r;"[object Object]"===Object.prototype.toString.call(t.data)&&(t.data=(e=t.data,(r=[]).add=function(t,e){this.push(_(t)+"="+_(e))},x(r,e,n),r.join("&").replace("%20","+"))),!t.data||t.type&&"GET"!=t.type.toUpperCase()||(t.url=y(t.url,t.data))}f.active=0,f.JSONP=function(t){if(!("type"in t))return f(t);var e,n=t.JSONPCallBackName||"JSONP"+ +new Date,r=o.createElement("script"),i={abort:function(){n in window&&(window[n]=g),m("abort",i,t)}},a=o.getElementsByTagName("head")[0]||o.documentElement;return t.error&&(r.onerror=function(){i.abort(),t.error()}),window[n]=function(r){clearTimeout(e),delete window[n],h(r,i,t)},b(t),r.src=t.url.replace(/=\?/,"="+n),r.type="text/javascript",a.insertBefore(r,a.firstChild),t.timeout>0&&(e=setTimeout((function(){i.abort(),m("timeout",i,t)}),t.timeout)),i},f.settings={type:"GET",beforeSend:g,success:g,error:g,complete:g,context:null,global:!0,xhr:function(){return new window.XMLHttpRequest},accepts:{script:"text/javascript, application/javascript",json:c,xml:"application/xml, text/xml",html:u,text:"text/plain"},crossDomain:!1,timeout:0},f.get=function(t,e){return f({url:t,success:e})},f.post=function(t,e,n,r){return"[object Function]"===Object.prototype.toString.call(e)&&(r=r||n,n=e,e=null),f({type:"POST",url:t,data:e,success:n,dataType:r})},f.getJSON=function(t,e){return f({url:t,success:e,dataType:"json"})};var _=encodeURIComponent;function x(t,e,n,r){var i="[object Array]"===Object.prototype.toString.call(e);for(var o in e){var a=e[o];r&&(o=n?r:r+"["+(i?"":o)+"]"),!r&&i?t.add(a.name,a.value):(n?"[object Array]"===Object.prototype.toString.call(a):"[object Object]"===Object.prototype.toString.call(a))?x(t,a,n,o):t.add(o,a)}}function w(t){var e=Array.prototype.slice;return e.call(arguments,1).forEach((function(e){for(r in e)void 0!==e[r]&&(t[r]=e[r])})),t}},4823:(t,e,n)=>{"use strict";n.d(e,{gq:()=>s});var r=n(22951),i=n(91976),o=(n(63238),n(61418),n(26252),n(95735),n(52077),n(1203),n(23938),n(27261)),a="cgclubs.com";window.$=o;var s=function(){function t(e){(0,r.Z)(this,t),this.opts=e,this.init()}return(0,i.Z)(t,[{key:"init",value:function(){var t=this.opts;this.opts.mock&&window.mockData?this.promise=new Promise((function(e,n){setTimeout((function(){e(window.mockData[t.mockUrl||t.url])}),1e3)})):this.promise=new Promise((function(e,n){var r=function(){var t,e=location.host;if(/^local/i.test(e))t="/ajax";else if(/^qa\d/i.test(e)){var n=location.host.match(/^qa\d/i),r=n?n[0]:"qa1";t="//".concat(r).concat(a,"/ajax")}else t=/^qa/i.test(e)?"//qa".concat(a,"/ajax"):/^yz/i.test(e)?"//yz".concat(a,"/ajax"):"//".concat(a,"/ajax");return t}();if("get"==t.type)if(t.dataType&&"JSONP"==t.dataType.toUpperCase())t.data.timeStamp=+new Date,$.ajax({type:"get",dataType:"jsonp",contentType:"text/javascript",url:r+t.url,data:t.data,success:function(t){200==t.status?e(t):n(t)},error:function(t){console.log(t)}});else{t.data.timeStamp=+new Date;var i={json:JSON.stringify(t.data)};$.ajax({type:"get",url:r+t.url,data:i,dataType:"json",success:function(t){200==t.status?e(t):n(t)},error:function(t){console.log(t)}})}else t.upload?$.ajax({type:t&&t.type?t.type:"get",url:r+t.url,data:t.data,dataType:"json",cache:!1,precessData:!1,contentType:"upload",success:function(t){200==t.status?e(t):n(t)},error:function(t){console.log(t)}}):$.ajax({type:t&&t.type?t.type:"get",url:r+t.url,data:JSON.stringify(t.data),dataType:"json",contentType:"application/json",success:function(t){200==t.status?e(t):n(t)},error:function(t){console.log(t)}})}))}}]),t}()},89474:(t,e,n)=>{t.exports={default:n(53030),__esModule:!0}},92811:(t,e,n)=>{t.exports={default:n(96076),__esModule:!0}},78445:(t,e,n)=>{t.exports={default:n(79376),__esModule:!0}},96476:(t,e,n)=>{t.exports={default:n(8924),__esModule:!0}},57252:(t,e,n)=>{t.exports={default:n(14753),__esModule:!0}},79512:(t,e,n)=>{t.exports={default:n(77117),__esModule:!0}},64918:(t,e,n)=>{t.exports={default:n(6889),__esModule:!0}},19343:(t,e)=>{"use strict";e.Z=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}},94990:(t,e,n)=>{"use strict";var r,i=n(57252),o=(r=i)&&r.__esModule?r:{default:r};e.Z=function(){function t(t,e){for(var n=0;n{"use strict";e.__esModule=!0;var r,i=n(57252),o=(r=i)&&r.__esModule?r:{default:r};e.default=function(t,e,n){return e in t?(0,o.default)(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}},50241:(t,e,n)=>{"use strict";e.__esModule=!0;var r,i=n(96476),o=(r=i)&&r.__esModule?r:{default:r};e.default=o.default||function(t){for(var e=1;e{"use strict";e.__esModule=!0,e.default=function(t,e){var n={};for(var r in t)e.indexOf(r)>=0||Object.prototype.hasOwnProperty.call(t,r)&&(n[r]=t[r]);return n}},11190:(t,e,n)=>{"use strict";e.__esModule=!0;var r=o(n(78445)),i=o(n(92811));function o(t){return t&&t.__esModule?t:{default:t}}e.default=function(t,e){if(Array.isArray(t))return t;if((0,r.default)(Object(t)))return function(t,e){var n=[],r=!0,o=!1,a=void 0;try{for(var s,c=(0,i.default)(t);!(r=(s=c.next()).done)&&(n.push(s.value),!e||n.length!==e);r=!0);}catch(t){o=!0,a=t}finally{try{!r&&c.return&&c.return()}finally{if(o)throw a}}return n}(t,e);throw new TypeError("Invalid attempt to destructure non-iterable instance")}},94415:(t,e,n)=>{"use strict";e.__esModule=!0;var r,i=n(89474),o=(r=i)&&r.__esModule?r:{default:r};e.default=function(t){if(Array.isArray(t)){for(var e=0,n=Array(t.length);e{"use strict";e.__esModule=!0;var r=a(n(64918)),i=a(n(79512)),o="function"==typeof i.default&&"symbol"==typeof r.default?function(t){return typeof t}:function(t){return t&&"function"==typeof i.default&&t.constructor===i.default&&t!==i.default.prototype?"symbol":typeof t};function a(t){return t&&t.__esModule?t:{default:t}}e.default="function"==typeof i.default&&"symbol"===o(r.default)?function(t){return void 0===t?"undefined":o(t)}:function(t){return t&&"function"==typeof i.default&&t.constructor===i.default&&t!==i.default.prototype?"symbol":void 0===t?"undefined":o(t)}},60042:(t,e)=>{var n;!function(){"use strict";var r={}.hasOwnProperty;function i(){for(var t=[],e=0;e{var r=n(20186);t.exports=r},76189:(t,e,n)=>{var r=n(54287);t.exports=r},4795:(t,e,n)=>{var r=n(10175);t.exports=r},64956:(t,e,n)=>{var r=n(97826);t.exports=r},88202:(t,e,n)=>{var r=n(18529);t.exports=r},3590:(t,e,n)=>{var r=n(68702);t.exports=r},26952:(t,e,n)=>{var r=n(35322);t.exports=r},91506:(t,e,n)=>{n(17460),n(15610);var r=n(79775);t.exports=r.Array.from},91349:(t,e,n)=>{n(5769),n(17460);var r=n(73546);t.exports=r},41015:(t,e,n)=>{n(5769),n(17460);var r=n(99517);t.exports=r},73645:(t,e,n)=>{n(48410);var r=n(79775);t.exports=r.Object.assign},59412:(t,e,n)=>{n(99785);var r=n(79775).Object,i=t.exports=function(t,e,n){return r.defineProperty(t,e,n)};r.defineProperty.sham&&(i.sham=!0)},49512:(t,e,n)=>{n(23938),n(63238),n(25901),n(98521),n(92189),n(76563),n(83301),n(91047),n(9038),n(5737),n(31918),n(12077),n(78605),n(13199),n(19068),n(6798),n(19745),n(82923),n(21897),n(61544);var r=n(79775);t.exports=r.Symbol},23289:(t,e,n)=>{n(5769),n(63238),n(17460),n(91047);var r=n(69251);t.exports=r.f("iterator")},53030:(t,e,n)=>{t.exports=n(40528)},96076:(t,e,n)=>{t.exports=n(49065)},79376:(t,e,n)=>{t.exports=n(77678)},8924:(t,e,n)=>{t.exports=n(16980)},14753:(t,e,n)=>{t.exports=n(41448)},77117:(t,e,n)=>{t.exports=n(44115)},6889:(t,e,n)=>{t.exports=n(73897)},40528:(t,e,n)=>{var r=n(12012);t.exports=r},49065:(t,e,n)=>{var r=n(76189);t.exports=r},77678:(t,e,n)=>{var r=n(4795);t.exports=r},16980:(t,e,n)=>{var r=n(64956);t.exports=r},41448:(t,e,n)=>{var r=n(88202);t.exports=r},44115:(t,e,n)=>{var r=n(3590);n(29517),n(34163),n(47140),n(48010),n(49998),n(33893),n(57343),t.exports=r},73897:(t,e,n)=>{var r=n(26952);t.exports=r},45089:(t,e,n)=>{var r=n(90930),i=n(9268),o=TypeError;t.exports=function(t){if(r(t))return t;throw o(i(t)+" is not a function")}},41449:(t,e,n)=>{var r=n(41956),i=n(9268),o=TypeError;t.exports=function(t){if(r(t))return t;throw o(i(t)+" is not a constructor")}},81378:(t,e,n)=>{var r=n(90930),i=String,o=TypeError;t.exports=function(t){if("object"==typeof t||r(t))return t;throw o("Can't set "+i(t)+" as a prototype")}},78669:(t,e,n)=>{var r=n(50211),i=n(44710),o=n(77826).f,a=r("unscopables"),s=Array.prototype;null==s[a]&&o(s,a,{configurable:!0,value:i(null)}),t.exports=function(t){s[a][t]=!0}},99966:(t,e,n)=>{"use strict";var r=n(83448).charAt;t.exports=function(t,e,n){return e+(n?r(t,e).length:1)}},51855:(t,e,n)=>{var r=n(95516),i=TypeError;t.exports=function(t,e){if(r(e,t))return t;throw i("Incorrect invocation")}},56112:(t,e,n)=>{var r=n(28759),i=String,o=TypeError;t.exports=function(t){if(r(t))return t;throw o(i(t)+" is not an object")}},21984:(t,e,n)=>{"use strict";var r=n(28062).forEach,i=n(72802)("forEach");t.exports=i?[].forEach:function(t){return r(this,t,arguments.length>1?arguments[1]:void 0)}},21842:(t,e,n)=>{"use strict";var r=n(18516),i=n(59413),o=n(3060),a=n(47850),s=n(92814),c=n(41956),u=n(82871),l=n(89720),f=n(73546),d=n(61667),p=Array;t.exports=function(t){var e=o(t),n=c(this),h=arguments.length,v=h>1?arguments[1]:void 0,m=void 0!==v;m&&(v=r(v,h>2?arguments[2]:void 0));var g,y,b,_,x,w,S=d(e),O=0;if(!S||this===p&&s(S))for(g=u(e),y=n?new this(g):p(g);g>O;O++)w=m?v(e[O],O):e[O],l(y,O,w);else for(x=(_=f(e,S)).next,y=n?new this:[];!(b=i(x,_)).done;O++)w=m?a(_,v,[b.value,O],!0):b.value,l(y,O,w);return y.length=O,y}},56198:(t,e,n)=>{var r=n(64088),i=n(7740),o=n(82871),a=function(t){return function(e,n,a){var s,c=r(e),u=o(c),l=i(a,u);if(t&&n!=n){for(;u>l;)if((s=c[l++])!=s)return!0}else for(;u>l;l++)if((t||l in c)&&c[l]===n)return t||l||0;return!t&&-1}};t.exports={includes:a(!0),indexOf:a(!1)}},28062:(t,e,n)=>{var r=n(18516),i=n(78240),o=n(95974),a=n(3060),s=n(82871),c=n(85574),u=i([].push),l=function(t){var e=1==t,n=2==t,i=3==t,l=4==t,f=6==t,d=7==t,p=5==t||f;return function(h,v,m,g){for(var y,b,_=a(h),x=o(_),w=r(v,m),S=s(x),O=0,A=g||c,C=e?A(h,S):n||d?A(h,0):void 0;S>O;O++)if((p||O in x)&&(b=w(y=x[O],O,_),t))if(e)C[O]=b;else if(b)switch(t){case 3:return!0;case 5:return y;case 6:return O;case 2:u(C,y)}else switch(t){case 4:return!1;case 7:u(C,y)}return f?-1:i||l?l:C}};t.exports={forEach:l(0),map:l(1),filter:l(2),some:l(3),every:l(4),find:l(5),findIndex:l(6),filterReject:l(7)}},69955:(t,e,n)=>{var r=n(63677),i=n(50211),o=n(21448),a=i("species");t.exports=function(t){return o>=51||!r((function(){var e=[];return(e.constructor={})[a]=function(){return{foo:1}},1!==e[t](Boolean).foo}))}},72802:(t,e,n)=>{"use strict";var r=n(63677);t.exports=function(t,e){var n=[][t];return!!n&&r((function(){n.call(null,e||function(){return 1},1)}))}},83329:(t,e,n)=>{var r=n(7740),i=n(82871),o=n(89720),a=Array,s=Math.max;t.exports=function(t,e,n){for(var c=i(t),u=r(e,c),l=r(void 0===n?c:n,c),f=a(s(l-u,0)),d=0;u{var r=n(78240);t.exports=r([].slice)},91147:(t,e,n)=>{var r=n(83329),i=Math.floor,o=function(t,e){var n=t.length,c=i(n/2);return n<8?a(t,e):s(t,o(r(t,0,c),e),o(r(t,c),e),e)},a=function(t,e){for(var n,r,i=t.length,o=1;o0;)t[r]=t[--r];r!==o++&&(t[r]=n)}return t},s=function(t,e,n,r){for(var i=e.length,o=n.length,a=0,s=0;a{var r=n(46526),i=n(41956),o=n(28759),a=n(50211)("species"),s=Array;t.exports=function(t){var e;return r(t)&&(e=t.constructor,(i(e)&&(e===s||r(e.prototype))||o(e)&&null===(e=e[a]))&&(e=void 0)),void 0===e?s:e}},85574:(t,e,n)=>{var r=n(18789);t.exports=function(t,e){return new(r(t))(0===e?0:e)}},47850:(t,e,n)=>{var r=n(56112),i=n(26737);t.exports=function(t,e,n,o){try{return o?e(r(n)[0],n[1]):e(n)}catch(e){i(t,"throw",e)}}},68939:(t,e,n)=>{var r=n(50211)("iterator"),i=!1;try{var o=0,a={next:function(){return{done:!!o++}},return:function(){i=!0}};a[r]=function(){return this},Array.from(a,(function(){throw 2}))}catch(t){}t.exports=function(t,e){if(!e&&!i)return!1;var n=!1;try{var o={};o[r]=function(){return{next:function(){return{done:n=!0}}}},t(o)}catch(t){}return n}},52306:(t,e,n)=>{var r=n(78240),i=r({}.toString),o=r("".slice);t.exports=function(t){return o(i(t),8,-1)}},90375:(t,e,n)=>{var r=n(12371),i=n(90930),o=n(52306),a=n(50211)("toStringTag"),s=Object,c="Arguments"==o(function(){return arguments}());t.exports=r?o:function(t){var e,n,r;return void 0===t?"Undefined":null===t?"Null":"string"==typeof(n=function(t,e){try{return t[e]}catch(t){}}(e=s(t),a))?n:c?o(e):"Object"==(r=o(e))&&i(e.callee)?"Arguments":r}},48474:(t,e,n)=>{var r=n(49606),i=n(46095),o=n(94399),a=n(77826);t.exports=function(t,e,n){for(var s=i(e),c=a.f,u=o.f,l=0;l{var r=n(63677);t.exports=!r((function(){function t(){}return t.prototype.constructor=null,Object.getPrototypeOf(new t)!==t.prototype}))},60471:(t,e,n)=>{"use strict";var r=n(13083).IteratorPrototype,i=n(44710),o=n(55736),a=n(70914),s=n(97719),c=function(){return this};t.exports=function(t,e,n,u){var l=e+" Iterator";return t.prototype=i(r,{next:o(+!u,n)}),a(t,l,!1,!0),s[l]=c,t}},72585:(t,e,n)=>{var r=n(25283),i=n(77826),o=n(55736);t.exports=r?function(t,e,n){return i.f(t,e,o(1,n))}:function(t,e,n){return t[e]=n,t}},55736:t=>{t.exports=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}}},89720:(t,e,n)=>{"use strict";var r=n(2258),i=n(77826),o=n(55736);t.exports=function(t,e,n){var a=r(e);a in t?i.f(t,a,o(0,n)):t[a]=n}},1343:(t,e,n)=>{var r=n(90930),i=n(72585),o=n(83712),a=n(79444);t.exports=function(t,e,n,s){s||(s={});var c=s.enumerable,u=void 0!==s.name?s.name:e;return r(n)&&o(n,u,s),s.global?c?t[e]=n:a(e,n):(s.unsafe?t[e]&&(c=!0):delete t[e],c?t[e]=n:i(t,e,n)),t}},79444:(t,e,n)=>{var r=n(22086),i=Object.defineProperty;t.exports=function(t,e){try{i(r,t,{value:e,configurable:!0,writable:!0})}catch(n){r[t]=e}return e}},98432:(t,e,n)=>{"use strict";var r=n(51695),i=n(59413),o=n(43296),a=n(94398),s=n(90930),c=n(60471),u=n(62130),l=n(77530),f=n(70914),d=n(72585),p=n(1343),h=n(50211),v=n(97719),m=n(13083),g=a.PROPER,y=a.CONFIGURABLE,b=m.IteratorPrototype,_=m.BUGGY_SAFARI_ITERATORS,x=h("iterator"),w="keys",S="values",O="entries",A=function(){return this};t.exports=function(t,e,n,a,h,m,C){c(n,e,a);var T,k,E,$=function(t){if(t===h&&N)return N;if(!_&&t in P)return P[t];switch(t){case w:case S:case O:return function(){return new n(this,t)}}return function(){return new n(this)}},j=e+" Iterator",I=!1,P=t.prototype,L=P[x]||P["@@iterator"]||h&&P[h],N=!_&&L||$(h),M="Array"==e&&P.entries||L;if(M&&(T=u(M.call(new t)))!==Object.prototype&&T.next&&(o||u(T)===b||(l?l(T,b):s(T[x])||p(T,x,A)),f(T,j,!0,!0),o&&(v[j]=A)),g&&h==S&&L&&L.name!==S&&(!o&&y?d(P,"name",S):(I=!0,N=function(){return i(L,this)})),h)if(k={values:$(S),keys:m?N:$(w),entries:$(O)},C)for(E in k)(_||I||!(E in P))&&p(P,E,k[E]);else r({target:e,proto:!0,forced:_||I},k);return o&&!C||P[x]===N||p(P,x,N,{name:h}),v[e]=N,k}},64145:(t,e,n)=>{var r=n(79775),i=n(49606),o=n(69251),a=n(77826).f;t.exports=function(t){var e=r.Symbol||(r.Symbol={});i(e,t)||a(e,t,{value:o.f(t)})}},58685:(t,e,n)=>{"use strict";var r=n(9268),i=TypeError;t.exports=function(t,e){if(!delete t[e])throw i("Cannot delete property "+r(e)+" of "+r(t))}},25283:(t,e,n)=>{var r=n(63677);t.exports=!r((function(){return 7!=Object.defineProperty({},1,{get:function(){return 7}})[1]}))},20821:(t,e,n)=>{var r=n(22086),i=n(28759),o=r.document,a=i(o)&&i(o.createElement);t.exports=function(t){return a?o.createElement(t):{}}},17620:t=>{var e=TypeError;t.exports=function(t){if(t>9007199254740991)throw e("Maximum allowed index exceeded");return t}},933:t=>{t.exports={CSSRuleList:0,CSSStyleDeclaration:0,CSSValueList:0,ClientRectList:0,DOMRectList:0,DOMStringList:0,DOMTokenList:1,DataTransferItemList:0,FileList:0,HTMLAllCollection:0,HTMLCollection:0,HTMLFormElement:0,HTMLSelectElement:0,MediaList:0,MimeTypeArray:0,NamedNodeMap:0,NodeList:1,PaintRequestList:0,Plugin:0,PluginArray:0,SVGLengthList:0,SVGNumberList:0,SVGPathSegList:0,SVGPointList:0,SVGStringList:0,SVGTransformList:0,SourceBufferList:0,StyleSheetList:0,TextTrackCueList:0,TextTrackList:0,TouchList:0}},73526:(t,e,n)=>{var r=n(20821)("span").classList,i=r&&r.constructor&&r.constructor.prototype;t.exports=i===Object.prototype?void 0:i},81799:(t,e,n)=>{var r=n(4999).match(/firefox\/(\d+)/i);t.exports=!!r&&+r[1]},70172:t=>{t.exports="object"==typeof window&&"object"!=typeof Deno},34172:(t,e,n)=>{var r=n(4999);t.exports=/MSIE|Trident/.test(r)},91848:(t,e,n)=>{var r=n(4999),i=n(22086);t.exports=/ipad|iphone|ipod/i.test(r)&&void 0!==i.Pebble},84344:(t,e,n)=>{var r=n(4999);t.exports=/(?:ipad|iphone|ipod).*applewebkit/i.test(r)},81801:(t,e,n)=>{var r=n(52306),i=n(22086);t.exports="process"==r(i.process)},54928:(t,e,n)=>{var r=n(4999);t.exports=/web0s(?!.*chrome)/i.test(r)},4999:(t,e,n)=>{var r=n(10563);t.exports=r("navigator","userAgent")||""},21448:(t,e,n)=>{var r,i,o=n(22086),a=n(4999),s=o.process,c=o.Deno,u=s&&s.versions||c&&c.version,l=u&&u.v8;l&&(i=(r=l.split("."))[0]>0&&r[0]<4?1:+(r[0]+r[1])),!i&&a&&(!(r=a.match(/Edge\/(\d+)/))||r[1]>=74)&&(r=a.match(/Chrome\/(\d+)/))&&(i=+r[1]),t.exports=i},49804:(t,e,n)=>{var r=n(4999).match(/AppleWebKit\/(\d+)\./);t.exports=!!r&&+r[1]},58684:t=>{t.exports=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"]},51695:(t,e,n)=>{var r=n(22086),i=n(94399).f,o=n(72585),a=n(1343),s=n(79444),c=n(48474),u=n(67189);t.exports=function(t,e){var n,l,f,d,p,h=t.target,v=t.global,m=t.stat;if(n=v?r:m?r[h]||s(h,{}):(r[h]||{}).prototype)for(l in e){if(d=e[l],f=t.dontCallGetSet?(p=i(n,l))&&p.value:n[l],!u(v?l:h+(m?".":"#")+l,t.forced)&&void 0!==f){if(typeof d==typeof f)continue;c(d,f)}(t.sham||f&&f.sham)&&o(d,"sham",!0),a(n,l,d,t)}}},63677:t=>{t.exports=function(t){try{return!!t()}catch(t){return!0}}},82331:(t,e,n)=>{"use strict";n(52077);var r=n(78240),i=n(1343),o=n(84861),a=n(63677),s=n(50211),c=n(72585),u=s("species"),l=RegExp.prototype;t.exports=function(t,e,n,f){var d=s(t),p=!a((function(){var e={};return e[d]=function(){return 7},7!=""[t](e)})),h=p&&!a((function(){var e=!1,n=/a/;return"split"===t&&((n={}).constructor={},n.constructor[u]=function(){return n},n.flags="",n[d]=/./[d]),n.exec=function(){return e=!0,null},n[d](""),!e}));if(!p||!h||n){var v=r(/./[d]),m=e(d,""[t],(function(t,e,n,i,a){var s=r(t),c=e.exec;return c===o||c===l.exec?p&&!a?{done:!0,value:v(e,n,i)}:{done:!0,value:s(n,e,i)}:{done:!1}}));i(String.prototype,t,m[0]),i(l,d,m[1])}f&&c(l[d],"sham",!0)}},67258:(t,e,n)=>{var r=n(86059),i=Function.prototype,o=i.apply,a=i.call;t.exports="object"==typeof Reflect&&Reflect.apply||(r?a.bind(o):function(){return a.apply(o,arguments)})},18516:(t,e,n)=>{var r=n(78240),i=n(45089),o=n(86059),a=r(r.bind);t.exports=function(t,e){return i(t),void 0===e?t:o?a(t,e):function(){return t.apply(e,arguments)}}},86059:(t,e,n)=>{var r=n(63677);t.exports=!r((function(){var t=function(){}.bind();return"function"!=typeof t||t.hasOwnProperty("prototype")}))},59413:(t,e,n)=>{var r=n(86059),i=Function.prototype.call;t.exports=r?i.bind(i):function(){return i.apply(i,arguments)}},94398:(t,e,n)=>{var r=n(25283),i=n(49606),o=Function.prototype,a=r&&Object.getOwnPropertyDescriptor,s=i(o,"name"),c=s&&"something"===function(){}.name,u=s&&(!r||r&&a(o,"name").configurable);t.exports={EXISTS:s,PROPER:c,CONFIGURABLE:u}},78240:(t,e,n)=>{var r=n(86059),i=Function.prototype,o=i.bind,a=i.call,s=r&&o.bind(a,a);t.exports=r?function(t){return t&&s(t)}:function(t){return t&&function(){return a.apply(t,arguments)}}},10563:(t,e,n)=>{var r=n(22086),i=n(90930),o=function(t){return i(t)?t:void 0};t.exports=function(t,e){return arguments.length<2?o(r[t]):r[t]&&r[t][e]}},61667:(t,e,n)=>{var r=n(90375),i=n(2964),o=n(97719),a=n(50211)("iterator");t.exports=function(t){if(null!=t)return i(t,a)||i(t,"@@iterator")||o[r(t)]}},73546:(t,e,n)=>{var r=n(59413),i=n(45089),o=n(56112),a=n(9268),s=n(61667),c=TypeError;t.exports=function(t,e){var n=arguments.length<2?s(t):e;if(i(n))return o(r(n,t));throw c(a(t)+" is not iterable")}},2964:(t,e,n)=>{var r=n(45089);t.exports=function(t,e){var n=t[e];return null==n?void 0:r(n)}},18509:(t,e,n)=>{var r=n(78240),i=n(3060),o=Math.floor,a=r("".charAt),s=r("".replace),c=r("".slice),u=/\$([$&'`]|\d{1,2}|<[^>]*>)/g,l=/\$([$&'`]|\d{1,2})/g;t.exports=function(t,e,n,r,f,d){var p=n+t.length,h=r.length,v=l;return void 0!==f&&(f=i(f),v=u),s(d,v,(function(i,s){var u;switch(a(s,0)){case"$":return"$";case"&":return t;case"`":return c(e,0,n);case"'":return c(e,p);case"<":u=f[c(s,1,-1)];break;default:var l=+s;if(0===l)return i;if(l>h){var d=o(l/10);return 0===d?i:d<=h?void 0===r[d-1]?a(s,1):r[d-1]+a(s,1):i}u=r[l-1]}return void 0===u?"":u}))}},22086:(t,e,n)=>{var r=function(t){return t&&t.Math==Math&&t};t.exports=r("object"==typeof globalThis&&globalThis)||r("object"==typeof window&&window)||r("object"==typeof self&&self)||r("object"==typeof n.g&&n.g)||function(){return this}()||Function("return this")()},49606:(t,e,n)=>{var r=n(78240),i=n(3060),o=r({}.hasOwnProperty);t.exports=Object.hasOwn||function(t,e){return o(i(t),e)}},7153:t=>{t.exports={}},71670:(t,e,n)=>{var r=n(22086);t.exports=function(t,e){var n=r.console;n&&n.error&&(1==arguments.length?n.error(t):n.error(t,e))}},25963:(t,e,n)=>{var r=n(10563);t.exports=r("document","documentElement")},26761:(t,e,n)=>{var r=n(25283),i=n(63677),o=n(20821);t.exports=!r&&!i((function(){return 7!=Object.defineProperty(o("div"),"a",{get:function(){return 7}}).a}))},95974:(t,e,n)=>{var r=n(78240),i=n(63677),o=n(52306),a=Object,s=r("".split);t.exports=i((function(){return!a("z").propertyIsEnumerable(0)}))?function(t){return"String"==o(t)?s(t,""):a(t)}:a},15070:(t,e,n)=>{var r=n(90930),i=n(28759),o=n(77530);t.exports=function(t,e,n){var a,s;return o&&r(a=e.constructor)&&a!==n&&i(s=a.prototype)&&s!==n.prototype&&o(t,s),t}},39277:(t,e,n)=>{var r=n(78240),i=n(90930),o=n(74489),a=r(Function.toString);i(o.inspectSource)||(o.inspectSource=function(t){return a(t)}),t.exports=o.inspectSource},83278:(t,e,n)=>{var r,i,o,a=n(9316),s=n(22086),c=n(78240),u=n(28759),l=n(72585),f=n(49606),d=n(74489),p=n(88944),h=n(7153),v="Object already initialized",m=s.TypeError,g=s.WeakMap;if(a||d.state){var y=d.state||(d.state=new g),b=c(y.get),_=c(y.has),x=c(y.set);r=function(t,e){if(_(y,t))throw new m(v);return e.facade=t,x(y,t,e),e},i=function(t){return b(y,t)||{}},o=function(t){return _(y,t)}}else{var w=p("state");h[w]=!0,r=function(t,e){if(f(t,w))throw new m(v);return e.facade=t,l(t,w,e),e},i=function(t){return f(t,w)?t[w]:{}},o=function(t){return f(t,w)}}t.exports={set:r,get:i,has:o,enforce:function(t){return o(t)?i(t):r(t,{})},getterFor:function(t){return function(e){var n;if(!u(e)||(n=i(e)).type!==t)throw m("Incompatible receiver, "+t+" required");return n}}}},92814:(t,e,n)=>{var r=n(50211),i=n(97719),o=r("iterator"),a=Array.prototype;t.exports=function(t){return void 0!==t&&(i.Array===t||a[o]===t)}},46526:(t,e,n)=>{var r=n(52306);t.exports=Array.isArray||function(t){return"Array"==r(t)}},90930:t=>{t.exports=function(t){return"function"==typeof t}},41956:(t,e,n)=>{var r=n(78240),i=n(63677),o=n(90930),a=n(90375),s=n(10563),c=n(39277),u=function(){},l=[],f=s("Reflect","construct"),d=/^\s*(?:class|function)\b/,p=r(d.exec),h=!d.exec(u),v=function(t){if(!o(t))return!1;try{return f(u,l,t),!0}catch(t){return!1}},m=function(t){if(!o(t))return!1;switch(a(t)){case"AsyncFunction":case"GeneratorFunction":case"AsyncGeneratorFunction":return!1}try{return h||!!p(d,c(t))}catch(t){return!0}};m.sham=!0,t.exports=!f||i((function(){var t;return v(v.call)||!v(Object)||!v((function(){t=!0}))||t}))?m:v},67189:(t,e,n)=>{var r=n(63677),i=n(90930),o=/#|\.prototype\./,a=function(t,e){var n=c[s(t)];return n==l||n!=u&&(i(e)?r(e):!!e)},s=a.normalize=function(t){return String(t).replace(o,".").toLowerCase()},c=a.data={},u=a.NATIVE="N",l=a.POLYFILL="P";t.exports=a},99517:(t,e,n)=>{var r=n(90375),i=n(49606),o=n(50211),a=n(97719),s=o("iterator"),c=Object;t.exports=function(t){var e=c(t);return void 0!==e[s]||"@@iterator"in e||i(a,r(e))}},28759:(t,e,n)=>{var r=n(90930);t.exports=function(t){return"object"==typeof t?null!==t:r(t)}},43296:t=>{t.exports=!1},67994:(t,e,n)=>{var r=n(28759),i=n(52306),o=n(50211)("match");t.exports=function(t){var e;return r(t)&&(void 0!==(e=t[o])?!!e:"RegExp"==i(t))}},92071:(t,e,n)=>{var r=n(10563),i=n(90930),o=n(95516),a=n(91876),s=Object;t.exports=a?function(t){return"symbol"==typeof t}:function(t){var e=r("Symbol");return i(e)&&o(e.prototype,s(t))}},94722:(t,e,n)=>{var r=n(18516),i=n(59413),o=n(56112),a=n(9268),s=n(92814),c=n(82871),u=n(95516),l=n(73546),f=n(61667),d=n(26737),p=TypeError,h=function(t,e){this.stopped=t,this.result=e},v=h.prototype;t.exports=function(t,e,n){var m,g,y,b,_,x,w,S=n&&n.that,O=!(!n||!n.AS_ENTRIES),A=!(!n||!n.IS_ITERATOR),C=!(!n||!n.INTERRUPTED),T=r(e,S),k=function(t){return m&&d(m,"normal",t),new h(!0,t)},E=function(t){return O?(o(t),C?T(t[0],t[1],k):T(t[0],t[1])):C?T(t,k):T(t)};if(A)m=t;else{if(!(g=f(t)))throw p(a(t)+" is not iterable");if(s(g)){for(y=0,b=c(t);b>y;y++)if((_=E(t[y]))&&u(v,_))return _;return new h(!1)}m=l(t,g)}for(x=m.next;!(w=i(x,m)).done;){try{_=E(w.value)}catch(t){d(m,"throw",t)}if("object"==typeof _&&_&&u(v,_))return _}return new h(!1)}},26737:(t,e,n)=>{var r=n(59413),i=n(56112),o=n(2964);t.exports=function(t,e,n){var a,s;i(t);try{if(!(a=o(t,"return"))){if("throw"===e)throw n;return n}a=r(a,t)}catch(t){s=!0,a=t}if("throw"===e)throw n;if(s)throw a;return i(a),n}},13083:(t,e,n)=>{"use strict";var r,i,o,a=n(63677),s=n(90930),c=n(44710),u=n(62130),l=n(1343),f=n(50211),d=n(43296),p=f("iterator"),h=!1;[].keys&&("next"in(o=[].keys())?(i=u(u(o)))!==Object.prototype&&(r=i):h=!0),null==r||a((function(){var t={};return r[p].call(t)!==t}))?r={}:d&&(r=c(r)),s(r[p])||l(r,p,(function(){return this})),t.exports={IteratorPrototype:r,BUGGY_SAFARI_ITERATORS:h}},97719:t=>{t.exports={}},82871:(t,e,n)=>{var r=n(24005);t.exports=function(t){return r(t.length)}},83712:(t,e,n)=>{var r=n(63677),i=n(90930),o=n(49606),a=n(25283),s=n(94398).CONFIGURABLE,c=n(39277),u=n(83278),l=u.enforce,f=u.get,d=Object.defineProperty,p=a&&!r((function(){return 8!==d((function(){}),"length",{value:8}).length})),h=String(String).split("String"),v=t.exports=function(t,e,n){"Symbol("===String(e).slice(0,7)&&(e="["+String(e).replace(/^Symbol\(([^)]*)\)/,"$1")+"]"),n&&n.getter&&(e="get "+e),n&&n.setter&&(e="set "+e),(!o(t,"name")||s&&t.name!==e)&&d(t,"name",{value:e,configurable:!0}),p&&n&&o(n,"arity")&&t.length!==n.arity&&d(t,"length",{value:n.arity});try{n&&o(n,"constructor")&&n.constructor?a&&d(t,"prototype",{writable:!1}):t.prototype&&(t.prototype=void 0)}catch(t){}var r=l(t);return o(r,"source")||(r.source=h.join("string"==typeof e?e:"")),t};Function.prototype.toString=v((function(){return i(this)&&f(this).source||c(this)}),"toString")},55681:t=>{var e=Math.ceil,n=Math.floor;t.exports=Math.trunc||function(t){var r=+t;return(r>0?n:e)(r)}},43173:(t,e,n)=>{var r,i,o,a,s,c,u,l,f=n(22086),d=n(18516),p=n(94399).f,h=n(84953).set,v=n(84344),m=n(91848),g=n(54928),y=n(81801),b=f.MutationObserver||f.WebKitMutationObserver,_=f.document,x=f.process,w=f.Promise,S=p(f,"queueMicrotask"),O=S&&S.value;O||(r=function(){var t,e;for(y&&(t=x.domain)&&t.exit();i;){e=i.fn,i=i.next;try{e()}catch(t){throw i?a():o=void 0,t}}o=void 0,t&&t.enter()},v||y||g||!b||!_?!m&&w&&w.resolve?((u=w.resolve(void 0)).constructor=w,l=d(u.then,u),a=function(){l(r)}):y?a=function(){x.nextTick(r)}:(h=d(h,f),a=function(){h(r)}):(s=!0,c=_.createTextNode(""),new b(r).observe(c,{characterData:!0}),a=function(){c.data=s=!s})),t.exports=O||function(t){var e={fn:t,next:void 0};o&&(o.next=e),i||(i=e,a()),o=e}},3441:(t,e,n)=>{var r=n(73193);t.exports=r&&!!Symbol.for&&!!Symbol.keyFor},73193:(t,e,n)=>{var r=n(21448),i=n(63677);t.exports=!!Object.getOwnPropertySymbols&&!i((function(){var t=Symbol();return!String(t)||!(Object(t)instanceof Symbol)||!Symbol.sham&&r&&r<41}))},9316:(t,e,n)=>{var r=n(22086),i=n(90930),o=n(39277),a=r.WeakMap;t.exports=i(a)&&/native code/.test(o(a))},98722:(t,e,n)=>{"use strict";var r=n(45089),i=function(t){var e,n;this.promise=new t((function(t,r){if(void 0!==e||void 0!==n)throw TypeError("Bad Promise constructor");e=t,n=r})),this.resolve=r(e),this.reject=r(n)};t.exports.f=function(t){return new i(t)}},88675:(t,e,n)=>{"use strict";var r=n(25283),i=n(78240),o=n(59413),a=n(63677),s=n(68779),c=n(66952),u=n(7446),l=n(3060),f=n(95974),d=Object.assign,p=Object.defineProperty,h=i([].concat);t.exports=!d||a((function(){if(r&&1!==d({b:1},d(p({},"a",{enumerable:!0,get:function(){p(this,"b",{value:3,enumerable:!1})}}),{b:2})).b)return!0;var t={},e={},n=Symbol(),i="abcdefghijklmnopqrst";return t[n]=7,i.split("").forEach((function(t){e[t]=t})),7!=d({},t)[n]||s(d({},e)).join("")!=i}))?function(t,e){for(var n=l(t),i=arguments.length,a=1,d=c.f,p=u.f;i>a;)for(var v,m=f(arguments[a++]),g=d?h(s(m),d(m)):s(m),y=g.length,b=0;y>b;)v=g[b++],r&&!o(p,m,v)||(n[v]=m[v]);return n}:d},44710:(t,e,n)=>{var r,i=n(56112),o=n(77711),a=n(58684),s=n(7153),c=n(25963),u=n(20821),l=n(88944),f=l("IE_PROTO"),d=function(){},p=function(t){return"块元素水平居中【宽度自适应】 fasfa块元素水平居中【宽度固定】块元素垂直居中方法:全兼容(position:内部块元素宽高必须确定,全浏览器兼容)!!!!!块元素垂直居中方法:ie8+(vertical-align+inline-block内部块元素高度可以不确定但with必须确定,低版本浏览器不兼容:ie8+)!!!!!!块元素垂直居中方法:ie9+(flex:内部块元素宽高可以不确定,低版本浏览器不兼容:ie9+)flex自适应float+margin左右宽度全部自适应:float+BFCfloat+BFC左侧宽度固定,右侧自适应:float+marginfloat+marginabsolute+margin-left左侧宽度固定,右侧自适应float+margin两侧absolute,中间用margin左侧右侧中间固定两边自适应左右float右侧中间固定两边自适应