Compare commits

..

500 Commits

Author SHA1 Message Date
caishi 00402ef13d Merge branch 'master' of https://git.trustie.net/jasder/forgeplus-react
# Conflicts:
#	src/forge/Main/sub/UpdateDescModal.jsx
2021-08-09 10:37:23 +08:00
caishi 8f2df90555 代码style 2021-08-09 10:36:15 +08:00
caishi 7530d3f9c4 Merge branch 'develop' 2021-08-06 17:07:54 +08:00
caishi 001cb8da53 issue 2021-08-06 15:06:23 +08:00
caishi d09e6e2bc6 issue 2021-08-06 14:07:59 +08:00
caishi e2ad3b1308 issue-同步镜像项目不能对仓库进行操作(新建合并请求、新建发行版等) 2021-08-05 17:13:57 +08:00
caishi 14f80d56ad Merge branch 'develop' of https://git.trustie.net/jasder/forgeplus-react into develop 2021-08-05 11:12:11 +08:00
caishi 65e7025035 Merge branch 'develop' of https://git.trustie.net/jasder/forgeplus-react into develop
# Conflicts:
#	src/forge/Main/sub/UpdateDescModal.jsx
2021-08-05 11:11:51 +08:00
hc1913847458 aa786f0cf0 限制字符 2021-08-05 10:57:43 +08:00
hc1913847458 2aad9c67f5 限制字符 2021-08-05 10:53:29 +08:00
hc1913847458 b7869e5203 Merge branch 'develop' of https://git.trustie.net/jasder/forgeplus-react 2021-08-05 10:48:43 +08:00
hc1913847458 b238bb51ca 限制字符 2021-08-05 10:47:22 +08:00
hc1913847458 de636eed6d 限制字符 2021-08-05 10:42:08 +08:00
caishi 4bde5da97c markdown-issue 2021-08-05 10:30:04 +08:00
caishi f944ebad6f issue 2021-08-04 17:12:29 +08:00
hc1913847458 ad7ab189b1 限制字符 2021-08-04 14:42:08 +08:00
caishi 5140bfbe77 issue修改 2021-08-03 17:37:14 +08:00
caishi affbe87dfd 新增流水线弹框z-index 2021-08-03 10:38:39 +08:00
caishi dd1beb3116 合并请求-已拒绝的不能编辑 2021-08-03 09:34:11 +08:00
caishi d67862156c update issue 2021-08-02 15:32:51 +08:00
caishi c9802c26a4 Merge branch 'develop' 2021-08-02 10:35:49 +08:00
caishi 47365c0bed webhook-修改一版 2021-08-02 10:35:36 +08:00
caishi 4ec840f252 Merge branch 'develop' 2021-07-30 20:13:49 +08:00
caishi b1ec068663 webhook自动填充 2021-07-30 20:13:34 +08:00
caishi 44a8f806e0 Merge branch 'develop' 2021-07-30 17:44:17 +08:00
caishi 51d34a7667 同上-password-webhook 2021-07-30 17:35:53 +08:00
caishi 9408ad7dcb Merge branch 'develop' 2021-07-30 17:03:19 +08:00
caishi 2b47c1ff9a 同上-修改bug 2021-07-30 17:02:44 +08:00
caishi f7698334ab webhook上线测试版-1 2021-07-30 15:06:32 +08:00
caishi 810ea37bed Merge branch 'develop' 2021-07-26 09:38:44 +08:00
caishi f100875b0f ssh翻页 2021-07-26 09:38:21 +08:00
caishi 6679fe8a48 Merge branch 'develop' 2021-07-22 17:44:30 +08:00
caishi 4f9f5649a9 设置模块-测试版第一版 2021-07-22 17:44:12 +08:00
caishi d31b932efe Merge branch 'develop' 2021-07-21 10:10:53 +08:00
caishi f90243243f 新建项目跳转后的地址 2021-07-21 10:09:48 +08:00
caishi 7a5db58a03 appconfig 2021-07-15 14:46:22 +08:00
caishi 0889ee69c5 未登录时:路由/不显示顶部和底部 2021-07-13 10:42:56 +08:00
caishi 876ee66a05 详情:复刻按钮不能连续点击 2021-07-13 09:58:08 +08:00
caishi cb514315a6 新建合并请求:切换目标分支或者源分支时不用调用check_can_merge接口 2021-07-12 18:22:36 +08:00
caishi c5b729038c 邀请码位置,页面整体的加载 2021-07-09 17:10:55 +08:00
caishi a6d713d1f6 代码库:增加文件类型submodule 不允许点击 2021-07-09 11:28:51 +08:00
caishi ee1217e171 本地版:replaceAll无替换时报错 2021-07-09 11:05:19 +08:00
caishi 967ff385aa 代码库根目录:点击readme文件的编辑按钮时要显示编辑状态 2021-07-07 11:16:07 +08:00
caishi e6e0546e27 permission有为空的情况 2021-07-06 14:40:23 +08:00
caishi 1bb339bfb1 新建:拥有者默认选中当前登录用户,默认路由 2021-07-06 11:54:57 +08:00
caishi 07852b204c Merge branch 'develop' 2021-07-05 20:35:59 +08:00
caishi 275b7d2015 数据为0时不显示 2021-07-05 20:35:29 +08:00
caishi 9e9e4c07bf 合并请求详情:发布合并请求者跳转链接错误 2021-07-05 15:04:17 +08:00
caishi 934ac61b77 Merge branch 'develop' 2021-07-02 18:19:02 +08:00
caishi f854d2164c 工作流-构建列表-头像地址错误 2021-07-02 18:18:49 +08:00
caishi 95091d0e08 Merge branch 'develop' 2021-07-02 15:37:43 +08:00
caishi e48628389e 镜像地址增加跳转链接 2021-07-02 15:35:43 +08:00
caishi e31ff9bdf3 Merge branch 'develop' 2021-07-01 17:00:43 +08:00
caishi 62b9abedbb index.html lang="zh-cN"禁止浏览器翻译 2021-07-01 16:45:47 +08:00
caishi f97ca92e41 update 2021-07-01 15:48:04 +08:00
caishi 84bbf5fd52 易修批量修改:非项目协作者不能操作 2021-07-01 13:56:09 +08:00
caishi ff60cf11e1 update issue 2021-06-30 10:43:22 +08:00
caishi 45f188e6f4 fork项目不能修改可见性(公有私有) 2021-06-29 17:29:35 +08:00
caishi 4b832f40c0 项目详情:顶部信息排版调整,修改显示bug 2021-06-29 14:03:53 +08:00
caishi eba6ed0876 搜索的接口改用正式版对应的服务器地址 2021-06-28 10:44:42 +08:00
caishi db682ace86 Merge branch 'develop' 2021-06-25 18:34:19 +08:00
caishi 1cdf316852 合并请求:冲突文件的显示换行 2021-06-25 18:33:54 +08:00
caishi 777dbd0f43 Merge branch 'develop' 2021-06-25 18:21:48 +08:00
caishi 79996bd185 权限:易修和合并请求的新建修改等操作权限 2021-06-25 18:21:31 +08:00
caishi 2d312b6176 路由:tree后面的参数branch内容含有/ 2021-06-25 14:10:13 +08:00
caishi b44b6530e5 Merge branch 'develop' 2021-06-25 09:14:50 +08:00
caishi bad4f79a0c 易修:批量删除和批量修改issue状态要更新数量 2021-06-22 10:22:00 +08:00
caishi fad42414dc 代码库:提交信息的显示和隐藏 2021-06-21 17:52:48 +08:00
caishi c10799b6d0 Merge branch 'develop_search' into develop 2021-06-21 10:00:35 +08:00
caishi b808bcee99 Merge branch 'develop' 2021-06-18 16:56:18 +08:00
caishi cb95e50a82 代码库:从文件详情切换到文件列表时,上传文件和新建文件的按钮没有显示 2021-06-18 16:55:52 +08:00
caishi 5eaebd4e42 上传文件显示: ADD file via upload
创建新文件显示: Add 文件名
修改文件: Update 文件名
2021-06-18 14:23:46 +08:00
caishi e9badf0d7c 合并请求默认选中开启中的 2021-06-18 09:59:33 +08:00
caishi e72e817bb1 复刻自,如果是组织要跳转到组织界面 2021-06-17 16:28:27 +08:00
caishi b5835145f7 个人中心性别icon不显示 2021-06-17 11:38:53 +08:00
caishi d4e1b2f414 详情banner数量,显示开启中的数量,且执行关闭或者拒绝等修改状态的操作时要更新数量 2021-06-16 15:51:47 +08:00
caishi f4b3afde6a 项目详情和个人中心的项目列表,增加私有标识 2021-06-16 11:17:46 +08:00
caishi 5806f60491 右侧按钮-帮助弹框 2021-06-16 09:17:33 +08:00
caishi 8298aef72f forked from 文案 2021-06-15 11:36:42 +08:00
caishi 7ed8d1c8c3 合并全局搜索 2021-06-15 09:21:56 +08:00
何童崇 1d274985ca 解决冲突并提交 2021-06-11 19:03:17 +08:00
caishi c0f7c489fb Merge branch 'develop' 2021-06-11 18:11:43 +08:00
何童崇 71d1eb57cc 还原代理的配置 2021-06-11 17:51:54 +08:00
caishi 56434a9714 Merge branch 'draft' into develop 2021-06-11 17:21:27 +08:00
caishi 8b161630c3 添加成员--随便输入不存在的用户时的提示 2021-06-11 16:46:59 +08:00
何童崇 405053696c 修改头部搜索框高度和代理服务路径 2021-06-11 15:28:40 +08:00
caishi 3dffbce8d9 头部导航栏-搜索小改 2021-06-11 11:01:46 +08:00
caishi 63e9cfe394 项目邀请码-第一版测试版上线 2021-06-11 09:25:59 +08:00
何童崇 b38cdd4bb3 修改search校验,同页搜索问题 2021-06-10 17:05:49 +08:00
何童崇 681d0b17e3 修改搜索的功能及图标 2021-06-09 19:47:14 +08:00
caishi b5fa231adf 小修 2021-06-09 18:00:31 +08:00
caishi 39f0a165b6 issue 2021-06-09 18:00:09 +08:00
caishi 2157f2ffe5 merge 2021-06-09 18:00:06 +08:00
caishi 7c40f9be36 merge 冲突 2021-06-09 17:59:07 +08:00
caishi 93694594c4 冲突 2021-06-09 17:58:11 +08:00
caishi 32299252ad 详情+邀请码的显示 2021-06-09 17:37:04 +08:00
caishi a12ab04ec0 小修 2021-06-09 11:52:36 +08:00
何童崇 f93df6069c 修改搜索placeplaceholder 2021-06-08 16:08:58 +08:00
何童崇 ff2586f5b9 注释众包/帖子等tab 2021-06-08 16:05:32 +08:00
caishi b7613584f9 添加成员后要清除选中的成员 2021-06-08 15:09:52 +08:00
caishi bc64cbb415 Merge branch 'develop' 2021-06-08 14:56:20 +08:00
caishi 0b7d6ab5fd issue 2021-06-08 14:56:00 +08:00
caishi 3d764d3075 issue+新建组织-未登录没有弹出登录框 2021-06-08 10:44:44 +08:00
caishi 3cd51d1c72 修改-个人主页 2021-06-07 11:13:38 +08:00
caishi 40f8f5d872 数据统计三个时间筛选参数值必须是时间戳 2021-06-04 14:29:55 +08:00
caishi e185ae6484 同上+样式 2021-06-04 13:58:42 +08:00
caishi 0bfa7572a5 bug 2021-06-04 10:55:05 +08:00
caishi fd19a43168 修改资料+密码管理 2021-06-04 09:43:38 +08:00
何童崇 dd9c11dbd9 上传搜索的页面 2021-06-03 10:37:03 +08:00
何童崇 695d5e4f50 Merge remote-tracking branch 'upstream/develop' into dev-search 2021-06-03 10:01:51 +08:00
何童崇 b88c5b1faf 修改导航的搜索 2021-06-03 10:00:24 +08:00
caishi 975d49b80b 同上=issue修改 2021-06-02 18:22:29 +08:00
caishi 4b6592dfb3 同上-修改细节 2021-05-31 18:39:30 +08:00
caishi 1432afebfd 个人中心整体上线 2021-05-31 17:44:30 +08:00
caishi a9285f37e7 概览页数据绑定完成,只差数据统计页 2021-05-31 09:48:30 +08:00
caishi d41dce26b1 year 2021-05-28 17:02:54 +08:00
caishi 7bbda5f65d 概览+用户画像 2021-05-28 16:19:40 +08:00
caishi fa169b27cd Merge branch 'develop' 2021-05-26 16:48:35 +08:00
caishi 0274cf84ee 上一版+update 2021-05-26 16:48:18 +08:00
caishi 8e419e63da 上一版-update 2021-05-26 16:00:55 +08:00
caishi 1378ba5c93 代码库-无默认分支时调用entries接口未传ref参数,+个人主页的三个echart 2021-05-26 15:25:21 +08:00
caishi 3e0814344f Merge branch 'develop' 2021-05-25 11:25:04 +08:00
caishi ae9b48953e markdown定位问题 2021-05-25 10:05:14 +08:00
caishi eb58f91dbf Merge branch 'develop' 2021-05-21 19:21:32 +08:00
caishi 3453aa31eb readme下拉 2021-05-21 19:21:16 +08:00
caishi ebf75ed433 issue 2021-05-21 18:58:17 +08:00
caishi a1bd41795a 分享功能(仅微信)+ 合并请求增加状态的显示,合并请求详情增加(冲突情况下的提示) 2021-05-21 16:44:40 +08:00
caishi 513255428c Merge branch 'develop'
# Conflicts:
#	package-lock.json
2021-05-14 17:04:57 +08:00
caishi 09bf75c6c3 右侧按钮-帮助列表超出没有隐藏 2021-05-14 17:03:27 +08:00
caishi 70af7dae5f 右侧按钮-帮助和返回顶部 2021-05-14 14:37:59 +08:00
caishi d029840874 头部导航栏无logo是nav也要显示 2021-05-14 11:30:08 +08:00
caishi 303e06586e 新增icon+添加右侧的返回顶部等按钮(接口没有,先隐藏、需要合并到其它分支,上一个提交也一样) 2021-05-14 09:32:23 +08:00
caishi 7ccc1221ef style 2021-05-11 14:22:01 +08:00
caishi 6a6f0ca784 组件之间进行页面跳转时,滚动条未返回至顶部 2021-05-10 17:24:49 +08:00
caishi b70dd5928e details 2021-05-10 11:34:30 +08:00
caishi 8baf2cb49c install babel-polyfill 2021-05-08 17:28:14 +08:00
caishi 705bfb07bd Merge branch 'develop' 2021-05-08 16:53:26 +08:00
caishi 202081bbeb 样式 2021-05-08 16:53:16 +08:00
caishi d783d998fc 编辑合并请求-url地址错误 2021-05-08 14:36:12 +08:00
caishi af8872176c 编辑合并请求-url地址错误 2021-05-08 14:24:02 +08:00
caishi 037a79de67 detail+同步镜像type=2的才不需要合并请求 2021-05-07 17:33:41 +08:00
caishi 51925542b8 Merge branch 'develop'
# Conflicts:
#	public/css/edu-purge.css
2021-05-07 16:37:21 +08:00
caishi a408d435f3 统一项目简介、项目概览 2021-05-07 16:26:50 +08:00
caishi 016f7f1a7e 去掉Markdown代码块的间隔色、编号等+issue 2021-05-07 16:00:57 +08:00
caishi ff06efe109 merge develop 2021-05-06 17:15:43 +08:00
caishi c33561c212 新建项目-maxlength 2021-05-06 17:14:42 +08:00
caishi 2deb6f8f9d 设置所有标签的marginbottom为0 2021-05-06 17:14:30 +08:00
caishi 63d69a955e 代码库-提交描述未换行 2021-05-06 17:14:19 +08:00
caishi e7eceb5b23 issue-字符限制 2021-05-06 17:12:42 +08:00
caishi c28ae9adb3 Revert "设置所有标签的marginbottom为0"
This reverts commit 227b686046.
2021-05-06 15:15:02 +08:00
caishi 870fbaa2a9 新建项目-maxlength 2021-05-06 14:59:54 +08:00
caishi 227b686046 设置所有标签的marginbottom为0 2021-05-06 10:56:09 +08:00
caishi 582f7a39b3 代码库-提交描述未换行 2021-05-06 10:14:06 +08:00
caishi ac4b7542e2 撤销隐藏-资源库 2021-04-28 20:22:54 +08:00
caishi 3a3a0251aa Merge branch 'undo' into develop
# Conflicts:
#	src/forge/Component/SearchUser.jsx
2021-04-28 20:17:59 +08:00
caishi 2fcb645d42 04-28休假期修改issue --需合并至其它分支(合并请求相关) 2021-04-28 20:17:30 +08:00
caishi 93a53e2c7f 转移项目-bug 2021-04-27 18:44:40 +08:00
caishi 79d8f4e5ad 清空弹窗里的内容 2021-04-27 18:27:56 +08:00
caishi ae34240bfb 通知-跳转 2021-04-27 17:46:05 +08:00
caishi 4d652d238d 不能修改组织账号 2021-04-27 17:25:00 +08:00
caishi efaf0c29b5 不能修改组织账号 2021-04-27 17:24:48 +08:00
caishi 81ad2358f5 不能修改组织账号 2021-04-27 17:23:58 +08:00
caishi 605d5a047d merge undo 2021-04-27 17:15:07 +08:00
caishi 1474f5d3fe 转移项目-bug和修改需求 2021-04-27 17:12:00 +08:00
caishi 8d509f1473 组织地址、website的问题,可合并至develop 2021-04-27 17:11:37 +08:00
caishi 4ba63fd8fa 项目转移-转移权限 2021-04-27 13:50:05 +08:00
caishi e10f9893e0 组织团队-无数据显示错误 2021-04-27 09:46:39 +08:00
caishi 63d7045444 组织团队-无数据显示错误 2021-04-27 09:46:29 +08:00
caishi 6da4dbc165 组织团队-无数据显示错误 2021-04-27 09:45:14 +08:00
caishi c0ddd6eaee 组织-项目列表显示name 2021-04-26 17:20:54 +08:00
caishi f65f4c273a 组织基本设置-正则和新建的页面不一致 2021-04-26 16:32:12 +08:00
caishi 0cdb491433 组织基本设置-正则和新建的页面不一致 2021-04-26 16:32:03 +08:00
caishi ac47ba1b29 组织基本设置-正则和新建的页面不一致 2021-04-26 16:31:26 +08:00
caishi 2bd6f9cb1e 组织-新增地址和网址的显示 2021-04-26 16:17:21 +08:00
caishi 0636e0a925 转移项目-修改1 2021-04-26 16:17:04 +08:00
caishi 631b05dfd6 代码库编辑文件-切换到其它目录后要重新将编辑状态改为显示状态 2021-04-26 15:00:31 +08:00
caishi 4e48b0b363 项目转移--整体数据绑定 2021-04-26 14:59:19 +08:00
caishi 1af504825c 代码库编辑文件-切换到其它目录后要重新将编辑状态改为显示状态 2021-04-25 18:00:05 +08:00
caishi fb41baacc1 代码库编辑文件-切换到其它目录后要重新将编辑状态改为显示状态 2021-04-25 17:46:38 +08:00
caishi 09065383c1 转移项目-前端页面已画完 2021-04-25 17:38:47 +08:00
caishi e94cf68cc5 样式覆盖 2021-04-23 18:04:49 +08:00
caishi c32e215b27 样式覆盖 2021-04-23 18:04:07 +08:00
caishi 5fa2fd99b9 Merge branch 'develop' 2021-04-23 14:51:04 +08:00
caishi 2f6597355c +上 关注后不需要提示 2021-04-23 14:50:52 +08:00
caishi 20ab8a6683 Merge branch 'develop' 2021-04-23 14:47:50 +08:00
caishi 1eb3c20af4 +上 贡献者悬浮框里增加的跳转链接不要新开页 2021-04-23 14:47:32 +08:00
caishi afb599f5be 贡献者-悬浮内容增加跳转链接 2021-04-23 14:46:11 +08:00
caishi a7f709a663 Merge branch 'develop' 2021-04-23 14:16:30 +08:00
caishi d6d6df806d imageUrl + / 2021-04-23 14:14:06 +08:00
caishi 6cc97bd039 个人中心关注-关注或者取消关注未更新状态 2021-04-23 11:49:56 +08:00
caishi 037150a63c 贡献者-悬浮卡片-测试版1 2021-04-23 11:15:14 +08:00
caishi 63c2cfed70 Merge branch 'develop' 2021-04-22 10:58:30 +08:00
caishi 52dc63362b 发布评论者头像路径错误 2021-04-22 10:58:11 +08:00
caishi 29e3f0d59d 新建组织-组织账号正则 2021-04-21 16:55:10 +08:00
caishi 233e6a8226 底部样式+新建组织账号正则 2021-04-21 16:54:47 +08:00
caishi 80cd6fbae0 md文件要用Markdown渲染 2021-04-20 15:33:21 +08:00
caishi 8fa31edaae md文件要用Markdown渲染 2021-04-20 15:31:49 +08:00
caishi 49d3db6746 合并请求-提出申请者头像显示问题 2021-04-20 11:18:44 +08:00
caishi ffbb5ba34e 合并请求-提出申请者头像显示问题 2021-04-20 11:17:54 +08:00
caishi bc11ec68e3 注释 2021-04-20 10:57:46 +08:00
caishi 2d2deec224 Merge branch 'develop' 2021-04-20 10:56:50 +08:00
caishi a67cabbfb4 团队项目-团队项目管理-显示的name和跳转的login 2021-04-20 10:54:20 +08:00
caishi ceb1915939 切换左侧目录,选择不同的文件时,文件详情没有更新 2021-04-20 10:30:47 +08:00
caishi 4c65e1981e all-默认头像(首字母加背景颜色) 2021-04-20 09:36:49 +08:00
caishi 09598d0e2c 个人主页头像url 2021-04-19 19:54:57 +08:00
caishi e09490d424 上线后的getImageURL也不用在前面加/ + 一些小样式修改 2021-04-19 18:19:21 +08:00
caishi a42a670146 头像url--接口会返回所有带images的字段值,所以前端不用加固定的内容了 2021-04-19 17:52:01 +08:00
caishi b8d40259e5 readme-文件增加一个目录下拉icon 2021-04-19 16:58:30 +08:00
caishi 487a2f0495 组织团队-新增一个团队标识 2021-04-19 11:53:19 +08:00
caishi ab34369642 新建团队板块无边框 2021-04-19 10:54:02 +08:00
caishi f12228aa51 组织详情显示nickname 2021-04-19 10:35:20 +08:00
caishi 5477c41f78 资源库不需要按引用次数排序 2021-04-14 10:31:33 +08:00
caishi dc05f9ce35 组织-项目-切换协作者管理和团队管理时会重复调用增加成员接口 2021-04-13 17:12:37 +08:00
caishi b601582d15 资源库数量显示错误 2021-04-13 11:14:04 +08:00
caishi 832b18e7f5 组织-团队列表的头像login为undefined 2021-04-13 11:06:09 +08:00
caishi 8c58f77afb 去掉右侧悬浮手册按钮 2021-04-09 14:18:44 +08:00
caishi 2c363965dd 去掉悬浮手册按钮 2021-04-09 13:58:58 +08:00
caishi 60a7f39c16 forge项目暂时不显示命令行功能 2021-04-09 11:45:04 +08:00
caishi 9811276a7c ssh-3(前端固定参数已调通) 2021-04-09 10:12:39 +08:00
caishi a27c74b9aa ssh-2 2021-04-08 18:14:19 +08:00
caishi 80cae93045 ssh-初步 2021-04-08 17:44:31 +08:00
caishi 78aba67917 项目详情右侧增加实践课程链接的显示 2021-04-08 15:37:01 +08:00
caishi 43223c7787 为2时不支持在线创建、在线上传、在线修改、在线删除、创建合并请求等功能 2021-04-08 14:21:35 +08:00
caishi 961587921a projectDetail.type:0是托管项目,1是镜像项目,2是同步镜像项目(为2时不能上传新建文件、下载zip等) 2021-04-08 10:07:55 +08:00
caishi 2f595d750a entries接口传的branch值为undefined 2021-04-07 18:44:20 +08:00
caishi bcaec7a2db 新增组织账号,组织名称增加新的check条件 2021-04-06 18:40:01 +08:00
caishi 70ea6259ae 仓库设置页面增加资源库配置项 2021-04-06 17:34:37 +08:00
caishi 5d6953f2b3 资源库模块测试版第一次上线 2021-04-06 17:17:01 +08:00
caishi c8eda704e5 列表的type字段为头像跳转到个人中心或者组织的判断依据 2021-04-06 11:45:03 +08:00
caishi 5d6b95ab8f 资源库部分接口调试 2021-04-06 11:36:38 +08:00
caishi 426ea3fece 合并请求分页 2021-04-02 18:55:26 +08:00
caishi ab052ebace 第三方登录-修改邮箱和密码 2021-04-02 18:40:59 +08:00
caishi 648c6e235b 第三方账号密码重置 2021-04-02 17:39:13 +08:00
caishi 96253f3f58 列表接口、上传资源 2021-04-02 17:31:15 +08:00
caishi 101478d924 协作者管理删除按钮没显示 2021-04-02 14:08:59 +08:00
caishi dccbd6735d 构建列表里的提交信息,作者头像错误 2021-04-02 11:57:48 +08:00
caishi a0ebba839e tips 2021-04-01 19:03:56 +08:00
caishi 171f14bd2a noticeurl 2021-04-01 16:25:53 +08:00
caishi c3e09f2672 第三方登录-educoder 2021-04-01 15:35:45 +08:00
caishi 6296434527 清理appconfig文件
资源库所有页面排版、数据未绑
2021-04-01 14:41:13 +08:00
caishi e2dbda3083 工作流author 2021-03-31 17:12:31 +08:00
caishi 02f382e6fb 登录框中的找回密码、注册的url 2021-03-31 11:15:41 +08:00
caishi b568aef34e issue 2021-03-30 15:01:25 +08:00
caishi 2c83221376 按钮 2021-03-30 11:50:25 +08:00
caishi 6a4fe4d277 左侧抽屉 2021-03-30 10:26:02 +08:00
caishi 99f7aea290 资源 2021-03-29 16:48:23 +08:00
caishi 50f39afffa style 2021-03-25 22:06:04 +08:00
caishi d0ccc92cc6 新建项目路由 2021-03-25 22:00:01 +08:00
caishi 2add7911dc readme 2021-03-25 14:38:52 +08:00
caishi ec1ff5d479 简介修改 2021-03-24 14:08:10 +08:00
caishi 55f23dea0d style 2021-03-23 17:58:12 +08:00
caishi 26e74e7ed4 condition 2021-03-23 17:40:23 +08:00
caishi 3384cd2703 style+banner 2021-03-23 09:20:16 +08:00
caishi 0290822ebf 代码库-默认显示 2021-03-22 11:24:07 +08:00
caishi 31edf6ff45 分页 2021-03-22 09:45:30 +08:00
caishi 8a1feed72b 未登录判断 2021-03-19 17:22:02 +08:00
caishi 0c0203a8ef name 2021-03-19 16:34:41 +08:00
caishi 45e69cb14a update 2021-03-19 16:29:43 +08:00
caishi d7f3c766b4 导航栏设置 2021-03-19 15:46:37 +08:00
caishi a3226dca4e banner 2021-03-19 12:11:55 +08:00
caishi d16ee801ec 背景色 2021-03-19 11:35:03 +08:00
caishi c3eb6edddc 项目详情新版 2021-03-18 17:28:53 +08:00
caishi ad8a127170 remove 2021-03-11 18:07:19 +08:00
caishi cbaf72b341 appconfig 2021-03-10 17:32:39 +08:00
caishi a4b5b67da6 diff-查看文件 2021-03-10 10:41:16 +08:00
caishi da31875a5a filedetail 2021-03-09 11:46:41 +08:00
caishi b7a92b17e7 active 2021-03-08 10:26:39 +08:00
caishi f4332db4ad style 2021-03-05 18:35:54 +08:00
caishi 99174c2782 取消上一个commit的修改 2021-03-05 15:59:30 +08:00
caishi f33f1f3ce5 参数管理-权限(仅创建者) 2021-03-05 14:39:59 +08:00
caishi 5d99d63267 style 2021-03-05 10:47:13 +08:00
caishi 9137b666ea style 2021-03-05 09:56:07 +08:00
caishi 1250a9b10b 删除 2021-03-04 17:05:27 +08:00
caishi 6ea82be73a 工作流-参数管理 2021-03-04 15:08:58 +08:00
caishi 964427b8fc 工作流-参数 2021-03-03 16:43:02 +08:00
caishi afd6904349 loading 2021-03-02 15:43:40 +08:00
caishi 72fcbcd4dd root 2021-03-02 11:40:55 +08:00
caishi 80f1e4d448 查看文件-url 2021-03-02 10:51:50 +08:00
caishi 3071c785bc sync mirror 2021-03-01 16:02:02 +08:00
caishi d01e8e32d4 设置 2021-02-26 15:40:44 +08:00
caishi e469ddae24 删除协作者 2021-02-26 11:57:35 +08:00
caishi f8b9003e15 我关注的-接口错误 2021-02-25 17:06:25 +08:00
caishi 19f66b0bcc 关注和取消关注 2021-02-25 14:08:35 +08:00
caishi 2ceaead909 fork列表 2021-02-24 15:45:48 +08:00
caishi 8d386ff70b tips 2021-02-24 15:27:58 +08:00
caishi d11cb7fc40 small problem 2021-02-24 10:53:17 +08:00
caishi 696fb22a58 class name 2021-02-23 17:26:52 +08:00
caishi 67b510923b 发行版 -loading 2021-02-23 14:45:18 +08:00
caishi ad3c9f837f 新建标签 2021-02-23 11:00:05 +08:00
caishi b8476cec1a nodata tip 2021-02-22 17:50:47 +08:00
caishi fcd859638e spining 2021-02-22 15:27:51 +08:00
caishi 518d341ed5 issues 2021-02-22 10:17:52 +08:00
caishi b4a608bcc3 img-siaze 2021-02-07 16:50:14 +08:00
caishi 658fd1b4f9 权限 2021-02-06 15:30:56 +08:00
caishi 58228e90c7 project 镜像、fork 2021-02-06 10:42:32 +08:00
caishi 10466ac4a2 标签长度 2021-02-06 10:18:05 +08:00
caishi 98d40482f3 issue 2021-02-05 16:19:35 +08:00
caishi 03cd10f599 新建团队 2021-02-04 18:31:27 +08:00
caishi 59836f69d0 f 2021-02-04 18:18:15 +08:00
caishi 591974aa6d 权限 2021-02-04 18:02:37 +08:00
caishi eaa46dbcee 项目-团队管理 2021-02-04 17:47:30 +08:00
caishi 0c5dd61fdc new 2021-02-04 14:54:26 +08:00
caishi 26d2e0f541 fix 2021-02-03 18:41:01 +08:00
caishi daa5cc212c 用户 url 2021-02-03 17:00:46 +08:00
caishi 7a8cbac912 Merge branch 'develop' into dev_orgnize 2021-02-03 15:53:24 +08:00
caishi 3b208ba751 组织 all over 2021-02-03 15:53:15 +08:00
caishi 9380c0172c meg 2021-02-02 18:26:55 +08:00
caishi 34ba476011 bug 2021-02-02 14:20:31 +08:00
caishi 185228d4b6 dispose 2021-02-02 13:46:22 +08:00
caishi cae10cec2a new 2021-02-02 12:22:47 +08:00
caishi 006ceff8fc bug 2021-02-02 10:05:16 +08:00
caishi c71d8512df issue 2021-02-02 09:49:03 +08:00
caishi 3b85567a1a new page 2021-02-02 09:31:15 +08:00
caishi ea77a13b6f url 2021-02-01 16:53:33 +08:00
caishi fcf03f2631 团队设置 2021-02-01 16:43:25 +08:00
caishi e65a1debc5 参数 2021-02-01 15:28:24 +08:00
caishi a2406bbf4b 组织团队 2021-02-01 15:20:38 +08:00
caishi eee8d4659c bug 2021-02-01 11:10:51 +08:00
Sylor-huang 7eef81b91a add team codes 2021-01-31 22:24:46 +08:00
Sylor-huang bd85703412 add group setting pages 2021-01-30 22:06:52 +08:00
Sylor-huang 7a2d1b7db1 add group setting 2021-01-30 21:12:26 +08:00
caishi 828cc2470d 个人中心-我的组织 2021-01-29 17:26:08 +08:00
caishi 7b7b206741 Merge branch 'develop' into dev_orgnize 2021-01-29 14:45:34 +08:00
caishi 5181d636d9 工作流配置-模板管理 2021-01-29 14:17:49 +08:00
caishi f68842beff 组织-基本管理 2021-01-28 11:48:21 +08:00
caishi 6deb8db08f Merge branch 'develop' into dev_orgnize 2021-01-25 16:01:49 +08:00
caishi 3a2d93c3a6 version 2021-01-25 16:01:18 +08:00
caishi b71980f6dc issue 2021-01-25 15:22:45 +08:00
caishi 586d9e0c05 新建组织 2021-01-25 10:49:39 +08:00
caishi 029bb89b11 新建 2021-01-21 18:01:59 +08:00
caishi 2278d03c47 iconfnt 2021-01-20 20:14:39 +08:00
caishi a22b5b3701 合并develop 2021-01-20 15:22:37 +08:00
caishi df438212c1 Merge branch 'develop' into dev_devopsDispose 2021-01-20 15:21:12 +08:00
caishi e1164875b0 update bug 2021-01-20 11:39:00 +08:00
caishi c53de4ad15 stage 2021-01-20 10:47:59 +08:00
caishi ef22be7e96 remove debug 2021-01-20 10:13:18 +08:00
caishi a235879dd0 update 2021-01-20 10:12:35 +08:00
caishi 0b007b35d9 new 2021-01-19 18:11:38 +08:00
caishi 68935245f0 pulls 权限 2021-01-13 15:46:45 +08:00
caishi f7fe479859 new 2021-01-13 15:46:17 +08:00
caishi 9d0adc0747 pulls 2021-01-13 14:16:18 +08:00
caishi 0e0eee8aaf pulls 2021-01-13 09:49:54 +08:00
caishi 7e47cad744 pullrequest 2021-01-12 17:36:30 +08:00
caishi 5e7fedb471 dispose 2021-01-12 17:25:22 +08:00
caishi 4ef05163d7 about page 2021-01-11 17:18:12 +08:00
caishi 4d9567bb94 Merge branch 'master' into dev_devopsDispose 2021-01-06 16:34:43 +08:00
caishi 246782f961 link 2021-01-06 16:23:59 +08:00
caishi e5d9728807 Merge branch 'develop' 2021-01-06 16:04:09 +08:00
caishi dd8856f7ac forge-工作流配置页改版-分支 2021-01-06 16:03:50 +08:00
caishi 502dfde9a2 详情顶部-为0时不显示 2021-01-05 15:31:26 +08:00
caishi 05ded94662 save 2021-01-05 14:27:35 +08:00
caishi bbe3766a40 工作流已开启和未开启两种状态链接跳转 2021-01-05 10:32:50 +08:00
caishi 05080e7948 工作流 2020-12-31 13:58:44 +08:00
caishi b59e83ee00 Merge branch 'master' of https://git.trustie.net/jasder/forgeplus-react
# Conflicts:
#	package-lock.json
2020-12-30 10:25:21 +08:00
caishi 0a67b9606a update webpack 2020-12-24 14:41:17 +08:00
caishi 2b063bb8f7 动态-user_login 2020-12-24 10:20:29 +08:00
caishi 2905bb41a7 md编辑器的高度 2020-12-24 09:36:02 +08:00
caishi d66b0580b7 issue 2020-12-23 17:39:50 +08:00
caishi d7e0d5b246 name 2020-12-22 10:31:10 +08:00
caishi fac62fc99e remove 2020-12-21 17:59:40 +08:00
caishi e294b14015 readme文件更新 2020-12-21 09:53:36 +08:00
caishi 59a0834300 readme更新 2020-12-21 09:51:59 +08:00
caishi 21b1c8cba3 readme文件内容 2020-12-18 18:24:01 +08:00
caishi 0929200f43 readme文件 2020-12-18 18:20:05 +08:00
caishi 8df79a85d2 Delete 'README.md' 2020-12-18 17:20:45 +08:00
caishi 94a2946d52 readme文件 2020-12-18 17:20:22 +08:00
caishi 5c91569bac c 2020-12-18 17:14:51 +08:00
caishi a4dbda8c5d 分支设置下拉列表不可选择标签 2020-12-18 14:01:38 +08:00
caishi e3c1e7b82f markdown 2020-12-17 17:59:30 +08:00
caishi 7795fe1d04 markdown 2020-12-17 14:35:36 +08:00
caishi 5d0afb265b 镜像设置相关 2020-12-16 13:52:44 +08:00
caishi 45fc4dcdcd position 2020-12-16 11:37:56 +08:00
caishi 2129a222e5 锚点跳转 2020-12-15 18:01:16 +08:00
caishi 68eb499a8c CI服务 2020-12-14 17:04:58 +08:00
caishi 5f36f9306a tag color 2020-12-14 14:12:41 +08:00
caishi e95ef11058 style 2020-12-11 18:14:25 +08:00
caishi 851afbc6c4 小修 2020-12-09 14:19:55 +08:00
caishi ee79efa6de bug 2020-12-08 17:16:07 +08:00
caishi 6b203d9d24 分支设置 2020-12-04 20:30:23 +08:00
caishi 0d1345f957 分支设置 2020-12-04 19:26:14 +08:00
caishi 57363291f1 change 2020-12-01 16:49:24 +08:00
caishi 2ba469f210 分支设置 2020-11-30 16:14:55 +08:00
caishi 06f0c53d3b 工作流分页 2020-11-27 16:29:08 +08:00
caishi 9005106332 clear 2020-11-27 15:43:55 +08:00
caishi 89b78bc046 修改和新建文件branch 2020-11-27 11:59:21 +08:00
caishi a38b74041e babelrc-runtime 2020-11-26 15:45:54 +08:00
caishi ccb5eb8ae5 Merge commit 'ef6559400411d4e9de4072441c9865e226936ba7' into dev_bei
# Conflicts:
#	src/AppConfig.js
2020-11-26 11:21:48 +08:00
caishi ef65594004 babel 2020-11-25 17:25:59 +08:00
caishi b27f0e796d === 2020-11-25 12:39:59 +08:00
caishi 92699347ec 分支设置 2020-11-24 18:00:34 +08:00
caishi 0062e84a45 Merge branch 'dev_bei' into dev_local 2020-11-24 10:47:05 +08:00
caishi 5827e96a53 branch router 2020-11-24 10:46:27 +08:00
caishi 8cc13f77e1 工作流-无权限提示 2020-11-23 15:23:19 +08:00
caishi ac5b50c26d detail 2020-11-23 10:14:29 +08:00
caishi b2eca51bd8 merge.css not found 2020-11-19 09:45:54 +08:00
caishi cbfb9c3ffe 本地版本-注册页面 2020-11-18 11:31:52 +08:00
caishi 1867497d52 detail 2020-11-17 14:08:21 +08:00
caishi d6fa304d01 detail 2020-11-17 09:48:33 +08:00
caishi bf84063a3c root 2020-11-16 16:17:03 +08:00
caishi 43fc24e114 没有数据时tab也不会显示 2020-11-16 14:18:41 +08:00
caishi a2e1b2abd1 version style 2020-11-13 14:26:06 +08:00
caishi 4edef931d5 style 2020-11-13 14:14:49 +08:00
caishi 49795b0682 && 2020-11-12 14:43:33 +08:00
caishi 0c59855e9c bug 2020-11-11 16:09:57 +08:00
caishi ef19107fcd sha link 2020-11-10 18:09:38 +08:00
caishi 0712904506 小bug 2020-11-10 16:56:05 +08:00
caishi 2f755e8d65 diff页面 2020-11-10 16:42:32 +08:00
caishi 0dd33faeb5 合并请求编辑权限 2020-11-09 09:57:15 +08:00
caishi 0dd722d898 router 2020-11-06 22:35:28 +08:00
caishi 2e04851b66 update 2020-11-06 18:41:23 +08:00
caishi f9588407b8 合并请求 2020-11-06 16:30:01 +08:00
caishi e9fef026a6 pr 2020-11-05 11:31:26 +08:00
caishi 5e36abb259 清除选中项-任务 2020-11-02 09:58:19 +08:00
caishi 0cb6986aed 无数据提示 2020-10-30 10:42:02 +08:00
caishi 80ef857048 box top 2020-10-30 10:13:08 +08:00
caishi 5bc172a492 update 2020-10-29 15:40:30 +08:00
caishi e42de09b99 pullrequest 2020-10-28 16:07:45 +08:00
caishi 3591666e5e 搜索时清除选中状态 2020-10-27 16:47:14 +08:00
caishi eb8cae5fb3 细节修改 2020-10-27 14:38:44 +08:00
caishi 8645eb8e1b merge 2020-10-23 10:34:03 +08:00
caishi 02f286ffad Merge branch 'dev_devOps' of https://git.trustie.net/jasder/forgeplus-react into dev_devOps 2020-10-23 10:15:48 +08:00
caishi ee6356daa0 style 2020-10-23 10:15:40 +08:00
caishi 62b99c7921 Merge branch 'dev_chain' of https://git.trustie.net/jasder/forgeplus-react into dev_devOps
# Conflicts:
#	src/forge/Merge/UpdateMerge.js
#	src/forge/Order/Detail.js
#	src/forge/Order/OrderItem.js
#	src/forge/Order/order_form.js
2020-10-22 22:41:16 +08:00
caishi 4ce8e4edd1 文件详情 2020-10-22 22:24:49 +08:00
caishi bba939094c educoder 项目 2020-10-22 19:34:11 +08:00
caishi 8d3c5c4c06 Merge branch 'newVersion_forge' into dev_devOps 2020-10-22 18:20:54 +08:00
caishi d1e7d2e935 image url 2020-10-22 18:20:42 +08:00
caishi ac2ac26036 Merge branch 'newVersion_forge' into dev_devOps 2020-10-21 17:29:35 +08:00
caishi 42ddb67c0e spin 2020-10-21 17:29:25 +08:00
caishi 849f695a78 Merge branch 'newVersion_forge' into dev_devOps 2020-10-21 16:50:15 +08:00
caishi d80f1d32dc 非trustie则新开页 2020-10-21 16:49:59 +08:00
caishi b6dfe2cd4a Merge branch 'newVersion_forge' into dev_devOps
# Conflicts:
#	src/forge/Main/Detail.js
2020-10-19 15:43:53 +08:00
caishi 7edaa9e09c manager/owner 2020-10-19 15:41:10 +08:00
caishi ded423ee2c ismanager 2020-10-19 11:45:58 +08:00
caishi a5657390fe 工作流权限 2020-10-16 17:29:10 +08:00
sylor_huang@126.com 5a8daf7cfe Change NewHeader active 2020-10-16 17:17:14 +08:00
caishi 51c2729916 马上认证 2020-10-16 11:39:12 +08:00
caishi aca923fe07 Merge branch 'newVersion_forge' into dev_devOps 2020-10-16 10:36:04 +08:00
caishi 3949584549 编辑文件-提交至 2020-10-16 10:35:51 +08:00
caishi d029a9ab6f devops流程 2020-10-15 19:44:17 +08:00
caishi 46097ee5e1 Merge branch 'newVersion_forge' into dev_devOps 2020-10-10 15:55:58 +08:00
caishi c66717bf1b Merge branch 'newVersion_forge' into dev_devOps 2020-10-10 10:11:58 +08:00
caishi 8b1b923c92 Merge branch 'newVersion_forge' into dev_devOps 2020-10-09 16:32:59 +08:00
caishi 4afa382c7c Merge branch 'newVersion_forge' into dev_devOps 2020-10-09 16:05:00 +08:00
caishi b27f6d5732 Merge branch 'newVersion_forge' into dev_devOps 2020-10-09 11:45:17 +08:00
caishi 4e657a4c15 Merge branch 'newVersion_forge' into dev_devOps 2020-10-09 10:17:20 +08:00
caishi 229b5a704e Merge branch 'newVersion_forge' into dev_devOps 2020-10-09 09:25:08 +08:00
caishi 69a9137c34 Merge branch 'newVersion_forge' into dev_devOps 2020-10-06 13:25:21 +08:00
caishi 8cee70c195 Merge branch 'newVersion_forge' into dev_devOps
# Conflicts:
#	public/css/iconfont.css
#	public/css/iconfont.eot
#	public/css/iconfont.js
#	public/css/iconfont.json
#	public/css/iconfont.svg
#	public/css/iconfont.ttf
#	public/css/iconfont.woff
#	public/css/iconfont.woff2
2020-10-05 18:03:32 +08:00
caishi f7adc17b5d Merge branch 'newVersion_forge' into dev_devOps 2020-09-30 16:54:43 +08:00
caishi 48d9580e78 Merge branch 'newVersion_forge' into dev_devOps 2020-09-30 16:34:14 +08:00
caishi f3d6e8c6dc Merge branch 'newVersion_forge' into dev_devOps 2020-09-29 11:21:13 +08:00
caishi a14b125d34 Merge branch 'newVersion_forge' into dev_devOps 2020-09-29 10:41:17 +08:00
caishi 593f76bba0 update 2020-09-28 17:56:27 +08:00
caishi 45273782c5 工作流流程更改 2020-09-28 14:51:24 +08:00
caishi c3ed52bc32 Merge branch 'newVersion_forge' into dev_devOps 2020-09-27 13:59:04 +08:00
caishi 8397daec22 Merge branch 'newVersion_forge' into dev_devOps 2020-09-24 10:34:22 +08:00
caishi 1e80457885 Merge branch 'newVersion_forge' into dev_devOps 2020-09-23 21:33:00 +08:00
caishi c052cf715b Merge branch 'newVersion_forge' into dev_devOps 2020-09-23 16:19:21 +08:00
caishi 53e444d85e Merge branch 'newVersion_forge' into dev_devOps 2020-09-16 18:28:03 +08:00
caishi cd6540a84c Merge branch 'newVersion_forge' into dev_devOps 2020-09-16 18:00:07 +08:00
caishi 10d4ad7221 Merge branch 'newVersion_forge' into dev_devOps 2020-09-16 17:48:12 +08:00
caishi 440e7cd91e 头部 2020-09-16 17:10:26 +08:00
Jasder 0991fee06a FIX 局部优化 2020-09-11 17:35:05 +08:00
Jasder 8307c014f6 FIX 项目激活ci服务的认证地址根据用户是否认证的状态来显示 2020-09-11 16:51:23 +08:00
Jasder dace62e2de skilled status css color for ci build 2020-09-11 16:44:15 +08:00
caishi 74ea4d504d 细节 2020-09-10 09:47:09 +08:00
caishi 942e88a6ea selectkeys 2020-09-09 16:50:48 +08:00
caishi 87449bde46 暂无-手动创建 2020-09-09 15:35:22 +08:00
caishi 3060c4bb2b Merge branch 'newVersion_forge' into dev_devOps 2020-09-09 14:20:52 +08:00
caishi b6bc59a775 Merge branch 'newVersion_forge' into dev_devOps 2020-09-09 10:46:56 +08:00
caishi 745179adae Merge branch 'newVersion_forge' into dev_devOps 2020-09-08 14:55:29 +08:00
caishi 15bd20122a Merge branch 'newVersion_forge' into dev_devOps
# Conflicts:
#	src/forge/Images/banner_list_old.png
#	src/forge/Main/list.css
2020-09-08 14:37:05 +08:00
caishi afeff6b0af Merge branch 'newVersion_forge' into dev_devOps 2020-09-08 10:23:28 +08:00
caishi b66c1c01de image 2020-09-07 17:15:03 +08:00
caishi ec98b6ad44 status 2020-09-07 15:29:25 +08:00
caishi e252f168f8 Merge branch 'newVersion_forge' into dev_devOps 2020-09-07 15:02:43 +08:00
caishi 6944406c49 status 2020-09-07 15:02:25 +08:00
caishi 2f09ca4315 link 2020-09-07 12:00:07 +08:00
caishi 4329b89ddf 列表 2020-09-07 11:38:43 +08:00
caishi 30f0fd82de devops-个人中心-权限 2020-09-07 11:00:59 +08:00
caishi 6795e61870 个人中心-工作流CI 2020-09-04 18:00:22 +08:00
caishi 3169867415 merge 2020-09-03 14:16:55 +08:00
caishi d697ad24a7 个人中心-devops 2020-09-03 14:14:49 +08:00
caishi f05b6eb804 loading 2020-09-02 18:09:06 +08:00
caishi d702a92e81 about 2020-09-02 11:29:56 +08:00
caishi 11e58a200c input 2020-09-02 11:29:31 +08:00
sylor_huang@126.com 6d478dd911 Merge branch 'newVersion_forge' into dev_devOps 2020-09-01 11:41:59 +08:00
caishi 15d3102c51 Merge branch 'newVersion_forge' into dev_devOps
# Conflicts:
#	src/forge/Main/CoderRootDirectory.js
2020-08-31 16:37:31 +08:00
caishi bac40864eb update 2020-08-31 14:07:09 +08:00
caishi cccdfeab32 build 2020-08-28 11:58:32 +08:00
caishi 3abbaa8899 devops 2020-08-27 15:15:03 +08:00
caishi 42a1418181 path 2020-08-27 10:26:28 +08:00
caishi ec073cdf71 .json 2020-08-26 18:37:15 +08:00
caishi a09b81df3f devops 2020-08-26 17:11:42 +08:00
caishi a411d2c111 devops 2020-08-26 16:09:27 +08:00
caishi 2f1bac24d5 Merge branch 'newVersion_forge' into dev_devOps
# Conflicts:
#	src/forge/Main/Detail.js
2020-08-21 10:29:08 +08:00
caishi 940c9c0253 工作流 2020-08-09 22:39:58 +08:00
caishi dfbcc09e5b devops 2020-07-31 20:15:28 +08:00
837816638@qq.com 40cc47dd93 样式 2020-07-03 16:21:19 +08:00
445 changed files with 26218 additions and 23885 deletions

