测试 #810

Open
durian wants to merge 66 commits from durian/forgeplus-react:software_factory into pre_gitlink_ssr
121 changed files with 5613 additions and 2560 deletions

View File

@ -1,5 +1,5 @@
<h3>前端react环境安装</h3>
<p>1、 安装node v6.9.x此安装包含了node和npm。</p>
<p>1、 安装node v14.12.3此安装包含了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>
@ -8,9 +8,4 @@
<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>
<p>102:4000环境</p>

3960
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -21,6 +21,8 @@
"code-prettify": "^0.1.0",
"codemirror": "^5.64.0",
"connected-react-router": "4.4.1",
"core-js": "^3.34.0",
"crypto-js": "^4.2.0",
"dompurify": "^2.3.3",
"dotenv": "4.0.0",
"dotenv-expand": "4.2.0",

View File

@ -0,0 +1,539 @@
/* Logo 字体 */
@font-face {
font-family: "iconfont logo";
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
}
.logo {
font-family: "iconfont logo";
font-size: 160px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* tabs */
.nav-tabs {
position: relative;
}
.nav-tabs .nav-more {
position: absolute;
right: 0;
bottom: 0;
height: 42px;
line-height: 42px;
color: #666;
}
#tabs {
border-bottom: 1px solid #eee;
}
#tabs li {
cursor: pointer;
width: 100px;
height: 40px;
line-height: 40px;
text-align: center;
font-size: 16px;
border-bottom: 2px solid transparent;
position: relative;
z-index: 1;
margin-bottom: -1px;
color: #666;
}
#tabs .active {
border-bottom-color: #f00;
color: #222;
}
.tab-container .content {
display: none;
}
/* 页面布局 */
.main {
padding: 30px 100px;
width: 960px;
margin: 0 auto;
}
.main .logo {
color: #333;
text-align: left;
margin-bottom: 30px;
line-height: 1;
height: 110px;
margin-top: -50px;
overflow: hidden;
*zoom: 1;
}
.main .logo a {
font-size: 160px;
color: #333;
}
.helps {
margin-top: 40px;
}
.helps pre {
padding: 20px;
margin: 10px 0;
border: solid 1px #e7e1cd;
background-color: #fffdef;
overflow: auto;
}
.icon_lists {
width: 100% !important;
overflow: hidden;
*zoom: 1;
}
.icon_lists li {
width: 100px;
margin-bottom: 10px;
margin-right: 20px;
text-align: center;
list-style: none !important;
cursor: default;
}
.icon_lists li .code-name {
line-height: 1.2;
}
.icon_lists .icon {
display: block;
height: 100px;
line-height: 100px;
font-size: 42px;
margin: 10px auto;
color: #333;
-webkit-transition: font-size 0.25s linear, width 0.25s linear;
-moz-transition: font-size 0.25s linear, width 0.25s linear;
transition: font-size 0.25s linear, width 0.25s linear;
}
.icon_lists .icon:hover {
font-size: 100px;
}
.icon_lists .svg-icon {
/* 通过设置 font-size 来改变图标大小 */
width: 1em;
/* 图标和文字相邻时,垂直对齐 */
vertical-align: -0.15em;
/* 通过设置 color 来改变 SVG 的颜色/fill */
fill: currentColor;
/* path stroke 溢出 viewBox 部分在 IE 下会显示
normalize.css 中也包含这行 */
overflow: hidden;
}
.icon_lists li .name,
.icon_lists li .code-name {
color: #666;
}
/* markdown 样式 */
.markdown {
color: #666;
font-size: 14px;
line-height: 1.8;
}
.highlight {
line-height: 1.5;
}
.markdown img {
vertical-align: middle;
max-width: 100%;
}
.markdown h1 {
color: #404040;
font-weight: 500;
line-height: 40px;
margin-bottom: 24px;
}
.markdown h2,
.markdown h3,
.markdown h4,
.markdown h5,
.markdown h6 {
color: #404040;
margin: 1.6em 0 0.6em 0;
font-weight: 500;
clear: both;
}
.markdown h1 {
font-size: 28px;
}
.markdown h2 {
font-size: 22px;
}
.markdown h3 {
font-size: 16px;
}
.markdown h4 {
font-size: 14px;
}
.markdown h5 {
font-size: 12px;
}
.markdown h6 {
font-size: 12px;
}
.markdown hr {
height: 1px;
border: 0;
background: #e9e9e9;
margin: 16px 0;
clear: both;
}
.markdown p {
margin: 1em 0;
}
.markdown>p,
.markdown>blockquote,
.markdown>.highlight,
.markdown>ol,
.markdown>ul {
width: 80%;
}
.markdown ul>li {
list-style: circle;
}
.markdown>ul li,
.markdown blockquote ul>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown>ul li p,
.markdown>ol li p {
margin: 0.6em 0;
}
.markdown ol>li {
list-style: decimal;
}
.markdown>ol li,
.markdown blockquote ol>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown code {
margin: 0 3px;
padding: 0 5px;
background: #eee;
border-radius: 3px;
}
.markdown strong,
.markdown b {
font-weight: 600;
}
.markdown>table {
border-collapse: collapse;
border-spacing: 0px;
empty-cells: show;
border: 1px solid #e9e9e9;
width: 95%;
margin-bottom: 24px;
}
.markdown>table th {
white-space: nowrap;
color: #333;
font-weight: 600;
}
.markdown>table th,
.markdown>table td {
border: 1px solid #e9e9e9;
padding: 8px 16px;
text-align: left;
}
.markdown>table th {
background: #F7F7F7;
}
.markdown blockquote {
font-size: 90%;
color: #999;
border-left: 4px solid #e9e9e9;
padding-left: 0.8em;
margin: 1em 0;
}
.markdown blockquote p {
margin: 0;
}
.markdown .anchor {
opacity: 0;
transition: opacity 0.3s ease;
margin-left: 8px;
}
.markdown .waiting {
color: #ccc;
}
.markdown h1:hover .anchor,
.markdown h2:hover .anchor,
.markdown h3:hover .anchor,
.markdown h4:hover .anchor,
.markdown h5:hover .anchor,
.markdown h6:hover .anchor {
opacity: 1;
display: inline-block;
}
.markdown>br,
.markdown>p>br {
clear: both;
}
.hljs {
display: block;
background: white;
padding: 0.5em;
color: #333333;
overflow-x: auto;
}
.hljs-comment,
.hljs-meta {
color: #969896;
}
.hljs-string,
.hljs-variable,
.hljs-template-variable,
.hljs-strong,
.hljs-emphasis,
.hljs-quote {
color: #df5000;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-type {
color: #a71d5d;
}
.hljs-literal,
.hljs-symbol,
.hljs-bullet,
.hljs-attribute {
color: #0086b3;
}
.hljs-section,
.hljs-name {
color: #63a35c;
}
.hljs-tag {
color: #333333;
}
.hljs-title,
.hljs-attr,
.hljs-selector-id,
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo {
color: #795da3;
}
.hljs-addition {
color: #55a532;
background-color: #eaffea;
}
.hljs-deletion {
color: #bd2c00;
background-color: #ffecec;
}
.hljs-link {
text-decoration: underline;
}
/* 代码高亮 */
/* PrismJS 1.15.0
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection,
pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection,
code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection,
pre[class*="language-"] ::selection,
code[class*="language-"]::selection,
code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre)>code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre)>code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #9a6e3a;
background: hsla(0, 0%, 100%, .5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function,
.token.class-name {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}

View File

@ -0,0 +1,133 @@
@font-face {
font-family: "iconfontColor"; /* Project id 4313222 */
/* Color fonts */
src:
url('iconfont.woff2?t=1702282377802') format('woff2'),
url('iconfont.woff?t=1702282377802') format('woff'),
url('iconfont.ttf?t=1702282377802') format('truetype');
}
.iconfontColor {
font-family: "iconfontColor" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.iconcolor-a-zu1428:before {
content: "\e6e4";
}
.iconcolor-wenjianicon:before {
content: "\e6e5";
}
.iconcolor-biaotiicon:before {
content: "\e6e6";
}
.iconcolor-tuoguanicon:before {
content: "\e6df";
}
.iconcolor-zuicon:before {
content: "\e6e1";
}
.iconcolor-dailiicon:before {
content: "\e6e3";
}
.iconcolor-xuqiuicon:before {
content: "\e6dd";
}
.iconcolor-xiangmuliebiaoicon:before {
content: "\e6e2";
}
.iconcolor-renwuicon:before {
content: "\e6de";
}
.iconcolor-quexianicon:before {
content: "\e6e0";
}
.iconcolor-xuanzhong-daimakuicon:before {
content: "\e6d4";
}
.iconcolor-xuanzhong-wendangicon:before {
content: "\e6d5";
}
.iconcolor-xuanzhong-liushuixianicon:before {
content: "\e6d6";
}
.iconcolor-xuanzhong-xiangmuicon:before {
content: "\e6d7";
}
.iconcolor-xuanzhong-zhipinkuicon:before {
content: "\e6d8";
}
.iconcolor-xuanzhong-chengyuanicon:before {
content: "\e6d9";
}
.iconcolor-xuanzhong-shezhiicon:before {
content: "\e6da";
}
.iconcolor-xuanzhong-chanpinicon:before {
content: "\e6db";
}
.iconcolor-gongzuotaiicon:before {
content: "\e6dc";
}
.iconcolor-chanpinliebiaoicon:before {
content: "\e6d3";
}
.iconcolor-gengduoicon:before {
content: "\e60b";
}
.iconcolor-chengyuanicon:before {
content: "\e6c1";
}
.iconcolor-xuanzhong-gongzuotaiicon:before {
content: "\e6c2";
}
.iconcolor-wendangicon:before {
content: "\e6b9";
}
.iconcolor-xiangmuicon:before {
content: "\e6b8";
}
.iconcolor-zhipinkuicon:before {
content: "\e6ba";
}
.iconcolor-chanpinicon:before {
content: "\e6bb";
}
.iconcolor-shezhiicon:before {
content: "\e6bc";
}
.iconcolor-daimakuicon:before {
content: "\e6bd";
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,212 @@
{
"id": "4313222",
"name": "项目管理系统-color",
"font_family": "iconfontColor",
"css_prefix_text": "iconcolor-",
"description": "项目管理系统彩色icon",
"glyphs": [
{
"icon_id": "38315554",
"name": "组 1428",
"font_class": "a-zu1428",
"unicode": "e6e4",
"unicode_decimal": 59108
},
{
"icon_id": "38405284",
"name": "文件icon",
"font_class": "wenjianicon",
"unicode": "e6e5",
"unicode_decimal": 59109
},
{
"icon_id": "38405285",
"name": "标题icon",
"font_class": "biaotiicon",
"unicode": "e6e6",
"unicode_decimal": 59110
},
{
"icon_id": "38405286",
"name": "托管icon",
"font_class": "tuoguanicon",
"unicode": "e6df",
"unicode_decimal": 59103
},
{
"icon_id": "38405289",
"name": "组icon",
"font_class": "zuicon",
"unicode": "e6e1",
"unicode_decimal": 59105
},
{
"icon_id": "38405290",
"name": "代理icon",
"font_class": "dailiicon",
"unicode": "e6e3",
"unicode_decimal": 59107
},
{
"icon_id": "37938701",
"name": "需求icon",
"font_class": "xuqiuicon",
"unicode": "e6dd",
"unicode_decimal": 59101
},
{
"icon_id": "37938697",
"name": "项目列表icon",
"font_class": "xiangmuliebiaoicon",
"unicode": "e6e2",
"unicode_decimal": 59106
},
{
"icon_id": "37938700",
"name": "任务icon",
"font_class": "renwuicon",
"unicode": "e6de",
"unicode_decimal": 59102
},
{
"icon_id": "37938699",
"name": "缺陷icon",
"font_class": "quexianicon",
"unicode": "e6e0",
"unicode_decimal": 59104
},
{
"icon_id": "37708678",
"name": "选中-代码库icon",
"font_class": "xuanzhong-daimakuicon",
"unicode": "e6d4",
"unicode_decimal": 59092
},
{
"icon_id": "37708677",
"name": "选中-文档icon",
"font_class": "xuanzhong-wendangicon",
"unicode": "e6d5",
"unicode_decimal": 59093
},
{
"icon_id": "37708675",
"name": "选中-流水线icon",
"font_class": "xuanzhong-liushuixianicon",
"unicode": "e6d6",
"unicode_decimal": 59094
},
{
"icon_id": "37708676",
"name": "选中-项目icon",
"font_class": "xuanzhong-xiangmuicon",
"unicode": "e6d7",
"unicode_decimal": 59095
},
{
"icon_id": "37708674",
"name": "选中-制品库icon",
"font_class": "xuanzhong-zhipinkuicon",
"unicode": "e6d8",
"unicode_decimal": 59096
},
{
"icon_id": "37708673",
"name": "选中-成员icon",
"font_class": "xuanzhong-chengyuanicon",
"unicode": "e6d9",
"unicode_decimal": 59097
},
{
"icon_id": "37708672",
"name": "选中-设置icon",
"font_class": "xuanzhong-shezhiicon",
"unicode": "e6da",
"unicode_decimal": 59098
},
{
"icon_id": "37708671",
"name": "选中-产品icon",
"font_class": "xuanzhong-chanpinicon",
"unicode": "e6db",
"unicode_decimal": 59099
},
{
"icon_id": "37708670",
"name": "工作台icon",
"font_class": "gongzuotaiicon",
"unicode": "e6dc",
"unicode_decimal": 59100
},
{
"icon_id": "37708691",
"name": "产品列表icon",
"font_class": "chanpinliebiaoicon",
"unicode": "e6d3",
"unicode_decimal": 59091
},
{
"icon_id": "1919171",
"name": "菜单",
"font_class": "gengduoicon",
"unicode": "e60b",
"unicode_decimal": 58891
},
{
"icon_id": "37537539",
"name": "成员icon",
"font_class": "chengyuanicon",
"unicode": "e6c1",
"unicode_decimal": 59073
},
{
"icon_id": "37537538",
"name": "选中-工作台icon",
"font_class": "xuanzhong-gongzuotaiicon",
"unicode": "e6c2",
"unicode_decimal": 59074
},
{
"icon_id": "37537549",
"name": "文档icon",
"font_class": "wendangicon",
"unicode": "e6b9",
"unicode_decimal": 59065
},
{
"icon_id": "37537546",
"name": "项目icon",
"font_class": "xiangmuicon",
"unicode": "e6b8",
"unicode_decimal": 59064
},
{
"icon_id": "37537547",
"name": "制品库icon",
"font_class": "zhipinkuicon",
"unicode": "e6ba",
"unicode_decimal": 59066
},
{
"icon_id": "37537540",
"name": "产品icon",
"font_class": "chanpinicon",
"unicode": "e6bb",
"unicode_decimal": 59067
},
{
"icon_id": "37537545",
"name": "设置icon",
"font_class": "shezhiicon",
"unicode": "e6bc",
"unicode_decimal": 59068
},
{
"icon_id": "37537544",
"name": "代码库icon",
"font_class": "daimakuicon",
"unicode": "e6bd",
"unicode_decimal": 59069
}
]
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -20,7 +20,6 @@
<meta name="octolytics-dimension-repository_nwo" content="GitLink"></meta>
<meta name="octolytics-dimension-repository_network_root_nwo" content="GitLink"></meta>
<meta name="theme-color" content="#000000">
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests" />
<meta content="IE=edge" http-equiv="X-UA-Compatible">
<meta name="twitter:image:src" content="https://www.gitlink.org.cn/images/logo.png">
<meta name="twitter:site" content="@gitlink">
@ -33,6 +32,7 @@
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/alex/alex.all.global.min.css">
<link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/iconfont.css">
<link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/iconColor/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"> -->
@ -45,8 +45,10 @@
<div id="md_div" style="display: none;"></div>
<div id="root" class="page -layout-v -fit widthunit"></div>
<div id="picture_display" style="display: none;"></div>
<script src="https://gw.alipayobjects.com/os/lib/react/16.14.0/umd/react.%REACT_URL%.js"></script>
<script src="https://gw.alipayobjects.com/os/lib/react-dom/16.14.0/umd/react-dom.%REACT_URL%.js"></script>
<!-- <script src="https://gw.alipayobjects.com/os/lib/react/16.14.0/umd/react.%REACT_URL%.js"></script>
<script src="https://gw.alipayobjects.com/os/lib/react-dom/16.14.0/umd/react-dom.%REACT_URL%.js"></script> -->
<script src="%PUBLIC_URL%js/react.%REACT_URL%.js"></script>
<script src="%PUBLIC_URL%js/react-dom.%REACT_URL%.js"></script>
<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/common.js"></script> -->
@ -54,18 +56,18 @@
<script src="%PUBLIC_URL%js/editormd/editormd.min.js"></script>
<script src="%PUBLIC_URL%js/codemirror/merge/merge.js"></script>
<script src="%PUBLIC_URL%js/alex/moment.js"></script>
<script src="https://gw.alipayobjects.com/os/lib/alipay/alex/2.0.19/bundle/alex.all.global.min.js"></script>
<!-- <script src="https://gw.alipayobjects.com/os/lib/alipay/alex/2.0.19/bundle/alex.all.global.min.js"></script> -->
<meta name="viewport" content="">
<%= htmlWebpackPlugin.tags.bodyTags %>
<script>
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?7e2def1fe918f15f9f1c5c061f69b256";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
// (function() {
// var hm = document.createElement("script");
// hm.src = "https://hm.baidu.com/hm.js?7e2def1fe918f15f9f1c5c061f69b256";
// var s = document.getElementsByTagName("script")[0];
// s.parentNode.insertBefore(hm, s);
})();
// })();
window.onload=function(){
$(".newContainer").delegate("a.anchors","click",function(){
let h = $(this).offset().top - 180;

View File

@ -1,3 +1,4 @@
@import url(./font/font.css);
.App {
text-align: center;
}

View File

@ -112,7 +112,7 @@ const Relaction = Loadable({
loading: Loading,
});
const LoginRegisterPage = Loadable({
loader: () => import("./modules/loginRegister/LoginRegisterPage"),
loader: () => import("./modules/loginRegister/LoginRegisterPageNew"),
loading: Loading,
});
@ -140,10 +140,10 @@ const SoftBot = Loadable({
loading: Loading,
})
const WebIDE = Loadable({
loader: () => import('./forge/Newfile/webIDE'),
loading: Loading,
});
// const WebIDE = Loadable({
// loader: () => import('./forge/Newfile/webIDE'),
// loading: Loading,
// });
const Badge = Loadable({
loader: () => import('./forge/Badge/Index'),
@ -159,8 +159,13 @@ const Topic = Loadable({
loading: Loading,
})
const Iframe = Loadable({
loader: () => import("./forge/iframe"),
loading: Loading,
});
// 此处仅维护前端可能的一级路由,不用进行项目或者组织判断的字段。
const keyWord = ["explore", "settings", "setting", "mulan", "wiki", "issues", "setting", "trending", "code", "projects", "pulls", "mine", "login", "register", "email", "export", "nopage", "404", "403", "500", "501", "search", "organize", "login", "register", "resetPassword", "aboutus","educoder", "glcc","bindlogin", "softbot","zone"];
const keyWord = ["explore", "settings", "setting", "mulan", "wiki", "issues", "setting", "trending", "code", "projects", "pulls", "mine", "login", "register", "email", "export", "nopage", "404", "403", "500", "501", "search", "organize", "login", "register", "resetPassword", "aboutus","educoder", "glcc","bindlogin", "softbot","zone", "hiagent"];
class App extends Component {
constructor(props) {
@ -333,9 +338,15 @@ class App extends Component {
<MuiThemeProvider theme={theme}>
<LoginDialog {...this.props} {...this.state} Modifyloginvalue={() => this.Modifyloginvalue()}></LoginDialog>
{/* <GlccModal /> */}
{!pathName || (pathName && pathName.toLowerCase() !== 'glcc') ? <SiderBar {...this.props}/> : <SiderBarHelp/>}
{/* {!pathName || (pathName && pathName.toLowerCase() !== 'glcc') ? <SiderBar {...this.props}/> : <SiderBarHelp/>} */}
{/* <Router> */}
<Switch>
{/* iframe页面 */}
<Route path="/hiagent"
render={
(props) => (<Iframe {...this.props} {...props} {...this.state} />)
}
></Route>
{/* wiki预览 */}
<Route path="/:owner/:projectsId/wiki/preview/:projectName/:projectId" render={
(props) => {
@ -351,11 +362,11 @@ class App extends Component {
} />
{/* webIDE */}
<Route path="/:owner/:projectsId/webIDE/tree/:branchName"
{/* <Route path="/:owner/:projectsId/webIDE/tree/:branchName"
render={
(props) => (<WebIDE {...this.props} {...props} {...this.state} />)
}
></Route>
></Route> */}
{/* 项目PR */}
<Route path="/:owner/:projectsId/compare"
@ -443,10 +454,10 @@ class App extends Component {
></Route>
{/* 忘记密码 */}
<Route
{/* <Route
path="/resetPassword"
render={(props) =><LoginRegisterPage {...this.props} {...props} mygetHelmetapi={mygetHelmetapi}/>}
></Route>
></Route> */}
{/* 关于我们 */}
<Route

View File

@ -66,6 +66,11 @@ export function initAxiosInterceptors(props) {
return
}
const config = response.config;
if (response.data.status === 401) {
window.location.href = "/login"
}
if (response.data.status === -1) {
if (window.location.pathname.startsWith('/tasks/')) {
props.showSnackbar(response.data.message || '服务器异常,请联系管理员。')

View File

@ -1,3 +1,5 @@
import CryptoJS from 'crypto-js';
export function isDev() {
return window.location.port === "3007";
}
@ -6,3 +8,12 @@ export function isDev() {
export const isMobile = (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase()));
// const isWeiXin = (/MicroMessenger/i.test(navigator.userAgent.toLowerCase()));
export function Encrypt(str){
let result = CryptoJS.AES.encrypt(str,CryptoJS.enc.Utf8.parse('59c96c3572ab8cc1'),{
iv:CryptoJS.enc.Utf8.parse('59c96c3572ab8cc1'),
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
})
return result.toString();
}

View File

@ -6,15 +6,11 @@ const { Search } = Input;
const $ = window.$;
const isDev = window.location.port == 3007;
const isdev2= window.location.hostname ==='www.educoder.net'
export const TEST_HOST = "https://testforgeplus.trustie.net/"
export const TEST_HOST = "https://testforgeplus.trustie.net"
export function getImageUrl(path) {
// https://www.educoder.net
// https://testbdweb.trustie.net
// const local = 'http://localhost:3000'
path && !path.startsWith('/') && !path.startsWith('http') && (path = '/'.concat(path));
const local = 'https://testforgeplus.trustie.net';
if (isDev) {
return `${local}${path}`
return `${TEST_HOST}${path}`
}
return `${path}`;
}
@ -35,14 +31,10 @@ export function IsPC(){
}
export function getImageUrlAbsolute(path) {
// https://www.educoder.net
// https://testbdweb.trustie.net
// const local = 'http://localhost:3000'
path && !path.startsWith('/') && !path.startsWith('http') && (path = '/'.concat(path));
const local = 'https://testforgeplus.trustie.net';
const prod = window.location.origin;
if (isDev) {
return `${local}${path}`
return `${TEST_HOST}${path}`
}else{
return `${prod}${path}`;
}
@ -295,13 +287,13 @@ export function turnbar(str){
let s = str;
if(s && s.length>0){
if(s.indexOf("%")>-1){
s = s.replaceAll('%','_25');
s = s.replace(/%/g,'_25');
}
if(s.indexOf("#")>-1){
s = s.replaceAll('#','%23');
s = s.replace(/#/g,'%23');
}
if(s.indexOf("/")>-1){
s = s.replaceAll('/','%2F');
s = s.replace(/\//g,'%2F');
}
}
return s;
@ -310,13 +302,13 @@ export function returnbar(str){
let s = str;
if(s && s.length>0){
if(str.indexOf("_25")>-1){
s = s.replaceAll('_25','%');
s = s.replace(/_25/g,'%');
}
if(s.indexOf("%23")>-1){
s = s.replaceAll('%23','#');
s = s.replace(/%23/g,'#');
}
if(s.indexOf("%2F")>-1){
s = s.replaceAll('%2F','/');
s = s.replace(/%2F/g,'/');
}
}
return s;

View File

@ -93,7 +93,7 @@ export default ({
for(var x=0;x<issues.length;x++){
let item = issues[x];
let content = item.id ? `<a href="`+`/${owner}/${projectsId}/issues/${item.project_issues_index}`+`">#${item.project_issues_index}:${item.subject}</a>` : `<span>#${item.project_issues_index}(已删除)</span>`;
rs = rs.replaceAll(`<a href="`+`/${owner}/${projectsId}/issues/${item.project_issues_index}`+`">#${item.project_issues_index}</a>`,content);
rs = rs.replace(new RegExp(`<a href="/${owner}/${projectsId}/issues/${item.project_issues_index}">#${item.project_issues_index}</a>`, 'g'), content);
}
}
@ -102,7 +102,9 @@ export default ({
return renderToString(_unescape(expression) || '', { displayMode: type === 'block', throwOnError: false, output: 'html' })
})
rs = dompurify.sanitize(rs.replace(/▁/g, "▁▁▁"))
rs = rs.replaceAll('<img ', `<img onerror="javascript:this.src='${ imgError }';"`)
rs = rs.replace(/<img\s+/g, function(match) {
return match + `onerror="javascript:this.src='${imgError}';" `;
});
resetMathExpressions()
return rs
}, [str,issues]);

Binary file not shown.

5
src/font/font.css Normal file
View File

@ -0,0 +1,5 @@
/* 导航栏 */
@font-face {
font-family: "YouSheBiaoTiHei";
src: url('./YouSheBiaoTiHei-2.ttf');
}

Binary file not shown.

View File

@ -1,6 +1,7 @@
.aboutPanels{
max-width: 1200px;
margin:0px auto;
// max-width: 1200px;
// margin:0px auto;
padding:0px 20px;
.aboutContent{
border-radius: 2px;
// border: 1px solid #EEEEEE;

View File

@ -2,6 +2,7 @@ import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import './activity.css';
import { getImageUrl } from 'educoder';
import { truncateCommitId } from "../common/util";
class ActivityItem extends Component {
@ -25,9 +26,16 @@ class ActivityItem extends Component {
<span className="activity_type">{item.trend_type}</span>
</p >
:
// 如果是commit--CommitLog
item.trend_type === "CommitLog" ?
<p className="itemLine">
<Link to={`/${owner}/${projectsId}/commits/${item.commit_log && truncateCommitId(item.commit_log.commit_id)}`} className="font-16">{item.name}</Link>
<span className="activity_type">{item.trend_type}</span>
</p >
:
// 如果是合并请求
<p className="itemLine">
<Link to={`/${owner}/${projectsId}/pulls/${item.trend_id}`} className="font-16">{item.name}</Link>
<Link to={`/${item.project && item.project.owner&& item.project.owner.login}/${item.project && item.project.identifier}/pulls/${item.trend_id}`} className="font-16">{item.name}</Link>
<span className="activity_type">{item.trend_type}</span>
</p >
}

View File

@ -18,8 +18,9 @@
padding-bottom: 20px!important;
}
.contentBox{
width: 1200px;
margin:0px auto;
/* width: 1200px;
margin:0px auto; */
padding:0px 20px;
}
.pageDIV{
text-align: center;

View File

@ -3,7 +3,7 @@ import { Link } from 'react-router-dom';
/**
* nav:{list:[],active:0} */
export default(({ header , nav })=>{
export default(({ header , nav, history })=>{
return(
<ul className="list-l-Menu">
{header}
@ -13,11 +13,11 @@ export default(({ header , nav })=>{
return(
!item.hide &&<li key={key} className={nav.active === key?"active":''}>
<p>
<Link to={item.href}>
<a onClick={()=>{ item.href.indexOf("https") !== -1 ? window.location.href = item.href : history.push(item.href)}}>
{item.icon && <i className={`iconfont ${item.icon || 'icon-huabanfuben'} font-18 mr10`}></i>}
{item.img && <img src={item.img} alt="" width="20px" className="mr10"/>}
{item.name}
</Link>
</a>
</p>
</li>
)

View File

@ -3,20 +3,19 @@ import AccountProfile from "../../modules/user/AccountProfile";
import { getImageUrl } from 'educoder'
import axios from 'axios';
import cookie from 'react-cookies';
import { notification , Dropdown ,Popover, Menu,Badge } from 'antd';
import { notification , Dropdown , Menu , Icon } from 'antd';
import { Link } from 'react-router-dom';
import LoginDialog from '../../modules/login/LoginDialog';
import HeadSearch from '../Component/HeadSearch';
import { getOrzCompanyList } from '../../forge/Information/api';
import AddProjectModal from './AddProjectModal';
import '../../modules/tpm/TPMIndex.css';
import CheckProfile from '../Component/ProfileModal/Profile';
import logo from './img/logo.png'
import './header.scss';
import NoticeContent from './NoticeContent';
import MainLogo from './img/logo.png';
// TODO 这部分脚本从公共脚本中直接调用
const { SubMenu } = Menu
window._header_componentHandler = null;
// 非trustie链接则新开页跳转
@ -47,6 +46,7 @@ class NewHeader extends Component {
visible:false, //浮动消息框展示控制
showSubMenu: false,
zoneList: [], // 专区列表
companyList:[] //已开通工作台列表
}
}
componentDidMount() {
@ -60,6 +60,7 @@ class NewHeader extends Component {
window._header_componentHandler = this;
this.getZoneList(settings && settings.common.zone +'/api')
this.getComlist();
try {
window.sessionStorage.setItem("yslgeturls", JSON.stringify(window.location.href))
@ -101,8 +102,8 @@ class NewHeader extends Component {
//退出账号
var url = `/accounts/logout.json`;
axios.get((url)).then((result) => {
if (result !== undefined) {
window.location.href = "/";
if (result) {
this.props.history.push("/login");
}
}).catch((error) => {
console.log(error);
@ -267,11 +268,18 @@ class NewHeader extends Component {
}
renderMenu=(personal)=>{
const { current_user } = this.props;
const { mygetHelmetapi } = this.props;
const { companyList } = this.state;
return(
<Menu className="currentMenu">
<Menu.Item>
{/* <Menu.Item>
<span className="currentName" title={current_user && current_user.username}>{current_user && current_user.username}</span>
</Menu.Item> */}
{/* <Menu.Item>
<a href={`/${this.props.current_user && this.props.current_user.login}`}>首页</a>
</Menu.Item> */}
<Menu.Item>
<a href={`/${this.props.current_user && this.props.current_user.login}`}>代码库主页</a>
</Menu.Item>
{
personal && personal.length > 0 && personal.map((item,key)=>{
@ -280,8 +288,19 @@ class NewHeader extends Component {
)
})
}
{/* <li><Link to={`/settings/profile`}>设置</Link></li> */}
<Menu.Item><a onClick={() => this.educoderloginysl()}>退出</a></Menu.Item>
<SubMenu title={<span>我的工作台<Icon type="right" /></span>} Icon={null} popupClassName='subMyworkList'>
{
companyList && companyList.length>0 ?
companyList.map((i,k)=>{
return(
<Menu.Item><a href={`${ mygetHelmetapi && mygetHelmetapi.common.zone }/${i.enterpriseIdentifier}`} target='_blank'>{i.enterpriseName}</a></Menu.Item>
)
})
:<span>暂无工作台</span>
}
</SubMenu>
<Menu.Item><a onClick={() => this.educoderloginysl()}>退出登录</a></Menu.Item>
</Menu>
)
}
@ -290,6 +309,16 @@ class NewHeader extends Component {
this.setState({ visible });
};
getComlist=()=>{
getOrzCompanyList().then(res=>{
if(res){
this.setState({
companyList:res.data.rows
})
}
})
}
render() {
const { resetUserInfo ,showNotification,publicNav,mygetHelmetapi} = this.props;
let settings = mygetHelmetapi;
@ -306,6 +335,10 @@ class NewHeader extends Component {
return (
<div className={publicNav ? `newHeaders publicNav`:`newHeaders`} id="nHeader">
<div className="headerContent">
<div className="titleByHead">
<img src={logo} alt="" style={{width: '32px'}} />
<span className='font32 ml15'>{mygetHelmetapi && mygetHelmetapi.name}</span>
</div>
{isRender === true ?
<LoginDialog
{...this.props}
@ -319,24 +352,15 @@ class NewHeader extends Component {
{...this.props}
{...this.state}
/> : ""}
<div style={{width:"78px"}}>
{
publicNav &&
<a href={'https://www.ccf.org.cn/'} className={"fl"}>
<img src={MainLogo} alt="ccf" width="63px"/>
</a>
}
</div>
{
{/* {
settings && settings.nav_logo_url ?
<a href={settings && settings.new_course.default_url} className={"fl mr30"}>
<img alt="可控开源社区" className="logoimg" src={getImageUrl(`/${settings.nav_logo_url}`)}></img>
</a>
:
""
}
{/* <div className="head-nav pr"> */}
{
} */}
{/*{
settings && settings.navbar && settings.navbar.length > 0 ?
<ul id="header-nav" className="head-nav pr">
{
@ -373,21 +397,20 @@ class NewHeader extends Component {
)
}
})
}
}
</ul>
: ""
}
{/* </div> */}
<div className="head-right">
{ search_url && <HeadSearch {...this.props}/>}
{
}*/}
{/*<div className="head-right">
{ search_url && <HeadSearch {...this.props}/>} */}
{/* {
current_user && (current_user.main_site || current_user.login) && (settings && settings.add && settings.add.length>0)?
<Dropdown overlay={this.addMenu(settings && settings.add)} placement="bottomRight">
<img src={require(`./img/add.png`)} alt="" width="16px" className="mr15 ml30"/>
</Dropdown>:""
}
} */}
{ (settings && settings.common && settings.common.notice) && (current_user && current_user.login)?
{/* { (settings && settings.common && settings.common.notice) && (current_user && current_user.login)?
<Popover
overlayClassName="notice-popover"
placement={`bottomRight`}
@ -403,11 +426,11 @@ class NewHeader extends Component {
</Link>
</Popover>
: ""
}
</div>
}
</div>*/}
{!user || (user && !user.login) ?
<span className="font-15 ml30">
<a onClick={() => this.educoderlogin()} className="mr5 color-white">登录</a>
<Link to="/login" className="mr5 color-white">登录</Link>
{
(settings && settings.common && settings.common.register) ?
publicNav ?
@ -419,9 +442,7 @@ class NewHeader extends Component {
</span>
:
<Dropdown placement={`bottomRight`} overlay={this.renderMenu(settings && settings.personal)}>
<a href={`/${this.props.current_user && this.props.current_user.login}`}>
<img alt="头像" src={getImageUrl(`/${user.image_url}`)} className="currentImg"></img>
</a>
<img alt="头像" src={getImageUrl(`/${user.image_url}`)} className="currentImg"></img>
</Dropdown>
}
</div>

View File

@ -27,6 +27,30 @@
margin-left: 15px;
}
.subMyworkList {
li{
&:hover{
background-color: #4cacff;
a{color: #fff!important;}
}
a{
height: 40px;
line-height: 40px;
max-width: 150px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
padding:0px 12px;
}
}
span{
display: block;
height: 40px;
line-height: 40px;
padding:0px 12px;
}
}
.ant-dropdown-menu.currentMenu{
width: 120px;
text-align: center;
@ -38,6 +62,21 @@
text-overflow: ellipsis;
display: block;
}
.ant-dropdown-menu-submenu .ant-dropdown-menu-submenu-title{
height: 100%;
line-height: 40px;
padding: 0px 10px;
&:hover{
background: #829BFF;
color: #fff;
}
i{
margin-right: 0px;
}
}
.ant-dropdown-menu-submenu-arrow{
display: none;
}
li{
height: 40px;
line-height: 40px;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -252,4 +252,44 @@ export function updateMyResource(data) {
method: 'PUT',
data: data
});
}
/** 非专区接口,组织工作台相关 */
// 获取已开通企业的组织列表
export function getOrzCompanyList(){
return fetch({
url:`/pms/pmsEnterprise/myList`,
method: 'get',
})
}
// 查询组织是否开通企业
export function checkOpenedEnterprise(orgId){
return fetch({
url:`/pms/pmsEnterprise/${orgId}/workbenchUrl`,
method: 'get',
})
}
// 组织升级为企业
export function createEnterpriseByGitlinkOrgId(orgId, data) {
return fetch({
url: `/pms/pmsEnterprise/createByGitlinkOrgId/${orgId}`,
method: 'POST',
data: data
})
}
// 可选角色列表
export function getRoleList(){
return fetch({
url:`/pms/pmsEnterprise/roleList`,
method: 'get',
})
}
// 获取工作台初始用户列表
export function getUserList(orgId){
return fetch({
url:`/pms/pmsEnterprise/gitlinkUserList/${orgId}`,
method: 'get',
})
}

View File

@ -1,5 +1,7 @@
import axios from 'axios';
import cookie from 'react-cookies';
import { message , notification } from 'antd';
import { TokenKey } from '../javaFetch';
function beforeFetch(actionUrl){
if (window.location.href.indexOf('localhost') < 0) {
@ -11,6 +13,15 @@ function beforeFetch(actionUrl){
timeout: 1800000, // 请求超时时间
});
service.interceptors.request.use(config => {
if (cookie.load(TokenKey)) {
config.headers['Authorization'] = cookie.load(TokenKey); // 让每个请求携带自定义token 请根据实际情况自行修改
}
return config;
}, error => {
console.log(error);
});
service.interceptors.response.use(
response => {
const res = response||{};

View File

@ -23,6 +23,7 @@ import Nodata from '../Nodata';
import Invite from './sub/Invite';
import CheckProfile from '../Component/ProfileModal/Profile';
import RenderHtml from '../../components/render-html';
import imNoneImg from './img/importNone.png';
/**
* projectDetail.type:0是托管项目1是镜像项目2是同步镜像项目(为2时不支持在线创建在线上传在线修改在线删除创建合并请求等功能)
*/
@ -399,7 +400,7 @@ function CoderDepot(props){
<WhiteBack>
{mirror_status ===0 && <UpdateDescModal desc={desc} website={website} lesson_url={lesson_url} topicsInfo={topics} visible={openModal} onCancel={()=>setOpenModal(false)} onOk={okUpdate}/> }
<Spin spinning={isSpin}>
{
{/* {
((dirInfo || fileInfo) && mirror_status===0 ) &&
<React.Fragment>
<DrawerPanel
@ -417,10 +418,27 @@ function CoderDepot(props){
<span>目录</span>
</div>
</React.Fragment>
}
} */}
<div style={{minHeight:"500px"}}>
{
projectDetail && mirror_status === 2 &&
<div className='importFailTip'>
<img src={imNoneImg} alt="" width={325}/>
{
projectDetail.permission && ["Manager","Admin","Owner"].includes(projectDetail.permission) ?
<div className='failInfo'>
<p className='font-18 weight500 color-grey-3'>导入项目失败可能存在以下原因</p>
<li>1导入的仓库 URL 错误</li>
<li>2您需要导入的可能是一个您无权访问的私有仓库需要输入授权验证仓库的帐号密码或者个人令牌此信息仅用于本次代码同步不做任何记录</li>
<p className='font-18 weight500 color-grey-3'>请前往 <Link className='color-blue' to={`/${owner}/${projectsId}/settings`}>仓库设置</Link> 删除本项目后重新导入</p>
</div>
:
<p>导入项目失败请联系管理员重新导入</p>
}
</div>
}
{
projectDetail &&
projectDetail && mirror_status === 0 &&
<Box className="Panels">
<LongWidth>
<div className="panelmenu">
@ -493,10 +511,10 @@ function CoderDepot(props){
baseOperate &&
<CheckProfile {...props} sureFunc={compare}>+ 合并请求</CheckProfile>
}
{
{/* {
issuesFlag &&
<CheckProfile {...props} sureFunc={createIssue} checklogin>+ 疑修</CheckProfile>
}
} */}
</div>
{ fileOperate &&
@ -509,12 +527,12 @@ function CoderDepot(props){
<a>文件 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-grey-6 mr-5"></i></a>
</Dropdown>
}
{
{/* {
checkIfLogin && checkIfLogin()?
<a className='newBtn' onClick={()=>eventTrack(`/${owner}/${projectsId}/webIDE/tree/${branchName||defaultBranch}`)}>Web IDE <div className='newBtnImg'></div></a>
:
<a className='newBtn' onClick={()=>{showLoginDialog(`/${owner}/${projectsId}`)}}>Web IDE <div className='newBtnImg'></div></a>
}
} */}
<Dropdown overlay={downloadMenu} placement="bottomRight" trigger={['click']}>
<Button type={'primary'}>下载 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-white mr-3"></i></Button>

View File

@ -27,7 +27,8 @@ class CoderRootFileDetail extends Component {
description: props.detail.replace_content,
menuList:undefined,
replaceVisible:false,
loading:false
loading:false,
random:0,
};
}
@ -140,6 +141,12 @@ class CoderRootFileDetail extends Component {
EditFile = (flag) => {
const { onEdit } = this.props;
onEdit && onEdit(flag);
if(flag){
let num = Math.random();
this.setState({
random:num
})
}
};
DownLoadFile = (url) => {
@ -272,7 +279,7 @@ class CoderRootFileDetail extends Component {
} = this.props;
// 文件只读状态
const readOnly = this.props.history.location.search.indexOf('edit') === -1
const { language, languages, description , replaceVisible , loading } = this.state;
const { language, languages, description , replaceVisible , loading , random } = this.state;
let flag = current_user && current_user.login && (isManager || isDeveloper);
const Option = Select.Option;
return (
@ -395,6 +402,7 @@ class CoderRootFileDetail extends Component {
filepath={`/${detail.path}`}
content={detail.content}
readOnly={readOnly}
random={random}
md={md}
editorType="update"
currentBranch={currentBranch}

View File

@ -1,5 +1,5 @@
import React, { Component } from 'react';
import { Spin, Tooltip } from 'antd';
import { Button, Spin, Tooltip } from 'antd';
import { Link, Route, Switch } from 'react-router-dom';
import { withRouter } from "react-router";
import { Content, AlignTop } from '../Component/layout';
@ -263,7 +263,9 @@ class Detail extends Component {
mirror_status:2,
firstSync: false
})
this.deleteProjectBack();
this.getBanner();
this.getDetail();
// this.deleteProjectBack();
} else {
this.setState({
firstSync: false,
@ -309,9 +311,10 @@ class Detail extends Component {
this.props.showNotification("镜像同步成功!");
window.location.reload();
} else {
if (data.project && data.project.mirror_status === 2) {
this.deleteProjectBack();
}
// 导入失败仓库用户自主
// if (data.project && data.project.mirror_status === 2) {
// this.deleteProjectBack();
// }
this.getDetail();
this.getBanner();
}
@ -341,22 +344,22 @@ class Detail extends Component {
}
deleteProjectBack = () => {
const { history } = this.props;
const { projectsId, owner } = this.props.match.params;
axios.delete(`/${owner}/${projectsId}.json`).then(res => {
let hash = '/projects/mirror/new';
if (res && res.data) {
history.push({
pathname: hash,
mirror_status: 2
});
}
else {
window.location.hash = hash;
}
});
}
// deleteProjectBack = () => {
// const { history } = this.props;
// const { projectsId, owner } = this.props.match.params;
// axios.delete(`/${owner}/${projectsId}.json`).then(res => {
// let hash = '/projects/mirror/new';
// if (res && res.data) {
// history.push({
// pathname: hash,
// mirror_status: 2
// });
// }
// else {
// window.location.hash = hash;
// }
// });
// }
getDetail = () => {
const { projectsId, owner } = this.props.match.params;
@ -537,7 +540,26 @@ class Detail extends Component {
</div> : ""
}
// 删除仓库
deleteProject = () => {
const { projectsId , owner } = this.props.match.params;
const { projectName } = this.state;
this.props.confirm({
content: <span style={{display:"block",textAlign:"left"}}>该操作无法撤销且将会一并删除相关的疑修合并请求工作流里程碑动态等数据<br/>是否确认删除 <span style={{fontWeight:"bold"}}>{owner}/{projectName}({projectsId})</span></span>,
onOk: () => {
const url = `/${owner}/${projectsId}.json`;
axios.delete(url).then((result) => {
window.scrollTo(0,0);
this.props.showNotification("仓库删除成功!");
this.props.history.push(`/${owner}`);
})
.catch((error) => {
console.log(error);
});
},
});
};
render() {
const { projectDetail, watchers_count, praises_count,
forked_count, firstSync, secondSync,
@ -679,6 +701,9 @@ class Detail extends Component {
firstSync &&
<Content className="spincontent">
<Spin className="spinstyle" tip={project && `正在从 ${project.mirror_url} 迁移`} size="large" />
<Button className="red_deleteBtn mt30" onClick={this.deleteProject}>
删除本仓库
</Button>
</Content>
}
<Spin spinning={secondSync && !firstSync} className="spinstyle" tip="正在同步镜像" size="large">

View File

@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react";
import React, { useEffect, useState , useRef } from "react";
import styled from "styled-components";
import { Button ,Spin } from "antd";
import { timeFormat, truncateCommitId } from '../common/util';
@ -57,6 +57,24 @@ export default (props) => {
const [isSpin, setIsSpin] = useState(true);
const { sha , projectsId, owner } = match.params;
const [ dropLoading, setDropLoading] = useState(false); //loading
const limit = 100;
const fRef = useRef();
useEffect(()=>{
window.addEventListener("scroll",scrollListener);
return ()=>{window.removeEventListener("scroll",scrollListener);}
},[])
const scrollListener=()=>{
let scrollHeight = document.documentElement.scrollHeight;
let clientHeight = document.documentElement.clientHeight;
let scrollTop = document.documentElement.scrollTop;
if(Math.ceil(scrollTop+clientHeight) >= scrollHeight-5){
InitDiffData();
}
}
useEffect(()=>{
if(projectDetail){
const { author, name} = projectDetail;
@ -66,17 +84,18 @@ export default (props) => {
useEffect(() => {
if (projectsId && owner && sha) {
InitDiffData();
const url = `/${owner}/${projectsId}/commits/${sha}.json`;
axios
.get(url)
.then(result => {
if (result) {
setData(result.data);
// setData(result.data);
setCommit(result.data.commit);
setParents(result.data.parents);
setCommitter(result.data.committer || (result.data.commit && result.data.commit.committer));
setIsSpin(false);
}
})
.catch(error => {
@ -84,6 +103,28 @@ export default (props) => {
});
}
}, [projectsId , owner, sha]);
async function InitDiffData (){
let f = fRef.current ? fRef.current.files : [];
let p = fRef.current ? fRef.current.page : 1;
let hm = fRef.current ? fRef.current.hasMore : true;
if (!hm || dropLoading || !isSpin) {
return;
}
setDropLoading(true);
const url = `/v1/${owner}/${projectsId}/commits/${sha}/files.json`;
await axios.get(url,{
params:{page:p,limit}
}).then(res=>{
if(res && res.status === 200){
let arr = p === 1 ? res.data.files : [...f,...res.data.files];
setData(res.data);
fRef.current = {files:arr,page:p+1,hasMore:arr.length === limit};
setDropLoading(false);
}
})
}
return (
<div className="main" style={{padding:"0px",border:"none"}}>
<Spin spinning={isSpin}>
@ -132,10 +173,13 @@ export default (props) => {
<Files
history={history}
data={data}
filesData={fRef.current && fRef.current.files}
owner={owner}
projectsId={projectsId}
parentsSha={parents && parents.length > 0 && parents[0].sha}
mergeId={`commits/${sha}`}
/>
{ dropLoading && <p style={{textAlign:"center",color:"#999",padding:"10px"}}>文件加载中...</p>}
</Spin>
</div>
);

View File

@ -119,7 +119,8 @@
}
// coderDepot
.Panels{
max-width: 1200px;
// max-width: 1200px;
padding:0px 20px;
margin: 0 auto;
.panelmenu{
padding-top:20px;
@ -501,8 +502,9 @@
}
}
.coderSubPage{
width: 1200px;
margin:0px auto;
// width: 1200px;
// margin:0px auto;
padding:0px 20px;
}
.griditemAnchor{
margin-left: 0px!important;
@ -551,4 +553,27 @@
.replaceStyle{
height: 140px!important;
}
}
.importFailTip{
height: 500px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
flex-direction: column;
font-weight: 400;
font-size: 15px;
color: #4C5B76;
padding-top: 50px;
.failInfo{
max-width: 480px;
li{
font-size: 15px;
}
}
img{
margin-bottom: 35px;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View File

@ -6,8 +6,9 @@
background-color: #050d34;
}
.ProjectListIndex{
width: 1200px;
margin:20px auto;
// width: 1200px;
// margin:20px auto;
padding:20px;
display: flex;
align-items: flex-start;
flex-wrap:wrap;
@ -211,6 +212,7 @@
}
.spincontent{
height:400px;
flex-direction: column;
}
.spinstyle .ant-spin-text{
margin-top:30px;

View File

@ -52,7 +52,7 @@ function DetailBanner({ history,list , owner , projectsId ,showNotification , ur
Array.isArray(menuName)&& menuName.map((item,key)=>{
return(
<React.Fragment key={item.menu_name}>
{
{/* {
item.menu_name === "home" &&
<li className={pathname==="about" ? "active" : ""}>
<Link to={{ pathname: `/${owner}/${projectsId}/about`, state }}>
@ -60,7 +60,7 @@ function DetailBanner({ history,list , owner , projectsId ,showNotification , ur
<span>主页</span>
</Link>
</li>
}
} */}
{
item.menu_name === "code" &&
<li className={(pathname==="" || urlFlag) ? "active" : ""}>
@ -70,7 +70,7 @@ function DetailBanner({ history,list , owner , projectsId ,showNotification , ur
</Link>
</li>
}
{
{/* {
item.menu_name === "issues" &&
<li className={pathname==="issues" ? "active" : ""}>
<Link to={{ pathname: `/${owner}/${projectsId}/issues`, state }}>
@ -81,7 +81,7 @@ function DetailBanner({ history,list , owner , projectsId ,showNotification , ur
{projectDetail && projectDetail.issues_count ? <span className="num">{numFormat(projectDetail.issues_count)}</span> : ""}
</Link>
</li>
}
} */}
{
item.menu_name === "pulls" && projectDetail && parseInt(projectDetail.type) !== 2 && platform ?
<li className={pathname==="pulls" ? "active" : ""}>
@ -93,17 +93,16 @@ function DetailBanner({ history,list , owner , projectsId ,showNotification , ur
</li>:""
}
{/* 引擎仅对当前仓库管理员可见 */}
{
{/* {
item.menu_name === "devops" ?
<li className={pathname==="devops" ? "active" : ""}>
{/* <Link to={{ pathname: `/${owner}/${projectsId}/devops${open_devops ? `/dispose`:""}`, state }}> */}
<Link className='newTab' to={{ pathname: `/${owner}/${projectsId}/devops`, state:{...state,open_devops} }}>
<i className="iconfont icon-gongzuoliuicon font-13 mr5 color-grey-3"></i>引擎(Engine)<div className='newBtnImg'></div>
{projectDetail && projectDetail.ops_count ? <span>{projectDetail.ops_count}</span> : ""}
</Link>
</li>
:""
}
} */}
{/* {
item.menu_name === "resources" &&
<li className={pathname==="source" ? "active" : ""}>
@ -114,7 +113,7 @@ function DetailBanner({ history,list , owner , projectsId ,showNotification , ur
</Link>
</li>
} */}
{
{/* {
item.menu_name === "versions" &&
<li className={pathname==="milestones" ? "active" : ""}>
<Link to={{ pathname: `/${owner}/${projectsId}/milestones`, state }}>
@ -123,8 +122,8 @@ function DetailBanner({ history,list , owner , projectsId ,showNotification , ur
{projectDetail && projectDetail.versions_count ? <span className="num">{numFormat(projectDetail.versions_count)}</span> :""}
</Link>
</li>
}
{
} */}
{/* {
item.menu_name === "wiki" &&
<li className={pathname === "wiki" ? "active" : ""}>
<Link to={{ pathname: `/${owner}/${projectsId}/wiki`, state }}>
@ -132,8 +131,8 @@ function DetailBanner({ history,list , owner , projectsId ,showNotification , ur
<span>维基(Wiki)</span>
</Link>
</li>
}
{
} */}
{/* {
item.menu_name === "services" &&
<li className={pathname === "server" ? "active" : ""}>
<Link className='newTab' to={{ pathname: `/${owner}/${projectsId}/service`, state }}>
@ -141,7 +140,7 @@ function DetailBanner({ history,list , owner , projectsId ,showNotification , ur
<span>服务</span><div className='newBtnImg'></div>
</Link>
</li>
}
} */}
{
item.menu_name === "activity" &&
<li className={pathname==="activity" ? "active" : ""}>

View File

@ -275,8 +275,8 @@ class CreateMerge extends Component {
let _url = `/${mergeOwner}/${projectId}/compare/`;
// type为pull时pullBranch取value否则取原有值
// type为pull时mergeBranch取原有值否则取value
let _pullBranch = type === 'pull' ? value : pullBranch;
let _mergeBranch = type === 'pull' ? mergeBranch : value;
let _pullBranch = type === 'pull' ? value : returnbar(pullBranch);
let _mergeBranch = type === 'pull' ? returnbar(mergeBranch) : value;
if (pullOwner === mergeOwner) {
// 如果仓库相同, compare/目标分支...源分支
_url += `${turnbar(_mergeBranch)}...${turnbar(_pullBranch)}`;
@ -513,6 +513,7 @@ class CreateMerge extends Component {
changeCommitFunc={this.changeCommitFunc}
comparesData={comparesData}
pullOwnerLogin={pullOwnerLogin}
branchParams = {getBranchParams(this.props.location.pathname)}
></MergeFooter>
)}
</Spin>

View File

@ -1,20 +1,19 @@
import React ,{useEffect,useState } from 'react';
import { truncateCommitId } from '../common/util';
import { AlignCenter , FlexAJ } from '../Component/layout';
import { Tooltip,Progress } from 'antd';
import { Tooltip , Progress } from 'antd';
import './merge.css';
import './Index.scss';
import FileDrop from './components/fileDrop';
function Files({ data,history,owner,projectsId , parentsSha }){
const [ files , setFiles ] = useState(data && data.files);
const [ copyfileTipTitle, setCopyfileTipTitle] = useState("复制文件路径");
function Files({ data , filesData , history,owner,projectsId , parentsSha , mergeId }){
const [ files , setFiles ] = useState(filesData);
const [ isOpen, setIsOpen] = useState(false);
useEffect(()=>{
if(data){
setFiles(data.files);
if(filesData){
setFiles(filesData);
}
},[data]);
},[filesData]);
useEffect(()=>{
document.addEventListener('click',()=>{setIsOpen(false)})
@ -29,33 +28,22 @@ function Files({ data,history,owner,projectsId , parentsSha }){
}
}
function copyFileName(fileName){
var copyCont = document.createElement('input');
copyCont.defaultValue = fileName;
document.body.appendChild(copyCont);
copyCont.select(); //
document.execCommand("Copy"); //
copyCont.className = 'copyCont';
copyCont.style.display='none';
setCopyfileTipTitle("复制成功");
}
const folderOpen = (
<div className="folders">
<div className="folderList">
{files && files.map((item, key) => {
return (
<a href={`#value${key}`}>
<FlexAJ className="filesInfo" key={key} onClick={() => {item.flag && showDown(item.flag, key, item.isBin);setIsOpen(false);}}>
<FlexAJ className="filesInfo" key={key} onClick={() => {item.flag && showDown(item.flag, key, item.is_bin);setIsOpen(false);}}>
<AlignCenter>
<i className="iconfont icon-wenjianicon mr4"></i>
<span className="cursor-pointer" data-clipboard-text={item.name}>{item.name}</span>
<span className="cursor-pointer" data-clipboard-text={item.filename}>{item.filename}</span>
</AlignCenter>
<div className="see-file">
<Tooltip placement="top" title={`${item.addition+item.deletion}处更改${item.addition + item.deletion > 0 ? "":""}${item.addition>0?item.addition+"处添加":""}${item.addition>0 && item.deletion>0 ?"和":""}${item.deletion>0?item.deletion+"处删除":""}`}>
<Progress showInfo = {false} strokeColor = "#2DB44D" size="small" percent={item.addition/(item.addition+item.deletion)*100} />
{item.addition >0 && <span className="color-green ml10">+{item.addition}</span>}
{item.deletion >0 && <span className="color-red ml10">-{item.deletion}</span>}
<Tooltip placement="top" title={`${item.additions+item.deletions}处更改${item.additions + item.deletions > 0 ? "":""}${item.additions>0?item.additions+"处添加":""}${item.additions>0 && item.deletions>0 ?"和":""}${item.deletions>0?item.deletions+"处删除":""}`}>
<Progress showInfo = {false} strokeColor = "#2DB44D" size="small" percent={item.additions/(item.additions+item.deletions)*100} />
{item.additions >0 && <span className="color-green ml10">+{item.additions}</span>}
{item.deletions >0 && <span className="color-red ml10">-{item.deletions}</span>}
</Tooltip>
</div>
</FlexAJ>
@ -66,22 +54,17 @@ function Files({ data,history,owner,projectsId , parentsSha }){
</div>
)
function subStrContent(content){
return content ? content.slice(1) :"";
}
return(
<div onClick={(e)=>{e.nativeEvent.stopImmediatePropagation()}}>
<AlignCenter className="color-grey-9" style={{position:'relative'}}>
<div onClick={()=>{setIsOpen(!isOpen)}}>
<i className={`iconfont mr5 ${isOpen? "font-18 icon-sanjiaoxing-down":"font-16 icon-triangle"}`}></i>
<span className="color-grey-6 update-file-count">
共有<span className="color-grey-3"> {data && data.files_count} 个文件 </span>被更改
{ data && data.total_addition ? <span>包括 <span className="color-green">{data && data.total_addition} 次插入</span></span>:"" }
{ data && data.total_addition && data.total_deletion ? " 和 ":""}
{ data && data.total_deletion ? <span className="color-red"> {data && data.total_deletion} 次删除</span>:""}
</span>
</div>
<AlignCenter className="color-grey-9" style={{position:'relative'}} onClick={()=>{setIsOpen(!isOpen)}}>
<div style={{width:20}}><i className={`iconfont mr5 ${isOpen? "font-18 icon-sanjiaoxing-down":"font-16 icon-triangle"}`}></i></div>
<span className="color-grey-6 update-file-count">
共有<span className="color-grey-3"> {data && data.file_nums} 个文件 </span>被更改
{ data && data.total_addition ? <span>包括 <span className="color-green">{data && data.total_addition} 次插入</span></span>:"" }
{ data && data.total_addition && data.total_deletion ? " 和 ":""}
{ data && data.total_deletion ? <span className="color-red"> {data && data.total_deletion} 次删除</span>:""}
</span>
{isOpen && folderOpen}
</AlignCenter>
{
@ -92,57 +75,7 @@ function Files({ data,history,owner,projectsId , parentsSha }){
return(
<div className="files" key={key}>
<a id= {`value${key}`} className="anchorPoint"></a>
<FlexAJ className="filesInfo">
<AlignCenter>
{!item.isBin ? <i className={!item.flag?"iconfont icon-sanjiaoxing-down color-grey-9":"iconfont icon-triangle font-15 color-grey-9"} onClick={()=>showDown(item.flag,key,item.isBin)}></i>:""}
<span className="cursor-pointer" data-clipboard-text={item.name} onClick={()=>showDown(item.flag,key,item.isBin)}>
{ item.isRenamed && item.old_name}
{ item.isRenamed && <i className="iconfont icon-youjiang font-12 color-grey-8 ml5 mr5"></i> }
{item.name}
</span>
<Tooltip
title={copyfileTipTitle}
onVisibleChange={()=>setCopyfileTipTitle("复制文件路径")}
>
<i className="iconfont icon-fuzhiicon ml6" onClick={()=>copyFileName(item.name)}></i>
</Tooltip>
</AlignCenter>
<div className="see-file">
<Tooltip placement="top" title={`${item.addition + item.deletion}处更改${item.addition + item.deletion > 0 ? "":""} ${item.addition > 0 ? item.addition + "处添加" : ""}${item.addition > 0 && item.deletion > 0 ? "和" : ""}${item.deletion > 0 ? item.deletion + "处删除" : ""}`}>
<Progress showInfo = {false} strokeColor = "#2DB44D" size="small" percent={item.addition/(item.addition+item.deletion)*100} />
<span className="ml10">{item.addition+item.deletion}</span>
</Tooltip>
{
!item.isSubmodule &&
<span className="see-file-btn" onClick={()=>{history.push(`/${owner}/${projectsId}${item.isDeleted ? `/commits/${truncateCommitId(parentsSha)}`:`/tree/${truncateCommitId(item.sha)}/${item.name}`}`)}}>查看文件</span>
}
</div>
</FlexAJ>
{
item.sections && item.sections.length >= 1 && !item.flag &&
<div className="filesContent">
{
item.sections.map((i,k)=>{
return(
i.lines && i.lines.length>0 && i.lines.map((item,key)=>{
return(
<div key={k+key} className={(item.type === 2) ? "linesContent add" : item.type === 3 ? "linesContent reduce": item.type===4?"linesContent translate":"linesContent"}>
<span className="lines">
<span>{item.leftIdx && item.leftIdx !=="0" ? item.leftIdx :"" }</span>
<span>{item.rightIdx && item.rightIdx !=="0" ? item.rightIdx :"" }</span>
</span>
<p style={{display:"flex"}}>
<span className="linetype">{item.type===2 ? "+" : item.type===3 ? "-" :""}</span>
{ (item.type===3 || item.type===2) ? subStrContent(item.content) : item.content}
</p>
</div>
)
})
)
})
}
</div>
}
<FileDrop item={item} prekey={key} projectsId={projectsId} owner={owner} history={history} parentsSha={parentsSha} mergeId={mergeId}/>
</div>
)
})

View File

@ -110,11 +110,19 @@
border-top: 1px solid #F3F4F6;
}
.mergeBox{
margin:0px auto;
width: 1200px;
// margin:0px auto;
// width: 1200px;
padding:0px 20px;
}
.linetype{
width:30px;
text-align: center;
display: inline-block;
}
.diffDesc{
padding:30px 0px;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}

View File

@ -22,14 +22,21 @@ class MergeFooter extends Component {
activeKey: '1',
commitCount: 0,
filesCount: 0,
unitData:undefined,
//
commentsTotalCount: 0,
page:1,
hasMore:true,
dropLoading:false,
limit:100
};
}
componentDidMount() {
this.Init();
// 便
this.props.bindFootRef && this.props.bindFootRef(this);
window.addEventListener("scroll",this.scrollListener);
return ()=>{window.removeEventListener("scroll",this.scrollListener);}
}
componentDidUpdate(prevProps) {
@ -41,6 +48,18 @@ class MergeFooter extends Component {
}
}
scrollListener=()=>{
let scrollHeight = document.documentElement.scrollHeight;
let clientHeight = document.documentElement.clientHeight;
let scrollTop = document.documentElement.scrollTop;
if(Math.ceil(scrollTop+clientHeight) >= scrollHeight-5){
const { match } = this.props;
const { projectsId, owner, mergeId } = match.params;
this.getFile(owner, projectsId, mergeId);
}
}
Init = (isTabChange) => {
const { data, location, match } = this.props;
const { pathname } = location;
@ -60,7 +79,7 @@ class MergeFooter extends Component {
this.setState({
activeKey: activeKey,
commitCount: data && data.commits_count,
filesCount: data && data.files_count,
filesCount:data && data.files_count
});
};
@ -81,7 +100,7 @@ class MergeFooter extends Component {
if (result) {
this.setState({
commitsData: result.data.commits,
commitCount: result.data.commits_count,
commitCount: result.data.commits_count
});
}
this.setState({ isSpin: false });
@ -91,29 +110,38 @@ class MergeFooter extends Component {
});
};
getFile = (owner, projectsId, mergeId) => {
this.setState({ isSpin: true });
const url = `/${owner}/${projectsId}/pulls/${mergeId}/files.json`;
axios
.get(url)
.then((result) => {
if (result) {
this.setState({
filesData: result.data,
filesCount: result.data.files_count,
});
}
this.setState({ isSpin: false });
})
.catch((error) => {
this.setState({ isSpin: false });
});
getFile = async(owner, projectsId, mergeId) => {
const { page,limit , hasMore , dropLoading , filesData } = this.state;
if(!hasMore || dropLoading){
return;
}
this.setState({ isSpin: page === 1 , dropLoading:page > 1 });
const url = `/v1/${owner}/${projectsId}/pulls/${mergeId}/files.json`;
await axios.get(url,{
params:{page,limit}
}).then((result) => {
if (result) {
let datas = result.data;
let files = page === 1 ? datas.files : filesData.concat(datas.files);
this.setState({
unitData:datas,
filesData: files,
hasMore:datas.files && datas.files.length === limit,
page:page+1
});
}
this.setState({ dropLoading:false,isSpin: false });
})
.catch((error) => {
this.setState({ isSpin: false });
});
};
render() {
const { projectsId, owner, mergeId } = this.props.match.params;
const { order_id, data = {} } = this.props;
const { order_id, data = {} , pullOwnerLogin } = this.props;
const {
isSpin,
activeKey,
@ -121,6 +149,8 @@ class MergeFooter extends Component {
commitCount,
filesData,
commitsData = [],
unitData,
dropLoading
} = this.state;
// Comment0
@ -128,7 +158,6 @@ class MergeFooter extends Component {
this.state.commentsTotalCount || data.comments_total_count || 0,
10
);
return (
<div className="main mergeRequest" style={{ paddingTop: '0px' }}>
<Spin spinning={isSpin}>
@ -193,12 +222,17 @@ class MergeFooter extends Component {
}
key="3"
>
<Files
{...this.props}
data={filesData}
projectsId={projectsId}
owner={owner}
/>
<div>
<Files
{...this.props}
data={unitData}
filesData={filesData}
projectsId={projectsId}
owner={owner}
mergeId={`pulls/${mergeId}`}
/>
{ dropLoading && <p style={{textAlign:"center",color:"#999",padding:"10px"}}>文件加载中...</p>}
</div>
</TabPane>
)}
</Tabs>

View File

@ -404,12 +404,20 @@ class MessageCount extends Component {
{
<div className="mt15">
<Tag className="pr-branch-tag">
<Link
to={`/${data.pull_request.is_original ? data.pull_request.fork_project_user : data.issue.project_author}/${data.pull_request.is_original?data.project_identifier:projectsId}/tree/${turnbar(data.pull_request && data.pull_request.head)}`}
className="ver-middle task-hide" style={{maxWidth:"300px"}} title={`${data.pull_request.fork_project_user}: ${data.pull_request && data.pull_request.head}`}
>
{data.pull_request && data.pull_request.fork_project_user}: {data.pull_request && data.pull_request.head}
</Link>
{
(data.pull_request.fork_project_user || data.issue.author_name!=="已注销") ?
<Link
to={`/${data.pull_request.is_original ? data.pull_request.fork_project_user : data.issue.project_author}/${data.pull_request.is_original?data.project_identifier:projectsId}/tree/${turnbar(data.pull_request && data.pull_request.head)}`}
className="ver-middle task-hide" style={{maxWidth:"300px"}} title={`${data.pull_request.fork_project_user}: ${data.pull_request && data.pull_request.head}`}
>
{data.pull_request && (data.pull_request.is_original ? data.pull_request.fork_project_user:data.issue.author_name)}: {data.pull_request && data.pull_request.head}
</Link>
:
<span className="ver-middle task-hide" style={{maxWidth:"300px"}} title={`${data.pull_request.fork_project_user}: ${data.pull_request && data.pull_request.head}`}>
{data.pull_request && (data.pull_request.is_original ? data.pull_request.fork_project_user:data.issue.author_name)}: {data.pull_request && data.pull_request.head}
</span>
}
</Tag>
<span className="mr8 ver-middle">
<i
@ -638,7 +646,7 @@ class MessageCount extends Component {
{...this.props}
{...this.state}
bindFootRef={this.bindFootRef}
pullOwnerLogin={data.pull_request && data.pull_request.fork_project_user}
pullOwnerLogin={data.pull_request && (data.pull_request.is_original ? data.pull_request.fork_project_user:data.issue.project_author)}
></MergeLinkFooter>
</div>
) : (

View File

@ -281,7 +281,6 @@ class NewMerge extends Component {
id,
comparesData
} = this.state;
const renderBrances = (list, type) => {
if (list && list.length > 0) {
return list.map((item, key) => {
@ -313,7 +312,9 @@ class NewMerge extends Component {
return <div dangerouslySetInnerHTML={{ __html: html }}></div>;
};
let { project } = this.props;
// 源仓库所有者login
const pullOwnerLogin = projects_names && projects_names.filter(item=>{return item.id === id})[0].project_user_login;
console.log("-------------",pullOwnerLogin,projects_names);
return (
<div>
<div className="main">

View File

@ -4,7 +4,6 @@ import axios from "axios";
import "../Order/order.scss";
import "./merge.css";
import MergeForm from "./merge_form";
import MergeFooter from "./merge_footer";
const Option = Select.Option;
class UpdateMerge extends Component {
constructor(props) {

View File

@ -0,0 +1,117 @@
import React ,{useEffect,useState } from 'react';
import { truncateCommitId } from '../../common/util';
import { AlignCenter , FlexAJ } from '../../Component/layout';
import { Tooltip , Progress , Spin } from 'antd';
import "../Index.scss";
import axios from 'axios';
function FileDrop({prekey,item,projectsId,owner , history , mergeId,parentsSha}){
const [ copyfileTipTitle, setCopyfileTipTitle] = useState("复制文件路径");
const [ sections, setSections ] = useState(undefined);
const [ show, setShow ] = useState(true);
const [ isSpin, setIsSpin ] = useState(false);
useEffect(()=>{
if(prekey < 3 && item && item.filename){
showDown(item.filename);
}
},[prekey,item])
function copyFileName(fileName){
var copyCont = document.createElement('input');
copyCont.defaultValue = fileName;
document.body.appendChild(copyCont);
copyCont.select(); //
document.execCommand("Copy"); //
copyCont.className = 'copyCont';
copyCont.style.display='none';
setCopyfileTipTitle("复制成功");
}
function subStrContent(content){
return content ? " " + content.slice(1) :"";
}
function showDown(filename){
if(!sections){
setIsSpin(true);
const url = `/v1/${owner}/${projectsId}/${mergeId}/files.json`;
axios.get(url,{
params:{filepath:filename}
}).then(res=>{
if(res){
let files = res.data && res.data.files && res.data.files.length>0 && res.data.files[0];
setSections(files.sections);
setShow(true);
setIsSpin(false);
}
})
}else{
setShow(!show);
}
}
return(
<div key={prekey}>
<Spin spinning={isSpin}>
<FlexAJ className="filesInfo">
<AlignCenter onClick={()=>setShow(!show)} style={{cursor:!item.is_bin && item.changes !== 0?"pointer":"default"}}>
{(!item.is_bin && item.changes !== 0) ? <div style={{width:20}}><i className={show ?"iconfont icon-sanjiaoxing-down color-grey-9":"iconfont icon-triangle font-15 color-grey-9"}></i></div>:""}
<span className="cursor-pointer" data-clipboard-text={item.name}>
{ item.is_renamed && item.old_name}
{ item.is_renamed && <i className="iconfont icon-youjiang font-12 color-grey-8 ml5 mr5"></i> }
{item.filename}
</span>
<Tooltip
title={copyfileTipTitle}
onVisibleChange={()=>setCopyfileTipTitle("复制文件路径")}
>
<i className="iconfont icon-fuzhiicon ml6" onClick={(e)=>{e.stopPropagation();copyFileName(item.filename);}}></i>
</Tooltip>
</AlignCenter>
<div className="see-file">
<Tooltip placement="top" title={`${item.additions + item.deletions}处更改${item.additions + item.deletions > 0 ? "":""} ${item.additions > 0 ? item.additions + "处添加" : ""}${item.additions > 0 && item.deletions > 0 ? "和" : ""}${item.deletions > 0 ? item.deletions + "处删除" : ""}`}>
<Progress showInfo = {false} strokeColor = "#2DB44D" size="small" percent={item.additions/(item.additions+item.deletions)*100} />
<span className="ml10">{item.additions+item.deletions}</span>
</Tooltip>
{
!item.is_submodule &&
<span className="see-file-btn" onClick={()=>{history.push(`/${owner}/${projectsId}${item.is_deleted ? `/commits/${truncateCommitId(parentsSha)}`:`/tree/${truncateCommitId(item.sha)}/${item.filename}`}`)}}>查看文件</span>
}
</div>
</FlexAJ>
{
(!item.is_bin && item.changes !== 0) && show &&
<div className="filesContent">
{
(sections && sections.length > 0) ? sections.map((i,k)=>{
return(
i.lines && i.lines.length>0 && i.lines.map((item,keys)=>{
return(
<div key={k+keys} className={(item.type === 2) ? "linesContent add" : item.type === 3 ? "linesContent reduce": item.type===4?"linesContent translate":"linesContent"}>
<span className="lines">
<span>{item.left_index && item.left_index !=="0" ? item.left_index :"" }</span>
<span>{item.right_index && item.right_index !=="0" ? item.right_index :"" }</span>
</span>
<div style={{display:"flex"}}>
<span className="linetype">{item.type===2 ? "+" : item.type===3 ? "-" :""}</span>
<div>
<span style={{whiteSpace:"pre-wrap"}}>{(item.type===3 || item.type===2) ? subStrContent(item.content) : item.content}</span>
</div>
</div>
</div>
)
})
)
})
:
<div className='diffDesc'>
<a onClick={()=>showDown(item.filename)} className='color-blue'>加载差异</a>差异被折叠
</div>
}
</div>
}
</Spin>
</div>
)
}
export default FileDrop;

View File

@ -197,6 +197,12 @@ form .ant-cascader-picker, form .ant-select {
.linesContent .lines > span:first-child{
margin-right: 0px;
}
.linesContent .lines,.linesContent .linetype,.no-select,.filesInfo{
-webkit-user-select: none; /* Safari */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* IE/Edge */
user-select: none; /* 标准语法 */
}
.linesContent .lines > span{
width: 50%;
text-align: right;

View File

@ -374,7 +374,7 @@ class merge extends Component {
</Dropdown>
</li>
<li>
{/* <li>
<Dropdown
className="topWrapperSelect"
overlay={this.renderMenu(
@ -390,7 +390,7 @@ class merge extends Component {
<Icon type="caret-down" className="ml5" />
</span>
</Dropdown>
</li>
</li> */}
<li>
<Dropdown

View File

@ -1,10 +1,13 @@
import React, { Component } from 'react';
import { Tabs } from 'antd';
import { Tabs , Spin } from 'antd';
import Commits from './Commits';
import Files from './Files';
import { returnbar , turnbar } from 'educoder';
import { Base64 } from 'js-base64';
import '../Order/order.scss';
import './merge.css';
import axios from 'axios';
const { TabPane } = Tabs;
@ -13,9 +16,30 @@ class MergeFooter extends Component {
super(props);
this.state = {
activeKey: '1',
diff:undefined,
filesData: undefined,
page:1,
hasMore:true,
dropLoading:false,
limit:100
};
}
componentDidMount(){
this.getFilesInfo();
window.addEventListener("scroll",this.scrollListener);
return ()=>{window.removeEventListener("scroll",this.scrollListener);}
}
scrollListener=()=>{
let scrollHeight = document.documentElement.scrollHeight;
let clientHeight = document.documentElement.clientHeight;
let scrollTop = document.documentElement.scrollTop;
if(Math.ceil(scrollTop+clientHeight) >= scrollHeight-5){
this.getFilesInfo();
}
}
changeTab = (index) => {
this.setState({
activeKey: index,
@ -27,11 +51,58 @@ class MergeFooter extends Component {
changeCommitFunc&& changeCommitFunc(page);
}
componentDidUpdate(prevProps) {
// 解决切换tab后浏览器回退不刷新的问题、点击tab后url变化但tab未切换的问题
const newPathname = this.props.location.pathname;
const prevPathname = prevProps.location.pathname;
if (newPathname !== prevPathname) {
this.getFilesInfo();
}
}
getFilesInfo=()=>{
const { hasMore , dropLoading , filesData , page , limit } = this.state;
if(!hasMore || dropLoading){
return;
}
this.setState({dropLoading:page>1})
const { branchParams = {} } = this.props;
const { mergeOwner, projectId } = branchParams;
let url = `/v1/${mergeOwner}/${projectId}/${this.getUrl()}/files.json`;
axios.get(url,{
params:{page,limit}
}).then(res=>{
if(res){
let datas = res.data;
let files = page === 1 ? datas.files : filesData.concat(datas.files);
this.setState({
diff:res.data ,
filesData: files,
hasMore:datas.files && datas.files.length === limit,
dropLoading:false,page:page+1
})
}
})
}
getUrl = ()=>{
const { branchParams = {} } = this.props;
const { pullOwner, pullBranch, mergeOwner, mergeBranch, projectId , pullIdentity } = branchParams;
let url = `compare`;
if (mergeOwner === pullOwner) {
url += `/${Base64.encode(returnbar(pullBranch))}...${Base64.encode(returnbar(mergeBranch))}`;
} else {
url += `/${Base64.encode(returnbar(mergeBranch))}...${pullOwner}/${pullIdentity || projectId}:${Base64.encode(returnbar(pullBranch))}`;
}
return url;
}
render() {
const { projectsId, owner } = this.props.match.params;
const { comparesData = {} ,limit } = this.props;
const { commits, diff, commits_count } = comparesData;
const { activeKey } = this.state;
const { comparesData = {} ,limit ,branchParams } = this.props;
const { commits,commits_count } = comparesData;
const { activeKey , diff , filesData , dropLoading } = this.state;
return (commits && commits.length === 0) || !diff ? (
''
@ -71,19 +142,24 @@ class MergeFooter extends Component {
tab={
<span>
<span className="font-16">文件</span>
{diff.files_count > 0 && (
<span className="tabNum">{diff.files_count}</span>
{diff.file_nums > 0 && (
<span className="tabNum">{diff.file_nums}</span>
)}
</span>
}
key="3"
>
<Files
{...this.props}
data={diff}
projectsId={projectsId}
owner={owner}
/>
<div>
<Files
{...this.props}
data={diff}
filesData={filesData}
projectsId={projectsId}
owner={owner}
mergeId={this.getUrl()}
/>
{ dropLoading && <p style={{textAlign:"center",color:"#999",padding:"10px"}}>文件加载中...</p>}
</div>
</TabPane>
)}
</Tabs>

View File

@ -358,7 +358,7 @@ class MergeForm extends Component {
</Select>
)}
</Form.Item>
<Form.Item>
{/* <Form.Item>
{getFieldDecorator("fixed_version_id", {
initialValue: fixed_version_id,
})(
@ -378,7 +378,7 @@ class MergeForm extends Component {
{this.renderSelect(issue_versions)}
</Select>
)}
</Form.Item>
</Form.Item> */}
<Form.Item>
{getFieldDecorator("issue_tag_ids", {
initialValue: issue_tag_ids,

View File

@ -57,7 +57,8 @@ class Index extends Component {
tokenConTri: false,
gitHubUrl:false,
checkToken:undefined
checkToken:undefined,
ownerDisabled:false
}
}
componentDidMount = () => {
@ -94,15 +95,21 @@ class Index extends Component {
})
if(OIdentifier){
owner = owner.filter(item=>item.login === OIdentifier);
this.setState({
ownerDisabled:owner[0].id ? true :false
})
}else if(user_id){
owner = owner.filter(item=>item.id === user_id);
this.setState({
ownerDisabled:false
})
}
this.props.form.setFieldsValue({
user_id:owner && owner[0].id
})
owner && this.setState({
owners_id:owner[0].id,
owners_name:owner[0].name
owners_name:owner[0].name,
})
this.setOptionsList(owner, 'owners');
}
@ -225,10 +232,10 @@ class Index extends Component {
license_id:licenseFlag ? license_id : undefined,
ignore_id:ignoreFlag ? ignore_id : undefined,
// user_id:owners_id,
blockchain: tokenConTri,
blockchain_token_all: 10000,
blockchain_init_token: parseInt(blockchain_init),
auth_token:((projectsType && projectsType === "mirror") && gitHubUrl)? values.auth_token : undefined
// blockchain: tokenConTri,
// blockchain_token_all: 10000,
// blockchain_init_token: parseInt(blockchain_init),
// auth_token:((projectsType && projectsType === "mirror") && gitHubUrl)? values.auth_token : undefined
}).then((result) => {
if (result && result.data.id) {
projectsType && projectsType !== "mirror" && this.props.showNotification(`项目创建成功!`);
@ -400,7 +407,7 @@ class Index extends Component {
const { getFieldDecorator } = this.props.form;
// 项目类型deposit-托管项目mirror-镜像项目
const { projectsType } = this.props.match.params;
const {current_user:{open_blockchain}} = this.props;
const {current_user:{open_blockchain,login}} = this.props;
const {
CategoryList,
@ -426,12 +433,13 @@ class Index extends Component {
categoreFlag,
tokenConTri,
gitHubUrl,
checkToken
checkToken,
ownerDisabled
} = this.state;
return (
<div className="main back-white" style={{padding:"0px",border:"none"}}>
<div className="newPanel">
<div className="newPanel_title">{projectsType && projectsType === "mirror" ? "导入" : "新建"}项目</div>
<div className="newPanel_title">{projectsType && projectsType === "mirror" ? "导入" : "新建"}代码库</div>
<Spin spinning={isSpin}>
<Form>
<div className="newPanel_content">
@ -448,7 +456,7 @@ class Index extends Component {
required: true, message: '请填写镜像版本库地址'
}],
})(
<Input placeholder="请输入需要导入到本项目的仓库地址" onBlur={this.ChangeAddr} />
<Input placeholder="请输入需要导入到本代码库的仓库地址" onBlur={this.ChangeAddr} />
)}
</Form.Item>
<p className="formTip" style={{color:"#D1d1c9"}}>示例https://github.com/Stability-AI/StableStudio.git</p>
@ -460,7 +468,7 @@ class Index extends Component {
<p className="mt10 mb10 color-grey-3 pointer" onClick={this.changeMirrorCheck}>
需要授权验证<i className={mirrorCheck ? "iconfont icon-xiajiantou font-13 ml10 color-grey-8":"iconfont icon-youjiantou font-13 ml10 color-grey-8"}></i>
<span className="ml20 font-12" style={{color:"#D1d1c9"}}>
如果导入项目为私有仓库{gitHubUrl ? `则需输入目标平台用户token进行授权`:"则必须填写相应平台正确的用户名和密码"}
如果导入代码库为私有仓库{gitHubUrl ? `则需输入目标平台用户token进行授权`:"则必须填写相应平台正确的用户名和密码"}
{gitHubUrl && <a href="https://forum.gitlink.org.cn/forums/8516/detail" className="color-blue" target="_blank">如何获取token</a>}
</span>
</p>
@ -526,6 +534,7 @@ class Index extends Component {
})(
<Select
showSearch
disabled={ownerDisabled}
style={{width:"260px",height:"33px"}}
placeholder="请选择拥有者"
className="plateAutoComplete"
@ -546,13 +555,13 @@ class Index extends Component {
</Form.Item>
<span className="ml10 mr10 mt10 font-18">/</span>
<Form.Item
label="项目名称"
label="代码库名称"
className="flex1 explainPos"
colon={false}
>
{getFieldDecorator('name', {
rules: [{
required: true, message: '请填写项目名称'
required: true, message: '请填写代码库名称'
}],
})(
<Input placeholder="例如:团队协作方法与研究" maxLength={50}/>// onBlur={this.changeName}
@ -560,28 +569,28 @@ class Index extends Component {
</Form.Item>
</AlignCenter>
<Form.Item
label={<span>项目标识 <span className="color-grey-9">(项目url标识部分)</span></span>}
label={<span>代码库标识 <span className="color-grey-9">(代码库url标识部分)</span></span>}
colon={false}
>
{getFieldDecorator('repository_name', {
rules: [{
required: true, message: '请填写项目标识'
required: true, message: '请填写代码库标识'
}],
})(
<Input placeholder="项目标识请使用与项目相关的英文关键字" maxLength={100} />
<Input placeholder="代码库标识请使用与代码库相关的英文关键字" maxLength={100} />
)}
</Form.Item>
<div className="pr">
<span className="toprightNum">{descNum}/200</span>
<Form.Item
label="项目简介"
label="代码库简介"
colon={false}
style={{marginBottom:"0px"}}
>
{getFieldDecorator('description', {
rules: [],
})(
<Input.TextArea maxLength={200} placeholder="项目的介绍" autoSize={{ minRows: 2, maxRows: 6 }} onChange={this.changeDesc}/>
<Input.TextArea maxLength={200} placeholder="代码库的介绍" autoSize={{ minRows: 2, maxRows: 6 }} onChange={this.changeDesc}/>
)}
</Form.Item>
</div>
@ -649,7 +658,7 @@ class Index extends Component {
className="privatePart"
>
{getFieldDecorator('private')(
<Checkbox value="limit">项目设为私有<span className="font-13 color-grey-9">(只有项目所有人或拥有权限的项目成员才能看到)</span></Checkbox>
<Checkbox value="limit">代码库设为私有<span className="font-13 color-grey-9">(只有代码库所有人或拥有权限的代码库成员才能看到)</span></Checkbox>
)}
</Form.Item >
{
@ -667,7 +676,7 @@ class Index extends Component {
className="privatePart"
>
{getFieldDecorator('categoreFlag')(
<Checkbox checked={categoreFlag} onChange={(e)=>this.showCateFunc(e)}>项目类别</Checkbox>
<Checkbox checked={categoreFlag} onChange={(e)=>this.showCateFunc(e)}>代码库类别</Checkbox>
)}
</Form.Item>
{categoreFlag &&
@ -676,13 +685,13 @@ class Index extends Component {
>
{getFieldDecorator('project_category', {
rules: [{
required: categoreFlag, message: '请选择项目类别',
required: categoreFlag, message: '请选择代码库类别',
}, {
validator: (rule, value, callback) => this.checkId(rule, value, callback, CategoryList, '项目类别')
validator: (rule, value, callback) => this.checkId(rule, value, callback, CategoryList, '代码库类别')
}],
})(
<AutoComplete
placeholder="请选择项目类别"
placeholder="请选择代码库类别"
onChange={(value, e) => this.ChangePlatform(value, e, 'project_category', CategoryList)}
className="plateAutoComplete"
onBlur={(value) => this.blurCategory(value, CategoryList, "project_category")}
@ -696,20 +705,20 @@ class Index extends Component {
className="privatePart"
>
{getFieldDecorator('languageFlag')(
<Checkbox checked={languageFlag} onChange={(e)=>this.showLanguageFunc(e)}>项目语言</Checkbox>
<Checkbox checked={languageFlag} onChange={(e)=>this.showLanguageFunc(e)}>代码库语言</Checkbox>
)}
</Form.Item>
{languageFlag &&
<Form.Item>
{getFieldDecorator('project_language', {
rules: [{
required: languageFlag, message: '请选择项目语言'
required: languageFlag, message: '请选择代码库语言'
}, {
validator: (rule, value, callback) => this.checkId(rule, value, callback, LanguageList, '项目语言')
validator: (rule, value, callback) => this.checkId(rule, value, callback, LanguageList, '代码库语言')
}],
})(
<AutoComplete
placeholder="请选择项目语言"
placeholder="请选择代码库语言"
onChange={(value, e) => this.ChangePlatform(value, e, 'project_language', LanguageList)}
className="plateAutoComplete"
onBlur={(value) => this.blurCategory(value, LanguageList, "project_language")}
@ -720,13 +729,13 @@ class Index extends Component {
</Form.Item>
}
{/* 确权 仅在新建项目时 */}
{/* 确权 仅在新建代码库时 */}
{open_blockchain && projectsType === "deposit" && <div className='mt10 mb10'>
<p className='font-16'>确权</p>
<div className='mt5 mb5 color-grey3'><Checkbox checked={tokenConTri} onChange={(e)=>{this.setState({tokenConTri:e.target.checked})}}>加入贡献值激励确权机制</Checkbox></div>
{tokenConTri && <Form.Item
className="flex1"
extra="Token指本项目的虚拟货币决定用户在本仓库贡献度的比例可以通过issue悬赏或在个人主页贡献确权页进行转移。创建项目时每个项目的Token总量为10000您可以分配您可获取的Token数量未分配的Token将保留至项目Token余额"
extra="Token指本代码库的虚拟货币决定用户在本仓库贡献度的比例可以通过issue悬赏或在个人主页贡献确权页进行转移。创建代码库时每个代码库的Token总量为10000您可以分配您可获取的Token数量未分配的Token将保留至代码库Token余额"
>
{getFieldDecorator('blockchain_init', {
rules: [{
@ -742,7 +751,7 @@ class Index extends Component {
}
}}],
})(
<Input placeholder='请填写您(项目创建者获取的初始Token值'/>
<Input placeholder='请填写您(代码库创建者获取的初始Token值'/>
)}
</Form.Item>}
</div>}
@ -751,8 +760,8 @@ class Index extends Component {
<span className="ant-form-item-required"></span>
</div>
<Form.Item className="formTip mt20">
<Button type="primary" onClick={this.subMitFrom} className="mr20">{projectsType && projectsType === "mirror" ? "导入" : "创建"}项目</Button>
<a onClick={()=>window.history.back(-1)} className="btn_32">取消</a>
<Button type="primary" onClick={this.subMitFrom} className="mr20">{projectsType && projectsType === "mirror" ? "导入" : "创建"}代码库</Button>
<Link to={`/${login}`} className="btn_32">取消</Link>
</Form.Item>
</div>
</Form>

View File

@ -1,5 +1,4 @@
.newPanel{
border:1px solid #eaeaea;
border-radius: 4px;
}
.newPanel_title{

View File

@ -5,7 +5,7 @@ import 'codemirror/mode/javascript/javascript.js';
import 'codemirror/mode/clike/clike';
import 'codemirror/mode/css/css';
import UserSubmitComponent from "./UserSubmitComponent";
import CloudIDE from "./cloudIDE";
// import CloudIDE from "./cloudIDE";
import { Base64 } from "js-base64";
import "./index.css";
@ -21,7 +21,14 @@ class m_editor extends Component {
};
}
componentDidUpdate = (prevProps) => {
if (prevProps && this.props && this.props.content !== prevProps.content) {
let firstCondition = prevProps && this.props && this.props.content !== prevProps.content;
let secondCondition = prevProps && this.props && this.props.random !== prevProps.random;
if (firstCondition) {
this.setState({
editorValue: this.props.content
})
}
if(secondCondition){
this.setState({
editorValue: this.props.content
})
@ -57,20 +64,17 @@ class m_editor extends Component {
enabled: false,
},
};
let download_url = detail && detail.download_url;
return (
<Fragment>
<div className="editorBorderBox">
{!readOnly ?
<CodeMirror
placeholder="请输入内容"
value={editorValue}
options={editor_options}
onChange={this.changeEditor}
/> :
<CloudIDE download_url={download_url} value={editorValue} params={params} filepath={filepath&&filepath.startsWith('/')?filepath.slice(1):filepath}/>
}
<CodeMirror
placeholder="请输入内容"
value={editorValue}
options={editor_options}
onChange={this.changeEditor}
readOnly={readOnly}
/>
</div>
{!readOnly && (
<div className="editorBorderSubmitBox" style={{ padding: "20px" }}>

View File

@ -514,7 +514,7 @@ class order_form extends Component {
)}
</Form.Item>
<Form.Item label="里程碑">
{/* <Form.Item label="">
{getFieldDecorator("fixed_version_id", {rules: []})(
<Select
showSearch
@ -536,7 +536,7 @@ class order_form extends Component {
)}
</Select>
)}
</Form.Item>
</Form.Item> */}
<Form.Item label="标记">
{getFieldDecorator("issue_tag_ids", {rules: []})(
<Select

View File

@ -143,17 +143,17 @@ function Index(props){
<li className={active === 1 ?"active":""}><Link to={`/settings/profile`}><i className="iconfont icon-gerenziliao mr5 font-14"></i><span className="text-shodow-bold">基本资料</span></Link></li>
<li className={active === 2 ?"active":""}><Link to={`/settings/phone`}><i className="iconfont icon-xuanzhonganquanshezhi_icon mr5 font-14"></i><span className="text-shodow-bold">账号管理</span></Link></li>
</ul>
{notice_url && <ul className="securityUl ul-border-buttom">
{/* {notice_url && <ul className="securityUl ul-border-buttom">
<li>消息通知</li>
<li className={active === 3 ?"active":""}><Link to={"/settings/notice"}><i className="iconfont icon-wodetongzhi font-14"></i><span className="text-shodow-bold">我的通知</span></Link></li>
<li className={active === 4 ?"active":""}><Link to={'/settings/notice/config'}><i className="iconfont icon-tongzhiguanli font-14"></i><span className="text-shodow-bold">通知管理</span></Link></li>
</ul>}
</ul>} */}
<ul className="securityUl ul-border-buttom">
<li>安全设置</li>
<li className={active === 5 ?"active":""}><Link to={`/settings/SSH`}><i className="iconfont icon-xuanzhongssh_icon mr5 font-14"></i><span className="text-shodow-bold">SSH密钥</span></Link></li>
<li className={active === 6 ?"active":""}><Link to={`/settings/CLA`}><i className="iconfont icon-a-zu2044 mr5 font-13"></i><span className="text-shodow-bold">我的CLA</span></Link></li>
{/* <li className={active === 6 ?"active":""}><Link to={`/settings/CLA`}><i className="iconfont icon-a-zu2044 mr5 font-13"></i><span className="text-shodow-bold">我的CLA</span></Link></li> */}
</ul>
<ul className="securityUl ul-border-buttom">
{/* <ul className="securityUl ul-border-buttom">
<li>Bot开发</li>
<li className={active === 7 ?"active":""}><Link to={`/settings/mybot`}><i className="iconfont icon-kaifabot mr5 font-18"></i><span className="text-shodow-bold">我的Bot</span></Link></li>
<li className={active === 8 ?"active":""}><Link to={`/settings/installbot`}><i className="iconfont icon-BOTpeizhi mr5 font-17"></i><span className="text-shodow-bold">Bot安装</span></Link></li>
@ -161,7 +161,7 @@ function Index(props){
<ul className="securityUl">
<li>个人建站</li>
<li className={active === 9 ?"active":""}><Link to={`/settings/mysite`}><i className="iconfont icon-liebiaoicon mr5 font-15"></i><span className="text-shodow-bold">我的站点</span></Link></li>
</ul>
</ul> */}
</div>
<LongWidth>
<Gap>

View File

@ -1,9 +1,9 @@
.whiteBack{
background-color: #fff;
.boies{
width: 1200px;
// width: 1200px;
margin:0px auto;
padding:30px 0px 10px;
padding:30px 20px 10px;
.shortW{
width: 198px;
border: 1px solid rgba(79, 108, 188, 0.21);

View File

@ -10,7 +10,7 @@
padding:0px;
margin-right:34px!important;
height: 34px;
width: 64px;
min-width: 64px;
text-align: center;
line-height: 0px;
position: relative;

View File

@ -244,7 +244,7 @@ function CollaboratorMember({projectsId,owner,project_id,author,showNotification
</a>
</Dropdown>
<Search
placeholder="搜索项目成员..."
placeholder="搜索代码库成员..."
enterButton="搜索"
onSearch={setSearch}
style={{width:300}}

View File

@ -145,17 +145,18 @@ class Setting extends Component {
this.setState({
loading:true
})
const { projectsId , owner } = this.props.match.params;
const navUrl = `/${owner}/${projectsId}/project_units.json`;
this.update(values);
// const { projectsId , owner } = this.props.match.params;
// const navUrl = `/${owner}/${projectsId}/project_units.json`;
let unit = values.project_units.filter(item => (item !== "home" && item!== "activity" && item!== "code"));
axios.post(navUrl, {
unit_types:unit
}).then((result) => {
if (result) {
this.update(values);
}
}).catch(error=>{})
// let unit = values.project_units.filter(item => (item !== "home" && item!== "activity" && item!== "code"));
// axios.post(navUrl, {
// unit_types:unit
// }).then((result) => {
// if (result) {
// this.update(values);
// }
// }).catch(error=>{})
}
});
};
@ -240,7 +241,7 @@ class Setting extends Component {
// 取消仓库转移
CancelDivertProject=()=>{
this.props.confirm({
content: "是否确认取消将此项目转移给他人?",
content: "是否确认取消将此代码库转移给他人?",
onOk: () => {
const { projectsId , owner } = this.props.match.params;
const url = `/${owner}/${projectsId}/applied_transfer_projects/cancel.json`;
@ -290,18 +291,18 @@ class Setting extends Component {
<WhiteBack>
<Title>基本设置</Title>
<Form className="baseForm" style={{marginLeft: '30px'}}>
<Form.Item label="项目名称">
<Form.Item label="代码库名称">
{getFieldDecorator("project_name", {
rules: [
{
required: true,
message: "请输入项目名称",
message: "请输入代码库名称",
},
],
})(<Input placeholder="请输入项目名称" />)}
})(<Input placeholder="请输入代码库名称" />)}
{
projectDetail && projectDetail.type && projectDetail.type !== 0 ?
<span className="color-grey-9">项目导入于 <a className="color-grey-6" target="_blank" href={projectDetail.mirror_url}>{projectDetail.mirror_url}</a></span>
<span className="color-grey-9">代码库导入于 <a className="color-grey-6" target="_blank" href={projectDetail.mirror_url}>{projectDetail.mirror_url}</a></span>
: ""
}
</Form.Item>
@ -325,45 +326,45 @@ class Setting extends Component {
</Form.Item>
</div>
<Form.Item
label={<span>项目标识 <span className="color-grey-9">(项目url标识部分更改项目标识将导致原仓库地址失效)</span></span>}
label={<span>代码库标识 <span className="color-grey-9">(代码库url标识部分更改代码库标识将导致原仓库地址失效)</span></span>}
>
{getFieldDecorator("project_identifier", {
rules: [
{
required: true,
message: "请输入项目标识",
message: "请输入代码库标识",
},
],
})(
<Input placeholder="项目标识请使用与项目相关的英文关键字" maxLength="100" />
<Input placeholder="代码库标识请使用与代码库相关的英文关键字" maxLength="100" />
)}
</Form.Item>
<Form.Item label="项目简介">
<Form.Item label="代码库简介">
{getFieldDecorator("project_description", {
rules: [],
})(
<TextArea
placeholder="请输入项目简介"
placeholder="请输入代码库简介"
style={{ height: "80px" }} maxLength={200}
/>
)}
</Form.Item>
<Form.Item label="项目类别">
<Form.Item label="代码库类别">
{getFieldDecorator("project_category_id", {
rules: [],
})(
<Select>
<Option key={0} value={""}>未选择项目类别</Option>
<Option key={0} value={""}>未选择代码库类别</Option>
{CategoryList}
</Select>
)}
</Form.Item>
<Form.Item label="项目语言">
<Form.Item label="代码库语言">
{getFieldDecorator("project_language_id", {
rules: [],
})(
<Select>
<Option key={0} value={""}>未选择项目语言</Option>
<Option key={0} value={""}>未选择代码库语言</Option>
{LanguageList}
</Select>
)}
@ -388,7 +389,7 @@ class Setting extends Component {
)}
</Form.Item>
</div>
<Form.Item label="项目导航">
{/* <Form.Item label="">
{getFieldDecorator("project_units", {
rules: [],
})(
@ -406,7 +407,7 @@ class Setting extends Component {
}
</Checkbox.Group>
)}
</Form.Item>
</Form.Item> */}
<p className="clearfix">
<a className="submitBtn" onClick={this.resetSetting}>
更新仓库设置
@ -447,7 +448,7 @@ class Setting extends Component {
<p className="font-bd font-16">删除本仓库</p>
<p className="mt10">
删除仓库是永久性的,
无法撤消且删除后与仓库关联的项目/任务/合并请求/版本发布等均会被删除
无法撤消且删除后与仓库关联的代码库/任务/合并请求/版本发布等均会被删除
</p>
</div>
<Button onClick={this.deleteProject} className="red_deleteBtn">

View File

@ -44,7 +44,7 @@ export default (props)=>{
return(
<Box>
<Short>
<Setnav header={<Title>团队设置</Title>} nav={array}></Setnav>
<Setnav header={<Title>团队设置</Title>} nav={array} history={props.history}></Setnav>
</Short>
<Long>
<Gap>

View File

@ -1,4 +1,4 @@
import React from 'react';
import React, { useEffect, useState } from 'react';
import { Route, Switch } from "react-router-dom";
import Loadable from "react-loadable";
@ -9,6 +9,8 @@ import { CNotificationHOC } from "../../modules/courses/common/CNotificationHOC"
import { TPMIndexHOC } from "../../modules/tpm/TPMIndexHOC";
import '../css/index.scss';
import './Index.scss';
import { checkOpenedEnterprise } from '../Information/api';
import axios from 'axios';
const GroupNew = Loadable({
loader: () => import("./Group/GroupNew"),
@ -41,6 +43,33 @@ const ProjectDetail = Loadable({
});
export default withRouter(CNotificationHOC()(SnackbarHOC()(TPMIndexHOC(
((props)=>{
const OIdentifier = props.match.params.OIdentifier;
const [ organizeDetail , setOrganizeDetail ] = useState(undefined);
const [ enterpriseOpenInfo, setEnterpriseOpenInfo] = useState(false);
useEffect(()=>{
if(OIdentifier){
getDetail(OIdentifier);
}
},[OIdentifier]);
function getDetail(identifier) {
const url = `/organizations/${identifier}.json`;
axios.get(url).then(result=>{
if(result && result.data){
setOrganizeDetail(result.data);
const {id} = result.data;
checkOrgOpenEnterprise(id)
}
}).catch(error=>{})
}
function checkOrgOpenEnterprise(orgId){
checkOpenedEnterprise(orgId).then(res=>{
if(res && res.data.code === 200){
setEnterpriseOpenInfo(res.data.data)
}
})
}
return (
<div className="newMain">
<Switch>
@ -83,7 +112,7 @@ export default withRouter(CNotificationHOC()(SnackbarHOC()(TPMIndexHOC(
<Route
path="/:OIdentifier/members"
render={(p) => {
return <TeamDetailIndex {...props} {...p}/>
return <TeamDetailIndex {...props} {...p} enterpriseOpened = {enterpriseOpenInfo && enterpriseOpenInfo.isOpen}/>
}}
></Route>
@ -91,10 +120,18 @@ export default withRouter(CNotificationHOC()(SnackbarHOC()(TPMIndexHOC(
<Route
path="/:OIdentifier/setting"
render={(p) => (
<TeamDetailIndex {...props} {...p}/>
<TeamDetailIndex {...props} {...p} enterpriseOpened = {enterpriseOpenInfo && enterpriseOpenInfo.isOpen}/>
)}
></Route>
{/* 开通企业工作台 */}
<Route
path="/:OIdentifier/enterprise"
render={(p) => {
return <TeamDetailIndex {...props} {...p}/>
}}
></Route>
{/* 组织下的项目详情 */}
<Route
path="/:owner/:projectsId"
@ -107,7 +144,7 @@ export default withRouter(CNotificationHOC()(SnackbarHOC()(TPMIndexHOC(
<Route
path="/:OIdentifier"
render={(p) => (
<DetailIndex {...props} {...p}/>
<DetailIndex {...props} {...p} organizeDetail={organizeDetail} enterpriseOpenInfo={enterpriseOpenInfo}/>
)}
></Route>
</Switch>

View File

@ -31,6 +31,9 @@
font-weight:700;
color:#333333;
font-size:22px;
flex: 1;
width: 0;
margin-right: 15px;
}
.orz-desc{
color:#4c5b76;
@ -93,6 +96,7 @@
width: 1200px;
margin:0px auto;
padding-top: 40px;
min-height: 72vh;
.list-l{
background-color: #fff;
// background-image: url('./images/left-bc.png');
@ -130,7 +134,7 @@
}
}
.sepment{
margin:30px auto 20px;
margin:0 auto 20px;
.ant-radio-group{
.ant-radio-button-wrapper{
height: 44px;
@ -220,6 +224,7 @@
}
.box{
background:rgba(255,255,255,1);
// min-height: 500px;
.head{
padding:25px 0px 15px;
display: flex;
@ -551,6 +556,7 @@
}
}
.overviewcontent{
min-height: 514px;
.concentrateUl li{
border-color:#cddbeb!important;
border-radius:4px;

View File

@ -7,12 +7,13 @@ import Item from './ListItem';
import Right from './RightBox';
import NoData from '../Nodata';
import CheckProfile from '../Component/ProfileModal/Profile';
import { Menu , Pagination , Dropdown , Spin , Tooltip , Radio } from 'antd';
import { Menu , Pagination , Dropdown , Spin , Tooltip , Radio, Button } from 'antd';
import ConcentrateProject from '../users/GeneralView/ConcentrateProject';
import { getImageUrl } from 'educoder';
import RenderHtml from "../../components/render-html";
import EmptyImg from '../Images/nodata.png';
import axios from 'axios';
import { checkOpenedEnterprise } from '../Information/api';
const limit = 15;
function List(props){
@ -22,27 +23,11 @@ function List(props){
const [ search , setSearch ] = useState(undefined);
const [ page , setPage ] = useState(1);
const [ sortBy , setSortBy ] = useState("updated_on");
const [ organizeDetail , setOrganizeDetail ] = useState(undefined);
const [ mode , setMode ] = useState("overview");
const OIdentifier = props.match.params.OIdentifier;
const { current_user } = props;
console.log(props);
const { current_user, organizeDetail, enterpriseOpenInfo } = props;
useEffect(()=>{
if(OIdentifier){
getDetail(OIdentifier);
}
},[OIdentifier]);
function getDetail(id) {
const url = `/organizations/${id}.json`;
axios.get(url).then(result=>{
if(result && result.data){
setOrganizeDetail(result.data);
}
}).catch(error=>{})
}
useEffect(()=>{
if(organizeDetail){
@ -109,17 +94,31 @@ function List(props){
<div className="content-orz">
<div className="top-orz">
<div className="box">
<img src={getImageUrl(organizeDetail && organizeDetail.avatar_url)} alt=""/>
<img src={getImageUrl(organizeDetail && organizeDetail.avatar_url)} alt="" />
<div className="info-orz">
<p className="orz-main">
<span className="orz-name">{organizeDetail && organizeDetail.nickname}</span>
{organizeDetail && organizeDetail.is_admin ?
<Link to={`/${OIdentifier}/setting`} className="color-blue ml10 font-14 df"><i className="iconfont icon-shezhi2"></i>设置</Link>
:""}
<span className="orz-name task-hide">{organizeDetail && organizeDetail.nickname}</span>
{organizeDetail && (
<div>
{
!enterpriseOpenInfo.isOpen ? organizeDetail.is_admin && (
<Link to={`/${OIdentifier}/enterprise`}>
<Button type='primary'>开通工作台</Button>
</Link>
) :
enterpriseOpenInfo.url ? (
<Button type='primary' onClick={() => { window.open(enterpriseOpenInfo.url) }}>前往工作台</Button>
) : (
<Button type='primary'>正在开通工作台</Button>
)
}
{organizeDetail.is_admin && <Link to={`/${OIdentifier}/setting`} className="color-blue ml20 font-14"><Button type='primary' ghost>设置</Button></Link>}
</div>
)}
</p>
<div className="orz-desc task-hide-2">
<Tooltip title={organizeDetail && organizeDetail.description} placement={"bottomLeft"}>
<span style={{display:"block"}}>{organizeDetail && organizeDetail.description}</span>
<span style={{ display: "block" }}>{organizeDetail && organizeDetail.description}</span>
</Tooltip>
</div>
</div>
@ -129,7 +128,7 @@ function List(props){
<div className="list-l">
{
organizeDetail.news_title &&
<div className="teamnewstatus">
<div className="teamnewstatus mb30">
<p className="teamname"><i className="iconfont icon-dongtaiicon1" /><span>新闻动态</span></p>
<p className="teamtitle">
{organizeDetail.news_title}
@ -228,6 +227,7 @@ function List(props){
showCompeleteDialog={props.showCompeleteDialog}
completeProfile={props.completeProfile}
history={props.history}
enterpriseOpened = {enterpriseOpenInfo.isOpen}
/>
</div>
</div>

View File

@ -49,7 +49,7 @@ const Img = styled.img`{
height:45px;
margin-right:12px;
}`
function RightBox({ OIdentifier , history , admin , showCompeleteDialog ,completeProfile }) {
function RightBox({ OIdentifier , history , admin , showCompeleteDialog ,completeProfile, enterpriseOpened }) {
const [ languageData, setLanguageData ] = useState(undefined);
const [ memberData, setMemberData ] = useState(undefined);
const [ groupData, setGroupData ] = useState(undefined);
@ -148,7 +148,7 @@ function RightBox({ OIdentifier , history , admin , showCompeleteDialog ,complet
</Box>
:""
}
<Box
{!enterpriseOpened && <Box
name="组织团队"
count={groupData && groupData.total_count}
icon={<i className="iconfont icon-zuzhituandui font-17 mr8"></i>}
@ -187,7 +187,7 @@ function RightBox({ OIdentifier , history , admin , showCompeleteDialog ,complet
})}
</React.Fragment>:<Nodata _html="暂无团队" small/>
}
</Box>
</Box>}
</div>
)
}

View File

@ -6,6 +6,7 @@ import styled from 'styled-components';
import UploadImage from '../Component/UploadImage';
import axios from 'axios';
import Modals from '../Component/Modals';
import { Encrypt } from '../../../common/Env';
import { getImageUrl } from 'educoder';
const TextArea = Input.TextArea;
@ -91,7 +92,7 @@ export default Form.create()(
function onOk(password){
const url = `/organizations/${organizeDetail.id}.json`;
axios.delete(url,{
params:{ password }
params:{ password:Encrypt(password) }
}).then(result=>{
if(result && result.data){
//

View File

@ -41,7 +41,7 @@ const CLANew = Loadable({
export default (( props )=>{
const pathname = props.location.pathname;
const OIdentifier = props.match.params.OIdentifier;
const {organizeDetail} = props;
const {organizeDetail, enterpriseOpened, mygetHelmetapi} = props;
useEffect(()=>{
if(organizeDetail){
const {nickname} = organizeDetail;
@ -68,8 +68,8 @@ export default (( props )=>{
const array = {list:[
{name:'基本设置',icon:"icon-base",href:`/${OIdentifier}/setting`},
{name:'组织首页管理',icon:"icon-huabanfuben",href:`/${OIdentifier}/setting/index`},
{name:'组织成员管理',icon:"icon-zuzhichengyuan",href:`/${OIdentifier}/setting/member`},
{name:'组织团队管理',icon:"icon-zuzhixiangmu",href:`/${OIdentifier}/setting/group`},
{name:'组织成员管理',icon:"icon-zuzhichengyuan",href: enterpriseOpened ? `${ mygetHelmetapi && mygetHelmetapi.common.zone }/${OIdentifier}/members` : `/${OIdentifier}/setting/member` , hide: enterpriseOpened},
{name:'组织团队管理',icon:"icon-zuzhixiangmu",href:`/${OIdentifier}/setting/group`, hide: enterpriseOpened},
// {name:'web',icon:"icon-zhongqingdianxinicon10",href:`/${OIdentifier}/setting/hooks`}
{name:'CLA管理',img:claIcon,href:`/${OIdentifier}/setting/agreement`,hide:organizeDetail && !organizeDetail.enabling_cla}
],
@ -78,7 +78,7 @@ export default (( props )=>{
return(
<Box>
<Short>
<Setnav header={<Title>组织设置</Title>} nav={array}></Setnav>
<Setnav header={<Title>组织设置</Title>} nav={array} history={props.history}></Setnav>
</Short>
<Long>
<Gap >

View File

@ -0,0 +1,181 @@
import React, { useEffect, useState } from 'react';
import { WhiteBack , FlexAJ } from '../../Component/layout';
import { Table , Pagination , Popconfirm, Button, message, Tooltip, Select, Spin } from 'antd';
import Title from '../../Component/Title';
import Search from '../../Component/Search';
import styled from 'styled-components';
import { getImageUrl } from 'educoder';
import axios from 'axios';
import { Link } from 'react-router-dom';
import './teamSetting.scss';
import { createEnterpriseByGitlinkOrgId, getRoleList, getUserList, checkOpenedEnterprise } from '../../Information/api';
const Img = styled.img`{
width:30px;
height:30px;
border-radius:50%;
}`
const limit = 15;
export default (({organizeDetail,history,match, current_user})=>{
const OIdentifier = match.params.OIdentifier;
const {login} = current_user
const [ page , setPage ] = useState(1);
const [ total , setTotal ] = useState(0);
const [ data , setData ] = useState(undefined);
const [ roleList, setRoleList] = useState([]);
const [loading, setLoading] = useState(false);
//
let intervalId = null;
useEffect(()=>{
getRoleList().then(res=>{
const {code, rows} = res && res.data
if(code === 200){
setRoleList(rows);
}
})
}, [])
useEffect(()=>{
if(organizeDetail){
const {nickname} = organizeDetail;
document.title = `开通组织工作台-${nickname}`;
pollData()
}
}, [organizeDetail])
useEffect(()=>{
if(organizeDetail && organizeDetail.id){
getData(organizeDetail.id);
}
},[organizeDetail,page])
//
const pollData = () => {
checkOpenedEnterprise(organizeDetail.id).then(res=>{
if(res && res.data.code === 200){
const {data} = res.data;
if(data.isOpen && !data.url){
setLoading(true)
}else if(data.isOpen){
clearInterval(intervalId);
window.location = data.url
}
}
})
};
function getData(id){
getUserList(id).then(res=>{
const {code, rows, total} = res && res.data
if(code === 200){
setData(rows);
setTotal(total);
}
})
}
//
function ChangePage(page){
setPage(page);
}
const columns = [
{
title: '头像',
dataIndex: 'imageUrl',
render:(value)=>{
return(
<Img src={value}></Img>
)
}
},
{
title: '用户名',
dataIndex: 'nickname',
},
{
title: '邮箱',
dataIndex: 'email',
},
{
title: '所属团队',
dataIndex: ['role', 'roleKey'],
width:"20%",
render:(value,record)=>{
return <Select value={value} onChange={(value)=>{
const users = [...data];
users.map(item=>item.username === record.username && (item.role.roleKey = value))
setData(users);
}}>
{roleList && roleList.map(item=>{return <Select.Option key={item.roleKey}>{item.roleName}</Select.Option>})}
</Select>
}
},
{
title: '操作',
dataIndex: 'username',
key: "action",
render:(value)=>{
return (
<Button type='danger' size='small' disabled={value === login} onClick={()=>{
const users = data.filter(item=>{return item.username !== value});
setData(users);
}}><i className='iconfont icon-fuzhi-shanchu font-14'></i></Button>
)
}
}
]
function createEnterprise(){
const users = data.map(item=>{return {userId: item.userId, roleKey: item.role.roleKey}})
createEnterpriseByGitlinkOrgId(organizeDetail.id, users).then(res=>{
if(res && res.data.code === 200){
message.success('开通成功');
intervalId = setInterval(pollData, 1000);
}else{
message.error(res && res.data.msg)
}
})
}
return(
<Spin spinning={loading}>
<WhiteBack style={{border:"1px solid #eee"}} className='exterpriseBox'>
<div className='padding30'>
首次创建组织工作台时系统将根据组织团队用户在组织工作台中根据不同团队初始化成不同角色请您知悉以下角色权限再次确认组织成员的角色分配<br/>
<span className='font-bd'>组织管理员</span>原owner团队成员对组织内所有代码库均具有管理员权限在组织工作台中拥有最高管理权限<br/>
<span className='font-bd'>项目管理员</span>原管理员团队成员对组织内所有代码库均具有管理员权限在组织工作台中拥有项目管理权限<br/>
<span className='font-bd'>普通成员</span>原开发者及报告者团队成员对组织内所有代码库均具有开发者权限在组织工作台中拥有项目基础使用权限及查看权限
</div>
<FlexAJ className="padding20-30">
<div style={{width:"580px"}}>
{/* <Search placeholder="输入用户名或邮箱、团队名搜索" onSearch={(value)=>{setSearch(value)}}/> */}
</div>
{/* <Sort menu={menu}>
<a className="color-blue">角色筛选<i className="iconfont icon-sanjiaoxing-down ml3 font-14"></i></a>
</Sort> */}
</FlexAJ>
<div className="pl30 pr30 pb30" style={{minHeight:"400px"}}>
<Table
size="small"
columns={columns}
dataSource={data}
pagination={false}
className="teamMemberTable"
></Table>
{
total > limit ?
<div className="edu-txt-center mt30 mb20">
<Pagination simple current={page} total={total} pageSize={limit} onChange={ChangePage}></Pagination>
</div>
:""
}
</div>
<div className='edu-txt-right pl30 pr30 pb30'>
<Button type='primary' ghost className='mr20' onClick={()=>{history.push(`/${OIdentifier}`)}}>暂不开通</Button>
<Button type='primary' onClick={createEnterprise}>确认并开通工作台</Button>
</div>
</WhiteBack>
</Spin>
)
})

View File

@ -129,4 +129,14 @@
margin-right: 40px;
}
}
}
.exterpriseBox{
.padding30{
color: #4C5876;
line-height: 30px;
border-bottom: 1px dashed #eee;
}
.font-bd{
color: #0D0F12;
}
}

View File

@ -26,9 +26,15 @@ const Setting = Loadable({
loader: () => import("../Setting/TeamSettingIndex"),
loading: Loading,
});
const Enterprise = Loadable({
loader: () => import("../Setting/enterprise"),
loading: Loading,
});
function Detail(props){
const OIdentifier = props.match.params.OIdentifier;
const pathname = props.location.pathname;
const {enterpriseOpened} = props;
const [ detail , setDetail ] = useState(undefined);
const [ flag , setFlag ] = useState(true);
@ -78,7 +84,7 @@ function Detail(props){
setDetail(d);
}
return(
<div className="teamDetail">
<div className="teamDetail mb50">
{
detail &&
<Cards
@ -86,18 +92,11 @@ function Detail(props){
title={detail.nickname}
desc={!buttonflag && detail.description}
img={detail.avatar_url}
rightBtn={
<React.Fragment>
{flag && !buttonflag && detail.is_admin ?
<Link to={`/${OIdentifier}/setting`} className="color-blue ml10 font-14">设置<i className="iconfont icon-shezhi2 ml3 fr"></i></Link>
:""}
{buttonflag &&
<span className="subNavs">
<Link to={`/${OIdentifier}/members`} className={pathname ===`/${OIdentifier}/members` ? "active":""}><span>组织成员</span>{detail.num_users && <lable>{detail.num_users}</lable>}</Link>
<Link to={`/${OIdentifier}/teams`} className={pathname ===`/${OIdentifier}/teams` ? "active":""}><span>组织团队</span>{detail.num_teams &&<lable>{detail.num_teams}</lable>}</Link>
</span>
}
</React.Fragment>
rightBtn={buttonflag && !enterpriseOpened &&
<span className="subNavs">
<Link to={`/${OIdentifier}/members`} className={pathname ===`/${OIdentifier}/members` ? "active":""}><span>组织成员</span>{detail.num_users && <lable>{detail.num_users}</lable>}</Link>
<Link to={`/${OIdentifier}/teams`} className={pathname ===`/${OIdentifier}/teams` ? "active":""}><span>组织团队</span>{detail.num_teams &&<lable>{detail.num_teams}</lable>}</Link>
</span>
}
bottomInfos={
!buttonflag && <div>
@ -137,19 +136,20 @@ function Detail(props){
}}
></Route>
<Route
path="/:OIdentifier/setting"
render={(p) => {
return <Setting {...props} {...p} organizeDetail={detail} updateFunc={updateDetail}/>
}}
></Route>
<Route
path="/:OIdentifier"
path="/:OIdentifier/setting"
render={(p) => {
return <DetailIndex {...props} {...p} organizeDetail={detail}/>
return <Setting {...props} {...p} organizeDetail={detail} updateFunc={updateDetail} enterpriseOpened={enterpriseOpened}/>
}}
></Route>
<Route
path="/:OIdentifier/enterprise"
render={(p) => {
return <Enterprise {...props} {...p} organizeDetail={detail}/>
}}
></Route>
</Switch>
</div>
)

View File

@ -7,7 +7,7 @@ import { Pagination , Spin } from 'antd';
import AddMemberBox from './Component/AddMemberBox';
const limit = 16;
function TeamMember({organizeDetail,current_user,history,match}){
function TeamMember({organizeDetail,current_user,history,match,enterpriseOpened}){
const OIdentifier = match.params.OIdentifier;
const [ page , setPage ] = useState(1);
const [ total , setTotal ] = useState(0);
@ -46,7 +46,7 @@ function TeamMember({organizeDetail,current_user,history,match}){
<WhiteBack style={{marginBottom:"30px",border:'1px solid #eee'}}>
<Banner>组织成员
{
organizeDetail && organizeDetail.is_admin &&
!enterpriseOpened && organizeDetail && organizeDetail.is_admin &&
<AddMemberBox
className="addMemberBtn"
orzId={organizeDetail && organizeDetail.id}

View File

@ -84,27 +84,25 @@ class CommonUsers extends Component {
const { users, count , isSpin, type_title } = this.state;
return (
<div className="pbt15">
<div className="main background-f minH-670" style={{padding:"0px"}}>
<div className="user-list-items">
<div className="font-18 padding10-20 border-b-line">{type_title}</div>
<Spin spinning={isSpin}>
<div className="w-100 inline-block">
{count === 0 ? (
<NoneData _html="暂时还没有相关数据!" />
) : (
<UserList
users={users}
userClass={'w-25'}
successFunc={this.getUsersList}
notReset={true}
{...this.props}
></UserList>
)}
</div>
</Spin>
{this.Paginations()}
</div>
<div className="main background-f minH-670" style={{padding:"0px"}}>
<div className="user-list-items">
<div className="font-18 padding10-20 border-b-line">{type_title}</div>
<Spin spinning={isSpin}>
<div className="w-100 inline-block">
{count === 0 ? (
<NoneData _html="暂时还没有相关数据!" />
) : (
<UserList
users={users}
userClass={'w-25'}
successFunc={this.getUsersList}
notReset={true}
{...this.props}
></UserList>
)}
</div>
</Spin>
{this.Paginations()}
</div>
</div>
);

View File

@ -133,18 +133,16 @@ class ForkUsers extends Component {
const { users, isSpin } = this.state;
return (
<div className="pbt15">
<div className="main background-f minH-670" style={{padding:"0px"}}>
<div className="user-list-items">
<div className="font-18 padding10-20 border-b-line">Fork列表</div>
<Spin spinning={isSpin}>
<div className="w-100 inline-block" style={{minHeight:"400px"}}>
{users && users.length === 0 ? <NoneData _html="暂时还没有相关数据!" /> :"" }
{this.renderList(users)}
</div>
</Spin>
{this.Paginations()}
</div>
<div className="main background-f minH-670" style={{padding:"0px"}}>
<div className="user-list-items">
<div className="font-18 padding10-20 border-b-line">Fork列表</div>
<Spin spinning={isSpin}>
<div className="w-100 inline-block" style={{minHeight:"400px"}}>
{users && users.length === 0 ? <NoneData _html="暂时还没有相关数据!" /> :"" }
{this.renderList(users)}
</div>
</Spin>
{this.Paginations()}
</div>
</div>
);

View File

@ -18,7 +18,7 @@ export default Form.create()(({ form, history, showNotification, projectDetail,
let wikiName = ''
let key = '';
if (!pathname.endsWith('/wiki/add')) {
wikiName = decodeURI(pathname.split('/')[4]);
wikiName = pathname.split('/')[4];
key = pathname.split('/')[5];
}else{
key = search.split('=').pop();
@ -94,7 +94,7 @@ export default Form.create()(({ form, history, showNotification, projectDetail,
const helper = useCallback(
(label, name, rules, widget, initialValue, rightComponent) => (
<Form.Item label={label} className="mb0">
<Form.Item label={label} className="mb0" wrapperCol={{span: 18}}>
{getFieldDecorator(name, { rules, initialValue, validateFirst: true, })(widget)}
{rightComponent}
</Form.Item>
@ -116,12 +116,6 @@ export default Form.create()(({ form, history, showNotification, projectDetail,
};
validateFields((err, values) => {
if (!err) {
let regEn = /[\\/:*?"<>|[\]-]/g;
if (regEn.test(values.title)) {
message.error('文件名不能有特殊字符: \\ / : * ? \" < > | [ \] -');
setOperateFlag(false);
return;
}
const {md_content, title} = values;
if (wikiName) {
updateWiki({
@ -130,7 +124,7 @@ export default Form.create()(({ form, history, showNotification, projectDetail,
projectId: project.id,
pageName: wikiName,
title,
commit_message: '',
message: '',
content_base64: Base64.encode(md_content)
}).then(res => dealRes(res, title));
} else {
@ -216,7 +210,7 @@ export default Form.create()(({ form, history, showNotification, projectDetail,
projectId: project.id,
pageName: '_Sidebar',
title: '_Sidebar',
commit_message: '',
message: '',
content_base64: Base64.encode(content)
}).then(res => {
if (res && res.message === "200") {
@ -326,7 +320,7 @@ export default Form.create()(({ form, history, showNotification, projectDetail,
"title",
[
{ required: true, message: "请输入标题" },
// { pattern: /[^`\[\]\/:*?''<>|%-+_]/g, message: '' }
{ pattern: /^(?!-).*$/, message: '不能以-开头' }
],
<Input
placeholder={"请输入标题"}
@ -336,7 +330,7 @@ export default Form.create()(({ form, history, showNotification, projectDetail,
/>
)}
<Form.Item className="mb0 wiki-md">
<Form.Item className="mb0 wiki-md" wrapperCol={{span: 18}}>
<MDEditor
placeholder={"请输入wiki内容"}
height={500}

View File

@ -114,7 +114,7 @@ export default (props) => {
project && checkItem.name && getWiki({
owner: owner,
repo: projectsId,
pageName: checkItem.name,
pageName: checkItem.sub_url,
projectId: project.id
}).then(res => {
if (res && res.message === "200") {
@ -189,11 +189,6 @@ export default (props) => {
setAddMenuError("不能仅输入空格");
return;
}
const regEn = /[\\/:*?"<>|[\]-]/g;
if (regEn.test(menuName)) {
setAddMenuError("不能有特殊字符: \\ / : * ? \" < > | [ \] -");
return;
}
//
const oneMenuList = fileList.filter(item=>!item.title.trim().startsWith('[[')).map(i=>i.title.trim())
if(oneMenuList.includes(`- ${menuName}`)){
@ -214,7 +209,7 @@ export default (props) => {
projectId: project.id,
pageName: '_Sidebar',
title: '_Sidebar',
commit_message: '',
message: '',
content_base64: Base64.encode(treeToMd(sidebarList))
}).then(res => {
if (res && res.message === "200") {
@ -231,8 +226,8 @@ export default (props) => {
});
}
function goEdit() {
history.push(`/${owner}/${projectsId}/wiki/${encodeURI(checkItem.name)}/${checkItem.key}/edit`);
function goEdit(params) {
history.push(`/${owner}/${projectsId}/wiki/${encodeURI(checkItem.sub_url)}/${checkItem.key}/edit${params}`);
}
function preview() {

View File

@ -8,9 +8,8 @@ body {
background: rgba(255,255,255,1);
}
.wiki-main {
width: 1200px;
min-height: 400px;
margin: 20px auto 60px;
margin: 20px;
.ant-btn-primary {
background-color: $wikiColor;

View File

@ -63,7 +63,7 @@ export default (props) => {
projectsId && checkItem.name && getWiki({
owner: owner,
repo: projectsId,
pageName: checkItem.name,
pageName: checkItem.sub_url,
projectId: projectId,
}).then(res => {
if (res && res.message === "200") {

View File

@ -3,10 +3,10 @@
flex-flow: column nowrap;
justify-content: center;
align-items: center;
width: 1200px;
min-height: 400px;
// width: 1200px;
min-height: 70vh;
padding: 20px;
margin: 20px auto;
margin: 20px;
background: rgba(250, 252, 255, 1);
font-family: "PingFangSC-Medium";
border-radius: 4px;

View File

@ -116,13 +116,16 @@ export function markdownToTree(markdownText){
lines.map((item, index) =>{
const title = item.trim();
const isFile = title.startsWith('[[') && title.endsWith(']]');
const titleStr = isFile ? title.substring(2, title.length - 2) : title.substring(2, title.length)
const node = {
// 带空格+[[]]或者- 标识
title: item,
children: [],
key: undefined,
// 纯内容
titleStr: isFile ? title.substring(2, title.length - 2) : title.substring(2, title.length),
titleStr,
// 编码后的title,获取wiki内容用title_sub
title_sub: encodeURIComponent(titleStr),
// 是否是wiki文件
isFile: isFile
}
@ -178,6 +181,22 @@ export function findNodeByKey(list, key){
return undefined;
}
// 找到children中有相同key的数组
export function findBrotherNodesByKey(list, key){
for (let index = 0; index < list.length; index++) {
const element = list[index];
if (element.key == key) {
return list;
}else if (element.children && element.children.length) {
let result = findBrotherNodesByKey(element.children, key);
if (result.length) {
return result;
}
}
}
return [];
}
// 找到children中有相同key的数组
export function findNodeByChildrenKey(list, key){
for (let index = 0; index < list.length; index++) {

View File

@ -163,7 +163,7 @@ export default function Sidebar(props) {
const {node, children, key} = item;
if(isFile){
//
deleteWiki({owner: owner, repo: projectsId, projectId: project.id, pageName: title}).then(res => {
deleteWiki({owner: owner, repo: projectsId, projectId: project.id, pageName: item.title_sub}).then(res => {
if(res && res.message === "204"){
// key
const menuListByDel = findSameKeyByDel(menuList, key);
@ -267,7 +267,7 @@ export default function Sidebar(props) {
projectId: project.id,
pageName: '_Sidebar',
title: '_Sidebar',
commit_message: '',
message: '',
content_base64: Base64.encode(content)
}).then(res => {
if (res && res.message === "200") {
@ -303,20 +303,18 @@ export default function Sidebar(props) {
e.stopPropagation();
setVisible(item);
setIsEditName(type);
let title = item.title.trim();
const isFile = title.startsWith('[[') && title.endsWith(']]');
title = isFile ? title.substring(2,title.length-2) : title.substring(2, title.length);
const {titleStr, title_sub} = item;
type === 2 && getWiki({
owner: owner,
repo: projectsId,
pageName: title,
pageName: title_sub,
projectId: project.id
}).then(res => {
if (res && res.message === "200") {
setWikiContent(res.data.md_content);
}
})
setMenuName(title);
setMenuName(titleStr);
}
//
@ -329,9 +327,8 @@ export default function Sidebar(props) {
setAddMenuError("不能仅输入空格");
return;
}
const regEn = /[\\/:*?"<>|[\]-]/g;
if (regEn.test(menuName)) {
setAddMenuError('不能有特殊字符: \\ / : * ? \" < > | [ \] -');
if (isEditName === 2 && /^-/.test(menuName)) {
setAddMenuError('不能以-开头');
return;
}
if(!isEditName){
@ -356,14 +353,16 @@ export default function Sidebar(props) {
}else{
// isEditName 1 2
const titleToJudge = isEditName === 2 ? `[[${menuName}]]` : `- ${menuName}`;
const {children, node, title, key} = visible;
const list = findNodeByChildrenKey(menuList, key) || [];
if(title.trim() === titleToJudge){
const {key, titleStr, title_sub} = visible;
//
if(titleStr === menuName){
setAddMenuError("请修改名称");
return
}
if(list.map(item=>item.title.trim()).includes(titleToJudge)){
message.error("不能与同级目录名称相同");
//
const list = findBrotherNodesByKey(menuList, key) || [];
if(list.map(item=>item.titleStr).includes(menuName)){
setAddMenuError("不能与同级目录名称相同");
return
}
// wiki
@ -380,17 +379,16 @@ export default function Sidebar(props) {
})
if(isEditName === 2){
// -> wiki
const oldTitle = title.substring(title.indexOf('[[')+2, title.indexOf(']]'))
updateWiki({
owner,
repo: projectsId,
projectId: project.id,
//
pageName: oldTitle,
pageName: title_sub,
//
title: menuName,
content_base64: wikiContent,
commit_message: '',
message: '',
}).then(res=>{
if(res && res.message === '200'){
// wikisidebar
@ -424,6 +422,20 @@ export default function Sidebar(props) {
}
}
function findBrotherNodesByKey(list, key){
for (let index = 0; index < list.length; index++) {
const element = list[index];
if (element.key == key) {
return list;
}else if (element.children && element.children.length) {
let result = findBrotherNodesByKey(element.children, key);
if (result.length) {
return result;
}
}
}
return [];
}
function onDrop(info){
// dragNode: node:

View File

@ -58,10 +58,8 @@ export default function UploadWiki(props) {
message.error('只能上传md、txt文件');
return false;
}
let regEn = /[\\/:*?"<>|[\]-]/g;
if (regEn.test(file.name)) {
message.error('文件名不能有特殊字符: \\ / : * ? \" < > | [ \] -');
if (/^-/.test(file.name)) {
message.error('文件名不能以-开头');
return false;
}
@ -85,7 +83,7 @@ export default function UploadWiki(props) {
projectId: project.id,
pageName: '_Sidebar',
title: '_Sidebar',
commit_message: '',
message: '',
content_base64: Base64.encode(treeToMd(sidebarList))
}).then(res => {
if (res && res.message === "200") {

View File

@ -54,9 +54,9 @@ ul,ol,dl{
text-align: right;
}
.main{
width: 1200px;
// width: 1200px;
padding:20px;
margin:20px auto;
margin:0px auto;
background: #fff;
border-radius: 2px;
border:1px solid #eee;
@ -65,8 +65,9 @@ ul,ol,dl{
border-radius: 2px;
}
.normal{
width: 1200px;
margin:0px auto;
// width: 1200px;
// margin:0px auto;
padding:0px 20px;
}
/* 背景色 */
.back-white{

34
src/forge/iframe.jsx Normal file
View File

@ -0,0 +1,34 @@
import React, { useEffect, useState, useCallback } from 'react';
import { withRouter } from "react-router";
import { SnackbarHOC } from "educoder";
import { CNotificationHOC } from "../modules/courses/common/CNotificationHOC";
import { TPMIndexHOC } from "../modules/tpm/TPMIndexHOC";
const Iframe = (props) => {
const history = props.history
const location = history.location
// if (!location.state.url) {
// history.push("/404");
// }
function iframeLoad() {
let myIframe = document.getElementById("iframe");
// if (myIframe.contentWindow.location && myIframe.contentWindow.location.href) {
// window.location.href = 'http://118.145.132.196:3000/product/llm/llm-chat'
// //myIframe.contentWindow.location.href
// }
}
return <iframe
id="iframe"
width="100%"
className="test-iframe"
src={ 'https://testllm.trustie.net' }
onLoad={iframeLoad}
></iframe>
}
export default withRouter(CNotificationHOC()(SnackbarHOC()(TPMIndexHOC(Iframe))));

View File

@ -387,7 +387,7 @@ class Infos extends Component {
}
<Menu.Item key="0"><Link to={`/${user && user.login}`} onClick={()=>this.chooseTab("0")}><i className="iconfont icon-gailan"></i></Link></Menu.Item>
<Menu.Item key="1"><Link to={`/${user && user.login}/statistics`}><i className="iconfont icon-shujutongji"></i></Link></Menu.Item>
<Menu.Item key="2"><Link to={`/${user && user.login}/projects`}><i className="iconfont icon-xiangmu"></i></Link></Menu.Item>
<Menu.Item key="2"><Link to={`/${user && user.login}/projects`}><i className="iconfont icon-xiangmu"></i></Link></Menu.Item>
{
current_user && user && user.login === current_user.login ?
<Menu.Item key="3">

View File

@ -194,7 +194,7 @@ class InfosUser extends Component {
<Spin spinning={isSpin}>
<div className="list-r-operation" style={{padding:"20px"}}>
<Search
placeholder="输入项目名称关键字进行搜索"
placeholder="输入代码库名称关键字进行搜索"
enterButton="搜索"
size="large"
onSearch={()=>{this.get_projects()}}

View File

@ -1,10 +1,10 @@
import React , { forwardRef, useEffect } from 'react';
import { Form , Checkbox , Input, Radio , Button , Cascader } from 'antd';
import { Form , Checkbox , Input, Radio , Button , Cascader , Row } from 'antd';
import { AlignCenter } from '../../Component/layout';
import './Index.scss';
import { locData } from '../../Utils/locData';
import Axios from 'axios';
import {Link} from "react-router-dom";
import { Link } from 'react-router-dom';
const { TextArea } = Input;
export default Form.create()(
@ -60,22 +60,24 @@ export default Form.create()(
)}
</Form.Item>
<Link className='gotoUpdateEmail mr30' to='/settings/phone'><i className='iconfont icon-bianji1 font-15 mr5'></i>更改手机号</Link>
<Form.Item label="邮箱">
{getFieldDecorator("email",{
rules:[{required:true,message:"请输入邮箱账号"}]
})(
<Input placeholder="请点击右侧更改邮箱按钮绑定邮箱" disabled style={{width:"400px"}}/>
)}
</Form.Item>
<Link className='gotoUpdateEmail mr30' to='/settings/emails'><i className='iconfont icon-bianji1 font-15 mr5'></i>更改邮箱</Link>
<Form.Item label="">
{getFieldDecorator("show_email",{
rules:[],
valuePropName:"checked"
})(
<Checkbox>在个人主页展示</Checkbox>
)}
</Form.Item>
<div>
<Form.Item label="邮箱">
{getFieldDecorator("email",{
rules:[{required:true,message:"请输入邮箱账号"}]
})(
<Input placeholder="请点击右侧更改邮箱按钮绑定邮箱" disabled style={{width:"400px"}}/>
)}
</Form.Item>
<Link className='gotoUpdateEmail mr30' to='/settings/emails'><i className='iconfont icon-bianji1 font-15 mr5'></i>更改邮箱</Link>
<Form.Item label="" >
{getFieldDecorator("show_email",{
rules:[],
valuePropName:"checked"
})(
<Checkbox>在个人主页展示</Checkbox>
)}
</Form.Item>
</div>
<Form.Item label="昵称">
{getFieldDecorator("nickname",{
rules:[]
@ -110,6 +112,7 @@ export default Form.create()(
<Checkbox>在个人主页展示</Checkbox>
)}
</Form.Item>
<div>
<Form.Item label="地区">
{getFieldDecorator("location",{
rules:[]
@ -125,6 +128,7 @@ export default Form.create()(
<Checkbox>在个人主页展示</Checkbox>
)}
</Form.Item>
</div>
<Form.Item label="签名">
{getFieldDecorator("description",{
rules:[]

View File

@ -10,7 +10,7 @@ function Index(props){
const { pathname } = props && props.location;
const [ key , setKey ] = useState("0");
const [ type, setType] = useState('0');
const [ type, setType] = useState('1');
useEffect(()=>{
if(pathname){
@ -55,8 +55,8 @@ function Index(props){
<Menu.Item key="3" className="font-16" onClick={()=>{props.history.push('/settings/phone')}}>手机号管理</Menu.Item>
<Menu.Item key="0" className="font-16" onClick={()=>{props.history.push('/settings/emails')}}>邮箱管理</Menu.Item>
<Menu.Item key="1" className="font-16" onClick={()=>{props.history.push('/settings/password')}}>密码管理</Menu.Item>
<Menu.Item key="4" className="font-16" onClick={()=>{props.history.push('/settings/verification')}}>实名认证</Menu.Item>
<Menu.Item key="2" className="font-16" onClick={()=>{props.history.push('/settings/cancel')}}>账号注销</Menu.Item>
{/* <Menu.Item key="4" className="font-16" onClick={()=>{props.history.push('/settings/verification')}}>实名认证</Menu.Item> */}
{/* <Menu.Item key="2" className="font-16" onClick={()=>{props.history.push('/settings/cancel')}}>账号注销</Menu.Item> */}
</Menu>}
</div>
<div>

View File

@ -7,6 +7,7 @@ import img1 from '../../Images/personalInfo3.png';
import { setmiyah } from '../../../common/Component';
import { useEffect } from 'react';
import Phone from './Phone';
import { Encrypt } from '../../../common/Env';
export default Form.create()(
forwardRef((props)=>{
@ -104,7 +105,7 @@ export default Form.create()(
const map = type === '0' ? passMap : updatePsdMap;
if(value){
current_user && Axios.post(`/v1/${current_user.login}/check_password.json`,{
password: value
password: Encrypt(value)
}).then(res=>{
if(res && !res.data.status){
if(type === '0'){
@ -195,7 +196,8 @@ export default Form.create()(
function confirmUpdateEmail(e){
validateFields((error,values)=>{
if(!error){
setVisible(true);
// setVisible(true);
updateEmailOrPsd();
}
})
}
@ -203,9 +205,9 @@ export default Form.create()(
function updateEmailOrPsd(){
if(type === '0'){
const {code, email, password1} = getFieldsValue();
if(code && email && password1){
if( email && password1){
current_user && Axios.patch(`/v1/${current_user.login}/update_email.json`,{
code, email, password: password1
code:"123123", email, password:Encrypt(password1)
}).then(res=>{
if(res && !res.data.status){
setPassMap({password: undefined, email: undefined, code: undefined});
@ -221,10 +223,13 @@ export default Form.create()(
}
}else{
const values = getFieldsValue();
const { old_password , password , new_password_repeat } = values;
const url = `/accounts/change_password.json`;
Axios.post(url,{
login:current_user && current_user.login,
...values
old_password:Encrypt(old_password),
password:Encrypt(password),
new_password_repeat:Encrypt(new_password_repeat),
}).then(result=>{
if(result && result.data){
resetFields();
@ -242,10 +247,11 @@ export default Form.create()(
<Fragment>
{type === '0' ?
<div>
<div className='tipsBox mb15'><img src={img1} alt="" width={16} className='mr10'/>更改邮箱后您在<span className='spanTil'>GitLink</span> 的登录账号接收通知的邮件地址将同步变更请谨慎更改!</div>
{/* <div className='tipsBox mb15'><img src={img1} alt="" width={16} className='mr10'/>更改邮箱后,您在<span className='spanTil'>GitLink</span> 的登录账号、接收通知的邮件地址将同步变更。请谨慎更改!</div> */}
<div className='tipsBox mb20 emailBox'>现邮箱地址<span className='ml10 email spanTil'>{current_user && current_user.email}</span></div>
<div className='updateEmail mb20'>更改邮箱</div>
<Form layout={'inline'} className="formBase passMan personalUpdateInfoForm">
<div>
<Form.Item label="登录密码" className={`${passMap.password ? 'hasSuccess' : ''}`}>
{getFieldDecorator("password1",{
rules:[
@ -257,6 +263,7 @@ export default Form.create()(
<Input.Password placeholder="请输入登录密码" autoComplete={"new-password"} style={{width:"400px"}}/>
)}
</Form.Item>
</div>
<Form.Item label="新邮箱地址" className={`${passMap.email ? 'hasSuccess' : ''}`}>
{getFieldDecorator("email",{
rules:[
@ -269,7 +276,7 @@ export default Form.create()(
<Input placeholder="请输入新邮箱地址" style={{width:"400px"}} autoComplete={"off"}/>
)}
</Form.Item>
<div>
{/* <div>
<Form.Item label="邮箱验证码" className={`${passMap.code ? 'hasSuccess' : ''}`}>
{getFieldDecorator("code",{
rules:[
@ -282,10 +289,10 @@ export default Form.create()(
)}
</Form.Item>
{countDown ? <Button className='getCaptchaBut ml50' disabled>重发 ({countDown})</Button> : <Button className='getCaptchaBut ml50' onClick={getCaptcha} disabled={!emailValue}>获取验证码</Button>}
</div>
</div> */}
<AlignCenter style={{marginTop:"20px"}}>
<span className="ant-form-item-label mr10"></span>
<Button className={`${passMap.password && passMap.email && passMap.code ? 'but25' : ''}`} type={"primary"} onClick={confirmUpdateEmail} disabled={!(passMap.password && passMap.email && passMap.code)}>确认更改</Button>
<Button className={`${passMap.password && passMap.email ? 'but25' : ''}`} type={"primary"} onClick={confirmUpdateEmail} disabled={!(passMap.password && passMap.email )}>确认更改</Button>
</AlignCenter>
</Form>
</div> :
@ -302,6 +309,7 @@ export default Form.create()(
<Input.Password placeholder="请输入旧密码" autoComplete={"new-password"} style={{width:"400px"}}/>
)}
</Form.Item>
<div>
<Form.Item label="新密码" className={`${updatePsdMap.password ? 'hasSuccess' : ''}`}>
{getFieldDecorator("password",{
rules:[
@ -314,6 +322,7 @@ export default Form.create()(
<Input.Password placeholder="请输入新密码" style={{width:"400px"}} onChange={(e)=>{setNewPass(e.target.value)}}/>
)}
</Form.Item>
</div>
<Form.Item label="确认新密码" className={`${updatePsdMap.password1 ? 'hasSuccess' : ''}`}>
{getFieldDecorator("new_password_repeat",{
rules:[

View File

@ -4,6 +4,7 @@ import Modals from '../../Component/PublicModal/Index';
import { AlignCenter } from '../../Component/layout';
import img1 from '../../Images/personalInfo3.png';
import { setmiyah } from '../../../common/Component';
import { Encrypt } from '../../../common/Env';
import Axios from 'axios';
@ -21,7 +22,7 @@ export default Form.create()(
const map = passMap;
if(value){
current_user && value.length > 7 && Axios.post(`/v1/${current_user.login}/check_password.json`,{
password: value
password: Encrypt(value)
}).then(res=>{
if(res && !res.data.status){
map.logpassword = value;
@ -138,16 +139,17 @@ export default Form.create()(
function confirmUpdatePhone(){
validateFields((error,values)=>{
if(!error){
setVisible(true);
// setVisible(true);
updateEmailOrPsd();
}
})
}
function updateEmailOrPsd(){
const {mescode, phone, logpassword} = getFieldsValue();
if(mescode && phone && logpassword){
if(phone && logpassword){
current_user && Axios.patch(`/v1/${current_user.login}/update_phone.json`,{
code:mescode, phone, password:logpassword
code:"123123", phone, password: Encrypt(logpassword)
}).then(res=>{
if(res && !res.data.status){
setPassMap({logpassword: undefined, phone: undefined, code: undefined});
@ -182,21 +184,23 @@ export default Form.create()(
<p>更改手机号后您在GitLink的登录账号将同步变更请再次确认</p>
</div>
</Modals>
<div className='tipsBox mb15'><img src={img1} alt="" width={16} className='mr10'/>更改手机号后您在<span className='spanTil'>GitLink</span> 的登录账号将同步变更请谨慎更改!</div>
{/* <div className='tipsBox mb15'><img src={img1} alt="" width={16} className='mr10'/>更改手机号后,您在<span className='spanTil'>GitLink</span> 的登录账号将同步变更。请谨慎更改!</div> */}
{current_user && current_user.phone && <div className='tipsBox mb20 emailBox'>现手机号码<span className='ml10 email spanTil'>{current_user.phone}</span></div> }
<div className='updateEmail mb20'>更改手机号</div>
<Form layout={'inline'} className="formBase passMan personalUpdateInfoForm">
<Form.Item label="登录密码" className={`${passMap.logpassword ? 'hasSuccess' : ''}`}>
{getFieldDecorator("logpassword",{
rules:[
{required:true,message:"请输入登录密码"},
{validator:(rule, value, callback)=>checkPsd(rule, value, callback)}
],
validateTrigger:"onChange",
})(
<Input.Password placeholder="请输入登录密码" autoComplete={"new-password"} style={{width:"400px"}}/>
)}
</Form.Item>
<div>
<Form.Item label="登录密码" className={`${passMap.logpassword ? 'hasSuccess' : ''}`}>
{getFieldDecorator("logpassword",{
rules:[
{required:true,message:"请输入登录密码"},
{validator:(rule, value, callback)=>checkPsd(rule, value, callback)}
],
validateTrigger:"onChange",
})(
<Input.Password placeholder="请输入登录密码" autoComplete={"new-password"} style={{width:"400px"}}/>
)}
</Form.Item>
</div>
<Form.Item label="新手机号码" className={`${passMap.phone ? 'hasSuccess' : ''}`}>
{getFieldDecorator("phone",{
rules:[
@ -208,7 +212,7 @@ export default Form.create()(
<Input placeholder="请输入新手机号码" style={{width:"400px"}} autoComplete={"off"}/>
)}
</Form.Item>
<div>
{/* <div>
<Form.Item label="短信验证码" className={`${passMap.mescode ? 'hasSuccess' : ''}`}>
{getFieldDecorator("mescode",{
rules:[
@ -221,10 +225,10 @@ export default Form.create()(
)}
</Form.Item>
{countDown ? <Button className='getCaptchaBut ml50' disabled>重发 ({countDown})</Button> : <Button className='getCaptchaBut ml50' onClick={getCaptcha} disabled={!phoneValue}>获取验证码</Button>}
</div>
</div> */}
<AlignCenter style={{marginTop:"20px"}}>
<span className="ant-form-item-label mr10"></span>
<Button onClick={confirmUpdatePhone} className={`${passMap.logpassword && passMap.phone && passMap.mescode ? 'but25' : ''}`} type={"primary"} disabled={!(passMap.logpassword && passMap.phone && passMap.mescode)}>确认更改</Button>
<Button onClick={confirmUpdatePhone} className={`${passMap.logpassword && passMap.phone ? 'but25' : ''}`} type={"primary"} disabled={!(passMap.logpassword && passMap.phone)}>确认更改</Button>
</AlignCenter>
</Form>
</div>

View File

@ -0,0 +1,73 @@
import React , { forwardRef, useState } from 'react';
import { Modal , Form , Button , Input } from 'antd';
import Axios from 'axios';
import { Encrypt } from '../../../../common/Env';
const { TextArea } = Input;
export default Form.create()(forwardRef((props)=>{
const { getFieldDecorator , validateFields } = props && props.form;
const { onCancel, visible , current_user} = props;
const [ loading , setLoading ] =useState(false);
function onDelete(){
validateFields((error,values)=>{
if(!error && current_user){
const { password } = values;
setLoading(true);
const url = `/v1/${current_user.login}.json`;
Axios.delete(url,{
data:{...values,password:Encrypt(password)}
}).then(result=>{
if(result.data && result.data.status === 0){
window.location.href = `/`;
onCancel();
}
setLoading(false);
}).catch(error=>{setLoading(false);})
}
})
}
return(
<Modal
title="注销账号"
width={560}
visible={visible}
footer={null}
onCancel={onCancel}
destroyOnClose={true}
>
<div>
<p className='AlignCenter font-bd font-17'><i className='iconfont icon-shanchu_important font-25 color-red mr5'/>是否仍要注销</p>
<p className='mt15'>注销后你将丢失该帐号产生的所有数据一旦注销相关数据将不可恢复请输入登录密码再次确认</p>
<Form className='mt25'>
<Form.Item label="密码校验">
{getFieldDecorator("password",{
rules:[
{required:true,message:"请输入登录密码"},
// {validator:(rule, value, callback)=>checkNewPass(rule, value, callback, NewPassRepeat)}
],
validateFirst: true,
validateTrigger:"onBlur",
})(
<Input.Password placeholder="请输入登录密码"/>
)}
</Form.Item>
<Form.Item label="注销原因">
{getFieldDecorator("memo",{
rules:[{required:true,message:"请输入注销原因"}],
})(
<TextArea rows={3} maxLength={500} placeholder="我们非常遗憾看到您想要注销账号。在您做出最终决定之前,请告诉我们您注销的原因,这将帮助我们改进社区服务。您的反馈对我们至关重要。"
/>
)}
</Form.Item>
</Form>
<div style={{textAlign:"center"}}>
<Button onClick={onDelete} style={{minWidth:"95px"}} loading={loading}>仍要注销</Button>
<Button type={"primary"} style={{width:"95px"}} className='ml25' onClick={onCancel}>再想想</Button>
</div>
</div>
</Modal>
)})
)

BIN
src/images/headerBg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

View File

@ -186,4 +186,71 @@ i.color-orange05:hover {
.color-light-green {
color: #29bd8b !important;
}
.AlignTop {
display:flex;
align-items: flex-start
}
.WhiteBack {
background-color:#fff;
border-radius:5px
}
.Box {
display:flex;
align-items:flex-start
}
.LongWidth {
flex:1;
width:0;
border-radius:5px;
margin-bottom:30px
}
.ShortWidth {
width:300px;
border-radius:5px;
margin-bottom:30px
}
.Gap {
padding-left:20px;
box-sizing:border-box;
}
.AlignCenter {
display:flex;
align-items: center
}
.FlexAJ {
display:flex;
align-items: center;
justify-content: space-between
}
.mt25 {
margin-top:25px
}
.User {
display:flex;
font-weight: bold;
align-items: center
}
.User img {
width:30px;
height:30px;
border-radius:50%
}
.User span {
margin-left:8px
}
.latex-error {
border: 1px solid #ff818266;
border-radius: 6px;
background-color: #ffebe9;
padding: 10px 8px;
font-size: 12px;
margin-bottom: 5px;
}
.test-iframe {
margin-top: -48px;
vertical-align:bottom;
height: 100vh;
}

View File

@ -16,10 +16,7 @@ class Shixunauthority extends Component {
{(!current_user || !current_user.login) && (
<p style={{display:"inline"}}>您可尝试<a href={`/login`} className="color-blue">登录</a></p>
)}
<a href="/" className="color-blue">返回首页</a>
<a target="_blank"
href="https://qm.qq.com/cgi-bin/qm/qr?k=YVGUhY7uK8ovpyd7tG_lHe2qGZ63LOij&jump_from=webapi"
className="color-blue">QQ</a>
<a href="/" className="color-blue">返回首页</a>
</p>
</div>
{/*<div style="clear:both;"></div>*/}

View File

@ -17,10 +17,6 @@ class http500 extends Component {
<p style={{display:"inline"}}>您可尝试<a href={`/login`} className="color-blue">登录</a></p>
)}
<a href="/" className="color-blue">返回首页</a>
也可通过
<a target="_blank"
href="https://qm.qq.com/cgi-bin/qm/qr?k=YVGUhY7uK8ovpyd7tG_lHe2qGZ63LOij&jump_from=webapi"
className="color-blue">QQ</a>
</p>
</div>
{/*<div style="clear:both;"></div>*/}

View File

@ -11,11 +11,7 @@ class Shixunnopage extends Component {
<p className="font-16 mt56 newImages">
<p>服务器异常请稍后重试</p>
您可尝试<a href="javascript:location.reload();" className="color-blue">刷新页面</a>或<a href="/"
className="color-blue">返回首页</a>
也可以通过
<a target="_blank"
href="https://qm.qq.com/cgi-bin/qm/qr?k=YVGUhY7uK8ovpyd7tG_lHe2qGZ63LOij&jump_from=webapi"
className="color-blue">QQ</a>
className="color-blue">返回首页</a>
</p>
</div>
</div>

View File

@ -13,6 +13,7 @@ import cookie from 'react-cookies';
import './LoginDialog.css';
import { broadcastChannelPostMessage } from 'educoder'
import Notcompletedysl from "../user/Notcompletedysl";
import { Encrypt } from '../../common/Env';
const $ = window.$;
var wait = 60;
@ -331,7 +332,7 @@ class LoginDialog extends Component {
this.setState({
isphone: flag,
//查询第三方登录信息
settings: JSON.parse(localStorage.getItem("chromesetting")),
settings: localStorage.getItem("chromesetting") !=="undefined" && JSON.parse(localStorage.getItem("chromesetting")),
})
if (this.props.isRender != undefined) {
@ -371,7 +372,7 @@ class LoginDialog extends Component {
let url = '/accounts/login.json'
axios.post(url, {
login: newloginValue,
password: newpassValue,
password: Encrypt(newpassValue),
autologin: isGoingValue
}
).then((response) => {

View File

@ -10,6 +10,7 @@ import axios from 'axios';
import OtherLogin from "./component/otherLogin";
import cookie from 'react-cookies';
import './LoginRegisterPage.scss';
import { Encrypt } from "../../common/Env";
function Login(props){
const [message,setMessage] = useState();
@ -18,6 +19,7 @@ function Login(props){
const {getFieldDecorator } = form;
const {search} = location;
useEffect(()=>{
//DOMvalue
clear();
@ -40,7 +42,7 @@ function Login(props){
if (!err) {
axios.post(`/accounts/login.json`, {
login: values.username,
password: values.password,
password: Encrypt(values.password),
autologin: values.remember?1:0,
}).then((response) => {
if (!response.data.login) {
@ -78,7 +80,7 @@ function Login(props){
<div>
<div className="right_cont login_content">
<div className="login_register_head mb30">
<span>欢迎登录 GitLink</span>
<span>欢迎登录 {mygetHelmetapi && mygetHelmetapi.name}</span>
<span className="link_span">没有账号<Link to={`/register`}>去注册</Link></span>
</div>
<p className = {message?"message active mb10":"message"}>{message}</p>
@ -116,7 +118,7 @@ function Login(props){
initialValue: cookie.load('autologin'),
})(<Checkbox>下次自动登录</Checkbox>)}
</Form.Item>
<Link to="/resetPassword" className="goResetPsdBut">忘记密码</Link>
{/* <Link to="/resetPassword" className="goResetPsdBut">忘记密码?</Link> */}
</div>
<Button type="primary" htmlType="submit" onClick={handleSubmit} className="login_register_cofBut">登录</Button>
</Form>
@ -137,7 +139,7 @@ function Login(props){
// })
// }
// </p>
<OtherLogin />
// <OtherLogin />
}
</div>
</div>

View File

@ -0,0 +1,159 @@
import React, { useEffect, useState } from "react";
import { Form, Input, Button, Checkbox , Tooltip } from "antd";
import { Link } from "react-router-dom";
import axios from 'axios';
// import educoderLogo from '../login/educoder.png';
// import qqlogo from '../login/qq@2x.png';
// import WeChatlogo from '../login/WeChat@2x.png';
// import giteelogo from '../login/gitee.png';
// import githublogo from '../login/github.png';
import cookie from 'react-cookies';
import './LoginRegisterPageNew.scss';
import { Encrypt } from "../../common/Env";
import { getOrzCompanyList } from "../../forge/Information/api";
function Login(props){
const [message,setMessage] = useState();
// const [setting, setSetting] = useState(undefined);
const {form, location, mygetHelmetapi} = props;
const {getFieldDecorator } = form;
const {search} = location;
useEffect(()=>{
//DOMvalue
clear();
//
// setSetting(JSON.parse(localStorage.getItem("chromesetting")));
},[])
//
useEffect(()=>{
if(mygetHelmetapi){
const {name} = mygetHelmetapi;
document.title = name;
}
}, [mygetHelmetapi])
//
function handleSubmit(){
setMessage(undefined);
form.validateFields((err, values) => {
if (!err) {
axios.post(`/accounts/login.json`, {
login: values.username,
password: Encrypt(values.password),
autologin: values.remember?1:0,
}).then((response) => {
if (!response.data.login) {
response.data.status === -2 ? setMessage(response.data.message) : setMessage("错误的账号或密码");
} else {
//
cookie.save('autologin',values.remember);
cookie.save('supplyphone',true);
cookie.save("login",response.data.login);
//
const searchParams = new URLSearchParams(search.substring(1));
const goPage = searchParams.get("go_page");
//
if(goPage){
window.location.href = goPage
}else{
getOrzCompanyList().then(res=>{
if(res && res.data && res.data.rows && res.data.rows[0]){
window.location.href = `${ mygetHelmetapi && mygetHelmetapi.common.zone }/${res.data.rows[0].enterpriseIdentifier}`
}else{
window.location.href = `/${response.data.login}`
}
}).catch(()=>{
window.location.href = `/${response.data.login}`
})
}
}
}).catch((error) => {
console.log('error',error);
})
}
});
}
//value->DOM
function clear(){
const password = document.getElementById("login_password");
if(password && password.type==="password"){
setTimeout(()=>{
password.removeAttribute('value');
},0)
}
}
return(
<div className="right_cont login_content">
<div className="login_register_head mb60">
<p>欢迎登录 <span className="head_blue">{mygetHelmetapi && mygetHelmetapi.name}</span></p>
</div>
<p className = {message?"message active mb10":"message"}>{message}</p>
<Form className="login-form">
<Form.Item>
{getFieldDecorator('username',{
rules:[
{
required:true,
message:"请输入手机号/邮箱/用户名"
}
],
validateTrigger:"onBlur",
})(<Input className="account" placeholder="请输入手机号/邮箱/用户名" prefix={<div className="input_icon"></div>} />)}
</Form.Item>
<Form.Item>
{getFieldDecorator('password', {
rules: [
{
required:true,
message:"请输入登录密码"
}
],
validateTrigger:"onBlur",
})(
<Input.Password className="psd" placeholder="请输入登录密码" onBlur={clear} onChange={clear} prefix={<div className="input_icon"></div>} />,
)}
</Form.Item>
<div className="login_register_head login mb60">
<Form.Item>
{getFieldDecorator('remember', {
valuePropName: 'checked',
initialValue: cookie.load('autologin'),
})(<Checkbox>下次自动登录</Checkbox>)}
</Form.Item>
{/* <Link to="/resetPassword" className="goResetPsdBut">忘记密码?</Link> */}
</div>
<Button type="primary" htmlType="submit" onClick={handleSubmit} className="login_register_cofBut">登录</Button>
</Form>
<div className="link_span">没有账号<Link to={`/register`}>去注册</Link></div>
{
// setting && setting.third_party_new && setting.third_party_new.length > 0 ?
// <p className="quick_logon">
// <p className="quick_logon_p"></p>
// <span className={"startlogin"}>&nbsp;&nbsp;</span>
// {setting.third_party_new.map((item,key)=>{
// return(
// <a href={`${item.url}`} className="ml15 mr15">
// <Tooltip title={`使${item.name === "qq" ? "QQ":item.name === "wechat" ? "" : item.name}`}>
// <img src={item.name === "educoder" ? educoderLogo : item.name === "qq" ? qqlogo : item.name === "wechat" ? WeChatlogo : item.name === "gitee" ? giteelogo : item.name === "github" ? githublogo : ""} width="46px" alt={`${item.name}`}/>
// </Tooltip>
// </a>
// )
// })
// }
// </p>
// <OtherLogin />
}
</div>
)
}
export default Form.create({ name: 'login' })(Login);

View File

@ -14,7 +14,7 @@ function LoginRegisterPage(props){
return(
<div className="loginRegister">
<div className="login_register_left">
<img src={logo} className="logo" alt="" onClick={()=>{window.location.href='/'}} />
{/* <img src={logo} className="logo" alt="" onClick={()=>{window.location.href='/'}} /> */}
<img src={ball} className="ball" alt="" />
<img src={banner} className="banner" alt="" />
</div>

View File

@ -15,19 +15,19 @@
margin-top: 45vh;
height: auto;
}
.ball{ top: 51vh; }
.ball{ top: 36vh; }
.right_cont{width: 540px; }
.ResetPassword_content{top: 12vh; }
}
/*当页面宽度大于1280px*/
@media screen and (min-width:1280px) {
.banner{ margin-top: 35vh; }
.ball{ top: 43vh; }
.ball{ top: 28vh; }
}
/*当页面宽度大于1680px*/
@media screen and (min-width:1680px) {
.banner{ height: 460px; }
.ball{ top: 42vh; }
.ball{ top: 27vh; }
.right_cont{width: 580px; }
.ResetPassword_content{top: 16vh; }
}
@ -73,7 +73,7 @@
position: absolute;
z-index: 2;
left: 45vw;
padding: 2.5em 5em;
padding: 2.5em 4em;
border-radius: 7px;
font-size: 15px;
top: 50%;

View File

@ -0,0 +1,25 @@
import React from "react";
import Login from "./LoginNew";
import Register from "./RegisterNew";
import ResetPassword from "./ResetPasswordNew";
import '../loginRegister/LoginRegisterPageNew.scss';
function LoginRegisterPage(props){
const {mygetHelmetapi} = props;
return(
<div className="loginRegister">
<div className="login_register_right">
{props.location.pathname === "/login" ?
<Login {...props}/>
:
props.location.pathname === "/register" ?
<Register mygetHelmetapi={mygetHelmetapi}/>
:
<ResetPassword mygetHelmetapi={mygetHelmetapi}/>
}
</div>
<div className="clear"></div>
</div>
)
}
export default LoginRegisterPage;

View File

@ -0,0 +1,161 @@
@import url(./font/font.css);
.loginRegister{
height: 100vh;
width: 100vw;
background-image: url(./img/bg1.png);
background-repeat: no-repeat;
background-size: 100% 100%;
display: flex;
align-items: center;
justify-content: center;
font-family: alibaba;
}
.clear{
clear: both;
}
.login_register_right {
width: 1200px;
height: 705px;
background:#ffffff;
box-shadow:0px 0px 20px rgba(37, 106, 206, 0.14);
background-image: url(./img/bglogin.png);
background-repeat: no-repeat;
background-size: 50% 100%;
.Register_content {
padding: 70px 75px 70px 75px;
.registerNav {
margin-bottom: 28px;
a {
color: #445a7a;
display: inline-block;
height: 26px;
line-height: 26px;
}
.activeRegisterNav {
font-family: alibaba-medium;
color: #0d5ef8;
border-bottom: 2px solid #0d5ef8;
}
}
.ant-form-item {
margin-bottom: 34px;
}
}
.login_content {
padding: 105px 75px 113px 75px;
.ant-form-item {
margin-bottom: 40px;
}
}
.right_cont {
height: 100%;
width: 50%;
margin-left: auto;
display: flex;
flex-direction: column;
justify-content: space-between;
.login_register_head {
font-family: alibaba-medium;
color: #283444;
font-size: 28px;
line-height: 28px;
.head_blue {
font-size: 26px;
color: #0d5ef8;
}
}
.account {
.input_icon::before {
background-image: url(./img/icon1.png);
}
&:hover {
.input_icon::before {
background-image: url(./img/icon2.png);
}
}
}
.psd, .psdComfirm, .register_psd {
.input_icon::before {
background-image: url(./img/icon3.png);
}
&:hover {
.input_icon::before {
background-image: url(./img/icon4.png);
}
}
}
.email {
.input_icon::before {
background-image: url(./img/icon7.png);
}
&:hover {
.input_icon::before {
background-image: url(./img/icon8.png);
}
}
}
.phone {
.input_icon::before {
background-image: url(./img/icon5.png);
}
&:hover {
.input_icon::before {
background-image: url(./img/icon6.png);
}
}
}
.input_icon {
margin-left: 50px;
width: 0px;
height: 30px;
border: 1px solid;
border-color: rgba(20, 49, 179, 0.12);
&::before {
transform: translate( 50%, -50%);
position: absolute;
content: "";
left: 0;
top: 50%;
width: 22px;
height: 22px;
background-image: url(./img/icon1.png);
background-repeat: no-repeat;
background-size: 100% 100%;
}
}
.ant-input{
width: 450px;
height: 48px;
border: 1px solid;
border-color: #9eaacb;
border-radius: 4px;
background: #FFFFFF !important;
color: #283444;
padding-left: 80px;
&:hover{
background: rgba(0, 88, 255, 0.03);
border-color: #0d5ef8;
}
}
.login_register_cofBut {
width: 450px;
height: 56px;
background: #0d5ef8;
border-radius: 10px;
color: #ffffff;
font-size: 16px;
}
.link_span {
font-size:14px;
line-height: 20px;
display: flex;
align-items: center;
justify-content: center;
margin-top: 20px;
a {
color: #0d5ef8;
}
}
}
}

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