16
.babelrc Normal file
View File

@ -0,0 +1,16 @@
{
"presets": [
"es2015",
"react",
"stage-2"
],
"plugins": [[
"transform-runtime",
{
"helpers": false,
"polyfill": false,
"regenerator": true,
"moduleName": "babel-runtime"
}
]]
}

16
README.md Normal file
View File

@ -0,0 +1,16 @@
<h3>前端react环境安装</h3>
<p>1、 安装node v6.9.x此安装包含了node和npm。</p>
<p>2、 安装cnpm命令行 npm install -g cnpm --registry=https://registry.npm.taobao.org</p>
<p>3、 安装依赖的js库public/react目录下<即项目package.json所在目录>,开启命令行): cnpm install</p>
<p>4、 如果你的ruby服务使用的是3000端口则需要在package.json中修改"port"参数的值</p>
<p>5、 启动服务(命令行-目录同3 npm start</p>
<p>6、 build初始化 npm run build</p>
<h3>分支信息:</h3>
<p>相关代码提交到对应分支能上线的代码先提交到develop分支上测试版测试通过后合并提交到master分支上线正式版</p>
<p>master:开发环境(正式环境)</p>
<p>develop:测试环境</p>
<p>dev_local:本地版本</p>
<p>dev_chain:含有区块链相关内容的分支</p>
<p>PS:新增加的需求功能先新建新分支开发在测试版测试没问题后再分别合并到develop和master分支</p>

View File

@ -17,16 +17,7 @@ const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const paths = require("./paths");
const getClientEnvironment = require("./env");
// Some apps do not use client-side routing with pushState.
// For these, "homepage" can be set to "." to enable relative asset paths.
let publicPath = "/react/build/";
// let nodeEnv = process.env.NODE_ENV
// if (nodeEnv === 'testBuild') {
// publicPath = 'https://testforgeplus.trustie.net/react/build/';
// }
// if (nodeEnv === 'production') {
// publicPath = 'https://forgeplus.trustie.net/react/build/';
// }
const publicUrl = publicPath.slice(0, -1);
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== "false";
const env = getClientEnvironment(publicPath);
@ -141,7 +132,6 @@ module.exports = {
name: "static/media/[name].[hash:8].[ext]",
},
},
// Process JS with Babel.
{
test: /\.(js|jsx|mjs)$/,
include: paths.appSrc,
@ -161,10 +151,8 @@ module.exports = {
],
},
},
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,

760
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,21 +1,20 @@
{
"name": "educoder",
"version": "0.1.0",
"name": "forge",
"version": "3.0.0",
"private": true,
"dependencies": {
"@monaco-editor/react": "^2.3.0",
"@novnc/novnc": "^1.1.0",
"actioncable": "^5.2.4-3",
"antd": "^3.26.15",
"antd-img-crop": "^3.14.1",
"array-flatten": "^2.1.2",
"autoprefixer": "7.1.6",
"axios": "^0.18.1",
"babel-core": "6.26.0",
"babel-eslint": "7.2.3",
"babel-jest": "20.0.3",
"babel-loader": "7.1.2",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"babel-polyfill": "^6.26.0",
"babel-preset-react-app": "^3.1.1",
"babel-runtime": "6.26.0",
"bizcharts": "^3.5.8",
@ -28,9 +27,11 @@
"codemirror": "^5.53.0",
"connected-react-router": "4.4.1",
"css-loader": "^3.5.2",
"dompurify": "^2.0.15",
"dotenv": "4.0.0",
"dotenv-expand": "4.2.0",
"echarts": "^4.7.0",
"echarts": "^4.9.0",
"echarts-wordcloud": "^2.0.0",
"editor.md": "^1.5.0",
"eslint": "4.10.0",
"eslint-config-react-app": "^2.1.0",
@ -47,6 +48,7 @@
"install": "^0.12.2",
"jest": "20.0.4",
"js-base64": "^2.5.2",
"js2wordcloud": "^1.1.12",
"katex": "^0.11.1",
"lodash": "^4.17.15",
"loglevel": "^1.6.8",
@ -63,7 +65,7 @@
"postcss-loader": "2.0.8",
"promise": "8.0.1",
"prop-types": "^15.6.1",
"qrcode.react": "^1.0.0",
"qrcode.react": "^1.0.1",
"qs": "^6.9.3",
"quill": "^1.3.7",
"quill-delta-to-html": "^0.11.0",
@ -93,6 +95,7 @@
"react-resizable": "^1.10.1",
"react-router": "^4.2.0",
"react-router-dom": "^4.2.2",
"react-slick": "^0.28.1",
"react-split-pane": "^0.1.91",
"react-url-query": "^1.5.0",
"react-zmage": "^0.8.5-beta.31",
@ -103,6 +106,7 @@
"scroll-into-view": "^1.14.2",
"showdown": "^1.9.1",
"showdown-katex": "^0.8.0",
"slick-carousel": "^1.8.1",
"store": "^2.0.12",
"style-loader": "0.19.0",
"styled-components": "^4.4.1",
@ -112,7 +116,9 @@
"webpack-dev-server": "^3.10.3",
"webpack-manifest-plugin": "^2.2.0",
"whatwg-fetch": "2.0.3",
"wrap-md-editor": "^0.2.20"
"wrap-md-editor": "^0.2.20",
"xterm": "4.8.1",
"xterm-addon-fit": "0.4.0"
},
"scripts": {
"start": "node --max_old_space_size=15360 scripts/start.js",
@ -183,7 +189,14 @@
"port": "3007",
"devDependencies": {
"@babel/runtime": "7.0.0-beta.51",
"babel-cli": "^6.26.0",
"babel-core": "^6.26.0",
"babel-plugin-import": "^1.13.0",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-polyfill": "^6.26.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-2": "^6.24.1",
"compression-webpack-plugin": "^1.1.12",
"concat": "^1.0.3",
"happypack": "^5.0.1",
@ -191,6 +204,7 @@
"node-sass": "^4.12.0",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"purgecss": "^2.1.2",
"react-json-view": "^1.21.3",
"reqwest": "^2.0.5",
"resize-observer-polyfill": "^1.5.1",
"terser-webpack-plugin": "^2.3.5",

File diff suppressed because one or more lines are too long

View File

@ -38,78 +38,6 @@
box-sizing: border-box;
}
.head-nav ul#header-nav li {
float: left;
height: 60px;
line-height: 60px;
margin-right: 30px;
cursor: pointer;
position: relative;
font-size: 16px
}
.head-nav ul#header-nav li a {
display: block;
height: 100%;
width: 100%;
color: #fff
}
.head-nav ul#header-nav li a:hover {
color: #cccccc;
}
.head-nav ul#header-nav li:last-child {
margin-right: 0px
}
.head-nav ul#header-nav li.active a {
color: #459be5 !important;
}
.head-nav ul#header-nav li.active p {
color: #459be5 !important;
}
.head-nav ul#header-nav li p:hover {
color: #cccccc;
}
.head-nav ul#header-nav li p {
display: block;
height: 100%;
width: 100%;
color: #fff
}
.head-nav ul#header-nav li.active div ul li a {
color: #000 !important;
}
.head-nav ul#header-nav li.active div ul li a:hover {
color: #FFF !important;
}
.head-nav ul#header-nav li.active ul li a {
color: #000 !important;
}
.head-nav ul#header-nav li.active ul li a:hover {
color: #FFF !important;
}
.head-nav ul#header-nav li.active:after {
content: '';
position: absolute;
left: 0px;
top: auto;
bottom: 10px;
right: auto;
height: 2px;
width: 14px;
background-color: #459be5;
}
.nav-img {
position: absolute;
top: 2px;

View File

@ -1753,7 +1753,7 @@ a.decoration {
}
.mb15 {
margin-bottom: 15px;
margin-bottom: 15px!important;
}
.mb16 {
@ -2325,6 +2325,9 @@ input::-ms-clear {
background-color: #F5F5F5;
}
.ant-modal-close{
top:8px!important;
}
.newContainer {
min-height: 100%;
@ -2344,10 +2347,6 @@ input::-ms-clear {
.newMain {
margin: 0 auto;
min-width: 1200px;
height: 100%;
min-height: 100%;
padding-top: 70px;
background-color: #fafafa;
}
@ -2425,10 +2424,16 @@ input::-ms-clear {
.color-grey-c {
color: #ccc !important;
}
a.hoverLine:hover{
text-decoration: underline;
}
.color-grey-cd {
color: #cdcdcd !important;
}
.color-grey-d {
color: #ddd;
}
.color-grey-9 {
color: #999999 !important;
@ -2661,7 +2666,7 @@ a.color-green:hover {
/*百分比宽度*/
.width100 {
width: 100%;
width: 100% !important;
}
.width89 {
@ -3410,7 +3415,7 @@ a.user_bluebg_btn {
}
.cdefault {
cursor: default
cursor: default!important;
}
@ -3585,42 +3590,6 @@ a.user_bluebg_btn {
margin-right: 5px;
}
/*-------------------个人主页:右侧提示区域--------------------------*/
.-task-sidebar {
position: fixed;
width: 40px;
height: 180px;
right: 0;
bottom: 80px;
z-index: 10;
}
.-task-sidebar div {
height: 40px;
line-height: 40px;
box-sizing: border-box;
width: 40px;
background: #4CACFF;
color: #fff;
font-size: 20px;
text-align: center;
margin-bottom: 5px;
border-radius: 4px;
}
.-task-sidebar div i {
color: #fff;
}
.-task-sidebar div i:hover {
color: #fff !important;
}
.gotop {
background-color: rgba(208, 207, 207, 0.5) !important;
padding: 0px !important;
}
/***** loading ******/
/*****载入中******/
@ -3945,11 +3914,21 @@ html>body #ajax-indicator {
max-height: 340px;
}/*头部导航条样式---2018-03-19--by-cs*/
.privateTag{
display: block;
padding:0px 6px;
border-radius: 12px;
border:1px solid #2FC25B;
height: 18px;
line-height: 18px;
font-size: 12px;
margin-left: 10px;
color: #2FC25B;
}
.head-nav {
text-align: center;
height: 70px;
box-sizing: border-box;
min-width: 780px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
@ -3971,7 +3950,7 @@ html>body #ajax-indicator {
cursor: pointer;
position: relative;
font-size: 16px;
padding:0px 20px;
padding-right:40px;
}
.head-nav ul#header-nav li a {
@ -4108,8 +4087,6 @@ em.vertical-line {
/* 右侧内容宽度变化的话需要调整posi-search right的值*/
/*底部*/
.footercon {
border-bottom: 1px solid #47494d;
@ -6705,4 +6682,19 @@ ul.count_ul li:not(:last-child):after {
}
input.ant-input-lg::placeholder{
font-size: 14px !important;
}
p{
margin-bottom: 0px!important;
}
.toprightNum{
position: absolute;
right: 0px;
top:4px;
color: #999;
}
.ant-input, .ant-input .ant-input-suffix{
background-color: #fff!important;
}
.has-error .ant-input{
background-color: #FEF1F0!important;
}

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 584 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

111
public/css/merge.css Executable file
View File

@ -0,0 +1,111 @@
.CodeMirror-merge {
position: relative;
white-space: pre;
}
.CodeMirror-merge, .CodeMirror-merge .CodeMirror {
min-height:50px;
}
.CodeMirror-merge-2pane .CodeMirror-merge-pane { width: 48%; }
.CodeMirror-merge-2pane .CodeMirror-merge-gap { width: 4%; }
.CodeMirror-merge-3pane .CodeMirror-merge-pane { width: 31%; }
.CodeMirror-merge-3pane .CodeMirror-merge-gap { width: 3.5%; }
.CodeMirror-merge-pane {
display: inline-block;
white-space: normal;
vertical-align: top;
}
.CodeMirror-merge-pane-rightmost {
position: absolute;
right: 0px;
z-index: 1;
}
.CodeMirror-merge-gap {
z-index: 2;
display: inline-block;
height: 100%;
-moz-box-sizing: border-box;
box-sizing: border-box;
overflow: hidden;
position: relative;
background: #515151;
}
.CodeMirror-merge-scrolllock-wrap {
position: absolute;
bottom: 0; left: 50%;
}
.CodeMirror-merge-scrolllock {
position: relative;
left: -50%;
cursor: pointer;
color: #d8d8d8;
line-height: 1;
}
.CodeMirror-merge-copybuttons-left, .CodeMirror-merge-copybuttons-right {
position: absolute;
left: 0; top: 0;
right: 0; bottom: 0;
line-height: 1;
}
.CodeMirror-merge-copy {
position: absolute;
cursor: pointer;
color: #ce374b;
z-index: 3;
}
.CodeMirror-merge-copy-reverse {
position: absolute;
cursor: pointer;
color: #44c;
}
.CodeMirror-merge-copybuttons-left .CodeMirror-merge-copy { left: 2px; }
.CodeMirror-merge-copybuttons-right .CodeMirror-merge-copy { right: 2px; }
.CodeMirror-merge-r-inserted, .CodeMirror-merge-l-inserted {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12MwuCXy3+CWyH8GBgYGJgYkAABZbAQ9ELXurwAAAABJRU5ErkJggg==);
background-position: bottom left;
background-repeat: repeat-x;
}
.CodeMirror-merge-r-deleted, .CodeMirror-merge-l-deleted {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12M4Kyb2/6yY2H8GBgYGJgYkAABURgPz6Ks7wQAAAABJRU5ErkJggg==);
background-position: bottom left;
background-repeat: repeat-x;
}
.CodeMirror-merge-r-chunk { background: #9a6868; }
.CodeMirror-merge-r-chunk-start { /*border-top: 1px solid #ee8; */}
.CodeMirror-merge-r-chunk-end {/* border-bottom: 1px solid #ee8; */}
.CodeMirror-merge-r-connect { fill:#9a6868;}
.CodeMirror-merge-l-chunk { background: #eef; }
.CodeMirror-merge-l-chunk-start { border-top: 1px solid #88e; }
.CodeMirror-merge-l-chunk-end { border-bottom: 1px solid #88e; }
.CodeMirror-merge-l-connect { fill: #eef; stroke: #88e; stroke-width: 1px; }
.CodeMirror-merge-l-chunk.CodeMirror-merge-r-chunk { background: #dfd; }
.CodeMirror-merge-l-chunk-start.CodeMirror-merge-r-chunk-start { border-top: 1px solid #4e4; }
.CodeMirror-merge-l-chunk-end.CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #4e4; }
.CodeMirror-merge-collapsed-widget:before {
content: "(...)";
}
.CodeMirror-merge-collapsed-widget {
cursor: pointer;
color: #88b;
background: #eef;
border: 1px solid #ddf;
font-size: 90%;
padding: 0 3px;
border-radius: 4px;
}
.CodeMirror-merge-collapsed-line .CodeMirror-gutter-elt { display: none; }

BIN
public/favicon.ico Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -1,15 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<html lang="zh-CN" class="notranslate translated-ltr" translate="no">
<head>
<meta charset="utf-8">
<meta name=”Keywords” Content="trustie,trustieforge,forge,确实让创建更美好,协同开发平台">
<meta name=”Keywords” Content="TrustieOpenSourceProject">
<meta name=”Keywords” Content="issue,bug,tracker,软件工程,课程实践">
<meta name=”Description” Content="持续构建协同、共享、可信的软件创建生态开源创作与软件生产相结合,支持大规模群体开展软件协同创新活动">
<meta name=”Keywords” Content=”trustie,trustieforge,forge,确实让创建更美好,协同开发平台″>
<meta name=”Keywords” Content=”TrustieOpenSourceProject″>
<meta name=”Keywords” Content=”issue,bug,tracker,软件工程,课程实践″>
<meta name=”Description” Content=持续构建协同、共享、可信的软件创建生态开源创作与软件生产相结合,支持大规模群体开展软件协同创新活动>
<meta name="theme-color" content="#000000">
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel=" stylesheet" type="text/css" href="%PUBLIC_URL%css/iconfont.css">
<link rel=" stylesheet" type="text/css" href="%PUBLIC_URL%css/edu-purge.css">
<link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/iconfont.css">
<link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/edu-purge.css">
<link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/editormd.min.css">
<link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/merge.css">
<%= htmlWebpackPlugin.tags.headTags %>
@ -20,6 +21,7 @@
<div id="root" class="page -layout-v -fit widthunit"></div>
<div id="picture_display" style="display: none;"></div>
<script src="%PUBLIC_URL%js/jquery-1.8.3.min.js"></script>
<script src="%PUBLIC_URL%js/js_min_all.js"></script>
<script src="%PUBLIC_URL%js/codemirror/codemirror.js"></script>
<script src="%PUBLIC_URL%js/editormd/editormd.min.js"></script>
<script src="%PUBLIC_URL%js/codemirror/merge/merge.js"></script>

View File

@ -60,12 +60,13 @@ body {
.ant-progress-textno {
color: #f5222d;
}
.CodeMirror pre.CodeMirror-line{
font-size: 16px!important;
}
/* md多空格 */
.markdown-body p {
margin:10px 0px!important;
font-size: 16px !important;
line-height: 2 !important;
white-space: pre-wrap;
}
@ -87,6 +88,10 @@ body {
border-left: 1px solid rgb(221, 221, 221);
/* 某些情况下被cm盖住了 */
z-index: 99;
padding:8px 8px 50px;
}
.editormd-preview .markdown-body{
padding:0px !important;
}
/* 图片点击放大的场景,隐藏图片链接 */

View File

@ -5,18 +5,11 @@ import zhCN from 'antd/lib/locale-provider/zh_CN';
import {
BrowserRouter as Router,
Route,
Switch,
Redirect
Switch
} from 'react-router-dom';
import axios from 'axios';
import LoginDialog from './modules/login/LoginDialog';
import Notcompletedysl from './modules/user/Notcompletedysl';
import Trialapplicationysl from './modules/login/Trialapplicationysl';
import Trialapplicationreview from './modules/user/Trialapplicationreview';
import AccountProfile from "./modules/user/AccountProfile";
import Accountnewprofile from './modules/user/Accountnewprofile';
import Certifiedprofessional from './modules/modals/Certifiedprofessional';
import 'babel-polyfill';
import Loading from './Loading'
import Loadable from 'react-loadable';
@ -24,8 +17,7 @@ import marked from './common/marked';
import moment from 'moment'
import { MuiThemeProvider, createMuiTheme } from 'material-ui/styles';
import history from './history';
import SiderBar from './forge/Component/SiderBar'
import { SnackbarHOC } from 'educoder'
import { initAxiosInterceptors } from './AppConfig'
@ -43,10 +35,15 @@ const theme = createMuiTheme({
},
});
//forge项目
// const Projects = Loadable({
// loader: () => import('./forge/Index'),
// loading: Loading,
// })
const Projects = Loadable({
loader: () => import('./forge/Index'),
loading: Loading,
})
//forge安全设置
const Security = Loadable({
loader: () => import('./forge/SecuritySetting/Index'),
loading: Loading,
})
//forge项目-devOps详情
const OpsDetail = Loadable({
loader: () => import('./forge/DevOps/opsDetail'),
@ -62,24 +59,34 @@ const Shixunnopage = Loadable({
loader: () => import('./modules/404/Shixunnopage'),
loading: Loading,
})
const ExchangeForums = Loadable({
loader: () => import("./exchange/index"),
loading: Loading,
});
// 新版论坛交流
const Forums = Loadable({
loader: () => import("./forums/Index"),
loading: Loading,
});
const Account = Loadable({
loader: () => import("./user_info/Index"),
loading: Loading,
});
//500页面
const http500 = Loadable({
loader: () => import('./modules/500/http500'),
loading: Loading,
})
const InfosIndex = Loadable({
loader: () => import('./forge/users/Index'),
loading: Loading,
})
// 组织
const OrganizeIndex = Loadable({
loader: () => import('./forge/Team/Index'),
loading: Loading,
})
const EducoderLogin = Loadable({
loader: () => import('./modules/login/EducoderLogin'),
loading: Loading,
})
const Search = Loadable({
loader: () => import('./modules/search/'),
loading: Loading,
})
const ProjectIndex = Loadable({
loader: () => import("./forge/Index"),
loading: Loading,
});
class App extends Component {
constructor(props) {
super(props);
@ -105,36 +112,9 @@ class App extends Component {
Addcoursestypes: false
})
};
ModalCancelsy = () => {
this.setState({
mydisplay: false,
})
window.location.href = "/";
};
ModalshowCancelsy = () => {
this.setState({
mydisplay: true,
})
};
disableVideoContextMenu = () => {
window.$("body").on("mousedown", "video", function (event) {
if (event.which === 3) {
window.$('video').bind('contextmenu', function () { return false; });
} else {
window.$('video').unbind('contextmenu');
}
});
}
componentDidMount() {
document.title = "loading...";
this.disableVideoContextMenu();
history.listen(() => {
this.forceUpdate();
const $ = window.$
$("html").animate({ scrollTop: $('html').scrollTop() - 0 })
});
initAxiosInterceptors(this.props);
this.getAppdata();
@ -212,47 +192,85 @@ class App extends Component {
};
render() {
const { mygetHelmetapi } = this.state;
let personal = mygetHelmetapi && mygetHelmetapi.personal;
return (
<Provider store={store}>
<ConfigProvider locale={zhCN}>
<MuiThemeProvider theme={theme}>
<LoginDialog {...this.props} {...this.state} Modifyloginvalue={() => this.Modifyloginvalue()}></LoginDialog>
<Router>
<SiderBar/>
<Router>
<Switch>
{/*项目*/}
<Route
path="/accounts/:login"
render={(props) => (
<Account {...this.props} {...this.state} {...props} />
)}
></Route>
{/* 论坛交流板块管理 */}
path={"/projects/:owner/:projectId/devops/:opsId/detail"}
render={
(props) => {
return (<OpsDetail {...this.props} {...props} {...this.state} />)
}
}>
</Route>
<Route
path="/forums/manage"
render={(props) => (
<ExchangeForums {...this.props} {...this.state} {...props} />
)}
></Route>
{/* 问吧、论坛交流 */}
path={"/settings"}
render={
(props) => {
return (<Security {...this.props} {...props} {...this.state} />)
}
}>
</Route>
{/*项目*/}
<Route
path="/forums"
render={(props) => (
<Forums {...this.props} {...this.state} {...props} />
)}
></Route>
path={"/projects"}
render={
(props) => {
return (<Projects {...this.props} {...props} {...this.state} />)
}
}>
</Route>
<Route
path="/register"
render={
(props) => {
return (<EducoderLogin {...this.props} {...props} {...this.state} />)
}
}
/>
{/*403*/}
<Route path="/403" component={Shixunauthority} />
<Route path="/500" component={http500} />
<Route path={"/organize"}
render={
(props) => {
return (<OrganizeIndex {...props} {...this.props} {...this.state} />)
}
}>
</Route>
{/*404*/}
<Route path="/nopage" component={Shixunnopage} />
<Redirect from="/projects" to="/nopage"/>
{/* 查询 */}
<Route path="/search" component={Search} />
{/* 个人主页 */}
<Route path="/users/:username"
render={
(props) => {
return (<InfosIndex {...this.props} {...this.state} />)
}
}></Route>
<Route exact path="/"
render={
(props) => (
<Forums {...this.props} {...this.state} {...props} />
personal && personal.length > 0 ?
<InfosIndex {...this.props} {...props} />
:
<ProjectIndex {...this.props} {...props} />
)
}
/>
<Route component={Shixunnopage} />
</Switch>
</Router>
</MuiThemeProvider>

View File

@ -2,19 +2,17 @@ import axios from 'axios';
import { requestProxy } from "./indexEduplus2RequestProxy";
import { broadcastChannelOnmessage, isDev, queryString } from 'educoder';
import { notification } from 'antd';
import cookie from 'react-cookies';
import './index.css';
let message501 = false;
import './index.css';
let message501 = false;
broadcastChannelOnmessage('refreshPage', () => {
window.location.reload()
window.location.reload();
})
function locationurl(list) {
if (window.location.port === "3007") {
} else {
window.location.href = list
if (window.location.port !== "3007") {
window.location.href = list
}
}
// TODO 开发期多个身份切换
@ -26,56 +24,22 @@ if (isDev) {
parsed = queryString.parse(_search);
}
debugType = window.location.search.indexOf('debug=t') !== -1 ? 'teacher' :
window.location.search.indexOf('debug=s') !== -1 ? 'student' :
window.location.search.indexOf('debug=a') !== -1 ? 'admin' : parsed.debug || 'admin'
}
function clearAllCookie() {
cookie.remove('_educoder_session', { path: '/' });
cookie.remove('autologin_trustie', { path: '/' });
setpostcookie()
}
clearAllCookie();
function setpostcookie() {
const str = window.location.pathname;
if (str.indexOf("/wxcode") !== -1) {
console.log("123")
cookie.remove('_educoder_session', { path: '/' });
cookie.remove('autologin_trustie', { path: '/' });
const _params = window.location.search;
if (_params) {
let _search = _params.split('?')[1];
let _educoder_sessions = _search.split('&')[0].split('=');
cookie.save('_educoder_session', _educoder_sessions[1], { domain: '.educoder.net', path: '/' });
let autologin_trusties = _search.split('&')[1].split('=');
cookie.save('autologin_trustie', autologin_trusties[1], { domain: '.educoder.net', path: '/' });
}
}
}
setpostcookie();
window.location.search.indexOf('debug=s') !== -1 ? 'student' :
window.location.search.indexOf('debug=a') !== -1 ? 'admin' : parsed.debug || 'admin'
}
window._debugType = debugType;
export function initAxiosInterceptors(props) {
initOnlineOfflineListener()
// TODO 避免重复的请求 https://github.com/axios/axios#cancellation
var
proxy = "http://localhost:3000"
proxy = "https://forum.trustie.net"
// 判断网络是否连接
initOnlineOfflineListener();
const requestMap = {};
window.setfalseInRequestMap = function (keyName) {
requestMap[keyName] = false;
}
var proxy = "https://testforgeplus.trustie.net";
//响应前的设置
axios.interceptors.request.use(
config => {
setpostcookie()
clearAllCookie()
if (config.url.indexOf(proxy) !== -1 || config.url.indexOf(':') !== -1) {
if(config.url.indexOf("http") !== -1) {
return config
}
requestProxy(config)
requestProxy(config);
let url = `/api${config.url}`;
if (`${config[0]}` !== `true`) {
@ -89,18 +53,12 @@ export function initAxiosInterceptors(props) {
} else {
config.url = url;
}
setpostcookie();
}
if (config.url.indexOf('update_file') === -1) {
requestMap[config.url] = true;
window.setTimeout("setfalseInRequestMap('" + config.url + "')", 900)
}
return config;
},
err => {
return Promise.reject(err);
});
});
axios.interceptors.response.use(function (response) {
if (response === undefined) {
@ -149,8 +107,6 @@ export function initAxiosInterceptors(props) {
message501 = false
}, 2000);
}
requestMap[response.config.url] = false;
setpostcookie();
return response;
}, function (error) {
return Promise.reject(error);

View File

@ -1,7 +1,4 @@
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import { Spin } from 'antd';
class Loading extends Component {
@ -12,21 +9,7 @@ class Loading extends Component {
}
render() {
// Loading
return (
<div className="App" style={{ minHeight: '800px', width: "100%" }}>
<style>
{
`
.margintop{
margin-top:20%;
}
`
}
</style>
<Spin size="large" className={"margintop"} />
</div>
);
return ""
}
}

View File

@ -1,32 +0,0 @@
import React, { PureComponent } from 'react';
function bytesToSize(bytes) {
if (bytes === 0) return '0 B';
let k = 1024,
sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
i = Math.floor(Math.log(bytes) / Math.log(k));
return (bytes / Math.pow(k, i)). toFixed(2) + ' ' + sizes[i];
}
class FileList extends PureComponent{
render(){
let { list , className } = this.props;
const listMap = list && list.map((item)=>{
return(
<li>
<i className="iconfont icon-fujian color-blue font-16 mr8"></i>
<a href={item.url} className="color-blue" target="_self">{item.filename}</a>
<span className="color-grey-9 ml10">{bytesToSize(`${item.filesize}`)}</span>
</li>
)
})
return(
<ul className={className}>
{ listMap }
</ul>
)
}
}
export default FileList;

View File

@ -1,343 +0,0 @@
import React, {Component} from 'react';
// import "antd/dist/antd.css";
import { getUrl } from 'educoder';
import './mdEditor.css';
require('codemirror/lib/codemirror.css');
let path = '/editormd/lib/'
path = getUrl("/editormd/lib/")
const $ = window.$;
// 保存数据
function md_add_data(k,mdu,d){
window.sessionStorage.setItem(k+mdu,d);
}
// 清空保存的数据
function md_clear_data(k,mdu,id){
window.sessionStorage.removeItem(k+mdu);
var id1 = "#e_tip_"+id;
var id2 = "#e_tips_"+id;
if(k == 'content'){
$(id2).html(" ");
}else{
$(id1).html(" ");
}
}
window.md_clear_data = md_clear_data
// editor 存在了jquery对象上应用不需要自己写md_rec_data方法了
function md_rec_data(k, mdu, id) {
if (window.sessionStorage.getItem(k + mdu) !== null) {
var editor = $("#e_tips_" + id).data('editor');
editor.setValue(window.sessionStorage.getItem(k + mdu));
// debugger;
// /shixuns/b5hjq9zm/challenges/3977/tab=3 setValue可能导致editor样式问题
md_clear_data(k, mdu, id);
}
}
window.md_rec_data = md_rec_data;
function md_elocalStorage(editor,mdu,id){
if (window.sessionStorage){
var oc = window.sessionStorage.getItem('content'+mdu);
if(oc !== null && oc != editor.getValue()){
console.log("#e_tips_"+id)
$("#e_tips_"+id).data('editor', editor);
var h = '您上次有已保存的数据,是否<a style="cursor: pointer;" class="link-color-blue" onclick="md_rec_data(\'content\',\''+ mdu + '\',\'' + id + '\')">恢复</a> ? / <a style="cursor: pointer;" class="link-color-blue" onclick="md_clear_data(\'content\',\''+ mdu + '\',\'' + id + '\')">不恢复</a>';
$("#e_tips_"+id).html(h);
}
setInterval(function() {
var d = new Date();
var h = d.getHours();
var m = d.getMinutes();
var s = d.getSeconds();
h = h < 10 ? '0' + h : h;
m = m < 10 ? '0' + m : m;
s = s < 10 ? '0' + s : s;
if(editor.getValue().trim() != ""){
md_add_data("content",mdu,editor.getValue());
var id1 = "#e_tip_"+id;
var id2 = "#e_tips_"+id;
var textStart = " 数据已于 "
var text = textStart + h + ':' + m + ':' + s +" 保存 ";
// 占位符
var oldHtml = $(id2).html();
if (oldHtml && oldHtml != ' ' && oldHtml.startsWith(textStart) == false) {
$(id2).html( oldHtml.split(' (')[0] + ` (${text})`);
} else {
$(id2).html(text);
}
// $(id2).html("");
}
},10000);
}else{
$("#e_tip_"+id).after('您的浏览器不支持localStorage.无法开启自动保存草稿服务,请升级浏览器!');
}
}
function create_editorMD(id, width, high, placeholder, imageUrl, callback, initValue,
onchange, watch, { noStorage, showNullButton, emoji }, that) {
// 还是出现了setting只有一份被共用的问题
var editorName = window.editormd(id, {
width: width,
height: high===undefined?400:high,
path: path, // "/editormd/lib/"
markdown : initValue,
dialogLockScreen: false,
watch:watch===undefined?true:watch,
syncScrolling: "single",
tex: true,
tocm: true,
emoji: !!emoji ,
taskList: true,
codeFold: true,
searchReplace: true,
htmlDecode: "style,script,iframe",
sequenceDiagram: true,
autoFocus: false,
// mine
toolbarIcons: function (mdEditor) {
let react_id = `react_${mdEditor.id}`;
const __that = window[react_id]
// Or return editormd.toolbarModes[name]; // full, simple, mini
// Using "||" set icons align right.
const icons = ["bold", "italic", "|", "list-ul", "list-ol", "|", "code", "code-block", "link", "|", "testIcon", "testIcon1", '|', "image", "table", '|', "watch", "clear"];
// 试卷处用到的填空题新增按钮
if (__that.props.showNullButton) {
icons.push('nullBtton')
}
return icons
},
toolbarCustomIcons: {
testIcon: "<a type=\"inline\" class=\"latex\" ><div class='zbg'></div></a>",
testIcon1: "<a type=\"latex\" class=\"latex\" ><div class='zbg_latex'></div></a>",
nullBtton: "<a type=\"nullBtton\" class='pr' title='增加填空'><div class='border-left'><span></span></div><span class='fillTip'>点击插入填空项</span><i class=\"iconfont icon-edit font-16\"></i></a>",
},
//这个配置在simple.html中并没有但是为了能够提交表单使用这个配置可以让构造出来的HTML代码直接在第二个隐藏的textarea域中方便post提交表单。
saveHTMLToTextarea: true,
// 用于增加自定义工具栏的功能可以直接插入HTML标签不使用默认的元素创建图标
dialogMaskOpacity: 0.6,
placeholder: placeholder,
imageUpload: true,
imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp", "JPG", "JPEG", "GIF", "PNG", "BMP", "WEBP"],
imageUploadURL: imageUrl,//url
onchange: onchange,
onload: function() {
let _id = this.id // 如果要使用this这里不能使用箭头函数
let _editorName = this;
let react_id = `react_${_editorName.id}`;
const __that = window[react_id]
// this.previewing();
// let _id = id;
$("#" + _id + " [type=\"latex\"]").bind("click", function () {
_editorName.cm.replaceSelection("```latex");
_editorName.cm.replaceSelection("\n");
_editorName.cm.replaceSelection("\n");
_editorName.cm.replaceSelection("```");
var __Cursor = _editorName.cm.getDoc().getCursor();
_editorName.cm.setCursor(__Cursor.line - 1, 0);
});
$("#" + _id + " [type=\"inline\"]").bind("click", function () {
_editorName.cm.replaceSelection("`$$$$`");
var __Cursor = _editorName.cm.getDoc().getCursor();
_editorName.cm.setCursor(__Cursor.line, __Cursor.ch - 3);
_editorName.cm.focus();
});
$("[type=\"inline\"]").attr("title", "行内公式");
$("[type=\"latex\"]").attr("title", "多行公式");
if (__that.props.showNullButton) {
const NULL_CH = '▁'
// const NULL_CH = ''
// const NULL_CH = '🈳'
$("#" + _id + " [type=\"nullBtton\"]").bind("click", function () {
_editorName.cm.replaceSelection(NULL_CH);
// var __Cursor = _editorName.cm.getDoc().getCursor();
// _editorName.cm.setCursor(__Cursor.line - 1, 0);
});
}
if (noStorage == true) {
} else {
md_elocalStorage(_editorName, `MDEditor__${_id}`, _id);
}
callback && callback(_editorName)
}
});
return editorName;
}
export default class MDEditor extends Component {
constructor(props) {
super(props)
this.state = {
initValue: ''
}
}
componentDidUpdate(prevProps, prevState) {
// 不能加,影响了试卷填空题
// if (this.props.initValue != prevProps.initValue) {
// this.answers_editormd.setValue(this.props.initValue)
// }
}
// react_mdEditor_
componentDidMount = () => {
const { mdID, initValue, placeholder, showNullButton} = this.props;
let _id = `mdEditor_${mdID}`
this.contentChanged = false;
const _placeholder = placeholder || "";
// amp;
// 编辑时要传memoId
const imageUrl = `/upload_with_markdown?container_id=${mdID || ''}&container_type=Memo`;
// 创建editorMd
let react_id = `react_${_id}`;
// 将实例存到了window
window[react_id] = this
const answers_editormd = create_editorMD(_id, '100%', this.props.height, _placeholder, imageUrl, (_editorName) => {
const __editorName = _editorName;
react_id = `react_${__editorName.id}`;
const that = window[react_id]
// 一个延迟的recreate或resize不加这段代码md初始化可能会出现样式问题
setTimeout(() => {
if (that.props.needRecreate == true) {
__editorName.recreate() // 注意 必须在setValue之前触发不然会清空
} else {
__editorName.resize()
}
console.log('timeout', __editorName.id)
__editorName.cm && __editorName.cm.refresh()
}, that.props.refreshTimeout || 500)
if (this.props.noSetValueOnInit) {
that.onEditorChange()
} else {
if (that.props.initValue != undefined && that.props.initValue != '') {
__editorName.setValue(that.props.initValue)
}
if (that.state.initValue) {
__editorName.setValue(that.state.initValue)
}
}
__editorName.cm.on("change", (_cm, changeObj) => {
that.contentChanged = true;
if (that.state.showError) {
that.setState({showError: false})
}
that.onEditorChange()
})
that.props.onCMBlur && __editorName.cm.on('blur', () => {
that.props.onCMBlur()
})
that.props.onCMBeforeChange && __editorName.cm.on('beforeChange', (cm,change) => {
that.props.onCMBeforeChange(cm,change)
})
that.answers_editormd = __editorName;
// 这里应该可以去掉了,方便调试加的
window[__editorName.id+'_'] = __editorName;
}, initValue, this.onEditorChange,this.props.watch, {
noStorage: this.props.noStorage,
showNullButton: this.props.showNullButton,
emoji: this.props.emoji
}, this);
}
// 用在form里时validate失败时出现一个红色边框
showError = () => {
this.setState({showError: true})
}
onEditorChange = () => {
if (!this.answers_editormd) return;
const val = this.answers_editormd.getValue();
//console.log('onEditorChange', this.props.id, val)
try {
this.props.onChange && this.props.onChange(val)
} catch(e) {
// http://localhost:3007/courses/1309/common_homeworks/6566/setting
// 从这个页面,跳转到编辑页面,再在编辑页面点击返回的时候,这里会报错
console.error('出错')
console.error(e)
}
}
resize = () => {
if (!this.answers_editormd) { // 还未初始化
return;
}
this.answers_editormd.resize()
this.answers_editormd.cm && this.answers_editormd.cm.refresh()
this.answers_editormd.cm.focus()
}
getValue = () => {
try {
return this.answers_editormd.getValue()
} catch (e) {
return ''
}
}
setValue = (val) => {
try {
this.answers_editormd.setValue(val)
} catch (e) {
// TODO 这里多实例的时候前一个实例的state会被后面这个覆盖 参考NewWork.js http://localhost:3007/courses/1309/homework/9300/edit/1
// 未初始化
this.setState({ initValue: val })
}
}
render() {
let {
showError
} = this.state;
let { mdID, className, noStorage, imageExpand } = this.props;
let _style = {}
if (showError) {
_style.border = '1px solid red'
}
return (
<React.Fragment>
<div className={`df ${className} ${imageExpand && 'editormd-image-click-expand' }`} >
{/* padding10-20 */}
<div className="edu-back-greyf5 radius4" id={`mdEditor_${mdID}`} style={{..._style}}>
<textarea style={{display: 'none'}} id={`mdEditors_${mdID}`} name="content"></textarea>
<div className="CodeMirror cm-s-defualt">
</div>
</div>
</div>
{
noStorage == true ? '' :
<div className={"fr rememberTip"}>
<p id={`e_tips_mdEditor_${mdID}`} className="edu-txt-right color-grey-cd font-12"> </p>
{/* {noStorage == true ? ' ' : <p id={`e_tips_mdEditor_${mdID}`} className="edu-txt-right color-grey-cd font-12"> </p>} */}
</div>
}
</React.Fragment>
)
}
}

View File

@ -11,11 +11,26 @@ export function getImageUrl(path) {
// https://www.educoder.net
// https://testbdweb.trustie.net
// const local = 'http://localhost:3000'
const local = 'https://testforgeplus.trustie.net/'
const local = 'https://testforgeplus.trustie.net';
if (isDev) {
return `${local}/${path}`
}
return `/${path}`;
return `${path}`;
}
export function getImage(path) {
// https://www.educoder.net
// https://testbdweb.trustie.net
// const local = 'http://localhost:3000'
const local = 'https://testforgeplus.trustie.net/';
if(path.indexOf("http://")===-1){
if (isDev) {
return `${local}/images/${path}`
}
return `/${path}`;
}else{
return path;
}
}
export function getcdnImageUrl(path) {
@ -147,28 +162,28 @@ export function getmyUrl(geturl) {
}
export function getUploadActionUrl(path, goTest) {
return `${getUrl()}/api/attachments.json?debug=${window._debugType || 'admin'}`;
return `${getUrl()}/api/attachments.json${isDev ?`${isDev ?`?debug=${window._debugType || 'admin'}` : ""}` : ""}`;
}
export function getUploadLogoActionUrl() {
return `${getUrl()}/api/resumes/logo.json?debug=${window._debugType || 'admin'}`;
return `${getUrl()}/api/resumes/logo.json${isDev ?`?debug=${window._debugType || 'admin'}` : ""}`;
}
export function getUploadActionUrltwo(id) {
return `${getUrlmys()}/api/shixuns/${id}/upload_data_sets.json?debug=${window._debugType || 'admin'}`
return `${getUrlmys()}/api/shixuns/${id}/upload_data_sets.json${isDev ?`?debug=${window._debugType || 'admin'}` : ""}`
}
export function getUploadActionUrlthree() {
return `${getUrlmys()}/api/jupyters/import_with_tpm.json?debug=${window._debugType || 'admin'}`
return `${getUrlmys()}/api/jupyters/import_with_tpm.json${isDev ?`?debug=${window._debugType || 'admin'}` : ""}`
}
export function getupload_git_file(id) {
return `${getUrlmys()}/api/shixuns/${id}/upload_git_file.json?debug=${window._debugType || 'admin'}`
return `${getUrlmys()}/api/shixuns/${id}/upload_git_file.json${isDev ?`?debug=${window._debugType || 'admin'}` : ""}`
}
export function getUploadActionUrlOfAuth(id) {
return `${getUrl()}/api/users/accounts/${id}/auth_attachment.json?debug=${window._debugType || 'admin'}`
return `${getUrl()}/api/users/accounts/${id}/auth_attachment.json${isDev ?`?debug=${window._debugType || 'admin'}` : ""}`
}
export function getRandomNumber(type) {

View File

@ -64,7 +64,7 @@ function CommentItem({
const commentAvatar = (author) => (
<img
className="item-flex flex-image"
src={author.image_url ? getImageUrl(`images/${author.image_url}`) : 'https://b-ssl.duitang.com/uploads/item/201511/13/20151113110434_kyReJ.jpeg'}
src={author.image_url ? getImageUrl(`/${author.image_url}`) : 'https://b-ssl.duitang.com/uploads/item/201511/13/20151113110434_kyReJ.jpeg'}
alt=""
/>
);

View File

@ -38,13 +38,11 @@ export const formatDelta = (deltas) => {
alt="${alt}"
/>
`;
// text = "<img src="+url+" width='60px' height='30px' onclick='' alt="+alt+"/>";
}
}
formatted.push(text);
});
console.log(formatted);
return formatted.join('');
}

View File

@ -4,7 +4,7 @@
export {
getUploadLogoActionUrl as getUploadLogoActionUrl,
getImageUrl as getImageUrl, getmyUrl as getmyUrl, getRandomNumber as getRandomNumber, getUrl as getUrl, publicSearchs as publicSearchs, getRandomcode as getRandomcode, getUrlmys as getUrlmys, getUrl2 as getUrl2, setImagesUrl as setImagesUrl
getImageUrl as getImageUrl,getImage as getImage, getmyUrl as getmyUrl, getRandomNumber as getRandomNumber, getUrl as getUrl, publicSearchs as publicSearchs, getRandomcode as getRandomcode, getUrlmys as getUrlmys, getUrl2 as getUrl2, setImagesUrl as setImagesUrl
, getUploadActionUrl as getUploadActionUrl, getUploadActionUrltwo as getUploadActionUrltwo, getUploadActionUrlthree as getUploadActionUrlthree, getUploadActionUrlOfAuth as getUploadActionUrlOfAuth
, getTaskUrlById as getTaskUrlById, TEST_HOST, htmlEncode as htmlEncode, getupload_git_file as getupload_git_file, getcdnImageUrl as getcdnImageUrl
} from './UrlTool';
@ -76,10 +76,4 @@ export { default as AliyunUploader } from './components/media/AliyunUploader'
export { default as ImageLayer2 } from './hooks/ImageLayer2'
// 外部
export { default as CBreadcrumb } from '../modules/courses/common/CBreadcrumb'
export { CNotificationHOC as CNotificationHOC } from '../modules/courses/common/CNotificationHOC'
export { default as ModalWrapper } from '../modules/courses/common/ModalWrapper'
export { default as NoneData } from '../modules/courses/coursesPublic/NoneData'
export { default as WordNumberTextarea } from '../modules/modals/WordNumberTextarea'

View File

@ -48,15 +48,15 @@ function buildToc(coll, k, level, ctx) {
});
ctx.push("</ul>")
}
ctx.push("</li>")
ctx.push("</li>");
k = buildToc(coll, k, level, ctx)
return k
}
export function getTocContent() {
buildToc(toc, 0, 0, ctx)
ctx.push("</ul>")
return ctx.join("")
buildToc(toc, 0, 0, ctx);
ctx.push("</ul>");
return ctx.join("");
}
const tokenizer = {
@ -157,7 +157,6 @@ renderer.heading = function (text, level, raw) {
})
return '<h' + level + ' id="' + anchor + '">' + text + '</h' + level + '>'
}
marked.setOptions({
silent: true,
smartypants: true,

View File

@ -1,269 +0,0 @@
.CodeMirror-scroll {
overflow: auto !important;
margin-bottom: -30px;
margin-right: -30px;
padding-bottom: 30px;
height: 100%;
outline: none;
position: relative;
}
a.white-btn.orange-btn:hover {
border: 1px solid #F06200;
color: #FFF !important;
}
.flex1 a.white-btn.orange-btn:hover {
border: 1px solid #F06200;
color: #FFF !important;
}
/*.challenge_nav li a{*/
/*color:#000 !important;*/
/*}*/
.questionli{
width: 95%;
margin-left: 37px;
}
#directory_file{
height:200px;
overflow-y:auto;
background:#f5f5f5;
padding:10px;
}
.directory_filepath{
width:120px;
text-align:left;
}
a{
text-decoration: none;
color: #05101a;
}
.repository_url_tippostion{
position: absolute;
left: 22%;
width: 500px;
top: 100%;
}
.top-black-trangleft {
display: block;
border-width: 8px;
position: absolute;
top: -16px;
/* right: 4px; */
border-style: dashed solid dashed dashed;
border-color: transparent transparent rgba(5,16,26,0.6) transparent;
font-size: 0;
line-height: 0;
}
#exercisememoMD .CodeMirror {
margin-top: 31px !important;
height: 370px !important;
/*width: 579px !important;*/
}
#exercisememoMD .editormd-preview {
top: 40px !important;
height: 370px !important;
width: 578px !important;
}
#exercisememoMD{
/*height: 700px !important;*/
}
#questioMD{
/*width: 95% !important;*/
height: 417px !important;
margin-left: 0% !important;
}
#questioMD .CodeMirror {
/*width: 550.5px !important;*/
margin-top: 31px !important;
height: 374px !important;
}
#questioMD .editormd-preview {
top: 40px !important;
height: 375px !important;
width: 550px !important;
}
#newquestioMD .CodeMirror {
/*width: 549px !important;*/
margin-top: 31px !important;
height: 364px !important;
}
#newquestioMD .editormd-preview {
top: 40px !important;
height: 364px !important;
width: 578px !important;
}
#challenge_choose_answer .CodeMirror {
margin-top: 31px !important;
height: 364px !important;
/*width: 578px !important;*/
}
#challenge_choose_answer .editormd-preview {
top: 40px !important;
height: 364px !important;
width: 578px !important;
}
#neweditanswer .CodeMirror {
margin-top: 31px !important;
height: 364px !important;
/*width: 549.5px !important;*/
}
#neweditanswer .editormd-preview {
top: 40px !important;
height: 364px !important;
width: 551px !important;
}
#repository_url_tip {
top: 30px !important;
left: 249px !important;
width: 292px !important;
}
#editanswers .CodeMirror{
/*width: 548px !important;*/
height: 358px !important;
margin-top: 30px !important;
}
#editanswers .editormd-preview{
width: 578px !important;
height: 358px !important;
}
#newquestioMDs .CodeMirror{
/*width: 510px !important;*/
height: 358px !important;
margin-top: 30px !important;
}
#newquestioMDs .editormd-preview{
width: 578px !important;
height: 358px !important;
}
.choose_names{
width: 80px;
margin-left: 20px;
}
#answerMD .CodeMirror{
/*width: 569px !important;*/
height: 600px !important;
margin-top: 30px !important;
}
#answerMD .editormd-preview{
width: 578px !important;
height: 600px !important;
}
#answerMD {
height: 600px !important;
}
.textareavalue{
width: 100%;
padding: 5px;
box-sizing: border-box;
}
.greyInput{
width: 107%;
}
.greyInpus{
width: 100%;
}
.pdr20{
padding-right:20px;
}
.winput-240-40s {
background-color: #F5F5F5;
}
.winput-240-40s:focus{
background-color: #fff;
}
.input-100-45{
background-color: #F5F5F5;
}
.input-100-45:focus{
background-color: #fff;
}
.wind100{
width:100% !important;
}
.color-bule-tip {
color: #5485f7 !important;
}
.martopf4{
margin-top:-4px;
}
.headdfgf{
display: block;
width: 100px;
height: 30px;
line-height: 30px;
float: left;
}
.color979797{
color: #979797 !important;
}
.border-left{
width: 0;
height: 0;
border-bottom: 6px solid transparent;
border-right: 6px solid #cccbcb;
border-top: 6px solid transparent;
position: absolute;
left: 30px;
top: 12px;
}
.border-left span{
display: block;
width: 0;
height: 0;
border-bottom: 6px solid transparent;
border-right: 6px solid #fff;
border-top: 6px solid transparent;
position: absolute;
left: 1px;
top: -6px;
z-index: 10;
}
.fillTip{
position: absolute;
left: 36px;
top: 2px;
width: 125px;
font-size: 12px;
display: block;
padding: 5px;
border: 1px solid #eaeaea;
border-radius: 5px;
box-sizing: border-box;
height: 32px;
line-height: 20px;
font-family: "微软雅黑","宋体";
}

View File

@ -1,46 +1,67 @@
import React, { useEffect, useRef, useMemo } from "react";
import "katex/dist/katex.min.css";
import { renderToString } from 'katex';
import marked, { getTocContent, cleanToc, getMathExpressions, resetMathExpressions } from "../common/marked";
import React, { useEffect, useRef, useMemo } from 'react'
import 'katex/dist/katex.min.css'
import marked, { getTocContent, cleanToc, getMathExpressions, resetMathExpressions } from '../common/marked';
import 'code-prettify'
import dompurify from 'dompurify';
import { renderToString } from 'katex'
const preRegex = /<pre[^>]*>/g
function _unescape(str) {
let div = document.createElement('div')
div.innerHTML = str
return div.childNodes.length === 0 ? "" : div.childNodes[0].nodeValue;
return div.childNodes.length === 0 ? "" : div.childNodes[0].nodeValue
}
export default ({ value = '', className, style = {} }) => {
let str = String(value)
export default ({
value = '',
className,
style = {},
url
}) => {
let str = String(value);
const html = useMemo(() => {
let rs = marked(str)
const math_expressions = getMathExpressions()
let rs = marked(str);
const math_expressions = getMathExpressions();
if (str.match(/\[TOC\]/)) {
rs = rs.replace("<p>[TOC]</p>", getTocContent())
cleanToc()
}
rs = rs.replace(/(__special_katext_id_\d+__)/g, (_match, capture) => {
const { type, expression } = math_expressions[capture]
return renderToString(_unescape(expression), { displayMode: type === 'block', throwOnError: false, output: 'html' })
return renderToString(_unescape(expression) || '', { displayMode: type === 'block', throwOnError: false, output: 'html' })
})
rs = rs.replace(/▁/g, "▁▁▁")
resetMathExpressions()
return rs
}, [str])
return dompurify.sanitize(rs)
}, [str]);
const el = useRef()
// #id
useEffect(()=>{
if(url && url.hash && html){
let u = url.hash;
if(u){
let id = decodeURIComponent(u.split("#")[1]);
let ele = document.getElementById(id);
if(ele){
window.scrollTo(0, ele.offsetTop + 120);
}
}
}
},[url,html])
const el = useRef();
function onAncherHandler(e) {
let target = e.target
let target = e.target;
if (target.tagName.toUpperCase() === 'A') {
let ancher = target.getAttribute('href')
if (ancher.startsWith('#')) {
let ancher = target.getAttribute('href');
if (ancher && ancher.startsWith('#')) {
e.preventDefault()
let viewEl = document.getElementById(ancher.replace('#', ''))
if (viewEl) {
viewEl.parentNode.scrollTop = viewEl.offsetTop
viewEl.scrollIntoView(true)
}
}
}
@ -61,6 +82,12 @@ export default ({ value = '', className, style = {} }) => {
}
}
}, [html, el.current, onAncherHandler])
return (<div ref={el} style={style} className={`${className ? className : ''} markdown-body`} dangerouslySetInnerHTML={{ __html: html }}></div>)
return (
<div
ref={el}
style={style}
className={`${className ? className : ''} markdown-body`}
dangerouslySetInnerHTML={{ __html: html }}
></div>
)
}

View File

@ -1,40 +0,0 @@
import React, { PureComponent } from 'react';
import { Popconfirm } from 'antd';
import './comment.css';
import RenderHtml from "../../components/render-html";
class CommentsItem extends PureComponent{
cancelEvent=()=>{}
render(){
const { username , time , content , id , admin , deleteReplyEvent } = this.props
// 当前用户是否是管理员或者版主true为有权限删除评论
const adminDelete = (
admin &&
<Popconfirm
title="确定删除这条评论?"
onConfirm={()=>deleteReplyEvent(id)}
onCancel={this.cancelEvent}
okText="确定"
cancelText="取消"
>
<a className="fr c_point color-grey-9">删除</a>
</Popconfirm>
)
return(
<React.Fragment>
<p className="mt3 mb10 clearfix">
<span className="color-grey3 font-16 mr20">{username}</span>
<span className="color-grey9">{time}</span>
{ adminDelete }
</p>
<RenderHtml className="forumsDetailHtml" value={content} />
</React.Fragment>
)
}
}
export default CommentsItem;

View File

@ -1,17 +0,0 @@
import React, { PureComponent } from 'react';
import { getImageUrl } from 'educoder';
import './comment.css';
class CommentsItemImg extends PureComponent{
render(){
const { image_url } = this.props
return(
<img alt="用户头像" src={getImageUrl(`images/${image_url}`)} width="64" height="64" className="radius mr20"></img>
)
}
}
export default CommentsItemImg;

View File

@ -1,72 +0,0 @@
import React, { Component } from 'react';
import MDEditor from '../../common/MDEditor';
import { Form , Button } from "antd";
import ItemImg from './CommentsItemImg'
import '../exchange.css'
import axios from 'axios';
class CommentsSend extends Component{
constructor(props){
super(props);
this.contentMdRef = React.createRef();
}
// 发送评论
handleSubmit=()=>{
this.props.form.validateFieldsAndScroll((err, values) => {
if(!err){
let { id , refresh } = this.props;
const url = `/memos/${id}/reply`;
axios.post(url,{
content:values.replyContent,
parent_id:id
}).then(result=>{
if(result){
this.contentMdRef.current.setValue(' ');
refresh();
}
}).catch(error=>{
})
}
})
}
render(){
const { getFieldDecorator } = this.props.form;
// 唯一键
const { unique , image_url } = this.props;
const imgWrap = (
image_url && <ItemImg image_url={image_url} ></ItemImg>
)
return(
<div className="df mt15">
{ imgWrap }
<div className="flex1">
<Form.Item label="" className="editorFromItem">
{getFieldDecorator('replyContent', {
rules: [{
required: true, message: '请输入评论内容',
},{
max: 5000 , message:'最大限制5000个字符'
}],
})(
<MDEditor ref={this.contentMdRef} placeholder="请输入评论内容最大限制5000字符" mdID={`replyContent${unique}`} refreshTimeout={1500}
className="CommentSendMD" height={150} watch={false} noStorage={true}></MDEditor>
)}
</Form.Item>
<p className="clearfix pb10 pt10">
<Button type="primary" onClick={this.handleSubmit} className="small-default-btn small-blue-btn fr">发送</Button>
</p>
</div>
</div>
)
}
}
const WrappedCommentsSendForm = Form.create({ name: 'CommentsSend' })(CommentsSend);
export default WrappedCommentsSendForm;

View File

@ -1,17 +0,0 @@
import React, { PureComponent } from 'react';
import './custom.css'
class Index extends PureComponent {
render() {
let { img_url , name ,hrefUrl} = this.props;
return (
<span {...this.props}>
<a target="_blank" rel="noopener noreferrer" href={hrefUrl} ><img alt="用户头像" src={img_url} className="radius custom-img"></img></a>
<a target="_blank" rel="noopener noreferrer" href={hrefUrl} ><span className="wrap-name">{name}</span></a>
</span>
)
}
}
export default Index;

View File

@ -1,34 +0,0 @@
/* 论坛主页 */
.custom-wrap{
display: flex;
align-items: center
}
.custom-wrap .wrap-name{
color:#333;
font-size: 16px;
}
.custom-wrap .custom-img{
width:36px;
height:36px;
margin-right: 8px;
}
/* 版块主页 */
.moderatorInfo{
width: 82px;
text-align: center;
display: flex;
flex-direction:column;
align-items: center;
margin:10px 2px 20px 2px;
}
.moderatorInfo .custom-img{
height: 48px;
width: 48px;
}
.moderatorInfo .wrap-name{
display: block;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
max-width: 80px;
}

View File

@ -1,15 +0,0 @@
import React, { PureComponent } from 'react';
import nodata from './images/nodata.png';
class Empty extends PureComponent{
render(){
return(
<div style={{textAlign:'center',fontSize:"20px"}}>
<img alt="暂无数据" src={nodata} style={{marginBottom:"20px"}}></img>
<p>暂无数据</p>
</div>
)
}
}
export default Empty;

View File

@ -1,164 +0,0 @@
import React, { Component } from 'react';
import { Menu, Dropdown , Pagination ,Spin} from 'antd';
import { Link } from 'react-router-dom'
import ExchangeItem from './ExchangeItem';
import ExchangeRight from './ExchangeRight'
import './exchange.css';
import Empty from './Empty'
import axios from 'axios';
class ExchangeIndex extends Component {
constructor(props){
super(props);
this.state={
// 热门话题
hottest_memos:undefined,
// 版主推荐
recommend_memos:undefined,
// 列表数据
memos:undefined,
// 列表总数量
memos_count:0,
// 板块导航
forum_sections:undefined,
page:1,
current_user:undefined,
// 默认一页数据
pageSize:15,
search:undefined,
//是否出现加载中的样式
loading:false
}
}
componentDidMount = () =>{
this.InitData();
}
// 数据加载
InitData=(page,search)=>{
let url = `/memos`;
axios.get((url),{params:{
page,search
}}).then((result)=>{
if(result){
this.setState({
loading:false,
hottest_memos:result.data.hottest_memos,
recommend_memos:result.data.recommend_memos,
forum_sections:result.data.forum_sections,
memos:result.data.memos,
memos_count:result.data.memos_count,
current_user:result.data.current_user
})
}
}).catch((error)=>{
})
}
// 搜索
searchEvent=(search)=>{
this.setState({
loading:true,
search,
page:1
})
this.InitData(0,search);
}
// 分页
changePageEvent = (pageNumber) =>{
this.setState({
page:pageNumber
})
const { search } = this.state;
this.InitData(pageNumber,search);
}
render(){
let { hottest_memos , recommend_memos , memos , memos_count , forum_sections , page , pageSize , current_user } = this.state;
// 板块导航dropdown显示内容
const menu = (
<div className="platePanel">
{
forum_sections && forum_sections.map(item => {
return(
<div className="plateItem">
<span className="plateItem_h"><Link to={`/forums/theme/${item.id}`}>{item.name}</Link></span>
<ul className="plateUl">
{
item.children_tags && item.children_tags.map(i=>{
return(<li><Link to={`/forums/theme/${i.id}`}>{i.title}</Link></li>)
})
}
</ul>
</div>
)
})
}
</div>
);
// 数据列表和暂无数据
const dataList = memos && memos.length > 0 ?
<ExchangeItem memos = {memos} {...this.props} {...this.state} refresh={this.InitData} current_user={current_user} page={page}/>
:
<div className="pt50 pb50"><Empty /></div>
return(
<div className="clearfix F_panel">
<div className="fl with76 pr20">
<div className="back-color-white">
<div className="f_left_head">
<ul>
<li className="active">
<a>论坛首页</a>
</li>
{ forum_sections &&
<li>
<Dropdown overlay={menu}>
<a>板块导航<i className="iconfont icon-xiajiantou font-16 ml10 color-dark-grey"></i></a>
</Dropdown>
</li>
}
</ul>
<ul>
<li><Link to='/forums/MyTopic'>我的话题</Link></li>
<li><Link to='/forums/MyEnshrine'>我的收藏</Link></li>
<li><Link to='/forums/MyInteresting'>我感兴趣的论坛</Link></li>
</ul>
</div>
<Spin spinning={this.state.loading} >
{ dataList }
</Spin>
</div>
{
memos_count > pageSize &&
<div className="pt30 pb50 edu-txt-center"><Pagination showQuickJumper current={page} total={memos_count} onChange={this.changePageEvent} pageSize={pageSize} /></div>
}
</div>
<ExchangeRight
{...this.props}
{...this.state}
searchEvent={this.searchEvent}
hottest_memos={hottest_memos}
recommend_memos={recommend_memos}
loading={this.setState.loading}
/>
</div>
)
}
}
export default ExchangeIndex;

View File

@ -1,198 +0,0 @@
import React, { Component, memo } from 'react';
import { Dropdown , Menu } from 'antd';
import {Link} from 'react-router-dom'
import { getImageUrl } from 'educoder';
import Tags from './TagComponent/Index';
import Infos from './InfoComponent/Index';
import Custom from './CustomComponent/Index';
import "./exchange.css"
import axios from 'axios';
class ExchangeItem extends Component {
// 右侧dropdown
InitItemMenu = (id,sticky,is_fine,memo_watched) => {
const { current_user , detail }= this.props;
if(current_user){
if(current_user.admin || current_user.banned_permission){
return(
<Dropdown className="fr c_point" overlay={ this.InitlistMenu(id,sticky,is_fine,memo_watched) } placement="bottomCenter">
<span className="addheight"></span>
</Dropdown>
)
}else if(detail){
return(
<span className="fr c_point color-blue" style={{lineHeight:'16px'}} onClick={()=>this.enShrineEvent(id,memo_watched)}>
{ memo_watched ? '取消收藏' : '收藏' }
</span>
)
}
}
}
// 右侧dropdown的选项
InitlistMenu = (id,sticky,is_fine,memo_watched) => (
<Menu className="edu-txt-center" style={{minWidth:"100px"}}>
<Menu.Item onClick={()=>this.topEvent(sticky,id)} > { sticky ? '取消置顶' : '置顶' } </Menu.Item>
<Menu.Item onClick={()=>this.bestEvent(is_fine,id)}> { is_fine ? '取消推荐' : '推荐' } </Menu.Item>
<Menu.Item onClick={()=>this.enShrineEvent(id,memo_watched)}> { memo_watched ? '取消收藏' : '收藏' } </Menu.Item>
<Menu.Item onClick={()=>this.editEvent(id)}> 编辑 </Menu.Item>
<Menu.Item onClick={()=>this.deleteEvent(id)}> 删除 </Menu.Item>
</Menu>
)
// 取消收藏+收藏
enShrineEvent=(id,memo_watched)=>{
const { refresh } = this.props;
const url = `/memos/${id}/watch_memo`;
// is_watch:1为添加关注
axios.post(url,{
is_watch:memo_watched ? 0 : 1
}).then((result)=>{
if(result){
this.props.showNotification(result.data.message);
refresh();
}
}).catch((error)=>{
})
}
// 取消置顶+置顶
topEvent = (sticky,id) =>{
const { refresh } = this.props;
const url =`/memos/${id}/set_top_or_down.json`;
axios.get(url,{params:{
sticky:sticky ? 0 : 1
}}).then((result)=>{
if(result){
// 调用父级方法刷新
this.props.showNotification(result.data.message);
refresh();
}
}).catch((error)=>{
})
}
// 取消推荐+推荐
bestEvent = (is_fine,id) =>{
const { refresh } = this.props;
const url =`/memos/${id}/is_fine.json`;
axios.post(url,{
is_fine:is_fine ? 0 : 1
}).then((result)=>{
if(result){
// 调用父级方法刷新
this.props.showNotification(result.data.message);
refresh();
}
}).catch((error)=>{
})
}
// 编辑
editEvent=(id)=>{
this.props.history.push(`/forums/${id}/edit`);
}
// 删除
deleteEvent = (id) =>{
this.props.confirm({
content: '确认删除帖子?',
onOk: () => {
const url =`/memos/${id}/destroy.json`;
axios.post(url).then((result)=>{
if(result){
if(result.data.status === 0){
this.props.showNotification(result.data.message);
const { page , refresh } = this.props;
if(page){
refresh(page);
}else{
this.props.history.push("/forums");
}
}
}
}).catch((error)=>{
})
},
onCancel() {
console.log('Cancel');
},
});
}
// 跳转页面
turnToEvent=(id,detail)=>{
{/*传了enshine就代表底部右侧操作按钮只有收藏或者取消收藏否则就是置顶、推荐等 */}
const { enShrine} = this.props;
if(enShrine){return}
if(detail!=true){
const w= window.open('about:blank');
w.location.href=`/forums/${id}`;
}
}
render(){
/**detail:true为详情否则为列表 */
const { memos , current_user , detail} = this.props;
console.log(memos)
const ListItem = memos && memos.map(item=>{
return(
<li>
<div>
<div className="tabulation_infos flex-align-top mb15 ">
<Tags bestClass={item.is_fine ? "mr15" : undefined } topClass={item.sticky ? "mr15" : undefined}></Tags>
<p onClick={()=>this.turnToEvent(item.id,detail)} className={ detail ? "exchangeItem-subject task-hide justify color_black" : "exchangeItem-subject task-hide justify c_point is_onclick" }>
{item.subject}
</p>
{/* 右侧的下拉操作菜单项:登录后才能有右侧信息 */}
{ current_user && this.InitItemMenu(item.id,item.sticky,item.is_fine,item.memo_watched) }
</div>
</div>
<div className="flex-align-center">
{/* 判断用户是否登录 */}
<Custom className="custom-wrap fl" hrefUrl={`/users/${item.user_login}`} img_url = {getImageUrl(`images/${item.image_url}`)} name={item.username}></Custom>
{ item.forum_section_title && <span className="sendPoint">发表在<Link className="color-blue c_point" to={`/forums/theme/${item.forum_section_id}`}>{item.forum_section_title}</Link></span> }
{ item.time && <span className="sendPoint">{item.time}</span> }
{
item.new_reply && item.new_reply.username &&
<span className="fl ml30 pl10 sendPoint">
<span className="color-grey-9 font-14">最新回复
<span className="color-grey-3">{item.new_reply.username}</span>
<span className="ml10 font-12">{item.new_reply.time}</span>
</span>
</span>
}
<span className="flex1"></span>
{/* 论坛首页和论坛详情公用,不同情况下左浮动或者有浮动 */}
<span className="fr">
<Infos className="icon-wrap" icon={"iconfont icon-liulan font-16"} count={item.viewed_count} />
<Infos className="icon-wrap" icon={"iconfont icon-dianzan font-16"} count={item.praises_count} />
<Infos className="icon-wrap" icon={"iconfont icon-pinglun font-16"} count={item.replies_count} />
</span>
</div>
</li>
)
})
return(
<div className="plateTabulation">
{ ListItem }
</div>
)
}
}
export default ExchangeItem;

View File

@ -1,68 +0,0 @@
import React, { PureComponent } from 'react';
import { Link } from "react-router-dom"
import { getImageUrl } from 'educoder';
import ExchangeRightSearch from './ExchangeRightSearch'
import './exchange.css'
class ExchangeRight extends PureComponent {
render(){
const { searchEvent , hottest_memos , recommend_memos , hideSearchPanel} = this.props;
// 热门话题
const hotList = hottest_memos && hottest_memos.length > 0 && (
<div className="bc-white mb20">
<p className="clearfix r_part_title">
<img src={getImageUrl("images/plate/hot.png")} width="13px" className="mr10 fl mt7" alt=""/>
<span className="color-grey3 font-16 fl">热门话题</span>
</p>
<ul className="r_part_list">
{
hottest_memos.map((apply)=>{
return(
<li><a target="_blank" href={`/forums/${apply.id}`}>{apply.subject}</a></li>
)
})
}
</ul>
</div>
)
// 版主推荐
const moderatorList = recommend_memos && recommend_memos.length > 0 && (
<div className="bc-white">
<p className="clearfix r_part_title">
<img src={getImageUrl("images/plate/point.png")} width="16px" className="mr10 fl mt7" alt=""/>
<span className="color-grey3 font-16 fl">版主推荐</span>
</p>
<ul className="r_part_list">
{
recommend_memos.map((apply)=>{
return(
<li><a target="_blank" href={`/forums/${apply.id}`}>{apply.subject}</a></li>
)
})
}
</ul>
</div>
)
return(
<div className="fl with24">
{
!hideSearchPanel && <ExchangeRightSearch {...this.props} {...this.state} searchEvent={searchEvent}></ExchangeRightSearch>
}
{/* 热门话题 */}
{hotList}
{/* 版主推荐 */}
{ moderatorList }
</div>
)
}
}
export default ExchangeRight;

View File

@ -1,64 +0,0 @@
import React, { Component } from 'react';
import { Input } from 'antd'
import { Link } from 'react-router-dom'
const Search = Input.Search;
class ExchangeRightSearch extends Component {
constructor(props) {
super(props)
this.state={
searchDefault:true
}
}
// 有关搜索部分
activeSearch =(e)=>{
this.props.searchEvent(e);
if(!e){
this.setState({
searchDefault:true
})
}
}
showSearchPanel = () =>{
this.setState({
searchDefault:false
})
}
render(){
let { searchDefault } = this.state;
const { current_user } = this.props;
const sendBtn =()=> {
if(current_user){
return(<Link to={'/forums/new'} className="send_btn">发布话题</Link>)
}else{
return(<a href="/login" className="send_btn">发布话题</a>)
}
}
return(
<div className="top_Operate">
{sendBtn()}
{
searchDefault ?
<Search
className="searchfrom"
placeholder="请输入您想搜索的内容"
size="large"
onSearch={this.showSearchPanel}
/>
:
<Search
className="searchfrom active"
placeholder="请输入您想搜索的内容"
size="large"
onSearch={this.activeSearch}
/>
}
</div>
)
}
}
export default ExchangeRightSearch;

View File

@ -1,19 +0,0 @@
import React, { PureComponent } from 'react';
class Index extends PureComponent {
render() {
const { icon , count = 0 , ...props } = this.props;
return (
<span {...props}>
<i className={icon}></i>
<span className={'span-text'}>
{count}
</span>
</span>
)
}
}
export default Index;

View File

@ -1,171 +0,0 @@
import React, { Component } from 'react';
import { Modal , Input , Table ,Pagination } from 'antd'
import './manage.css'
import '../exchange.css';
import axios from 'axios';
const Search = Input.Search;
class AddModeratorModal extends Component {
constructor(props){
super(props);
this.state={
data:undefined,
page:1,
user_name:undefined,
limit:10,
total:undefined,
selectedRowKeys:undefined
}
}
componentDidUpdate=(prevState)=>{
if(prevState.operationPlateId !== this.props.operationPlateId && this.props.visible){
this.setState({
user_name:undefined,
page:1
})
this.getTabData(undefined , 1);
}
}
getTabData=(user_name,page)=>{
const { operationPlateId } = this.props;
const url =`/forum_sections/${operationPlateId}/search_users.json`;
axios.get(url,{
params:{
user_name,
page
}
}).then(result=>{
if(result){
const user_lists = result.data.user_lists;
let array = [];
for(var i = 0;i<user_lists.length;i++){
array.push({
key:user_lists[i].id,
username:user_lists[i].username,
nickname:user_lists[i].nickname,
})
}
this.setState({
data:array,
limit:result.data.limit,
total:result.data.users_count
})
}
}).catch(error=>{
})
}
getSelectKeys=(selectedRowKeys,selectedRows)=>{
this.setState({
selectedRowKeys
})
}
// 搜索
searchEvent=(value)=>{
this.setState({
user_name:value,
page:1
})
this.getTabData(value,1);
}
// 翻页
changePageEvent=(page)=>{
const { user_name } = this.state;
this.setState({
page
})
this.getTabData(user_name,page);
}
// 取消
cancel=()=>{
const { hideAddBox }=this.props;
this.setState({
user_name:undefined,
page:1
})
hideAddBox();
}
// 确定
modalSave=()=>{
const { selectedRowKeys } = this.state;
console.log(selectedRowKeys);
const { plateId } = this.props.match.params;
const { operationPlateId , hideAddBox , getSubModerator } = this.props;
const url = `/forum_sections/${plateId}/add_users.json`;
axios.post(url,{
user_ids:selectedRowKeys,
children_section_id:operationPlateId
}).then(result=>{
if(result){
this.props.showNotification(result.data.message);
hideAddBox();
getSubModerator();
}
}).catch(error=>{
})
}
render(){
const { visible } = this.props;
let { data , total , page , limit } = this.state;
const rowSelection = {
onChange: (selectedRowKeys, selectedRows) => this.getSelectKeys(selectedRowKeys,selectedRows)
};
const columns = [{
title:"姓名",
dataIndex:"username"
},{
title:"昵称",
dataIndex:"nickname"
}];
return(
<Modal
keyboard={false}
title={"添加版主"}
visible={ visible }
closable={false}
footer={null}
destroyOnClose={true}
centered={true}
width="700px"
className="addPlateModal"
>
<div>
<div className="edu-txt-right clearfix mb20 pr30">
<div style={{width:"400px"}} className="fr">
<Search
placeholder="请输入用户名进行搜索"
enterButton="搜索"
onSearch={(value) => this.searchEvent(value)}
/>
</div>
</div>
<Table rowSelection={rowSelection} columns={columns} dataSource={data} size={"small"} pagination={false}/>
{
total && total > limit ?
<div className="edu-txt-center mt10">
<Pagination current={page} size={"small"} total={total} pageSize={limit} onChange={this.changePageEvent}></Pagination>
</div>:""
}
<div className="clearfix mt30 edu-txt-center">
<a className="task-btn mr30" onClick={this.cancel}>取消</a>
<a className="task-btn task-btn-orange" onClick={this.modalSave}>确定</a>
</div>
</div>
</Modal>
)
}
}
export default AddModeratorModal;

View File

@ -1,54 +0,0 @@
import React, { Component } from 'react';
import MenuWraps from '../MenuComponent/Menu';
import SendItem from './SubSendItem';
import CheckItem from './SubCheckItem'
import CheckReplyItem from './SubCheckReplyItem'
const menu_nav = [
{
name:"待审查帖子",
key:`checkPost`,
content:CheckItem
},
{
name:"待审查回复",
key:`checkReply`,
content:CheckReplyItem
},
{
name:"已发布的帖子",
key:`sendPost`,
content:SendItem
}
]
class CheckPublic extends Component {
constructor(props){
super(props);
this.state={
activeKey:undefined
}
}
changeTab=(activeKey)=>{
this.setState({
activeKey
})
}
render(){
return(
<div className="edu-back-white mb20">
<MenuWraps
{...this.props}
{...this.state}
className="plate-left-Menu moderatorMenu"
menu_nav={menu_nav}
defaultUrlKey={"checkPost"}
changeTab={this.changeTab}/>
</div>
)
}
}
export default CheckPublic;

View File

@ -1,40 +0,0 @@
import React, { Component } from 'react';
import {Link} from 'react-router-dom';
import { getImageUrl } from 'educoder';
import RenderHtml from "../../components/render-html";
import Customers from '../CustomComponent/Index'
import "./manage.css"
class ItemLeft extends Component {
render(){
// user_url,username , time , image_url :用户链接,用户名,时间,头像,
// memo_title , forum_title待审查帖子以及已发布帖子帖子名称发表的论坛名
// source_title , reply_content待审查回复帖子来源回复内容
//memo_id,forum_id,source_id 待审查帖子id发表在版块id,来源版块id
const {user_url,id, memo_id,username , time , image_url , memo_title , forum_title ,source_title , reply_content,forum_id,source_id} = this.props;
const title_Url= id || memo_id;
return(
<div className="flex1">
<p className="flex-align-center mb15">
<Customers className="ItemsHeadPhoto flex-align-center" hrefUrl={user_url} img_url={getImageUrl(`images/${image_url}`)} name={username}></Customers>
<span className="sendPoint">{time}</span>
{ forum_title && <span className="sendPoint">发表在 <Link to={`/forums/theme/${forum_id}`}><span className="green">{forum_title}</span></Link></span> }
{ source_title && <span className="sendPoint">来源 <Link to={`/forums/theme/${source_id}`}><span className="green">{source_title}</span></Link></span> }
</p>
{ memo_title && <p><Link to={`/forums/${title_Url}`}>{memo_title}</Link></p>}
{
reply_content &&
<Link to={`/forums/${title_Url}/detail`}>
<RenderHtml className="reply_manage_content" value={reply_content} />
</Link>
}
</div>
)
}
}
export default ItemLeft;

View File

@ -1,87 +0,0 @@
import React, { Component } from 'react';
import { Dropdown } from 'antd';
import { Link } from 'react-router-dom';
import Nav from '../NavComponent/Index';
class ModeratorNav extends Component {
render(){
const { current_user , bread_crumb }=this.props;
const forum_tag = bread_crumb && bread_crumb.forum_tag;
const forum = bread_crumb && bread_crumb.forum;
// {
// name:current_user && current_user.username,
// url:`/users/${current_user && current_user.login}`
// },
const routerMap = [
{
name: forum && forum.title,
url:"/forums"
},
{
url:`/forums/theme/${forum_tag && forum_tag.id}`,
name:forum_tag && forum_tag.title
},
{
url:`/forums/theme/${forum_tag && forum_tag.children_bread_crumb && forum_tag.children_bread_crumb.id}`,
name:forum_tag && forum_tag.children_bread_crumb && forum_tag.children_bread_crumb.title
},{
name:"版主管理"
}
];
// 板块导航dropdown显示内容
const menu =(item)=> {
// console.log("item",item);
if(item){
return(
<div className="platePanel">
<div className="plateItem">
<ul className="plateUl ">
{
item.map((i,key)=>{
return(<li key={key}><Link to={`/forums/manage/${i.id}`}>{i.title}</Link></li>)
})
}
</ul>
</div>
</div>
)
}
}
const titleFlag = () => {
if (forum_tag ) {
console.log(forum_tag.children_bread_crumb);
if (bread_crumb && bread_crumb.is_children) {
return (<div className="padding20-30 edu-back-white font-22 mb20">{forum_tag.children_bread_crumb && forum_tag.children_bread_crumb.title}</div>)
} else {
return (
<div className="padding20-30 edu-back-white font-22 mb20">
{ forum_tag.children_bread_crumb ?
<Dropdown overlay={menu(forum_tag.children_bread_crumb) } >
<div>{forum_tag.title}<i className="iconfont icon-xiajiantou font-16 ml10 color-dark-grey"></i></div>
</Dropdown>
:
<span>{forum_tag.title}</span>
}
</div>
)
}
}
}
return(
<div>
<Nav className="mt20 mb30" NavMap = {routerMap} ></Nav>
{titleFlag()}
</div>
)
}
}
export default ModeratorNav;

View File

@ -1,35 +0,0 @@
import React, { Component } from 'react';
import '../exchange.css';
import './manage.css';
import axios from 'axios'
class PassItem extends Component {
passEvent=(checked)=>{
const { id , refresh ,page } = this.props;
const url = `/memos/${id}/memo_hidden`;
axios.post(url,{
checked
}).then((result)=>{
if(result){
this.props.showNotification(result.data.message);
refresh(page);
}
})
}
render(){
return(
<p className="ml50">
<span className="middle-default-btn small-blue-btn c_point" onClick={()=>this.passEvent(true)}>通过</span>
<span className="middle-default-btn ml20 c_point" onClick={()=>this.passEvent(false)}>不通过</span>
</p>
)
}
}
export default PassItem;

View File

@ -1,122 +0,0 @@
import React, { Component } from 'react';
import { getImageUrl } from 'educoder';
import axios from 'axios';
import './manage.css'
import { Link } from 'react-router-dom';
class PreApplyPlate extends Component {
constructor(props){
super(props);
this.state={
applylist:undefined
}
}
componentDidMount=()=>{
const { plateId } = this.props.match.params;
this.getApplyInfo(plateId);
}
getApplyInfo=(id)=>{
const url=`/forum_sections/${id}/applied_forums`;
axios.get(url).then((result)=>{
if(result){
this.setState({
applylist:result.data.applied_moderators
})
}
}).catch(error=>{
})
}
// 通过,拒绝
passApplyEvent=(flag,applyId)=>{
this.props.confirm({
content: `确认${flag?"通过":"拒绝"}版主申请?`,
onOk: () => {
const { plateId } = this.props.match.params;
const url = `/forum_sections/${plateId}/deal_applies/${applyId}`
axios.post(url,{
deal_type:flag?1:2
}).then((result)=>{
if(result){
this.props.showNotification(result.data.message);
this.getApplyInfo(plateId);
}
}).catch((error)=>{
})
},
onCancel() {
console.log('Cancel');
}
})
}
render(){
const { applylist } = this.state;
// const applylist = [
// {
// apply_id: 5,
// username: "OpenGCC",
// login: "innov",
// image_url: "avatars/User/girl.jpg",
// user_url: "/users/innov",
// user_ip: null,
// user_ip_address: "--",
// time: "14小时前",
// forum_title: "MAC安全",
// forum_id: 9,
// forum_url: "/memos/forum_memos/9",
// parent_forum: {
// forum_title: "网络安全网络安全333",
// forum_id: 6,
// forum_url: "/memos/forum_memos/6"
// }
// }
// ]
const listItem= () => {
if(applylist && applylist.length > 0){
return(
<div className="mt20">
<p className="font-16 mb15 color-grey3">版主申请</p>
<div className="applyList">
{ applylist.map((item,key)=>{
return(
<div>
<a href={`/users/${item.login}`} > <img alt="用户头像" src={getImageUrl(`images/${item.image_url}`)} width="36" height="36" className="radius mr15"></img></a>
<div className="flex1">
<p className="mb10">
<a href={`/users/${item.login}`} > <span className="color-blue mr15">{item.username}</span></a>
{ item.user_ip && <span className="color-grey9">IP{item.user_ip}{item.user_ip_address}</span> }
</p>
<p>申请成为<Link to={`/forums/theme/${item.forum_id}`}><span className="color-blue">{item.forum_title}</span></Link></p>
</div>
<div className="edu-txt-right">
<p className="color-grey9 mb10">{item.time}</p>
<p>
<span className="middle-default-btn small-blue-btn c_point" onClick={()=>this.passApplyEvent(true,item.apply_id)}>通过</span>
<span className="middle-default-btn ml20 c_point" onClick={()=>this.passApplyEvent(false,item.apply_id)}>拒绝</span>
</p>
</div>
</div>
)
})
}
</div>
</div>
)
}
}
return(
<React.Fragment>
{listItem()}
</React.Fragment>
)
}
}
export default PreApplyPlate;

View File

@ -1,88 +0,0 @@
import React, { Component } from 'react';
import { Modal , Form , Input } from 'antd';
import '../exchange.css';
import axios from 'axios';
class PreCreate extends Component {
componentDidUpdate=(preState)=>{
const { subId , subName } = this.props;
if(preState.subId !== subId){
if(subId){
this.props.form.setFieldsValue({
title:subName
})
}
}
}
// 确定
modalSave=()=>{
this.props.form.validateFieldsAndScroll((err, values) => {
if(!err){
// subId存在就是编辑否则就是新增
const { refresh , subId } = this.props;
const { plateId } = this.props.match.params;
const url = `/forum_sections${subId ? "/rename":""}.json`;
axios.post(url,{
title:values.title,
children_section_id:subId,
id: plateId
}).then((result)=>{
if(result){
refresh();
this.props.showNotification(result.data.message);
}
}).catch((error)=>{
})
}
})
}
modalCancel=()=>{
this.props.close();
}
render(){
const { getFieldDecorator } = this.props.form;
const { title , visible } = this.props
return(
<Modal
keyboard={false}
title={title}
visible={ visible }
closable={false}
footer={null}
destroyOnClose={true}
centered={true}
width="530px"
>
<div className="task-popup-content">
<Form className="formInline">
<Form.Item
label="标题"
>
{getFieldDecorator('title', {
rules: [{
required: true, message: '请输入板块名称',
},{
max: 5000 , message:'最大限制20个字符'
}],
})(
<Input placeholder="请输入名称最大限制20个字符" maxLength="60" style={{height:"40px"}}/>
)}
</Form.Item>
<div className="clearfix mt30 edu-txt-center">
<a className="task-btn mr30" onClick={this.modalCancel}>取消</a>
<a className="task-btn task-btn-orange" onClick={this.modalSave}>确定</a>
</div>
</Form>
</div>
</Modal>
)
}
}
const WrappedPreCreate = Form.create({ name: 'PreCreate' })(PreCreate);
export default WrappedPreCreate;

View File

@ -1,76 +0,0 @@
import React, { Component } from 'react';
import CheckPublic from './CheckPublic'
import ModeratorNav from './ModeratorNav';
import ApplyPlate from './PreApplyPlate';
import PrePlateManage from './PrePlateManage'
import axios from 'axios';
class PreModerator extends Component {
constructor(props){
super(props);
this.state={
activeKey:undefined,
bread_crumb:undefined,
is_children:false,
}
}
changeTab=(activeKey)=>{
this.setState({
activeKey
})
}
componentDidMount=()=>{
const { plateId } = this.props.match.params;
this.getPlateInfo(plateId);
}
componentDidUpdate=(prevState)=>{
let prePlateId = prevState.match.params.plateId;
const { plateId } = this.props.match.params;
if(prePlateId !== prePlateId){
this.getPlateInfo(plateId);
}
}
getPlateInfo=(plateId)=>{
const url = `/forum_sections/${plateId}/forum_section_header`;
axios.get(url).then((result)=>{
if(result){
this.setState({
bread_crumb:result.data.bread_crumb,
is_children:result.data.bread_crumb && result.data.bread_crumb.is_children
})
}
}).catch(error=>{
})
}
render(){
const { bread_crumb , is_children } = this.state;
const parentManage =()=> {
if(!is_children){
return(
<React.Fragment>
<PrePlateManage {...this.props} {...this.state} getPlateInfo={this.getPlateInfo}/>
{/* 板块申请 */}
<ApplyPlate {...this.props} {...this.state}/>
</React.Fragment>
)
}
}
return(
<div className="newMain">
<div className="educontent">
<ModeratorNav {...this.props} {...this.state}/>
{parentManage()}
{/* 审批(二级版主只有这一块) */}
<CheckPublic {...this.props} {...this.state} bread_crumb={bread_crumb}/>
</div>
</div>
)
}
}
export default PreModerator;

View File

@ -1,286 +0,0 @@
import React, { Component } from 'react';
import { getImageUrl} from 'educoder';
import PreCreate from './PreCreate';
import './manage.css'
import '../exchange.css'
import {Link} from 'react-router-dom'
import axios from 'axios';
import update from 'immutability-helper'
import AddModeratorModal from './AddModeratorModal'
class PrePlateManage extends Component {
constructor(props){
super(props);
this.state={
visible:false,
children_tags:undefined,
subId:undefined,
subName:undefined,
// 新增版主有关
addVisible:undefined,
operationPlateId:undefined
}
}
componentDidMount=()=>{
this.getSubModerator();
}
// 获取所有二级板块
getSubModerator=()=>{
const { plateId } = this.props.match.params;
const url = `/forum_sections/${plateId}/managements`;
axios.get(url).then((result)=>{
if(result){
this.setState({
children_tags:result.data.forum_tag && result.data.forum_tag.children_tags
})
}
}).catch((error)=>{
})
}
// 新建板块和重命名板块后的刷新方法
reSetInfo=()=>{
this.setState({
visible:false,
subId:undefined,
subName:undefined
})
this.getSubModerator();
const { plateId } = this.props.match.params;
const { getPlateInfo } = this.props;
getPlateInfo(plateId);
}
// 展开
expandEvent=(index,flag)=>{
this.setState(
(prevState) => ({
children_tags : update(prevState.children_tags, {[index]: { expand: {$set: flag} }}),
})
)
}
// 显示删除版主的按钮
deleteManageEvent=(index,flag)=>{
console.log(index)
this.setState(
(prevState) => ({
children_tags : update(prevState.children_tags, {[index]: { isDeleting: {$set: flag} }}),
})
)
}
// 新建二级板块
createSubPlateEvent=()=>{
this.setState({
visible:true,
subId:undefined,
subName:undefined
})
}
// 二级板块重命名
RenamneSubPlateEvent=(id,name)=>{
this.setState({
visible:true,
subId:id,
subName:name
})
}
// 删除二级板块
DeleteSubPlateEvent=(id)=>{
this.props.confirm({
content: '确认删除二级板块?',
onOk: () => {
const { plateId } = this.props.match.params;
const url=`/forum_sections/destroy_forum.json`
axios.post(url,{
children_section_id:id,
id: plateId
}).then(result=>{
if(result){
this.props.showNotification(result.data.message);
this.getSubModerator();
const { getPlateInfo } = this.props;
getPlateInfo(plateId);
}
}).catch((error)=>{
})
},
onCancel() {
console.log('Cancel');
}
})
}
// 关闭新建弹框
colseModalEvent=()=>{
this.setState({
visible:false
})
}
// 删除版主
deletePlateEvent=(id,name,index,key)=>{
console.log(index,'dddd',key);
this.props.confirm({
content: `是否确认解除“${name}”的二级版主权限?`,
onOk: () => {
const { plateId } = this.props.match.params;
const url=`/forum_sections/${plateId}/destroy_moderator/${id}`
axios.post(url).then(result=>{
if(result){
this.props.showNotification(result.data.message);
const { children_tags } = this.state;
// 去掉当前选中的版主
let tempObj = children_tags[index].forum_moderators;
tempObj = tempObj.filter((_, i) => i !== key) ;
children_tags[index].forum_moderators = tempObj;
this.setState({ children_tags })
}
}).catch((error)=>{
})
},
onCancel() {
console.log('Cancel');
}
})
}
// 新增版主弹框
showAddBox=(flag,plateId)=>{
this.setState({
addVisible:true,
operationPlateId:plateId
})
}
hideAddBox=()=>{
this.setState({
addVisible:false,
operationPlateId:undefined
})
}
render(){
const { visible ,children_tags , subId , subName , addVisible , operationPlateId } = this.state;
// console.log("child",children_tags);
const forumTagList = ()=>{
if(children_tags && children_tags.length>0){
return(
<div className="subPlateList">
{
children_tags.map((item,key)=>{
return(
<div>
<div className={item.expand ? "subPlateItem active":"subPlateItem"}>
<p className="subPlateItem_head">
<span>{item.title}</span>
<span>
<span className="c_point mr10 color-green font-12" onClick={()=>this.RenamneSubPlateEvent(item.id,item.title)}>重命名</span>
<span className="c_point color-grey-9 sendPoint pl10" onClick={()=>this.DeleteSubPlateEvent(item.id)}>删除板块</span>
</span>
</p>
<p className="mt10 mb10 color-grey3">二级版主</p>
<div className="plateManager">
{ renderSubList(item.forum_moderators,key,item.isDeleting) }
<span className="fr">
{/* 展开 */}
{
item.forum_moderators && item.forum_moderators.length > 5 && !item.expand &&
<span className="c_point mr30" onClick={()=>this.expandEvent(key,true)}><i className="iconfont icon-gengduo1 font-36 color-grey-9"></i></span>
}
{/* 收起 */}
{
item.forum_moderators && item.forum_moderators.length > 5 && item.expand &&
<span className="c_point mr30" onClick={()=>this.expandEvent(key,false)}><i className="iconfont icon-shangjiantou-tianchong font-36 color-grey-9"></i></span>
}
{/* 新增版主 */}
<span className="c_point mr30" onClick={()=>this.showAddBox(true,item.id)}><i className="iconfont icon-roundaddfill color-green font-36"></i></span>
{/* 删除版主 */}
{
item.forum_moderators && item.forum_moderators.length > 0 && !item.isDeleting &&
<span className="c_point mr30" onClick={()=>this.deleteManageEvent(key,true)}><i className="iconfont icon-default color-grey-9 font-36"></i></span>
}
{
item.isDeleting && <span className="c_point mr30 completeIcon" onClick={()=>this.deleteManageEvent(key,false)}>完成</span>
}
</span>
</div>
</div>
</div>
)
})
}
</div>
)
}
}
const renderSubList = (item,index,deletingFlag) =>{
if(item){
return(
<ul>
{
item.map((i,key)=>{
return(
<React.Fragment>
{
!i.isDelete &&
<li>
<a href={`/users/${i.login}`}><img alt="" src={getImageUrl(`images/${i.image_url}`)} width="39" height="39" className="radius mb3"/></a>
{
deletingFlag &&
<i className="iconfont icon-htmal5icon19 deletePlateIcon" onClick={()=>this.deletePlateEvent(`${i.moderator_id}`,`${i.username}`,index,key)}></i>
}
<a href={`/users/${i.login}`}><span className="task-hide" style={{width:"39px",display:"block"}}>{i.username}</span></a>
</li>
}
</React.Fragment>
)
})
}
</ul>
)
}
}
return(
<div>
<div className="padding20-30 edu-back-white font-22 mb20 clearfix">
<PreCreate
{...this.props}
{...this.state}
visible={visible}
title="新建"
refresh={this.reSetInfo}
close={this.colseModalEvent}
subId={subId}
subName={subName}
/>
<AddModeratorModal
{...this.props}
{...this.state}
visible = {addVisible}
operationPlateId={operationPlateId}
hideAddBox={this.hideAddBox}
getSubModerator={this.getSubModerator}
/>
<span className="fl color-grey3 font-16">二级板块管理</span>
<a onClick={this.createSubPlateEvent} className="fr middle-default-btn small-green-btn">新建板块</a>
</div>
{forumTagList()}
</div>
)
}
}
export default PrePlateManage;

View File

@ -1,146 +0,0 @@
import React, { Component } from 'react';
import { Spin , Pagination } from 'antd';
import '../exchange.css';
import './manage.css';
import Empty from '../Empty'
import ItemLeft from './ItemLeft';
import PassItem from './PassItem';
import axios from 'axios'
class SubCheckItem extends Component {
constructor(props){
super(props);
this.state={
page:1,
data:undefined,
isSpin:true,
limit:10
}
}
componentDidMount=()=>{
this.getList(1);
}
getList = (page) =>{
this.setState({
isSpin:true
})
const { plateId } = this.props.match.params;
const url = `/forum_sections/${plateId}/unchecked_memos.json`;
axios.get(url,{params:{
page
}}).then((result)=>{
if(result){
this.setState({
data:result.data,
isSpin:false
})
}
}).catch((error)=>{
})
}
// 禁言
stopEvent=(id,banned,user_id)=>{
const { current_user } = this.props;
const url =`/memos/${id}/banned_user.json`
axios.post((url),{
user_id:user_id,
banned
}).then((result)=>{
if(result){
const { page } = this.state;
this.props.showNotification(result.data.message);
this.getList(page);
}
}).catch((error)=>{
})
console.log("banned",banned);
}
// 分页
changePageEvent=(page)=>{
this.setState({
page
})
this.getList(page);
}
render(){
const { data , page , isSpin , limit } = this.state;
const { current_user } = this.props;
const pageCom = (
data && data.memos_count > limit &&
<div className="edu-txt-center pt30 pb30">
<Pagination showQuickJumper current={page} total={data.memos_count} pageSize={limit} onChange={this.changePageEvent}/>
</div>
)
const dataList = (
data && data.memos_lists && data.memos_lists.length > 0 ?
<div className="pl30 pr30">
{
data.memos_lists.map((item,key)=>{
const userInfo = {
forum_id:item.forum_id,
memo_id:item.memo_id,
user_url:item.user_url,
username:item.username,
time:item.time,
image_url:item.image_url,
memo_title:item.memo_title,
forum_title:item.forum_title,
user_id:item.user_id
}
const passItem = {
refresh:this.getList,
page,
id:item.memo_id
}
return(
<div className="moderatorItems">
<div className="df">
<ItemLeft {...userInfo}/>
<div className="flex-align-bottom between_">
{
current_user && current_user.admin &&
( item.is_banned ?
<p className="edu-txt-right color-red mb15 mt12 c_point" onClick={()=>this.stopEvent(item.memo_id,0,item.user_id)}><i className="iconfont icon-jinzhi font-16 mr10"></i></p>
:
<p className="edu-txt-right color-grey-9 mb15 mt12 c_point" onClick={()=>this.stopEvent(item.memo_id,1,item.user_id)}><i className="iconfont icon-jinzhi font-16 mr10"></i></p>
)
}
<PassItem {...this.props} {...this.state} {...passItem} ></PassItem>
</div>
</div>
</div>
)
})
}
{ pageCom }
</div>
:
<div className="edu-back-white pt50 pb50">
<Empty></Empty>
</div>
)
return(
<Spin spinning={isSpin}>
{ dataList }
</Spin>
)
}
}
export default SubCheckItem;

View File

@ -1,148 +0,0 @@
import React, { Component } from 'react';
import { Spin , Pagination } from 'antd';
import '../exchange.css';
import './manage.css';
import Empty from '../Empty'
import ItemLeft from './ItemLeft';
import PassItem from './PassItem';
import axios from 'axios'
class SubCheckReplyItem extends Component {
constructor(props){
super(props);
this.state={
page:1,
data:undefined,
isSpin:true,
limit:10
}
}
componentDidMount=()=>{
this.getList(1);
}
getList = (page) =>{
this.setState({
isSpin:true
})
const { plateId } = this.props.match.params;
const url = `/forum_sections/${plateId}/unchecked_replies.json`;
axios.get(url,{params:{
page
}}).then((result)=>{
if(result){
this.setState({
data:result.data,
isSpin:false
})
}
}).catch((error)=>{
})
}
// 禁言
stopEvent=(id,banned,user_id)=>{
const { current_user } = this.props;
const url =`/memos/${id}/banned_user.json`
axios.post((url),{
user_id:user_id,
banned
}).then((result)=>{
if(result){
const { page } = this.state;
this.props.showNotification(result.data.message);
this.getList(page);
}
}).catch((error)=>{
})
}
// 分页
changePageEvent=(page)=>{
this.setState({
page
})
this.getList(page);
}
render(){
const { data , page , isSpin , limit } = this.state;
const { current_user } = this.props;
const pageCom = (
data && data.memos_count > limit &&
<div className="edu-txt-center pt30 pb30">
<Pagination showQuickJumper current={page} total={data.memos_count} pageSize={limit} onChange={this.changePageEvent}/>
</div>
)
const dataList = (
data && data.replies_lists && data.replies_lists.length > 0 ?
<div className="pl30 pr30">
{
data.replies_lists.map((item,key)=>{
const userInfo = {
source_id:item.source_id,
user_url:item.user_url,
username:item.username,
time:item.time,
image_url:item.image_url,
reply_content:item.reply_content,
source_title:item.source_title,
user_id:item.user_id,
id:item.reply_id
}
const passItem = {
refresh:this.getList,
page,
id:item.reply_id
}
return(
<div className="moderatorItems">
<div className="df">
<ItemLeft {...userInfo}/>
<div className="flex-align-bottom between_">
{
current_user && current_user.admin &&
( item.is_banned ?
<p className="edu-txt-right color-red mb15 mt12 c_point" onClick={()=>this.stopEvent(item.reply_id,0,item.user_id)}><i className="iconfont icon-jinzhi font-16 mr10"></i></p>
:
<p className="edu-txt-right color-grey-9 mb15 mt12 c_point" onClick={()=>this.stopEvent(item.reply_id,1,item.user_id)}><i className="iconfont icon-jinzhi font-16 mr10"></i></p>
)
}
<PassItem {...this.props} {...this.state} {...passItem} ></PassItem>
</div>
</div>
</div>
)
})
}
{ pageCom }
</div>
:
<div className="edu-back-white pt50 pb50">
<Empty></Empty>
</div>
)
return(
<Spin spinning={isSpin}>
{ dataList }
</Spin>
)
}
}
export default SubCheckReplyItem;

View File

@ -1,174 +0,0 @@
import React, { Component } from 'react';
import { Spin , Pagination } from 'antd';
import Tags from '../TagComponent/Index';
import '../exchange.css';
import './manage.css';
import Empty from '../Empty'
import ItemLeft from './ItemLeft';
import PassItem from './PassItem';
import axios from 'axios'
class SubSendItem extends Component {
constructor(props){
super(props);
this.state={
page:1,
data:undefined,
isSpin:true,
limit:10
}
}
componentDidMount=()=>{
this.getList(1);
}
getList = (page) =>{
this.setState({
isSpin:true
})
const { plateId } = this.props.match.params;
const url = `/forum_sections/${plateId}/checked_memos.json`;
axios.get(url,{params:{
page
}}).then((result)=>{
if(result){
this.setState({
data:result.data,
isSpin:false
})
}
}).catch((error)=>{
})
}
// 删除-已发布的帖子
deleteEvent=(id)=>{
const { page } = this.state;
const url = `/memos/${id}/destroy.json`;
axios.post(url).then(result=>{
if(result){
this.props.showNotification(result.data.message);
this.getList(page);
}
}).catch(error=>{
})
}
// 取消推荐/推荐-已发布的帖子
isFineEvent=(id,flag)=>{
const { page } = this.state;
const url = `/memos/${id}/is_fine.json`;
axios.post(url,{
is_fine:flag ? 0 : 1
}).then(result=>{
if(result){
this.props.showNotification(result.data.message);
this.getList(page);
}
}).catch(error=>{
})
}
// 取消置顶/置顶-已发布的帖子
stickyEvent=(id,flag)=>{
const { page } = this.state;
const url = `/memos/${id}/set_top_or_down.json`;
axios.get(url,{params:{
sticky:flag ? 0 : 1
}}).then(result=>{
if(result){
this.props.showNotification(result.data.message);
this.getList(page);
}
}).catch(error=>{
})
}
// 禁言
stopEvent=(id,banned)=>{
const { current_user } = this.props;
const url =`/memos/${id}/banned_user.json`
axios.post((url),{
user_id:current_user && current_user.user_id,
banned
}).then((result)=>{
if(result){
const { page } = this.state;
this.props.showNotification(result.data.message);
this.getList(page);
}
}).catch((error)=>{
})
}
// 分页
changePageEvent=(page)=>{
this.setState({
page
})
this.getList(page);
}
render(){
const { data , page , isSpin , limit } = this.state;
const pageCom = (
data && data.memos_count > limit &&
<div className="edu-txt-center pt30 pb30">
<Pagination showQuickJumper current={page} total={data.memos_count} pageSize={limit} onChange={this.changePageEvent}/>
</div>
)
const dataList = (
data && data.memos_lists && data.memos_lists.length > 0 ?
<div className="pl30 pr30">
{
data.memos_lists.map((item,key)=>{
const userInfo = {
forum_id:item.forum_id,
memo_id:item.memo_id,
user_url:item.user_url,
username:item.username,
time:item.time,
image_url:item.image_url,
memo_title:item.memo_title,
forum_title:item.forum_title
}
return(
<div className="moderatorItems">
<div className="df">
<ItemLeft {...userInfo}/>
<div>
<p className="edu-txt-right color-red mb15 mt12" style={{height:"33px"}}>
<Tags bestClass={item.is_fine ? "mb5 ml15" : undefined} topClass={item.sticky ? "mb10 ml15" : undefined}></Tags>
</p>
<p className="ml50 color-grey-9">
<span className="c_point" onClick={()=>this.stickyEvent(item.memo_id,item.sticky)}>{item.sticky?"取消置顶":"置顶"}</span>
<span className="sendPoint c_point font-14" onClick={()=>this.isFineEvent(item.memo_id,item.is_fine)}>{item.is_fine?"取消推荐":"推荐"}</span>
<span className="sendPoint c_point font-14" onClick={()=>this.deleteEvent(item.memo_id)}>删除</span>
</p>
</div>
</div>
</div>
)
})
}
{ pageCom }
</div>
:
<div className="edu-back-white pt50 pb50">
<Empty></Empty>
</div>
)
return(
<Spin spinning={isSpin}>
{ dataList }
</Spin>
)
}
}
export default SubSendItem;

View File

@ -1,134 +0,0 @@
.moderatorMenu .ant-tabs-ink-bar{
display: none!important;
}
.moderatorItems{
padding:20px 0px;
border-bottom: 1px solid #eaeaea;
}
.moderatorItems:last-child{
border-bottom: none;
}
.ItemsHeadPhoto .custom-img{
width:36px;
height: 36px;
margin-right: 15px;
}
.reply_manage_content img{
width: 30px
}
/* 一级板块管理-版主申请 */
.applyList{
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between
}
.applyList > div{
background: #fff;
width: 585px;
display: flex;
padding:20px 30px;
box-sizing: border-box;
margin-bottom: 20px;
}
/* 表单form---标题和内容在统一行 */
.formInline .ant-row.ant-form-item{
display: flex
}
.formInline .ant-col.ant-form-item-control-wrapper{
flex: 1;
}
/* 二级板块管理 */
.subPlateList{
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content:space-between;
}
.subPlateList > div{
width:585px;
height: 180px;
background: #fff;
position: relative;
margin-bottom: 20px;
}
.subPlateList > div .subPlateItem{
position: absolute;
width: 100%;
left: 0px;
top:0px;
padding-left:30px;
box-sizing: border-box;
background: #fff;
}
.subPlateList > div .subPlateItem.active{
box-shadow: 0px 5px 26px rgba(0,0,0,0.1);
z-index: 1;
}
.subPlateItem_head{
display: flex;
justify-content: space-between;
height: 50px;
line-height: 50px;
border-bottom: 1px solid #f4f4f4;
margin-right: 30px;
}
.subPlateItem.active .plateManager > ul{
width: auto;
height: auto;
display: inline
}
.plateManager > ul{
display: inline-block;
width: 345px;
height: 60px;
overflow: hidden;
}
.font-36{font-size: 36px!important;}
.plateManager > ul > li{
display: flex;
flex-direction: column;
font-size: 12px;
align-items: center;
float: left;
margin-right: 30px;
text-align: center;
margin-bottom: 20px;
position: relative;
}
.deletePlateIcon{
position: absolute;
top: -11px;
right: -8px;
font-size: 18px;
color: #FF5555;
cursor: pointer;
}
.completeIcon{
background: #5091FF;
width: 36px;
height: 36px;
line-height: 36px;
font-size: 12px;
color: #fff;
text-align: center;
float: right;
border-radius: 50%;
margin-top: 18px;
}
/* 添加版主弹框 */
.addPlateModal .ant-modal-body{
padding:30px 0px!important;
}
/* .addPlateModal .ant-table-tbody > tr > td{
padding:10px 5px;
} */
/*禁言两端对齐*/
.between_{
flex-direction: column;
justify-content: space-between;
}

View File

@ -1,18 +0,0 @@
.plate-left-Menu .ant-tabs-tab{
height: 80px;
line-height: 80px;
font-size: 16px;
margin-left: 30px;
margin-right: 0px;
padding:0px;
}
.plate-left-Menu .ant-tabs-bar{
margin-bottom: 0px;
border-bottom: 1px solid #f4f4f4;
background: #fff;
}
.plate-left-Menu .ant-tabs-extra-content{
margin-top: 18px;
margin-right: 30px;
}

View File

@ -1,51 +0,0 @@
import React, { Component } from 'react';
import { Tabs } from 'antd';
import './Menu.css';
const { TabPane } = Tabs;
class MenuCom extends Component{
constructor(props){
super(props);
this.state={
activeKey: ''
}
}
componentDidMount () {
const { defaultUrlKey } = this.props;
this.setState({
activeKey: defaultUrlKey
})
}
changeTabs=(activeKey)=>{
this.setState({
activeKey:activeKey
})
const { changeTab } = this.props;
changeTab(activeKey);
}
render(){
const { menu_nav , btn , ...props } = this.props;
const tabs = menu_nav.map((tab)=>{
const Content = tab.content;
return(
<TabPane tab={tab.name} key={tab.key}>
<Content condition={tab.key} {...this.props} {...this.state}/>
</TabPane>
)
})
let { activeKey } = this.state;
return(
<Tabs { ...props } onChange={ this.changeTabs } activeKey={ activeKey } animated={false} tabBarExtraContent={ btn }>
{ tabs }
</Tabs>
)
}
}
export default MenuCom;

View File

@ -1,115 +0,0 @@
import React, { Component } from 'react';
import ExchangeRight from '../ExchangeRight'
import '../exchange.css';
import './myExchange.css';
import Nav from '../NavComponent/Index'
import MyTopic from './MyTopic';
import MyInteresting from './MyInteresting';
import MyEnshrine from './MyEnshrine';
import MenuWraps from '../MenuComponent/Menu'
import axios from 'axios';
const menu_nav = [
{
name:"我的话题",
key:`MyTopic`,
content:MyTopic
},
{
name:"我的收藏",
key:`MyEnshrine`,
content:MyEnshrine
},
{
name:"我感兴趣的论坛",
key:`MyInteresting`,
content:MyInteresting
}
]
class Index extends Component {
constructor(props){
super(props);
this.state={
activeKey:"MyTopic",
data:undefined
}
}
componentDidMount=()=>{
this.getMain();
}
getMain=()=>{
const url =`/my_memos/recommend_memos`;
axios.get(url).then(result=>{
if(result){
this.setState({
data:result.data
})
}
}).catch(error=>{
})
}
// 切换第一个nav
changeTab=(activeKey)=>{
// console.log('1--',activeKey);
this.setState({
activeKey
})
}
render(){
let pathname = this.props.location.pathname;
let urllength = pathname.split("/").length;
let urlLast = pathname.split("/")[urllength-1];
const { current_user } = this.props;
const { activeKey , data } = this.state;
const NavMap=[
{
url:current_user && current_user.user_url,
name:current_user && current_user.username
},
{
url:"/forums",
name:"论坛交流"
},
{
name:activeKey === "MyTopic" ? "我的话题" :activeKey === "MyEnshrine" ? "我的收藏" : "我感兴趣的论坛"
}
]
return(
<div className="educontent">
<Nav className="mt30" NavMap = {NavMap}></Nav>
<div className="clearfix F_panel" style={{marginTop:"10px"}}>
<div className="fl with76 pr20">
<div>
<MenuWraps
className="plate-left-Menu mainNav-style"
{...this.props}
{...this.state}
menu_nav={menu_nav}
defaultUrlKey={urlLast}
changeTab={this.changeTab}/>
</div>
</div>
<ExchangeRight
hideSearchPanel={true}
hottest_memos={data && data.hottest_memos}
recommend_memos={data && data.recommend_memos}
></ExchangeRight>
</div>
</div>
)
}
}
export default Index;

View File

@ -1,17 +0,0 @@
import React, { Component } from 'react';
import MyTopicItem from './MyTopicItem';
class MyEnshrine extends Component {
render(){
return(
<div>
<MyTopicItem {...this.props} {...this.state} urlName={'my_memos/my_watched'}></MyTopicItem>
</div>
)
}
}
export default MyEnshrine;

View File

@ -1,101 +0,0 @@
import React, { Component } from 'react';
import { Spin } from 'antd';
import { Link } from 'react-router-dom'
import Empty from '../Empty';
import './myExchange.css';
import box1 from '../images/box1.png';
import box2 from '../images/box2.png';
import box3 from '../images/box3.png';
import box4 from '../images/box4.png';
import box5 from '../images/box5.png';
import box6 from '../images/box6.png';
import axios from 'axios';
const backImgArray = [box1,box2,box3,box4,box5,box6];
class MyInteresting extends Component {
constructor(props){
super(props);
this.state={
forum_details:undefined,
isSpin:true
}
}
componentDidMount = () =>{
this.getInfo();
}
getInfo = () =>{
this.setState({
isSpin:true
})
const url = `/my_memos/my_interested`;
axios.get(url).then((result)=>{
if(result){
this.setState({
forum_details:result.data.forum_details,
isSpin:false
})
}
}).catch(error=>{
})
}
// 取消收藏
cancelEnshrineEvent=(id)=>{
const url = `/memos/forum_memos/${id}/is_watch.json`;
axios.post((url),{
is_watch:0
}).then(result=>{
if(result){
this.getInfo();
}
}).catch(error=>{
})
}
render(){
const { forum_details , isSpin } = this.state;
const divList = ( forum_details && forum_details.length > 0 ?
<div className="ForumList">
{
forum_details.map((item,key) => {
const index = Number(Number((key)%6)+1)-1;
// console.log(index);
return(
<div className="interestItem">
<div className="interestingUpper" style={{backgroundImage:`url(${backImgArray[index]})`}}>
<div>
<p className="font-20 color-white mb10">{item.title}</p>
<p className="color-white font-12 edu-txt-center">{item.memos_count} 个话题</p>
</div>
</div>
<span className="interestingOperate">
<span className="operateBtn c_point" onClick={()=>this.cancelEnshrineEvent(`${item.id}`)}>取消收藏</span>
<Link className="operateBtn color-blue" to={`/forums/theme/${item.id}`}>查看</Link>
</span>
</div>
)
})
}
</div>
:
<div className="pt50 pb50 edu-back-white"><Empty/></div>
)
return(
<Spin spinning={isSpin}>
<div style={{backgroundColor:"#fafafa"}}>
{ divList }
</div>
</Spin>
)
}
}
export default MyInteresting;

View File

@ -1,59 +0,0 @@
import React, { Component } from 'react';
import MenuWraps from '../MenuComponent/Menu';
import MyTopicItem from './MyTopicItem';
import './myExchange.css';
const menu_nav = [
{
name:"发表的话题",
key:`published`,
content:MyTopicItem
},
{
name:"回复的话题",
key:`replied`,
content:MyTopicItem
},
{
name:"看过的话题",
key:`watched`,
content:MyTopicItem
}
]
class MyTopic extends Component {
constructor(props){
super(props);
this.state={
activeKey:"published"
}
}
// 切换第2个nav发表的话题、回复的话题、看过的话题
changeTab=(activeKey)=>{
this.setState({
activeKey
})
}
render(){
let { activeKey } = this.state;
return(
<div>
<MenuWraps
{...this.props}
{...this.state}
className="plate-left-Menu"
subActiveKey={activeKey}
menu_nav={menu_nav}
defaultUrlKey={activeKey}
changeTab={this.changeTab}
urlName={'my_memos'}
/>
</div>
)
}
}
export default MyTopic;

View File

@ -1,239 +0,0 @@
import React, { Component } from 'react';
import { Dropdown , Menu , Icon , DatePicker , Pagination , Spin } from 'antd';
import { Link } from 'react-router-dom'
import moment from 'moment'
import Empty from '../Empty'
import ExchangeItems from '../ExchangeItem';
import './myExchange.css'
import '../exchange.css'
import axios from 'axios';
const { SubMenu } = Menu;
const dateFormat = 'YYYY-MM-DD';
class MyTopicItem extends Component {
constructor(props){
super(props);
this.state={
// 筛选条件
memo_type:undefined,
forum_section_id:undefined,
is_hidden:undefined,
is_hidden_name:undefined,
start_time:undefined,
end_time:undefined,
page:1,
plateName:undefined,
// 分页
pageSize:15,
// 数据
data:undefined,
isSpin:true
}
}
// 搜索
searchEvent=()=>{}
// 清除
clearEvent=()=>{}
componentDidMount=()=>{
this.refresh();
}
// 我的话题和我的收藏公用当前组件但接口不同根据url判断调用哪个接口
getMytopicInfo = (forum_section_id,is_hidden,start_time,end_time,page) =>{
this.setState({
isSpin:true
})
const { subActiveKey , urlName } = this.props;
const url = `/${urlName}`;
axios.get(url,{params:{
memo_type:subActiveKey,
forum_section_id,
is_hidden,
start_time,
end_time,
page
}}).then(result=>{
if(result){
this.setState({
data:result.data,
isSpin:false
})
}
}).catch(error=>{
})
}
// 刷新时需要用到
refresh=()=>{
const {forum_section_id,is_hidden,start_time,end_time } = this.state;
this.getMytopicInfo(forum_section_id,is_hidden,start_time,end_time,1);
}
// 切换分页
changePageEvent = (page) =>{
this.setState({
page
})
const {forum_section_id,is_hidden,start_time,end_time } = this.state;
this.getMytopicInfo(forum_section_id,is_hidden,start_time,end_time,page);
}
// 选择板块
changeForumId=(plateId,name)=>{
this.setState({
forum_section_id:plateId,
plateName:name
})
const {is_hidden,start_time,end_time , page } = this.state;
this.getMytopicInfo(plateId,is_hidden,start_time,end_time,page);
}
// 选择帖子状态
forumType=(type)=>{
this.setState({
is_hidden:type,
is_hidden_name:type === "show" ? "已发布的话题":"待审查的话题"
})
const {forum_section_id,start_time,end_time , page } = this.state;
this.getMytopicInfo(forum_section_id,type,start_time,end_time,page);
}
// 清除搜索条件
clearEvent=()=>{
this.setState({
forum_section_id:undefined,
plateName:undefined,
is_hidden:undefined,
is_hidden_name:undefined,
start_time:undefined,
end_time:undefined
})
this.getMytopicInfo(undefined,undefined,undefined,undefined,1);
}
// 选择开始时间
changeBeginEvent=(e,dateString)=>{
this.setState({
start_time:dateString
})
}
// 选择结束时间
changeEndEvent=(e,dateString)=>{
this.setState({
end_time:dateString
})
}
// 搜索
searchEvent=()=>{
this.setState({
page:1
})
const {forum_section_id,is_hidden,start_time,end_time } = this.state;
this.getMytopicInfo(forum_section_id , is_hidden , start_time , end_time , 1);
}
render(){
const { data , pageSize , page , plateName , is_hidden_name , start_time , end_time , isSpin } = this.state;
// 选择板块
const menuList =(
<div className="platePanel">
{
data && data.forum_sections && data.forum_sections.map(item => {
return(
<div className="plateItem">
<span className="plateItem_h"><a onClick={()=>this.changeForumId(item.id,item.name)}>{item.name}</a></span>
<ul className="plateUl">
{
item.children_tags && item.children_tags.map(i=>{
return(<li><a onClick={()=>this.changeForumId(i.id,i.title)}>{i.title}</a></li>)
})
}
</ul>
</div>
)
})
}
</div>
)
// 全部帖子
const forumList = (
<Menu>
<Menu.Item onClick={()=>this.forumType('hidden')}>待审查的话题</Menu.Item>
<Menu.Item onClick={()=>this.forumType('show')}>已发布的话题</Menu.Item>
</Menu>
)
const pagination = (
data && data.memos && data.memos_count > pageSize &&
<div className="edu-txt-center pt30 pb50">
<Pagination current={page} pageSize={pageSize} total={data.memos_count} showQuickJumper onChange={this.changePageEvent}></Pagination>
</div>
)
const dataList = (
<Spin spinning={isSpin}>
<div className="MyTopicSearch">
<Dropdown overlay={menuList}>
<a className="ant-dropdown-link">
{plateName || "选择板块"} <Icon type="down" />
</a>
</Dropdown>
<Dropdown overlay={forumList}>
<a className="ant-dropdown-link">
{ is_hidden_name || '全部帖子' } <Icon type="down" />
</a>
</Dropdown>
<div>
<span className="mr10">开始日期</span>
<DatePicker style={{width:"145px"}}
placeholder={'请选择开始时间'}
format={dateFormat}
value={start_time && moment(start_time,dateFormat)}
onChange={this.changeBeginEvent}
/>
<span className="ml15 mr10">结束日期</span>
<DatePicker style={{width:"145px"}}
placeholder={'请选择结束时间'}
format={dateFormat}
value={end_time && moment(end_time,dateFormat)}
onChange={this.changeEndEvent}
/>
</div>
<span className="df">
<a onClick={this.searchEvent} className="small-default-btn small-blue-btn mr15">搜索</a>
<a onClick={this.clearEvent} className="small-default-btn">清除</a>
</span>
<span className="color-grey9 font-12"><span className="color-blue">{ data && data.memos_count }</span></span>
</div>
{
data && data.memos && data.memos.length>0 ?
<div>
<ExchangeItems memos = { data && data.memos } {...this.props} {...this.state} refresh={this.refresh}></ExchangeItems>
{ pagination }
</div>
:
<div className="pt50 pb50 edu-back-white">
<Empty/>
</div>
}
</Spin>
)
return( dataList )
}
}
export default MyTopicItem;

View File

@ -1,56 +0,0 @@
.MyTopicSearch{
display: flex;
border-bottom: 1px solid #f4f4f4;
padding:20px 30px;
align-items: center;
justify-content: space-between;
background: #fff;
}
/* 我感兴趣的论坛 */
.ForumList{
display: flex;
flex-flow: row;
flex-wrap:wrap;
justify-content: space-between;
}
.interestItem{
width: 280px;
margin:20px 0px;
background: #FFFFFF;
}
.interestItem .interestingUpper{
height: 150px;
background-repeat:no-repeat;
background-size:100% 100%;
background-color:#fff ;
display: flex;
flex-flow: row;
align-items: center;
justify-content: center;
}
.interestingOperate{
display: flex;
height: 50px;
line-height: 50px;
}
.interestingOperate .operateBtn{
width: 50%;
display: block;
text-align: center;
position: relative;
color: #666666;
}
.interestingOperate .operateBtn:first-child::after{
height: 24px;
width:1px;
top:13px;
position: absolute;
right: 0px;
content: '';
background: #eee;
}
.mainNav-style > .ant-tabs-bar .ant-tabs-ink-bar{
display: none!important;
}

View File

@ -1,28 +0,0 @@
import React , { PureComponent } from "react";
import { Link } from 'react-router-dom';
import './nav.css'
class Index extends PureComponent{
render(){
const { NavMap , ...props } = this.props;
let navRouter = NavMap && NavMap.map((item) => {
return(
<React.Fragment>
{
item.name ? (item.url ?
<Link to={item.url} className="color-grey-9 nav_Link" >{ item.name }</Link>
:
<span className="color-grey3">{ item.name }</span>)
:""
}
</React.Fragment>
)
})
return(
<p {...props}>{ navRouter }</p>
)
}
}
export default Index;

View File

@ -1,13 +0,0 @@
.nav_Link{
position: relative;
margin-right: 20px;
}
.nav_Link::after{
position: absolute;
right: -15px;
content: '>';
top:0px;
color: #999;
height: 20px;
line-height: 18px;
}

View File

@ -1,36 +0,0 @@
import React, { PureComponent } from 'react';
import ExchangeItem from '../ExchangeItem'
import Empty from '../Empty'
import '../exchange.css'
import './plate.css'
class All extends PureComponent{
state = {
condition:"all"
}
componentDidMount = () =>{
const { condition } = this.props;
this.setState({
condition
})
}
render(){
const { memos } = this.props;
const memosList = (
memos && memos.length > 0 ?
<ExchangeItem memos={ memos } {...this.props} {...this.state}></ExchangeItem>
:
<div className="pt50 pb50">
<Empty/>
</div>
)
return(
memosList
)
}
}
export default All;

View File

@ -1,263 +0,0 @@
import React, { Component } from 'react';
import { Pagination , Spin } from 'antd'
import {Link} from 'react-router-dom'
import '../exchange.css';
import './plate.css'
import Nav from '../NavComponent/Index';
import MenuWraps from '../MenuComponent/Menu';
import PlateRight from './PlateRight'
import axios from 'axios';
import All from './All'
const menu_nav = [
{
name:"全部",
key:`all`,
content:All
},
{
name:"推荐精华",
key:`is_fine`,
content:All
},
{
name:"我的话题",
key:`my_memos`,
content:All
},
{
name:"我参与的话题",
key:`my_topics`,
content:All
}
]
class Index extends Component {
constructor(props){
super(props);
this.state = {
collectFlag:false,
// 列表搜索相关
page:1,
search:undefined,
pageSize:10,
select_type:"all",
memos:undefined,
memos_count:0,
// 接口返回的所有数据
data:undefined,
forum_tag :undefined,
forum_moders:undefined,
forum_sections:undefined,
bread_crumb:undefined,
current_user:undefined,
isSpin:true
}
}
componentDidMount () {
this.InitData();
}
InitData=()=>{
this.setState({
isSpin:true
})
const { plateid } = this.props.match.params;
const { page , search , select_type} = this.state;
this.getInfos(plateid , page , search , select_type);
}
getInfos = (plateid , page , search , select_type) =>{
const url= `/memos/forum_memos/${plateid}.json`;
axios.get(url,{params:{
page,
search,
select_type
}}).then(result=>{
if(result){
this.setState({
data:result.data,
memos:result.data.memos,
memos_count:result.data.memos_count,
collectFlag:result.data.watched,
forum_tag :result.data.bread_crumb && result.data.bread_crumb.forum_tag,
forum_moders:result.data.forum_moders,
forum_sections:result.data.forum_sections,
bread_crumb:result.data.bread_crumb,
current_user:result.data.current_user,
isSpin:false
})
}
}).catch(error=>{
})
}
// 点击收藏
colectPlate = () =>{
const { collectFlag } = this.state;
const { plateid } = this.props.match.params;
const url = `/memos/forum_memos/${plateid}/is_watch.json`;
// is_watch:1为添加关注
axios.post(url,{
is_watch: collectFlag ? 0 : 1
}).then((result)=>{
if(result){
if(result.data.status === 0){
this.setState({
collectFlag:!collectFlag
})
this.props.showNotification(result.data.message);
}
}
}).catch((error)=>{
})
}
// 搜索
searchEvent=(e)=>{
this.setState({
search:e
})
const { plateid } = this.props.match.params;
const { select_type } = this.state;
this.getInfos(plateid , 1 , e , select_type);
}
// 切换菜单项
changeTabEvent = (key) =>{
this.setState({
select_type:key,
isSpin:true
})
const { plateid } = this.props.match.params;
const { search} = this.state;
this.getInfos(plateid , 1 , search , key);
}
// 切换分页
changePageEvent=(pageNum)=>{
this.setState({
page:pageNum
})
const { plateid } = this.props.match.params;
const { search , select_type} = this.state;
this.getInfos(plateid , pageNum , search , select_type);
}
render(){
let {
title,
collectFlag ,
memos ,
forum_tag ,
select_type,
forum_moders ,
forum_sections ,
page,
data,
pageSize,
bread_crumb ,
current_user,
isSpin } = this.state;
const { plateid } = this.props.match.params;
let pathname = this.props.location.pathname;
let urlLastLength = pathname.split("/").length;
let urlLast = pathname.split("/")[urlLastLength-1];
const children_bread_crumb = forum_tag && forum_tag.children_bread_crumb;
//获取当前版块标题
const title_post=forum_tag && ((children_bread_crumb && children_bread_crumb.title) || forum_tag.title);
// 顶部导航栏
const routerMap = [
{
name:current_user && current_user.username,
url:current_user && current_user.user_url
},
{
name:bread_crumb && bread_crumb.forum && bread_crumb.forum.title,
url:"/forums"
},
{
name:forum_tag && ((children_bread_crumb && children_bread_crumb.title) || forum_tag.title)
}
];
let collectMap = current_user? <span className="mt2 collecting" onClick={() => this.colectPlate()}>{collectFlag ?'取消收藏':'收藏'}</span>:<span className="mt2 collecting" ><a href={`/login`}> </a> </span>;
// 菜单行右侧按钮
//只有登录管理员可见
const btn = (current_user && current_user.admin_permission) ?<Link to={`/forums/manage/${plateid}`} className={"color-grey-6"}>版块管理</Link> : undefined;
console.log(btn);
// 操作列表item需要刷新页面以及切换菜单项需要重新调用参数
const commonEvent = {
refresh:this.InitData,
changeTab:this.changeTabEvent
}
// 列表分页
const pageination = (
data && data.memos_count > pageSize &&
<div className="mb50 edu-txt-center">
<Pagination showQuickJumper current={page} total={data && data.memos_count} pageSize={pageSize} onChange={this.changePageEvent}/>
</div>
)
return(
<div className="clearfix educontent pt20">
<Spin spinning={isSpin}>
<Nav NavMap = {routerMap} ></Nav>
<p className="mt30 mb10 clearfix">
<span className="font-22 color-grey3 mr20 fl lineh-25 task-hide" style = {{ maxWidth : "900px"}}>{title_post}</span>
{ collectMap }
</p>
<div className="clearfix">
<div className="fl with76 pr20">
<div className={"edu-back-white mb30"}>
<MenuWraps
{...this.props}
{...this.state}
{...commonEvent}
className="plate-left-Menu"
menu_nav={menu_nav}
btn={btn}
defaultUrlKey={urlLast}
{...this.state}/>
</div>
{ pageination }
</div>
<PlateRight
forum_sections={forum_sections}
forum_moders={forum_moders}
searchEvent={this.searchEvent}
{...this.props}
{...this.state}
></PlateRight>
</div>
</Spin>
</div>
)
}
}
export default Index;

View File

@ -1,93 +0,0 @@
import React, { PureComponent } from 'react';
import { getImageUrl } from 'educoder';
import { Link } from 'react-router-dom';
import '../exchange.css';
import './plate.css'
import ExchangeRightSearch from '../ExchangeRightSearch'
import Custom from '../CustomComponent/Index';
import axios from 'axios';
class PlateRight extends PureComponent {
// 申请版主
applyModerator = () =>{
this.props.confirm({
content: '是否确认申请版主?',
onOk: () => {
const { plateid } = this.props.match.params;
const url = `/forum_sections/${plateid}/user_apply`;
axios.post(url).then(result=>{
if(result){
this.props.showNotification(result.data.message);
}
}).catch(error=>{
})
},
onCancel() {
console.log('Cancel');
},
});
}
render(){
const { forum_sections , forum_moders , searchEvent , current_user }= this.props;
// admin_permission:是否是版主
const moderatorInfo = ( forum_moders && forum_moders.length > 0 &&
<div className="bc-white mb20">
<p className="clearfix r_part_title">
<img src={getImageUrl("images/plate/person.png")} width="18px" className="mr10 fl mt7" alt=""/>
<span className="color-grey3 font-16 fl">版主</span>
{
current_user && current_user.admin_permission === false && <a onClick={this.applyModerator} className="applyBtn fr mt3">申请版主</a>
}
</p>
<div className="moderatorPanel">
{ forum_moders.map((item,key)=>{
return(
<Custom className="moderatorInfo" hrefUrl={`/users/${item.user_login}`} img_url={getImageUrl(`images/${item.image_url}`)} name={item.username}></Custom>
)
}) }
</div>
</div>
)
const choiceInfo = ( forum_sections && forum_sections.length > 0 &&
<div className="bc-white mb20">
<p className="clearfix r_part_title">
<img src={getImageUrl("images/plate/plate.png")} width="18px" className="mr10 fl mt7" alt=""/>
<span className="color-grey3 font-16 fl">精选版块</span>
</p>
<ul className="choicePlate">
{
forum_sections.map((item,key) => {
return(
<li className="clearfix">
<span className="fl"><a href={`/forums/theme/${item.id}`}>{item.title}</a></span>
<span className="fr"><a href={`/forums/theme/${item.id}`} className="color-blue">{item.memo_size}</a></span>
</li>
)
})
}
</ul>
</div>
)
return(
<div className="fl with24">
<ExchangeRightSearch {...this.props} {...this.state} searchEvent={searchEvent}></ExchangeRightSearch>
{ moderatorInfo }
{ choiceInfo }
</div>
)
}
}
export default PlateRight;

View File

@ -1,45 +0,0 @@
/* plate */
.collecting{
height: 22px;
padding:0px 11px;
border: 1px solid #5091FF;
color: #5091FF;
border-radius: 4px;
line-height: 22px;
font-size: 12px;
float: left;
cursor: pointer;
}
.collected{
color: #999999;
border:1px solid #999999;
}
.applyBtn{
border:1px solid #5091FF;
color: #5091FF;
height: 26px;
line-height: 26px;
padding:0px 8px;
border-radius: 4px;
}
/* 版主 */
.moderatorPanel{
display: flex;
flex-wrap:wrap;
padding: 10px 15px 0px;
}
/* 精选版块 */
.choicePlate{
padding:10px 20px 0px 20px;
}
.choicePlate > li{
padding: 10px 0px;
}
.searchForHide .ant-tabs-bar.ant-tabs-top-bar{
display: none;
}

View File

@ -1,155 +0,0 @@
import React, { PureComponent } from 'react';
import './post.css'
import Item from '../Comments/CommentsItem'
import ItemImg from '../Comments/CommentsItemImg'
import axios from 'axios';
import CommentsSend from '../Comments/CommentsSend';
class CommentsIndex extends PureComponent{
// 调用父组件的刷新方法
refreshReply=()=>{
let { refresh , page} = this.props;
refresh(page);
}
// 删除评论
deleteReplyEvent=(id)=>{
const url = `/memos/${id}/destroy.json`
axios.post(url).then((result)=>{
if(result){
this.props.showNotification(result.data.message);
this.refreshReply();
}
}).catch((error)=>{
})
}
commentReplyEvent=(index,flag)=>{
console.log("1",flag);
this.props.showCommentEvent(index,true);
}
// 点赞评论
praiseEvent=(id)=>{
const url = `/discusses/${id}/plus.json`;
axios.post(url,{
container_type:'Memo',
type:1
}).then(result=>{
if(result){
this.refreshReply();
}
}).catch(error=>{
})
}
parseCommentContent = (oldContent) => {
if (oldContent && oldContent.startsWith('<') && oldContent.endsWith('>')) {
} else if (window.$('#md_div').length) { // 有这个临时处理md内容的dom
window.$('#md_div').html('')
// markdown to html
try {
var markdwonParser = window.editormd.markdownToHTML("md_div", {
markdown: oldContent,
emoji: true,
htmlDecode: "style,script,iframe", // you can filter tags decode
taskList: true,
tex: true, // 默认不解析
flowChart: true, // 默认不解析
sequenceDiagram: true // 默认不解析
});
oldContent = window.$('#md_div').html()
} catch (e) {
// TODO 可能公式parse时报错了
console.error(e)
}
}
return oldContent;
}
render(){
// 评论列表,当前用户信息
const { repliesData , current_user , page } = this.props;
const renderNum = (arrs,flag) =>{
return(<p>展开其余1条评论</p>)
}
//二级评论
const renderChild = (arrs) => {
return(
<div className="">
{
arrs.map((child)=>{
return(
<div className="commentsItem_infos">
<ItemImg image_url={child.image_url} ></ItemImg>
<div className="flex1">
<Item image_url={child.image_url} username={child.username} time={child.time} content={child.content} id={child.id}></Item>
</div>
</div>
)
})
}
</div>
)
}
const replyInfoWrap = (i,index)=> (
<React.Fragment>
<p className="edu-txt-right color-grey-6">
<span className={ i.user_praise ? "ml30":"ml30 c_point"} onClick={ i.user_praise ? undefined : ()=>this.praiseEvent(i.id)}>
<i className={ i.user_praise ? "iconfont icon-dianzan color-grey-9 font-16 mr5" : "iconfont icon-dianzan-xian color-grey3 font-16 mr5"}></i>
<span>{i.praise_count}</span>
</span>
{
current_user && (current_user.is_banned === false || current_user.admin) &&
<span className="ml30 c_point" onClick={()=>this.commentReplyEvent(index,i.commentsFlag)}>
<i className="iconfont icon-pinglun color-grey-9 font-16 mr5"></i><span>{i.replies_count}</span>
</span>
}
</p>
{
i.commentsFlag &&
<CommentsSend unique={`sub_${i.id}`} id={i.id} image_url={current_user && current_user.image_url} refresh={this.refreshReply}/>
}
</React.Fragment>
)
// 判断是否是管理员或者版主
const manage = current_user && (current_user.admin || current_user.banned_permission);
const itemMap = repliesData && repliesData.map((i,index)=>{
let _content = this.parseCommentContent(i.content);
return(
<div className="pre_stage" key={index}>
<div className="commentsItem_infos">
<ItemImg image_url={i.image_url} ></ItemImg>
<div className="flex1">
<Item username={i.username} time={i.time} content={_content} id={i.id} admin={manage} deleteReplyEvent={this.deleteReplyEvent}></Item>
{
i.children && i.children.length > 0 &&
<div className="sub_stage">
{renderChild(i.children)}
{/* { i.children.length > 1 && renderNum(i.children)} */}
</div>
}
{replyInfoWrap(i,index)}
</div>
</div>
</div>
)
})
return( itemMap )
}
}
export default CommentsIndex;

View File

@ -1,128 +0,0 @@
import React, { Component } from 'react';
import moment from 'moment'
import Select, {Option, OptGroup} from 'rc-select';
import 'rc-select/assets/index.css';
import { Upload, Icon, Modal, message } from 'antd';
import 'antd/lib/upload/style/index.css'
import 'antd/lib/modal/style/index.css'
import 'antd/lib/style/index.css'
import 'antd/lib/message/style/index.css'
import './MemoNew.css'
// -------------------------------------------
let uploadValidateFailed = false;
function beforeUpload(file) {
const isJPG = file.type === 'image/jpeg';
const isPNG = file.type === 'image/png';
const isGIF = file.type === 'image/gif';
if (!isJPG && !isPNG && !isGIF) {
message.error('只能上传图片文件!(jpg、png或gif)');
uploadValidateFailed = true;
return false;
}
const isLt2M = (file.size / 1024 / 1024) < 2;
if (!isLt2M) {
uploadValidateFailed = true;
message.error('图片大小必须小于 2MB!');
return false;
}
uploadValidateFailed = false;
return true;
}
class ImageUpload extends Component {
state = {
previewVisible: false,
previewImage: '',
fileList: [
// {
// uid: -1,
// name: 'xxx.png',
// status: 'done',
// url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
// }
],
};
handleCancel = () => {
this.setState({ previewVisible: false })
}
handlePreview = (file) => {
this.setState({
previewImage: file.url || file.thumbUrl,
previewVisible: true,
});
}
handleRemove = () => {
const { onImageUploadRemove } = this.props;
onImageUploadRemove()
}
componentWillReceiveProps(newProps, oldProps) {
// 初始化值
if (newProps.fileList && this.props.fileList.length != newProps.fileList.length) {
this.setState({
fileList: newProps.fileList
})
}
}
handleChange = ({ fileList }) => {
const { onImageUploadDone } = this.props;
if (fileList.length && fileList[0].status === 'done') {
onImageUploadDone(fileList[0])
}
if (!uploadValidateFailed) {
this.setState({ fileList })
}
}
render() {
const { previewVisible, previewImage, fileList } = this.state;
const { currentMemoId } = this.props;
const uploadButton = (
<div className="antuploadName">
<div className="antIconName"><Icon type="plus" /></div>
<div className="ant-upload-text">点击上传封面</div>
<div className="ant-upload-text">只支持JPGPNGJPEG大小不超过2M</div>
<div className="ant-upload-text">建议尺寸4:3</div>
</div>
);
return (
<div className="clearfix">
<Upload
action={"http://123.59.135.93/upload_memo_heads"}
listType="picture-card"
fileList={fileList}
onPreview={this.handlePreview}
onChange={this.handleChange}
onRemove={this.handleRemove}
beforeUpload={beforeUpload}
data={{
container_type: 'Memo',
container_id: currentMemoId ? currentMemoId : ''
}}
>
{fileList.length >= 1 ? null : uploadButton}
</Upload>
<Modal visible={previewVisible} footer={null} onCancel={this.handleCancel}>
<img alt="example" style={{ width: '100%' }} src={previewImage} />
</Modal>
</div>
);
}
}
export default ImageUpload;

View File

@ -1,248 +0,0 @@
import React, { Component } from 'react';
import { Pagination , Spin } from 'antd';
import '../exchange.css'
import './post.css'
import Nav from '../NavComponent/Index'
import Parse from './Parse';
import ExchangeItem from '../ExchangeItem'
import CommentsIndex from './CommentsIndex';
import CommentsSend from '../Comments/CommentsSend';
import RenderHtml from "../../components/render-html";
import FileList from '../../common/FileList';
import update from 'immutability-helper'
import axios from 'axios';
class Index extends Component{
constructor(props){
super(props);
this.state={
// 当前用户是否点赞
judge:true,
parseNum:0,
// 帖子用户信息
author_info:undefined,
// 当前用户信息
current_user:undefined,
// 面包屑
bread_crumb:undefined,
// 当前帖子详情
memos:undefined,
// 帖子评论
repliesData:undefined,
// 帖子评论分页相关
replyPage:1,
replyPageSize:10,
replyCount:0,
is_Spin:true
}
}
componentDidMount = () =>{
this.getInfo();
}
getInfo=()=>{
this.InitDetailInfo();
this.getReply(1);
}
InitDetailInfo = ()=>{
let postid = this.props.match.params.postid;
const url = `/memos/${postid}.json`;
axios.get(url).then((result)=>{
if(result.data && result.data.status === -1){
this.props.history.push("/forums");
}
if(result){
this.setState({
judge:result.data.memo.user_praise,
parseNum:result.data.memo && result.data.memo.praises_count,
author_info:result.data.author_info,
current_user:result.data.current_user,
bread_crumb:result.data.bread_crumb,
memos:result.data.memo,
is_Spin:false
})
}
}).catch((error)=>{
})
}
getReply = (replyPage) =>{
let postid = this.props.match.params.postid;
const url = `/memos/${postid}/more_reply.json`;
axios.get(url,{params:{
page:replyPage
}}).then((result)=>{
if(result){
this.setState({
repliesData:result.data.memo_replies,
replyCount:result.data.memos_count,
is_Spin:false
})
}
}).catch((error)=>{
})
}
// 点赞
thumbForum = () =>{
let postid = this.props.match.params.postid;
const url = `/discusses/${postid}/plus.json`
axios.post(url,{
container_type:'Memo',
type:1
}).then((result)=>{
if(result){
this.InitDetailInfo();
}
}).catch((error)=>{
})
}
// 切换评论分页
changeReplyEvent=(pageNumber)=>{
this.setState({
replyPage:pageNumber
})
this.getReply(pageNumber);
}
// 点击显示评论输入框
commentReplyEvent=(index,flag)=>{
console.log("2",flag);
this.setState(
(prevState) => ({
repliesData : update(prevState.repliesData, {[index]: { commentsFlag: {$set: flag} }}),
})
)
}
// 删除评论
deleteReplyEvent=(id)=>{
const url = `/memos/${id}/destroy.json`
axios.post(url).then((result)=>{
if(result){
this.props.showNotification(result.data.message);
let{ replyPage } = this.state;
this.getReply(replyPage);
}
}).catch((error)=>{
})
}
render(){
let {
judge , parseNum , author_info , current_user , bread_crumb , memos , repliesData ,
replyPage,
replyPageSize,
replyCount,
is_Spin
} = this.state;
let postid = this.props.match.params.postid;
const NavMap=[
{
url:`/users/${current_user && current_user.login}`,
name:current_user && current_user.username
},
{
url:"/forums",
name:bread_crumb && bread_crumb.forum && bread_crumb.forum.title
},
{
url:`/forums/theme/${bread_crumb && bread_crumb.forum_tag && bread_crumb.forum_tag.id}`,
name:bread_crumb && bread_crumb.forum_tag && bread_crumb.forum_tag.title
},
{
name:"帖子详情"
}
]
//插入字段从author_info表内选取
const memos_list = [{
...memos,
image_url:author_info && author_info.image_url,
username:author_info && author_info.username,
user_login:author_info && author_info.login
}];
// 评论列表
const memo_replies = repliesData;
const repliesList = (
memo_replies && memo_replies.length > 0 &&
<div className="commentsForm">
<p className="replyTitle">
<span className="font-24 color-grey-3 mr20">全部回复</span>
<span className="color-grey9 font-20">{replyCount}</span>
</p>
<CommentsIndex {...this.props} {...this.state} refresh={this.getReply} page={replyPage} showCommentEvent={this.commentReplyEvent}></CommentsIndex>
</div>
)
// 附件显示
const fileListCom = ( memos && memos.attachment_url && <FileList list = { memos.attachment_url } className="fileTeam"></FileList> )
return(
<Spin spinning={is_Spin}>
<div className="educontent">
<Nav className="mt20 mb20" NavMap = {NavMap}></Nav>
<div className="educontent-min bc-white mb30">
{/* 调用和首页共用的列表item传了enshine就代表底部右侧操作按钮只有收藏或者取消收藏否则就是置顶、推荐等 */}
<ExchangeItem
{...this.props}
{...this.state}
memos={memos_list}
current_user = { current_user }
detail={true}
refresh={this.getInfo}
></ExchangeItem>
<div className="postContent">
{/* 帖子详情 */}
<RenderHtml className="postDetail" value={memos && memos.content} />
{/* 文件列表 */}
{ fileListCom }
{/* 点赞 */}
<div className="edu-txt-center pb40">
<Parse judge={!judge} current_user = { current_user } num = {parseNum} clickEvent = { this.thumbForum }></Parse>
</div>
{/* 发送评论部分 */}
{
current_user && (current_user.is_banned === false || current_user.admin) &&
<CommentsSend unique={`main_Send`} id={postid} refresh={()=>this.getReply(replyPage)}/>
}
{/* 评论列表 */}
{ repliesList }
</div>
</div>
{
replyCount && replyCount > replyPageSize ?
<div className="edu-txt-center mb50">
<Pagination showQuickJumper current={replyPage} pageSize={replyPageSize} total={replyCount} onChange={this.changeReplyEvent}></Pagination>
</div>:""
}
</div>
</Spin>
)
}
}
export default Index;

View File

@ -1,128 +0,0 @@
.compilegoback{
float:right;
color:#676767 !important;
cursor: pointer;
}
.compilegodell{
float:right;
margin-right:20px;
color:#dadada;
cursor: pointer;
}
.Releasethetitle{
height: 48px !important;
padding-left: 20px !important;
background:#f4f4f4 !important;
}
.Releasethetitle:focus{
background:#FFF !important;
}
.Releasethetitle::-webkit-input-placeholder{
color:#999999;
}
.Releasethetitle:-moz-placeholder{
color:#999999;
}
.Releasethetitle::-moz-placeholder{
color:#999999;
}
.Releasethetitle:-ms-input-placeholder{
color:#999999;
}
.ecSelectbox{
margin-top: 30px;
}
.ant-select-selection__placeholder{
color:#999999;
}
.antuploadName{
width: 280px;
height: 170px;
}
.antuploadName div:nth-child(2){
color:#999898;
font-size:16px;
}
.antuploadName div:nth-child(3){
margin-top: 10px;
color:#d2d2d2;
}
.antuploadName div:nth-child(4){
margin-top: 10px;
color:#d2d2d2;
}
.antIconName{
width: 30px;
height: 30px;
background: #21B351;
border: 1px solid #21B351;
border-radius: 50%;
color: #FFF;
text-align: center;
line-height: 25px;
margin: 40px auto 12px;
font-size: 20px;
position: relative;
}
.antIconName i{
position: absolute;
top: 4px;
left: 3.8px;
}
.ReleasTopic{
color:#333;
font-size:18px;
}
.ant-calendar-picker-input::-webkit-input-placeholder{
color:#999999;
}
.ant-calendar-picker-input:-moz-placeholder{
color:#999999;
}
.ant-calendar-picker-input::-moz-placeholder{
color:#999999;
}
.ant-calendar-picker-input:-ms-input-placeholder{
color:#999999;
}
.ml57{
margin-left:57px;
}
.newdefalutSubmitbtn{
width: 120px !important;
height: 38px !important;
line-height: 38px !important;
margin-top: -5px;
}
.newdefalutCancelbtn{
width: 120px !important;
height: 38px !important;
line-height: 38px !important;
margin-top: -5px;
border: 1px solid #CDCDCD;
}
.ecSelect{
background: #f4f4f4 !important;
padding-left: 4px !important;
height: 48px;
overflow: hidden;
width: 526px;
position: relative;
}
.newLeftgrey{
margin-left: 18px;
}
.uploadBtnclick{
margin-left: 34px;
}
.ant-select-selection--multiple{
height:100%;
border: 1px solid transparent;
}

View File

@ -1,811 +0,0 @@
import React, { Component } from 'react';
import axios from 'axios';
import { Select } from 'antd';
import 'antd/lib/select/style/index.css'
import 'antd/lib/date-picker/style/index.css'
import zhCN from 'antd/lib/date-picker/locale/zh_CN';
import './MemoNew.css'
import './post.css'
import '../exchange.css'
import ImageUpload from './ImageUpload'
const Option = Select.Option;
const $ = window.$;
const isDevServer = window.location.port === "3007";
let origin = window.location.origin;
let path = "/editormd/lib/" // origin + '/react/build/js/editormd/lib/'
if (isDevServer) {
origin = 'http://localhost:3000'
path = 'http://localhost:3000/editormd/lib/'
}
// load
if (!window.postUpMsg) {
$.getScript(
`${origin}/javascripts/attachments.js`,
(data, textStatus, jqxhr) => {
});
}
// editorMD to create
/**
*
* @param id 渲染DOM的id
* @param width 宽度
* @param high 高度
* @param placeholder
* @param imageUrl 上传图片的url
* @returns {*} 返回一个editorMD实例
*/
function create_editorMD(id, width, high, placeholder, imageUrl, callback){
var editorName = window.editormd(id, {
width : width,
height : high,
syncScrolling : "single",
//你的lib目录的路径我这边用JSP做测试的
path : path , // "/editormd/lib/"
tex : true,
tocm : true,
emoji : true,
taskList : true,
codeFold : true,
searchReplace : true,
htmlDecode : "style,script,iframe",
sequenceDiagram : true,
autoFocus: false,
toolbarIcons : function() {
// Or return editormd.toolbarModes[name]; // full, simple, mini
// Using "||" set icons align right.
return ["bold", "italic", "|", "list-ul", "list-ol", "|", "code", "code-block", "|", "testIcon", "testIcon1", '|', "image", "table", '|', "watch", "clear" ]
},
toolbarCustomIcons : {
testIcon : "<a type=\"inline\" class=\"latex\" ><div class='zbg'></div></a>",
testIcon1 : "<a type=\"latex\" class=\"latex\" ><div class='zbg_latex'></div></a>"
},
//这个配置在simple.html中并没有但是为了能够提交表单使用这个配置可以让构造出来的HTML代码直接在第二个隐藏的textarea域中方便post提交表单。
saveHTMLToTextarea : true,
// 用于增加自定义工具栏的功能可以直接插入HTML标签不使用默认的元素创建图标
dialogMaskOpacity : 0.6,
placeholder: placeholder,
imageUpload : true,
imageFormats : ["jpg", "jpeg", "gif", "png", "bmp", "webp", "JPG", "JPEG", "GIF", "PNG", "BMP", "WEBP"],
imageUploadURL : imageUrl,//url
onload: function(){
// this.previewing();
$("#"+ id +" [type=\"latex\"]").bind("click", function(){
editorName.cm.replaceSelection("```latex");
editorName.cm.replaceSelection("\n");
editorName.cm.replaceSelection("\n");
editorName.cm.replaceSelection("```");
var __Cursor = editorName.cm.getDoc().getCursor();
editorName.cm.setCursor(__Cursor.line-1, 0);
});
$("#"+ id +" [type=\"inline\"]").bind("click", function(){
editorName.cm.replaceSelection("$$$$");
var __Cursor = editorName.cm.getDoc().getCursor();
editorName.cm.setCursor(__Cursor.line, __Cursor.ch-2);
editorName.cm.focus();
});
$("[type=\"inline\"]").attr("title", "行内公式");
$("[type=\"latex\"]").attr("title", "多行公式");
callback && callback()
}
});
return editorName;
}
class MemoNew extends Component {
constructor(props) {
super(props)
this.state = {
memoSubject: '',
memoContent: '',
memoType: undefined,
memoTime: undefined,
memoRepertoire: '',
memoLanguage: [],
fileList: [],
memoSubjectLength:undefined,
repertoires: [],
currentSelectRepertoiresIndex: -1,
repertoiresTagMap: {},
// 主题板块
smallOption:undefined,
bigPlateId:undefined,
smallPlateId:undefined,
}
}
onCommit() {
const { memoSubject , memoLanguage, currentMemoId, attachmentData , bigPlateId , smallPlateId} = this.state;
const { showSnackbar } = this.props;
this.setState({
memoSubjectLength : memoSubject.length
})
if (!memoSubject) {
showSnackbar('请先输入标题')
return
}
let mdVal;
try {
mdVal = this.taskpass_editormd.getValue()
} catch (e) {
showSnackbar('编辑器还未加载完毕,请稍后')
return
}
if (!mdVal) {
showSnackbar('请输入话题内容')
return
}
if (!bigPlateId) {
showSnackbar('请选择一级板块');
return
}
/*
<meta content="authenticity_token" name="csrf-param" />
<meta content="G7peAyb1T37RvdwxnVUKmTXuL8T7FaBze5mK0j6MCKs=" name="csrf-token" />
http://localhost:3000/attachments/download/185790/Git-2.17.1.2-32-bit.exe
https://www.educoder.net/attachments/205112.js?attachment_id=1
*/
// collect attachments
const $ = window.$;
const attachmentsMap = {};
let lastIndex = 0;
$('#attachments_fields .attachment').each(( index, item ) => {
const filename = $(item).find('.upload_filename').val();
// $($('#attachments_fields .attachment')[0]).find('input:nth-child(6)').val()
const token = $(item).find('input:nth-child(6)').val()
const attachment_id = $(item).find('input:nth-child(7)').val()
attachmentsMap[index] = {
filename,
token,
attachment_id
}
lastIndex = index;
})
if (attachmentData) {
const { response } = attachmentData
lastIndex++;
attachmentsMap[lastIndex] = {
filename: attachmentData.name,
token: '',
attachment_id: response.attachment_id
}
}
if (currentMemoId) {
this.updateMemo(attachmentsMap)
} else {
this.newMemo(attachmentsMap)
}
}
onCancel() {
const { currentMemoId } = this.state;
if (currentMemoId) { // 编辑
this.props.history.push(`/forums/${currentMemoId}`)
} else { // 新建
this.props.history.push(`/forums`)
}
}
onOkTime(value, dateString){
this.setState({
memoTime:dateString
})
}
updateMemo(attachmentsMap) {
const { memoSubject , currentMemoId, content, attachmentData , smallPlateId , bigPlateId} = this.state;
const mdVal = this.taskpass_editormd.getValue()
console.log('isContentEdit: ', mdVal === content);
const newMemoUrl = `/memos/${currentMemoId}/update`
const params = {
content_changed: this.contentChanged,
memo: {
subject: memoSubject ,
content: mdVal,
},
forum_id:bigPlateId,
attachments: attachmentsMap,
children_forum_id:smallPlateId
}
if (attachmentData) {
const attachment_id = attachmentData.response.attachment_id
if (attachment_id) {
params.attachment_id = attachment_id;
}
}
axios.post(newMemoUrl, params)
.then((response) => {
const { status, message } = response.data;
if (status === 0) {
window.$("html,body").animate({"scrollTop":0})
this.props.history.push(`/forums/${currentMemoId}`)
} else {
if (message.indexOf("Couldn't find Attachment with") !== -1) {
this.props.showSnackbar('附件不存在或正在被删除中,请稍后再试。。。')
} else {
this.props.showSnackbar(message)
}
}
}).catch((error) => {
console.log(error)
})
}
newMemo(attachmentsMap) {
const { memoSubject , attachmentData , smallPlateId , bigPlateId } = this.state;
const mdVal = this.taskpass_editormd.getValue()
const newMemoUrl = `/memos/create`
const params = {
memo: {
subject: memoSubject ,
content: mdVal
},
forum_id:bigPlateId,
attachments: attachmentsMap,
children_forum_id:smallPlateId,
}
if (attachmentData) {
const attachment_id = attachmentData.response.attachment_id
if (attachment_id) {
params.attachment_id = attachment_id;
// params.filename = attachmentData.name // 服务端处理 服务端使用默认的origin_filename
}
}
axios.post(newMemoUrl, params).then((response) => {
const { status, message, memo_id } = response.data;
if (status === 0) {
window.$("html,body").animate({"scrollTop":0})
this.props.history.push(`/forums/${memo_id}`)
} else {
if (message.indexOf("Couldn't find Attachment with") !== -1) {
this.props.showSnackbar('附件不存在或正在被删除中,请稍后再试。。。')
} else {
this.props.showNotification(message)
}
}
}).catch((error) => {
console.log(error)
})
}
onMemoDelete(memo) {
const deleteUrl = `/memos/${memo.id}`;
// 获取memo list
axios.delete(deleteUrl, {
withCredentials: true,
})
.then((response) => {
const status = response.data.status
if (status === 0) {
this.props.showSnackbar('删除成功');
this.props.history.push(`/forums`)
}
}).catch((error) => {
console.log(error)
})
}
componentWillUnmount() {
$('body>#root').off('onMemoDelete')
}
componentDidMount(){
$('body>#root').on('onMemoDelete', (event) => {
// const val = $('body>#root').data('onMemoDelete')
const val = window.onMemoDelete ;
this.onMemoDelete( JSON.parse(decodeURIComponent(val)) )
})
const newMemoUrl = `/memos/new`
axios.get(newMemoUrl,{
// withCredentials: true,
})
.then((response) => {
const data = response.data;
if ( data.current_user ) {
this.setState({
memo_tag: data.memo_type,
memoTime:""
})
const user = response.data.current_user;
user.tidding_count = response.data.tidding_count;
// this.props.initCommonState(user)
// 初始化 csrf meta
const $ = window.$
$('head').append( $('<meta content="authenticity_token" name="csrf-param" />') )
$('head').append( $(`<meta content="${response.data.csrf_token}" name="csrf-token" />`) )
}
}).catch((error) => {
console.log(error)
})
// 如果是编辑
const { match } = this.props
const memoId = match.params.memoId;
if (memoId) {
const memoUrl = `/memos/${match.params.memoId}/edit`;
axios.get(memoUrl).then((response) => {
const current_user = response.data.current_user;
if (current_user) {
const { content, forum_section, id, subject , attachments_url, memo_image_info,
memo_type, published_at , children_forum_section} = response.data;
let date;
let date_value;
this.initMD(content, memoId);
if(published_at){
date = new Date(published_at);
date_value=date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate() + ' ' + date.getHours() + ':' + date.getMinutes() + ':' + date.getSeconds();
}
const newState = {
currentMemoId: id,
attachments_url,
memoSubject: subject,
memo_tag: memo_type,
memoLanguage: forum_section.forum_id,
memoTime:date_value,
content,
bigPlateId: forum_section.forum_id,
smallPlateId: children_forum_section.children_forum_id
}
// 编辑,初始化小板块的下拉选项(如果大板块有值)
this.getChildPlate(memo_type,forum_section && forum_section.forum_id);
if (memo_image_info && memo_image_info.id) {
newState.fileList = [{
uid: memo_image_info.id,
name: memo_image_info.filename,
status: 'done',
url: memo_image_info.url,
}]
newState.attachmentData = { // 初始化
name: memo_image_info.filename,
response: {
attachment_id: memo_image_info.id,
}
}
}
this.setState({...newState})
// 加载完后滚动条滚动
window.$("html,body").animate({"scrollTop":0})
// this.props.initForumState({
// current_user,
// tag_list
// })
}
}).catch((error) => {
console.log(error)
})
} else {
this.initMD();
}
}
initMD(initValue, memoId) {
this.contentChanged = false;
const placeholder = "";
// amp;
// 编辑时要传memoId
const imageUrl = `/upload_with_markdown?container_id=${memoId?memoId:''}&container_type=Memo`;
// 创建editorMd
setTimeout(()=>{
const taskpass_editormd = create_editorMD("memoMD", '100%', 400, placeholder, imageUrl, () => {
setTimeout(()=>{
taskpass_editormd.resize()
taskpass_editormd.cm && taskpass_editormd.cm.refresh()
}, 500)
if (initValue) {
taskpass_editormd.setValue(initValue)
}
taskpass_editormd.cm.on("change", (_cm, changeObj) =>{
console.log('....contentChanged')
this.contentChanged = true;
})
});
this.taskpass_editormd = taskpass_editormd;
window.taskpass_editormd = taskpass_editormd;
}, 300)
}
renderOptions(array) {
const elementArray = [];
array.forEach(( item, index ) => {
elementArray.push(
<Option key={index} value={item}>{item}</Option>
)
})
return elementArray
}
onRepertoiresChange(value) {
const index = this.state.repertoires.indexOf(value)
this.setState({
currentSelectRepertoiresIndex: index,
memoRepertoire: value,
memoLanguage: []
});
};
onTagChange(value) {
if (value && value.length > 3) {
this.props.showSnackbar(`最多选择3个技术标签`)
return;
}
this.setState({
memoLanguage: value
})
}
onTypeChange(value) {
this.setState({
memoType: value
})
}
onMemoNameChange(e) {
this.setState({
memoSubject: e.target.value
})
}
renderMemoType() {
const { memo_type } = this.state;
if (!memo_type || memo_type.length === 0) {
return ''
}
const result = []
// memo_type.map((item, index) => <Option value={item.id} key={index} >{item.name}</Option> )
memo_type.forEach((item, index) => {
result.push(<Option value={item.id} key={index} >{item.name}</Option>)
})
return result;
}
renderTag() {
let { memo_tag } = this.state;
if (!memo_tag || memo_tag.length === 0) {
return ''
}
const result = []
memo_tag.forEach((item, index) => {
result.push(<Option value={item.id+''} key={index} >{item.name}</Option>)
})
return result;
}
renderAttachment() {
const { attachments_url } = this.state;
const attachments = []
attachments_url.forEach((item, index) => {
const ar = item.url.split('/')
attachments.push(
<React.Fragment>
<span id={`attachments_10${index}`} className="attachment">
<i className="fa fa-folder mr5 color-light-grey newLeftgrey" aria-hidden="true"></i>
<input type="text" className="upload_filename readonly hidden" name="attachments[2][filename]" readonly="readonly"
style={{border:'none', width:'220px',whiteSpace: 'nowrap', textOverflow:'ellipsis',fontFamily: 'Consolas'}}
size="8" value={item.filename}></input>
<a href={`/attachments/${item.id}.js?attachment_id=10${index}`} className="remove-upload"
style={{verticalAlign: 'top', display: 'inlineBlock'}} data-remote="true"
data-method="delete">
<i className="fa fa-trash-o mr5"></i>
</a>
<div className="div_attachments" name="div_attachments_xx"></div>
<input type="hidden" name="attachments[xx][token]" value="185811.24305bb2c4912f715629aa3615cdbabc"></input>
<input type="hidden" name="attachments[xx][attachment_id]" value={item.id}></input>
</span>
<div className="cl"></div>
</React.Fragment>
)
})
return attachments;
}
_findById(id, arg_items) {
if (!arg_items) {
return undefined
}
const items = arg_items;
for(let i = 0; i < items.length; i++) {
if (id === items[i].id) {
return i;
}
}
}
// 是否是技术动态吧
_isTechShare() {
const { memoType, memo_type } = this.state
const index = this._findById(memoType, memo_type)
return !!index && memo_type[index] && memo_type[index].name.indexOf('技术问答') !== -1
}
onImageUploadDone = (data) => {
this.setState({
attachmentData: data
})
}
onImageUploadRemove = () => {
const { attachment_id } = this.state.attachmentData.response;
const deleteUrl = `/attachments/${attachment_id}.js?attachment_id=1`;
// 获取memo list
axios.delete(deleteUrl, {
withCredentials: true,
})
.then((response) => {
const data = response.data
if (data) {
this.setState({
attachmentData: undefined
})
this.props.showSnackbar('删除成功');
}
}).catch((error) => {
console.log(error)
})
}
// 切换大板块
changeLargeOption=(value)=>{
const { memo_tag } = this.state;
this.getChildPlate(memo_tag,value);
}
getChildPlate =(memo_tag,value)=>{
let listFilter = memo_tag && memo_tag.length > 0 && memo_tag.filter((item=> item.id === value))[0];
let list = listFilter && listFilter.children_tags;
this.setState({
smallOption:list && list.map(item=>{
return(
<Option value={item.id}>{item.title}</Option>
)
}),
bigPlateId:value,
smallPlateId: list && list.length > 0 ? (list[0].id || undefined) : undefined
})
}
// 切换二级板块
changeSmallOption=(value)=>{
this.setState({
smallPlateId:value
})
}
render() {
const { match } = this.props
const {
memoSubject ,
attachments_url,
currentMemoId,
fileList,
memoSubjectLength ,
memo_tag,
smallOption,
bigPlateId,
smallPlateId
} = this.state;
const memoId = match.params.memoId;
console.log("bigPlateId",bigPlateId);
return (
<div className="educontent-min postNewform">
<p className="font-22 color-grey3 mt30 mb10">{ memoId ? '编辑' : '新建'}</p>
<div className="edu-back-white mb10 clearfix" id="memoSubject" style={{position:'relative'}}>
<div className="padding30">
<div className="df">
<span className="mr20 new_label"><span className="color-orange">*</span></span>
<div className="flex1">
<input type="text" className="input-100-45" maxlength="50"
value={memoSubject} onChange={(val)=>this.onMemoNameChange(val)} placeholder="请输入发布标题最大限制50字符">
</input>
</div>
<div style={{width: '57px'}}>
<span className="color-orange mt8 fl" style={memoSubjectLength==0?{display:'block'}:{display:'none'}}>
<i className="fa fa-exclamation-circle mr3"></i>
</span>
</div>
</div>
{/* 发布时间 */}
{/* <div className="df ecSelectbox">
<span className="mr30 color-orange pt10"></span>
<div className="flex1 mr20">
<DatePicker
disabledDate={disabledDate}
showTime
format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择发布时间"
locale={zhCN}
placeholder={"请选择时间"}
onChange={(value, dateString)=>this.onOkTime(value, dateString)}
/>
</div>
<div style={{width: '57px'}}>
<span className="color-orange mt8 fl none" >
<i className="fa fa-exclamation-circle mr3"></i>
</span>
</div>
</div> */}
{/* <p className="color-grey-6 font-16 mb30">内容</p> */}
<div className="df mt20">
<span className="mr20 new_label"><span className="color-orange">*</span></span>
<div className="flex1">
<div className="break_word new_li" id="memoMD">
<textarea style={{'display':'none'}}></textarea>
</div>
</div>
<div style={{width: '57px'}}>
<span className="color-orange mt8 fl none" >
<i className="fa fa-exclamation-circle mr3"></i>
</span>
</div>
</div>
<form className="newForm" style={{marginLeft:"70px"}}>
<span id={`attachments_fields`} className="attachments_fields newforgeattachment" xmlns="http://www.w3.org/1999/html">
{ attachments_url && !!attachments_url.length &&
this.renderAttachment()
}
</span>
<span className="add_attachment">
<input className="file_selector" data-are-you-sure="您确定要删除吗?"
data-delete-all-files="您确定要删除所有文件吗" data-description-placeholder="可选的描述"
data-field-is-public="公开" data-file-count="个文件已上传"
data-lebel-file-uploding="个文件正在上传" data-max-concurrent-uploads="2"
data-max-file-size-message="该文件无法上传。超过文件大小限制 (50 MB)建议上传到百度云等其他共享工具里然后在txt文档里给出链接以及共享密码并上传"
data-max-file-size="52428800" data-upload-path="/uploads.js" id="_file"
multiple="multiple" name="attachments[dummy][file]"
onChange={()=>{debugger;window.addInputFiles( window.$('.file_selector')[0] ) }}
style={{'display':'none'}} type="file">
</input>
</span>
</form>
{/* 请求status 422 X-CSRF-Token: eVo38laEF880o3cwZ/0F9kH01q4jMkriuVRemIBq06Y= */}
<div className="df uploadBtn uploadBtnclick mb20" >
<a className="fl" onClick={()=>window.$('#_file').click()}>
<span style={{color: '#21B351', fontSize: "14px", marginLeft: "62px"}}>上传附件</span>
<span style={{color: '#CDCDCD', fontSize: "14px"}}>(单个文件50M以内)</span>
</a>
</div>
{/* 选择了技术问答才显示树标签 */}
{/* this._isTechShare() &&
<div className="edu-back-white mb10 clearfix">
<div className="padding30-20">
<p className="color-grey-6 font-16 mb30">技术标签</p>
<div className="df">
<span className="mr30 color-orange pt10">*</span>
<div className="flex1 mr20">
<Select
className="ecSelect"
value={memoLanguage}
placeholder="请选择技术标签"
onChange={(e) => this.onTagChange(e)}
dropdownStyle={{'maxHeight': '500px', 'overflow': 'auto'}}
mode="multiple"
tokenSeparators={[';']} >
{this.renderTag()}
</Select>
</div>
<div style={{width: '57px'}}>
<span className="color-orange mt8 fl none" >
<i className="fa fa-exclamation-circle mr3"></i>
</span>
</div>
</div>
</div>
</div> */}
<div className="df ecSelectbox mb20">
<span className="mr20 new_label"><span className="color-orange">*</span></span>
<div className="flex1">
{/* <Select className="ecSelect"
value={memoType}
placeholder="请选择技术标签"
onChange={(val)=>this.onTypeChange(val)}>
{ this.renderMemoType()}
</Select> */}
{/* <Select
mode="multiple"
className="ecSelect"
value={memoLanguage}
placeholder="请选择技术标签"
onChange={(e) => this.onTagChange(e)}
dropdownStyle={{'maxHeight': '500px', 'overflow': 'auto'}}
>
{this.renderTag()}
</Select> */}
<Select className="selectItem" value={bigPlateId} onChange={this.changeLargeOption}>
{
memo_tag && memo_tag.length > 0 && memo_tag.map((item,key)=>{
return(
<Option value={item.id} key={key}>{item.name}</Option>
)
})
}
</Select>
<Select className="selectItem" value={smallPlateId} onChange={this.changeSmallOption}>
{ smallOption }
</Select>
</div>
<div style={{width: '57px'}}>
<span className="color-orange mt8 fl none" >
<i className="fa fa-exclamation-circle mr3"></i>
</span>
</div>
</div>
{/* */}
<div className="df">
<span className="mr20 new_label">上传封面</span>
<div className="flex1 mr20">
<ImageUpload
fileList={fileList}
currentMemoId={currentMemoId}
onImageUploadRemove={this.onImageUploadRemove}
onImageUploadDone={this.onImageUploadDone}
></ImageUpload>
</div>
<div style={{width: '57px'}}>
<span className="color-orange mt8 fl none" >
<i className="fa fa-exclamation-circle mr3"></i>
</span>
</div>
</div>
</div>
</div>
<div className="clearfix mt30 mb50 edu-txt-center">
<span className="inline">
<a onClick={()=>{ this.onCancel() }} className="defalutCancelbtn mr20 fl newdefalutCancelbtn">返回</a>
<a className="defalutSubmitbtn fl newdefalutSubmitbtn" onClick={()=>{this.onCommit()}}>提交</a>
</span>
</div>
</div>
);
}
}
const children = [];
for (let i = 10; i < 36; i++) {
children.push(<Option key={i.toString(36) + i}>{i.toString(36) + i}</Option>);
}
export default MemoNew;

View File

@ -1,277 +0,0 @@
import React, { PureComponent } from 'react';
import {appendFileSizeToUploadFileAll ,appendFileSizeToUploadFile} from 'educoder';
import { Form , Input , Upload ,Button , Select , Icon , message } from "antd";
import './post.css'
import '../exchange.css'
import axios from 'axios';
import MDEditor from '../../common/MDEditor';
const Option = Select.Option;
const uploadButton = (
<div>
<i className="iconfont icon-tianjia mb30"></i>
<div className="font-16 mb10">点击上传封面</div>
<p className="font-12">只支持JPGPNGJPEG大小不超过2M建议尺寸43</p>
</div>
)
function getBase64(img, callback) {
debugger;
const reader = new FileReader();
reader.addEventListener('load', () => callback(reader.result));
reader.readAsDataURL(img);
}
class New extends PureComponent{
constructor(props){
super(props);
this.contentMdRef = React.createRef();
this.state={
// 封面图
imageUrl:undefined,
// 大板块下拉选项
memo_type:undefined,
// 小板块
smallOption:undefined,
// 附件列表
contentFileList:undefined,
}
}
componentDidMount = () =>{
this.getInfo();
}
// 获取信息
getInfo = () =>{
let url = '/memos/new';
axios.get((url)).then((result)=>{
if(result){
this.setState({
memo_type:result.data.memo_type
})
}
}).catch((error)=>{
})
}
changeUploadImage =(info)=>{
if (info.file.status === 'done') {
// Get this url from response in real world.
getBase64(info.file.originFileObj, imageUrl =>
this.setState({
imageUrl
}),
);
}
}
// 切换大板块
changeLargeOption=(value)=>{
// console.log(value);
const { memo_type } = this.state;
let list = memo_type.filter((item=> item.id === value))[0].children_tags;
// console.log(list);
this.setState({
smallOption:list && list.map(item=>{
return(
<Option value={item.id}>{item.title}</Option>
)
})
})
}
// 提交
handleSubmit=()=>{
this.props.form.validateFieldsAndScroll((err, values) => {
console.log(values);
if(!err){
let url=`/memos.json`;
axios.post((url),{
forum_id:values.bigPlate,
children_forum_id:values.smallPlate,
memo:{
subject:values.title,
content:values.description
}
}).then(result=>{
if(result){
this.props.showNotification(result.data.message);
this.props.history.push(`/forums/${result.data && result.data.memo_id}`);
}
}).catch(error=>{
})
}
})
}
// 上传附件
handleContentUploadChange = (info) => {
console.log("changeFIle==================>",info);
if (info.file.status === 'done' || info.file.status === 'uploading' || info.file.status === 'removed') {
let contentFileList = info.fileList;
this.setState({ contentFileList: appendFileSizeToUploadFileAll(contentFileList)});
let list = appendFileSizeToUploadFileAll(contentFileList);
let arr = list.map(item=>{
return ( item.response && item.response.id )
})
this.setState({
filesID:arr,
checkFile:arr.length > 0 ? false : true
})
}
}
// 上传附件-删除确认框
onAttachmentRemove = (file, stateName) => {
if(!file.percent || file.percent == 100){
this.props.confirm({
content: '是否确认删除?',
onOk: () => {
this.deleteAttachment(file, stateName)
},
onCancel() {
console.log('Cancel');
},
});
return false;
}
}
deleteAttachment=(file,list)=>{
console.log("delete===============>",file)
}
render(){
const { getFieldDecorator } = this.props.form;
/** 上传封面图 */
let { imageUrl , memo_type , smallOption , contentFileList } = this.state;
const largeOption = memo_type && memo_type.length > 0 && memo_type.map(item=>{
return(
<Option value={item.id}>{item.name}</Option>
)
})
let uploadImg = ( imageUrl ? <img src={imageUrl} alt="avatar" style={{ width: '100%' }} /> : uploadButton )
// 上传封面图
const uploadCover = {
listType:"picture-card",
className:"avatar-uploader",
showUploadList:false,
action:`/uploads.js`,
data: { attachment_id: 1 },
onChange:this.changeUploadImage,
}
/**上传附件 */
const uploadProps = {
width: 600,
fileList: contentFileList,
multiple: true,
action: 'http://127.0.0.1:3000/uploads.js',
onChange: this.handleContentUploadChange,
onRemove: (file) => this.onAttachmentRemove(file, 'contentFileList'),
beforeUpload: (file) => {
console.log('beforeUpload', file.name);
const isLt150M = file.size / 1024 / 1024 < 150;
if (!isLt150M) {
this.props.showNotification('文件大小必须小于150MB!');
}
return isLt150M;
},
};
return(
<div className="educontent-min">
<p className="font-22 color-grey3 mt30 mb10">新建</p>
<div className="bc-white padding30">
<Form className="postNewform">
<Form.Item
label="标题"
>
{getFieldDecorator('title', {
rules: [{
required: true, message: '请输入帖子标题',
},{
max: 5000 , message:'最大限制60个字符'
}],
})(
<Input placeholder="请输入标题最大限制60个字符" maxLength="60" style={{height:"40px"}}/>
)}
</Form.Item>
<Form.Item label="内容" className="editorFromItem">
{getFieldDecorator('description', {
rules: [{
required: true, message: '请输入帖子内容',
},{
max: 5000 , message:'最大限制5000个字符'
}],
})(
<MDEditor ref={this.contentMdRef} placeholder="请输入内容最大限制5000字符" mdID={'courseContentMD'} refreshTimeout={1000}
initValue={""} className="courseMessageMD" ></MDEditor>
)}
</Form.Item>
<Upload {...uploadProps} className="upload_1 newPostUpload">
<Button className="uploadBtn">
<i className="iconfont icon-fabu font-22 color-blue fl mr10"></i>
</Button>
</Upload>
<div className="df mt10">
<Form.Item label="主题板块">
{
getFieldDecorator('bigPlate',{
rules:[{
required:true,message:'请选择大板块'
}]
})(
<Select className="selectItem" onChange={this.changeLargeOption}>
{ largeOption }
</Select>
)
}
</Form.Item>
<Form.Item label="">
{
getFieldDecorator('smallPlate',{
rules:[{
required:true,message:'请选择小板块'
}]
})(
<Select className="selectItem">
{ smallOption }
</Select>
)
}
</Form.Item>
</div>
<div className="df uploadImageBox">
<label className="new_label">上传封面</label>
<Upload {...uploadCover}>
{uploadImg}
</Upload>
</div>
</Form>
</div>
<p className="clearfix mt20 mb50 edu-txt-center">
<span className="inline">
<a className="defalutCancelbtn fl mr20">取消</a>
<Button type="primary" onClick={this.handleSubmit} className="defalutSubmitbtn fl mr20">提交</Button>
</span>
</p>
</div>
)
}
}
const WrappedNewPostForm = Form.create({ name: 'New' })(New);
export default WrappedNewPostForm;

View File

@ -1,33 +0,0 @@
import React, { PureComponent } from 'react';
class Parse extends PureComponent{
render(){
let { judge , num , clickEvent ,current_user} = this.props;
const info = (
current_user? (judge ?
<a className={`forumParse`} onClick={clickEvent}>
<i className="iconfont icon-dianzan font-24" style={{height:"30px",lineHeight:"40px"}}></i>
<span>{num}</span>
</a>
:
<span className={`forumParse parsed`} >
<i className="iconfont icon-dianzan font-24" style={{height:"30px",lineHeight:"40px"}}></i>
<span>{num}</span>
</span>
):
<a className={`forumParse`} href="/login">
<i className="iconfont icon-dianzan font-24" style={{height:"30px",lineHeight:"40px"}}></i>
<span>{num}</span>
</a>
)
return(
<React.Fragment>
{ info }
</React.Fragment>
)
}
}
export default Parse;

View File

@ -1,157 +0,0 @@
.postDetail{
padding:20px 0px;
}
.postContent{
margin:0px 30px;
border-top: 1px solid #f4f4f4;
}
.fileTeam{
padding-bottom: 40px;
}
.fileTeam > li {
height: 18px;
line-height: 18px;
margin-bottom: 10px;
}
/* parse.js */
.forumParse{
width: 72px;
height: 72px;
display: inline-flex;
align-items: center;
flex-flow: column;
background: #5091FF;
color: #fff!important;
border-radius: 50%;
padding-top: 7px;
}
.forumParse.parsed{
background:#999999;
}
/* 评论 */
.replyTitle{
line-height: 30px;
padding:20px;
border-bottom: 1px solid #f4f4f4;
}
.pre_stage{
border-bottom: 1px solid #f4f4f4;
padding : 10px 0px;
}
.pre_stage:last-child{
border-bottom: none;
}
.pre_stage .sub_stage{
padding: 10px 20px;
box-sizing: border-box;
background: #fafafa;
position: relative;
margin-top: 20px;
border-radius:4px;
}
.pre_stage .sub_stage::before{
position: absolute;
content: "";
top:-20px;
z-index: 1;
left: 20px;
width: 0;
height: 0;
border-width: 10px;
border-style: solid;
border-color: transparent transparent #fafafa transparent;
}
.commentsItem_infos{
display: flex;
padding:10px 0px 10px;
}
.commentsItem_infos .markdown-body{
padding:0px;
}
.commentsItem_infos .editormd-html-preview,.commentsItem_infos .editormd-preview-container{
background-color: unset;
}
/* 新建 */
.postNewform.ant-form .ant-row{
display: flex;
align-items: top;
}
.postNewform.ant-form .ant-form-item-control-wrapper{
flex: 1;
}
.postNewform.ant-form .ant-form-item-label,.postNewform .new_label{
width: 90px;
text-align: right;
margin-right: 8px;
height: 40px;
line-height: 40px;
margin-top: 3px;
font-size: 16px
}
.postNewform.ant-form label{
font-size: 16px;
color: #333;
}
.editorFromItem {
align-items: flex-start!important;
margin-bottom: 0px!important;
}
.editorFromItem .editormd.editormd-vertical{
margin-bottom: 0px;
}
.editorFromItem .rememberTip{
height: 20px;
line-height: 20px;
}
.newPostUpload{
margin-left: 84px;
}
.newPostUpload .uploadBtn{
border:none;
box-shadow: none;
color:#5091FF;
line-height: 30px;
}
.newPostUpload .ant-upload-list{
padding-left: 100px;
}
.newPostUpload .ant-upload-list-item-info{
padding:0px;
font-size: 15px;
height: 24px;
line-height: 24px;
max-width: 500px;
position: relative;
}
.selectItem .ant-select-selection--single{
width: 200px;
margin-right: 20px;
height: 40px;
}
.selectItem .ant-select-selection__rendered{
line-height: 40px;
}
/* 上传封面 */
.uploadImageBox .ant-upload-picture-card-wrapper{
width: 340px;
height: 248px;
border:none;
background: #fafafa;
display: flex;
flex-direction: column;
padding:0px 60px;
color: #999;
}
.uploadImageBox .ant-upload.ant-upload-select-picture-card{
width: 100%;
height: 100%;
border: none;
}
.uploadImageBox .ant-upload.ant-upload-select-picture-card i{
font-size: 44px!important;
color:#999;
}

View File

@ -1,16 +0,0 @@
import React, { PureComponent } from 'react';
class Index extends PureComponent {
render(){
const {count, returnEvent} = this.props;
return(
<p className="clearfix pl30 pr30 mb10">
<span className="fl color-grey3 font-16">共找到相关结果<span className="color-blue">{count}</span></span>
<span onClick={returnEvent} className="color-grey-6 fr mt2 c_point">返回</span>
</p>
)
}
}
export default Index;

View File

@ -1,18 +0,0 @@
import React, { PureComponent } from 'react';
import { getImageUrl } from 'educoder';
class Index extends PureComponent {
render(){
let { topClass , bestClass } = this.props;
return(
<React.Fragment>
{ topClass && <img alt="" src={getImageUrl("images/plate/top.png")} width="42px" className={ topClass }></img> }
{ bestClass && <img alt="" src={getImageUrl("images/plate/best.png")} width="28px" className={ bestClass }></img> }
</React.Fragment>
)
}
}
export default Index;

View File

@ -1,289 +0,0 @@
.newContainer{
padding:60px 0px 120px 0px;
}
ul,p{
margin: 0px;
}
.flex1{
flex: 1;
width: 0
}
.ant-tabs-nav .ant-tabs-tab-active,.ant-tabs-nav .ant-tabs-tab:hover{
color:#21B350!important;
}
/* shownotification的z-index */
.ant-notification{
z-index: 100000;
}
/* 小按钮 */
.small-default-btn{
height: 24px;
line-height: 24px;
padding: 0px 15px;
font-size: 12px;
background:rgba(244,244,244,1);
border-radius:2px;
color: #999;
display: inline-block;
}
.middle-default-btn{
height: 30px;
line-height: 30px;
padding: 0px 15px;
font-size: 12px;
background:rgba(244,244,244,1);
border-radius:2px;
color: #999;
display: inline-block;
}
.small-blue-btn{
background:rgba(80,145,255,1);
color:rgba(255,255,255,1);
}
.small-green-btn{
background:#21B350;
color:rgba(255,255,255,1)!important;
}
.educontent{
width: 1200px;
margin:0px auto;
}
.educontent-min{
width: 960px;
margin:0px auto;
}
.F_panel{
width: 1200px;
display: flex;
margin:30px auto;
}
.f_left_head{
display: flex;
justify-content:space-between;
border-bottom: 1px solid #eaeaea;
padding-left:30px;
background: #fff;
}
.f_left_head > ul{
display: flex;
align-items: center;
height:80px;
margin-bottom: 0px;
}
.f_left_head > ul >li{
margin-right: 30px;
color: #666666
}
.f_left_head > ul >li a{
color: #666666
}
.f_left_head > ul:first-child > li{
font-size: 16px;
position: relative;
color: #333;
}
.f_left_head > ul:first-child > li.active a{
color: #5091FF;
}
.f_left_head > ul:first-child > li.active a:after{
position: absolute;
width: 100%;
bottom: -25px;
height: 2px;
background: #5091FF;
content: '';
left: 0px;
}
.platePanel{
top: 24px;
background: #fff;
left: 0px;
box-shadow:0px 6px 16px 0px rgba(7,12,70,0.2);
border-radius:4px;
max-width: 770px;
max-height: 500px;
padding:10px 10px 0px 10px;
overflow: auto;
box-sizing: border-box;
}
.platePanel .plateItem{
display: flex;
padding-bottom:10px;
box-sizing: border-box;
}
.platePanel .plateItem .plateItem_h{
color: #333;
margin:5px 20px 0px 10px;
}
.plateUl{
flex: 1;
}
.plateUl li{
position: relative;
margin-right: 11px;
color: #666;
float: left;
padding:5px 0px;
box-sizing: border-box;
margin-left: 10px;
}
.plateUl li:after{
width: 1px;
position: absolute;
right: -12px;
height:10px;
background: #ccc;
top:11px;
content: ''
}
.plateUl li:last-child:after{
display:none;
}
.radius{
border-radius: 50%;
}
.flex1{
flex: 1;
}
.color-blue {
color: #5091FF!important;
}
.flex-align-center{
display: flex;
align-items: center;
}
.flex-align-top{
display: flex;
align-items: flex-start;
}
.flex-align-bottom{
display: flex;
align-items: flex-end;
}
/* 列表 */
.plateTabulation{
padding: 0px 30px;
box-sizing: border-box;
background: #fff;
}
.plateTabulation > li{
border-bottom: 1px solid #f4f4f4;
padding:20px 0px;
}
.plateTabulation > li:last-child{
border-bottom: none;
}
.exchangeItem-subject{
font-size: 16px;
color: #333;
flex:1;
height: 20px;
line-height: 20px;
margin-right: 20px;
}
.flex_h{
display: flex;
align-items: center
}
.sendPoint{
font-size: 12px;
color: #999;
position: relative;
margin-left: 20px;
height: 18px;
line-height: 18px;
}
.sendPoint::before{
position: absolute;
left: -10px;
top:3px;
height:12px;
width:1px ;
content: '';
background: #ccc;
}
p{
margin:0px;padding:0px
}
.edu-txt-center .ant-dropdown-menu-item,.edu-txt-center .ant-dropdown-menu-submenu-title{
text-align: center;
}
.c_point{
cursor: pointer;
}
.top_Operate{
position: relative;
background: #fff;
padding:20px;
margin-bottom: 20px;
}
.top_Operate .send_btn{
width: 188px;
height: 40px;
background: #5091ff;
text-align: center;
color: #fff;
font-size: 16px;
line-height: 40px;
display: block;
border-radius: 4px;
}
.top_Operate .searchfrom{
position: absolute;
width: 40px;
right:20px;
top:20px;
}
.top_Operate .searchfrom.ant-input-affix-wrapper .ant-input-suffix{
right:-2px
}
.top_Operate .searchfrom .ant-input-search-icon svg{
width: 3em;
height: 1.3em;
}
.top_Operate .searchfrom.active{
width: 250px;
z-index: 10;
}
.r_part_title{
border-bottom: 1px solid #F4F4F4;
padding:20px;
}
.r_part_list{
padding:20px;
}
.r_part_list li{
margin-bottom: 20px;
color: #333;
}
.r_part_list li:last-child{
margin-bottom: 0px;
}
/* InfoComponent */
.icon-wrap{
margin-left: 30px;
color: #ccc;
float: left;
line-height: 20px;
}
.icon-wrap > i{
margin-right: 5px;
float: left;
}
/*給下拉列表的……添加高宽*/
.addheight{
background: url(./images/more.png) no-repeat right;
width: 30px;
height: 20px;
}
/*帖子列表标题点击变颜色*/
.is_onclick:hover{
color: #5091FF;
}
/*帖子详情标题颜色不变*/
.color_black{
color: black;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

View File

@ -1,98 +0,0 @@
import React, { Component } from 'react';
import { Route , Switch } from 'react-router-dom';
import { TPMIndexHOC } from '../modules/tpm/TPMIndexHOC';
import { SnackbarHOC , CNotificationHOC } from 'educoder';
import ExchangeIndex from './ExchangeIndex';
import Post from './Post/Index'
import PostNew from './Post/MemoNew';
import PlateIndex from './Plate/Index';
import MyExchange from './MyExchange/Index'
import PreManager from './Manage/PreModerator'
import axios from 'axios';
import './exchange.css';
class Index extends Component{
constructor(props){
super(props);
this.state={
current_user:undefined
}
}
componentDidMount=()=>{
const url = `/users/get_user_info.json`;
axios.get(url).then(result=>{
if(result){
this.setState({
current_user:result.data.current_user
})
// 给NewHeader传值当前用户的信息
if(result.data.current_user && result.data.current_user.login){
this.props.initCommonState(result.data.current_user);
}
}
}).catch(error=>{
})
}
componentDidUpdate=()=>{
this.props.history.listen(()=>{
if (document.body.scrollTop || document.documentElement.scrollTop > 0) {
window.scrollTo(0, 0)
}
})
}
render(){
return(
<Switch {...this.props}>
{/* 帖子列表 */}
<Route path='/forums/plates/:plateid/all' render={
(props) => (<PlateIndex {...this.props} {...this.state} {...props} />)
} ></Route>
{/* 编辑帖子 */}
<Route path={`/forums/:memoId/edit`} render={
(props) => {
return (<PostNew {...this.props} {...this.state} {...props}></PostNew>)}
}></Route>
{/* 新建帖子 */}
<Route path={`/forums/new`} render={
(props) => {
return (<PostNew {...this.props} {...this.state} {...props}></PostNew>)}
}></Route>
{/* 版主管理 */}
<Route path={`/forums/manage/:plateId`} render={
(props) => {
return (<PreManager {...this.props} {...this.state} {...props}></PreManager>)}
}></Route>
{/* 我的话题 */}
<Route path={`/forums/MyTopic`} render={
(props) => {
return (<MyExchange {...this.props} {...this.state} {...props}></MyExchange>)}
}></Route>
<Route path={`/forums/MyEnshrine`} render={
(props) => {
return (<MyExchange {...this.props} {...this.state} {...props}></MyExchange>)}
}></Route>
<Route path={`/forums/MyInteresting`} render={
(props) => {
return (<MyExchange {...this.props} {...this.state} {...props}></MyExchange>)}
}></Route>
{/* 帖子详情 */}
<Route path={`/forums/:postid`} render={
(props) => {
return (<Post {...this.props} {...this.state} {...props}></Post>)}
}></Route>
{/* 论坛首页 */}
<Route path={`/forums`} render={
(props) => (<ExchangeIndex {...this.props} {...this.state} {...props} />)
}></Route>
</Switch>
)
}
}
export default SnackbarHOC() (CNotificationHOC() (TPMIndexHOC ( Index ))) ;

View File

@ -67,18 +67,17 @@ function Index(props){
}
return(
<div className="aboutPanels">
<div className="aboutContent">
<AlignCenterBetween style={{padding:"14px 0px"}}>
<span className="font-16"><i className="iconfont icon-xiangmujianjie mr5 font-16 color-blue"></i>项目简介</span>
{ editOpration && <a onClick={editContent} className="color-blue">编辑</a> }
<AlignCenterBetween style={{padding:"14px 20px"}}>
<span className="font-16"><i className="iconfont icon-xiangmujianjie mr5 font-16 color-blue"></i>项目概览</span>
{ editOpration && !edit && <a onClick={editContent} className="color-blue">编辑</a> }
</AlignCenterBetween>
{
edit ?
<div>
<div className="padding20">
<MDEditor
placeholder={"请输入描述信息"}
height={200}
height={500}
mdID={"order-new-description"}
initValue={content}
onChange={onContentChange}
@ -114,11 +113,11 @@ function Index(props){
</div>
</div>
:
<div style={{padding:"20px 0px"}}>
<div className="padding20">
{content ?
<RenderHtml className="break_word_comments imageLayerParent" value={content} />
<RenderHtml className="break_word_comments imageLayerParent" value={content} url={props.history.location}/>
:
<div>暂无简介~</div>
<div>暂无概览~</div>
}
{attachments && attachments.length > 0 &&
<Attachments

View File

@ -4,7 +4,6 @@
.aboutContent{
border-radius: 2px;
border: 1px solid #EEEEEE;
padding:0px 30px;
width:100%;
background-color: #fff;
margin-top:20px;

View File

@ -1,7 +1,7 @@
import React , { Component } from 'react';
import { Dropdown , Menu , Icon , Pagination , Spin } from 'antd';
import '../css/index.scss';
import '../Branch/branch.css';
import '../Branch/branch.scss';
import './activity.css';
import NoneData from '../Nodata';
@ -177,7 +177,7 @@ class Activity extends Component{
}
</div>
:
<NoneData _html="暂时还没有相关数据!" />
<NoneData _html="暂时还没有相关数据!" />
}
</Spin>
{

View File

@ -32,8 +32,8 @@ class ActivityItem extends Component {
</p >
}
<p className="itemLine mt10">
<Link to={`/users/${item && item.login}`} className="show-user-link">
<img alt="" src={getImageUrl(`images/${item.user_avatar}`)} className="createImage" />
<Link to={`/users/${item && item.user_login}`} className="show-user-link">
<img alt="" src={getImageUrl(`/${item.user_avatar}`)} className="createImage" />
<span className="mr20">{item.user_name}</span>
</Link>
{item.created_at && <span className="color-grey-9">创建于<span className="ml2 color-grey-6">{item.created_at}</span></span>}

View File

@ -1,39 +1,35 @@
import React, { Component } from 'react';
import { Dropdown, Icon, Tooltip } from 'antd';
import "./branch.css";
import React, { useState } from 'react';
import { Dropdown, Menu, Tooltip } from 'antd';
import "./branch.scss";
class CloneAddress extends Component {
function CloneAddress({http_url , ssh_url , zip_url , tar_url}) {
const [ key , setKey ] = useState("HTTP");
// 点击按钮复制功能
jsCopy = () => {
function jsCopy(){
var e = document.getElementById("copy_rep_content");
e.select();
document.execCommand("Copy");
}
render() {
const { http_url, downloadUrl } = this.props;
return (
<div className="gitAddressClone">
{/* <p className="addressTips"><span>版本库地址已变更,请基于新地址提交代码</span></p> */}
{
http_url && <span>HTTP</span>
}
<input type="text" id="copy_rep_content" value={http_url} />
<Tooltip title="复制链接">
<span className="color-blue" onClick={() => this.jsCopy()}><i className="iconfont icon-fuzhi"></i></span>
</Tooltip>
{
downloadUrl &&
<span>
<Dropdown overlay={downloadUrl} trigger={['click']} placement="bottomRight">
<a className="ant-dropdown-link">
<Icon type="cloud-download" className="font-18 fl color-blue" />
</a>
</Dropdown>
</span>
}
return (
<div className="downMenu">
<div style={{padding:"10px 20px 20px 20px",borderBottom:"1px solid #eee"}}>
<Menu className="urlMenu" selectedKeys={[key]} mode={"horizontal"}>
<Menu.Item key="HTTP" onClick={(e)=>{setKey(e.key)}}>HTTP</Menu.Item>
<Menu.Item key="SSH" onClick={(e)=>{setKey(e.key)}}>SSH</Menu.Item>
</Menu>
<div className="gitAddressClone">
<input type="text" id="copy_rep_content" value={key==="HTTP" ? http_url:ssh_url} />
<Tooltip title="复制链接">
<span className="color-blue" onClick={jsCopy}><i className="iconfont icon-fuzhi"></i></span>
</Tooltip>
</div>
</div>
)
}
<Menu className="edu-txt-center">
<Menu.Item><a href={zip_url}>下载 ZIP</a></Menu.Item>
<Menu.Item><a href={tar_url}>下载 TAR.GZ</a></Menu.Item>
</Menu>
</div>
)
}
export default CloneAddress;

View File

@ -1,10 +1,10 @@
import React , { useState , useEffect } from 'react';
import { Popover , Input , Spin } from 'antd';
import './branch.css';
import './branch.scss';
import { getBranch , getTag } from '../GetData/getData';
export default (({ projectsId , repo_id , changeBranch , branch , owner })=>{
export default (({ projectsId , branch , owner , changeBranch , branchList , tagflag = true })=>{
const [ showValue , setShowValue ] = useState(branch);
const [ inputValue , setInputValue] = useState(undefined);
const [ nav , setNav ] = useState(0);
@ -17,10 +17,11 @@ export default (({ projectsId , repo_id , changeBranch , branch , owner })=>{
useEffect(()=>{
setShowValue(branch);
},[branch])
useEffect(()=>{
document.body.addEventListener('click', e => {
let name = e.target.className;
let turn = name == "ant-input OptionsInput" || name == "navli active"|| name == "navli" || name == "padding10 bor-bottom-greyE";
let turn = name === "ant-input OptionsInput" || name === "navli active"|| name === "navli" || name === "padding10 bor-bottom-greyE";
if(turn){
return;
}else{
@ -30,8 +31,12 @@ export default (({ projectsId , repo_id , changeBranch , branch , owner })=>{
})
useEffect(()=>{
getBranchs(projectsId,owner);
},[projectsId])
if(branchList){
setData(branchList);
setDatas(branchList);
setIsSpin(false);
}
},[branchList])
async function getBranchs(id,owner){
@ -63,7 +68,7 @@ export default (({ projectsId , repo_id , changeBranch , branch , owner })=>{
}
}
function chooseitem(value){
setShowValue(value);
// setShowValue(value);
changeBranch(value);
}
@ -77,8 +82,8 @@ export default (({ projectsId , repo_id , changeBranch , branch , owner })=>{
onChange={changeInputValue} style={{width:"220px"}}
/>
<ul className="navUl">
<li className={nav==0?"navli active":"navli"} onClick={()=>changeNav(0)}><i className="iconfont icon-fenzhi1 font-14 mr3"></i>分支列表</li>
<li className={nav==1?"navli active":"navli"} onClick={()=>changeNav(1)}><i className="iconfont icon-biaoqian3 font-14 mr3"></i>标签列表</li>
<li className={nav === 0?"navli active":"navli"} onClick={()=>changeNav(0)}><i className="iconfont icon-fenzhi1 font-14 mr3"></i>分支列表</li>
{ tagflag && <li className={nav === 1?"navli active":"navli"} onClick={()=>changeNav(1)}><i className="iconfont icon-biaoqian3 font-14 mr3"></i>标签列表</li> }
</ul>
</div>
<Spin spinning={isSpin}>
@ -97,9 +102,10 @@ export default (({ projectsId , repo_id , changeBranch , branch , owner })=>{
</div>
);
return(
<Popover placement="bottom" visible={flag} content={menu} onClick={()=>setFlag(!flag)} overlayClassName="branch-tagBox-list">
<Popover placement='bottomLeft' visible={flag} content={menu} onClick={()=>setFlag(!flag)} overlayClassName="branch-tagBox-list">
<div className="branch-tagBox">
<span className="color-grey-9 mr3 ml8">{nav === 0 ?"分支":"标签"}:</span>
{/* {nav === 0 ?"分支":"标签"} */}
<span className="color-grey-9 mr3 ml8"><i className="iconfont icon-fenzhi2 font-18"></i></span>
<a className="ant-dropdown-link">
{showValue}
</a>

View File

@ -51,7 +51,7 @@
display: flex;
align-items: center;
cursor: pointer;
width: 240px;
min-width: 140px;
}
.branch-tagBox-list .ant-popover-arrow{
display: none;
@ -81,4 +81,25 @@
.listTips{
padding:20px 0px;
text-align: center;
}
.urlMenu{
line-height: 30px;
margin-bottom: 10px;
border-bottom: none;
li.ant-menu-item{
height: 30px;
line-height: 30px;
padding:0px 5px;
margin-right: 20px!important;
&.ant-menu-item-selected,&.ant-menu-item-active{
color: #333;
}
&.ant-menu-item-selected{
border-color:#1890ff!important;
}
&.ant-menu-item-active{
border-color:transparent ;
}
}
}

View File

@ -0,0 +1,83 @@
import React, { useEffect, useState } from 'react';
import { AutoComplete , Button , Icon } from 'antd';
import axios from 'axios';
const { Option } = AutoComplete;
function AddGroup({organizeId,getGroupID}){
const [ id , setID ] = useState(undefined);
const [ source , setSource ] = useState(undefined);
const [ searchKey , setSearchKey ] = useState("");
useEffect(()=>{
getUserList();
},[searchKey])
function getUserList(e){
const url = `/organizations/${organizeId}/teams/search.json`;
axios.get(url, {
params: {
search: searchKey,
},
}).then((result) => {
if (result) {
sourceOptions(result.data.teams);
}
})
.catch((error) => {
console.log(error);
});
};
function sourceOptions(userDataSource){
const s = userDataSource && userDataSource.map((item, key) => {
return (
<Option
key={key}
value={`${item.id}`}
name={item.name}
>
{item.name}
</Option>
);
});
setSource(s);
}
function changeInputUser(e){
setSearchKey(e || "");
};
//
function selectInputUser(e, option){
setID(e);
setSearchKey(option.props.name);
};
function addCollaborator(){
getGroupID && getGroupID(id);
}
return(
<div className="addPanel">
<AutoComplete
dataSource={source}
value={searchKey}
style={{ width: 300 }}
onChange={changeInputUser}
onSelect={selectInputUser}
placeholder="搜索需要添加的团队..."
allowClear
/>
<Button
type="primary"
ghost
onClick={addCollaborator}
className="ml15"
>
<Icon type="plus" size="16"></Icon>
添加团队
</Button>
</div>
)
}
export default AddGroup;

View File

@ -0,0 +1,100 @@
import React, { useEffect, useState } from 'react';
import { AutoComplete , Button , Icon } from 'antd';
import axios from 'axios';
import { getImageUrl } from 'educoder';
const { Option } = AutoComplete;
function AddMember({getID,login,showNotification}){
const [ id , setID ] = useState(undefined);
const [ source , setSource ] = useState(undefined);
const [ searchKey , setSearchKey ] = useState(undefined);
useEffect(()=>{
getUserList();
},[searchKey])
function getUserList(e){
const url = `/users/list.json`;
axios.get(url, {
params: {
search: searchKey,
},
}).then((result) => {
if (result) {
sourceOptions(result.data.users);
}
})
.catch((error) => {
console.log(error);
});
};
function sourceOptions(userDataSource){
const s = userDataSource && userDataSource.map((item, key) => {
return (
<Option
key={key}
value={`${item.user_id}`}
login={`${item.login}`}
name={item.username}
>
<img
className="user_img radius"
width="28"
height="28"
src={getImageUrl(`/${item && item.image_url}`)}
alt=""
/>
<span className="ml10" style={{ verticalAlign: "middle" }}>
{item.username}
<span className="color-grey ml10">({item.login})</span>
</span>
</Option>
);
});
setSource(s);
}
function changeInputUser(e){
setSearchKey(e);
};
//
function selectInputUser(e, option){
setID(login ? e : option.props.login);
setSearchKey(option.props.name);
};
function addCollaborator(){
if(source && source.length>0){
getID && getID(id);
setSearchKey(undefined);
}else{
showNotification("请选择存在的用户!");
}
}
return(
<div className="addPanel">
<AutoComplete
dataSource={source}
value={searchKey}
style={{ width: 300 }}
onChange={changeInputUser}
onSelect={selectInputUser}
placeholder="搜索需要添加的用户..."
allowClear
/>
<Button
type="primary"
ghost
onClick={addCollaborator}
className="ml15"
>
<Icon type="plus" size="16"></Icon>
添加成员
</Button>
</div>
)
}
export default AddMember;

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